/Modules/dlmodule.c

http://unladen-swallow.googlecode.com/ · C · 284 lines · 243 code · 27 blank · 14 comment · 42 complexity · f48fc84fa79d8bef18d71f9b5b43bd58 MD5 · raw file

  1. /* dl module */
  2. #include "Python.h"
  3. #include <dlfcn.h>
  4. #ifdef __VMS
  5. #include <unistd.h>
  6. #endif
  7. #ifndef RTLD_LAZY
  8. #define RTLD_LAZY 1
  9. #endif
  10. typedef void *PyUnivPtr;
  11. typedef struct {
  12. PyObject_HEAD
  13. PyUnivPtr *dl_handle;
  14. } dlobject;
  15. static PyTypeObject Dltype;
  16. static PyObject *Dlerror;
  17. static PyObject *
  18. newdlobject(PyUnivPtr *handle)
  19. {
  20. dlobject *xp;
  21. xp = PyObject_New(dlobject, &Dltype);
  22. if (xp == NULL)
  23. return NULL;
  24. xp->dl_handle = handle;
  25. return (PyObject *)xp;
  26. }
  27. static void
  28. dl_dealloc(dlobject *xp)
  29. {
  30. if (xp->dl_handle != NULL)
  31. dlclose(xp->dl_handle);
  32. PyObject_Del(xp);
  33. }
  34. static PyObject *
  35. dl_close(dlobject *xp)
  36. {
  37. if (xp->dl_handle != NULL) {
  38. dlclose(xp->dl_handle);
  39. xp->dl_handle = NULL;
  40. }
  41. Py_INCREF(Py_None);
  42. return Py_None;
  43. }
  44. static PyObject *
  45. dl_sym(dlobject *xp, PyObject *args)
  46. {
  47. char *name;
  48. PyUnivPtr *func;
  49. if (PyString_Check(args)) {
  50. name = PyString_AS_STRING(args);
  51. } else {
  52. PyErr_Format(PyExc_TypeError, "expected string, found %.200s",
  53. Py_TYPE(args)->tp_name);
  54. return NULL;
  55. }
  56. func = dlsym(xp->dl_handle, name);
  57. if (func == NULL) {
  58. Py_INCREF(Py_None);
  59. return Py_None;
  60. }
  61. return PyInt_FromLong((long)func);
  62. }
  63. static PyObject *
  64. dl_call(dlobject *xp, PyObject *args)
  65. {
  66. PyObject *name;
  67. long (*func)(long, long, long, long, long,
  68. long, long, long, long, long);
  69. long alist[10];
  70. long res;
  71. Py_ssize_t i;
  72. Py_ssize_t n = PyTuple_Size(args);
  73. if (n < 1) {
  74. PyErr_SetString(PyExc_TypeError, "at least a name is needed");
  75. return NULL;
  76. }
  77. name = PyTuple_GetItem(args, 0);
  78. if (!PyString_Check(name)) {
  79. PyErr_SetString(PyExc_TypeError,
  80. "function name must be a string");
  81. return NULL;
  82. }
  83. func = (long (*)(long, long, long, long, long,
  84. long, long, long, long, long))
  85. dlsym(xp->dl_handle, PyString_AsString(name));
  86. if (func == NULL) {
  87. PyErr_SetString(PyExc_ValueError, dlerror());
  88. return NULL;
  89. }
  90. if (n-1 > 10) {
  91. PyErr_SetString(PyExc_TypeError,
  92. "too many arguments (max 10)");
  93. return NULL;
  94. }
  95. for (i = 1; i < n; i++) {
  96. PyObject *v = PyTuple_GetItem(args, i);
  97. if (PyInt_Check(v))
  98. alist[i-1] = PyInt_AsLong(v);
  99. else if (PyString_Check(v))
  100. alist[i-1] = (long)PyString_AsString(v);
  101. else if (v == Py_None)
  102. alist[i-1] = (long) ((char *)NULL);
  103. else {
  104. PyErr_SetString(PyExc_TypeError,
  105. "arguments must be int, string or None");
  106. return NULL;
  107. }
  108. }
  109. for (; i <= 10; i++)
  110. alist[i-1] = 0;
  111. res = (*func)(alist[0], alist[1], alist[2], alist[3], alist[4],
  112. alist[5], alist[6], alist[7], alist[8], alist[9]);
  113. return PyInt_FromLong(res);
  114. }
  115. static PyMethodDef dlobject_methods[] = {
  116. {"call", (PyCFunction)dl_call, METH_VARARGS},
  117. {"sym", (PyCFunction)dl_sym, METH_O},
  118. {"close", (PyCFunction)dl_close, METH_NOARGS},
  119. {NULL, NULL} /* Sentinel */
  120. };
  121. static PyObject *
  122. dl_getattr(dlobject *xp, char *name)
  123. {
  124. return Py_FindMethod(dlobject_methods, (PyObject *)xp, name);
  125. }
  126. static PyTypeObject Dltype = {
  127. PyVarObject_HEAD_INIT(NULL, 0)
  128. "dl.dl", /*tp_name*/
  129. sizeof(dlobject), /*tp_basicsize*/
  130. 0, /*tp_itemsize*/
  131. /* methods */
  132. (destructor)dl_dealloc, /*tp_dealloc*/
  133. 0, /*tp_print*/
  134. (getattrfunc)dl_getattr,/*tp_getattr*/
  135. 0, /*tp_setattr*/
  136. 0, /*tp_compare*/
  137. 0, /*tp_repr*/
  138. 0, /*tp_as_number*/
  139. 0, /*tp_as_sequence*/
  140. 0, /*tp_as_mapping*/
  141. 0, /*tp_hash*/
  142. };
  143. static PyObject *
  144. dl_open(PyObject *self, PyObject *args)
  145. {
  146. char *name;
  147. int mode;
  148. PyUnivPtr *handle;
  149. if (sizeof(int) != sizeof(long) ||
  150. sizeof(long) != sizeof(char *)) {
  151. PyErr_SetString(PyExc_SystemError,
  152. "module dl requires sizeof(int) == sizeof(long) == sizeof(char*)");
  153. return NULL;
  154. }
  155. if (PyArg_ParseTuple(args, "z:open", &name))
  156. mode = RTLD_LAZY;
  157. else {
  158. PyErr_Clear();
  159. if (!PyArg_ParseTuple(args, "zi:open", &name, &mode))
  160. return NULL;
  161. #ifndef RTLD_NOW
  162. if (mode != RTLD_LAZY) {
  163. PyErr_SetString(PyExc_ValueError, "mode must be 1");
  164. return NULL;
  165. }
  166. #endif
  167. }
  168. handle = dlopen(name, mode);
  169. if (handle == NULL) {
  170. char *errmsg = dlerror();
  171. if (!errmsg)
  172. errmsg = "dlopen() error";
  173. PyErr_SetString(Dlerror, errmsg);
  174. return NULL;
  175. }
  176. #ifdef __VMS
  177. /* Under OpenVMS dlopen doesn't do any check, just save the name
  178. * for later use, so we have to check if the file is readable,
  179. * the name can be a logical or a file from SYS$SHARE.
  180. */
  181. if (access(name, R_OK)) {
  182. char fname[strlen(name) + 20];
  183. strcpy(fname, "SYS$SHARE:");
  184. strcat(fname, name);
  185. strcat(fname, ".EXE");
  186. if (access(fname, R_OK)) {
  187. dlclose(handle);
  188. PyErr_SetString(Dlerror,
  189. "File not found or protection violation");
  190. return NULL;
  191. }
  192. }
  193. #endif
  194. return newdlobject(handle);
  195. }
  196. static PyMethodDef dl_methods[] = {
  197. {"open", dl_open, METH_VARARGS},
  198. {NULL, NULL} /* sentinel */
  199. };
  200. /* From socketmodule.c
  201. * Convenience routine to export an integer value.
  202. *
  203. * Errors are silently ignored, for better or for worse...
  204. */
  205. static void
  206. insint(PyObject *d, char *name, int value)
  207. {
  208. PyObject *v = PyInt_FromLong((long) value);
  209. if (!v || PyDict_SetItemString(d, name, v))
  210. PyErr_Clear();
  211. Py_XDECREF(v);
  212. }
  213. PyMODINIT_FUNC
  214. initdl(void)
  215. {
  216. PyObject *m, *d, *x;
  217. if (PyErr_WarnPy3k("the dl module has been removed in "
  218. "Python 3.0; use the ctypes module instead", 2) < 0)
  219. return;
  220. /* Initialize object type */
  221. Py_TYPE(&Dltype) = &PyType_Type;
  222. /* Create the module and add the functions */
  223. m = Py_InitModule("dl", dl_methods);
  224. if (m == NULL)
  225. return;
  226. /* Add some symbolic constants to the module */
  227. d = PyModule_GetDict(m);
  228. Dlerror = x = PyErr_NewException("dl.error", NULL, NULL);
  229. PyDict_SetItemString(d, "error", x);
  230. x = PyInt_FromLong((long)RTLD_LAZY);
  231. PyDict_SetItemString(d, "RTLD_LAZY", x);
  232. #define INSINT(X) insint(d,#X,X)
  233. #ifdef RTLD_NOW
  234. INSINT(RTLD_NOW);
  235. #endif
  236. #ifdef RTLD_NOLOAD
  237. INSINT(RTLD_NOLOAD);
  238. #endif
  239. #ifdef RTLD_GLOBAL
  240. INSINT(RTLD_GLOBAL);
  241. #endif
  242. #ifdef RTLD_LOCAL
  243. INSINT(RTLD_LOCAL);
  244. #endif
  245. #ifdef RTLD_PARENT
  246. INSINT(RTLD_PARENT);
  247. #endif
  248. #ifdef RTLD_GROUP
  249. INSINT(RTLD_GROUP);
  250. #endif
  251. #ifdef RTLD_WORLD
  252. INSINT(RTLD_WORLD);
  253. #endif
  254. #ifdef RTLD_NODELETE
  255. INSINT(RTLD_NODELETE);
  256. #endif
  257. }