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