• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 (PyInt_Check(v))
111             alist[i-1] = PyInt_AsLong(v);
112         else if (PyString_Check(v))
113             alist[i-1] = (long)PyString_AsString(v);
114         else if (v == Py_None)
115             alist[i-1] = (long) ((char *)NULL);
116         else {
117             PyErr_SetString(PyExc_TypeError,
118                        "arguments must be int, string or None");
119             return NULL;
120         }
121     }
122     for (; i <= 10; i++)
123         alist[i-1] = 0;
124     res = (*func)(alist[0], alist[1], alist[2], alist[3], alist[4],
125                   alist[5], alist[6], alist[7], alist[8], alist[9]);
126     return PyInt_FromLong(res);
127 }
128 
129 static PyMethodDef dlobject_methods[] = {
130     {"call",            (PyCFunction)dl_call, METH_VARARGS},
131     {"sym",             (PyCFunction)dl_sym, METH_O},
132     {"close",           (PyCFunction)dl_close, METH_NOARGS},
133     {NULL,              NULL}                    /* Sentinel */
134 };
135 
136 static PyObject *
dl_getattr(dlobject * xp,char * name)137 dl_getattr(dlobject *xp, char *name)
138 {
139     return Py_FindMethod(dlobject_methods, (PyObject *)xp, name);
140 }
141 
142 
143 static PyTypeObject Dltype = {
144     PyVarObject_HEAD_INIT(NULL, 0)
145     "dl.dl",                    /*tp_name*/
146     sizeof(dlobject),           /*tp_basicsize*/
147     0,                          /*tp_itemsize*/
148     /* methods */
149     (destructor)dl_dealloc, /*tp_dealloc*/
150     0,                          /*tp_print*/
151     (getattrfunc)dl_getattr,/*tp_getattr*/
152     0,                          /*tp_setattr*/
153     0,                          /*tp_compare*/
154     0,                          /*tp_repr*/
155     0,                          /*tp_as_number*/
156     0,                          /*tp_as_sequence*/
157     0,                          /*tp_as_mapping*/
158     0,                          /*tp_hash*/
159 };
160 
161 static PyObject *
dl_open(PyObject * self,PyObject * args)162 dl_open(PyObject *self, PyObject *args)
163 {
164     char *name;
165     int mode;
166     PyUnivPtr *handle;
167     if (sizeof(int) != sizeof(long) ||
168         sizeof(long) != sizeof(char *)) {
169         PyErr_SetString(PyExc_SystemError,
170  "module dl requires sizeof(int) == sizeof(long) == sizeof(char*)");
171                 return NULL;
172     }
173 
174     if (PyArg_ParseTuple(args, "z:open", &name))
175         mode = RTLD_LAZY;
176     else {
177         PyErr_Clear();
178         if (!PyArg_ParseTuple(args, "zi:open", &name, &mode))
179             return NULL;
180 #ifndef RTLD_NOW
181         if (mode != RTLD_LAZY) {
182             PyErr_SetString(PyExc_ValueError, "mode must be 1");
183             return NULL;
184         }
185 #endif
186     }
187     handle = dlopen(name, mode);
188     if (handle == NULL) {
189         char *errmsg = dlerror();
190         if (!errmsg)
191             errmsg = "dlopen() error";
192         PyErr_SetString(Dlerror, errmsg);
193         return NULL;
194     }
195 #ifdef __VMS
196     /*   Under OpenVMS dlopen doesn't do any check, just save the name
197      * for later use, so we have to check if the file is readable,
198      * the name can be a logical or a file from SYS$SHARE.
199      */
200     if (access(name, R_OK)) {
201         char fname[strlen(name) + 20];
202         strcpy(fname, "SYS$SHARE:");
203         strcat(fname, name);
204         strcat(fname, ".EXE");
205         if (access(fname, R_OK)) {
206             dlclose(handle);
207             PyErr_SetString(Dlerror,
208                 "File not found or protection violation");
209             return NULL;
210         }
211     }
212 #endif
213     return newdlobject(handle);
214 }
215 
216 static PyMethodDef dl_methods[] = {
217     {"open",            dl_open, METH_VARARGS},
218     {NULL,              NULL}           /* sentinel */
219 };
220 
221 /* From socketmodule.c
222  * Convenience routine to export an integer value.
223  *
224  * Errors are silently ignored, for better or for worse...
225  */
226 static void
insint(PyObject * d,char * name,int value)227 insint(PyObject *d, char *name, int value)
228 {
229     PyObject *v = PyInt_FromLong((long) value);
230     if (!v || PyDict_SetItemString(d, name, v))
231         PyErr_Clear();
232 
233     Py_XDECREF(v);
234 }
235 
236 PyMODINIT_FUNC
initdl(void)237 initdl(void)
238 {
239     PyObject *m, *d, *x;
240 
241     if (PyErr_WarnPy3k("the dl module has been removed in "
242                         "Python 3.0; use the ctypes module instead", 2) < 0)
243         return;
244 
245     /* Initialize object type */
246     Py_TYPE(&Dltype) = &PyType_Type;
247 
248     /* Create the module and add the functions */
249     m = Py_InitModule("dl", dl_methods);
250     if (m == NULL)
251         return;
252 
253     /* Add some symbolic constants to the module */
254     d = PyModule_GetDict(m);
255     Dlerror = x = PyErr_NewException("dl.error", NULL, NULL);
256     PyDict_SetItemString(d, "error", x);
257     x = PyInt_FromLong((long)RTLD_LAZY);
258     PyDict_SetItemString(d, "RTLD_LAZY", x);
259 #define INSINT(X)    insint(d,#X,X)
260 #ifdef RTLD_NOW
261     INSINT(RTLD_NOW);
262 #endif
263 #ifdef RTLD_NOLOAD
264     INSINT(RTLD_NOLOAD);
265 #endif
266 #ifdef RTLD_GLOBAL
267     INSINT(RTLD_GLOBAL);
268 #endif
269 #ifdef RTLD_LOCAL
270     INSINT(RTLD_LOCAL);
271 #endif
272 #ifdef RTLD_PARENT
273     INSINT(RTLD_PARENT);
274 #endif
275 #ifdef RTLD_GROUP
276     INSINT(RTLD_GROUP);
277 #endif
278 #ifdef RTLD_WORLD
279     INSINT(RTLD_WORLD);
280 #endif
281 #ifdef RTLD_NODELETE
282     INSINT(RTLD_NODELETE);
283 #endif
284 }
285