1
2/* fcntl module */
3
4#define PY_SSIZE_T_CLEAN
5
6#include "Python.h"
7
8#ifdef HAVE_SYS_FILE_H
9#include <sys/file.h>
10#endif
11
12#include <sys/ioctl.h>
13#include <fcntl.h>
14#ifdef HAVE_STROPTS_H
15#include <stropts.h>
16#endif
17
18static int
19conv_descriptor(PyObject *object, int *target)
20{
21    int fd = PyObject_AsFileDescriptor(object);
22
23    if (fd < 0)
24    return 0;
25    *target = fd;
26    return 1;
27}
28
29
30/* fcntl(fd, opt, [arg]) */
31
32static PyObject *
33fcntl_fcntl(PyObject *self, PyObject *args)
34{
35    int fd;
36    int code;
37    long arg;
38    int ret;
39    char *str;
40    Py_ssize_t len;
41    char buf[1024];
42
43    if (PyArg_ParseTuple(args, "O&is#:fcntl",
44                         conv_descriptor, &fd, &code, &str, &len)) {
45        if (len > sizeof buf) {
46            PyErr_SetString(PyExc_ValueError,
47                            "fcntl string arg too long");
48            return NULL;
49        }
50        memcpy(buf, str, len);
51        Py_BEGIN_ALLOW_THREADS
52        ret = fcntl(fd, code, buf);
53        Py_END_ALLOW_THREADS
54        if (ret < 0) {
55            PyErr_SetFromErrno(PyExc_IOError);
56            return NULL;
57        }
58        return PyString_FromStringAndSize(buf, len);
59    }
60
61    PyErr_Clear();
62    arg = 0;
63    if (!PyArg_ParseTuple(args,
64         "O&i|l;fcntl requires a file or file descriptor,"
65         " an integer and optionally a third integer or a string",
66                          conv_descriptor, &fd, &code, &arg)) {
67      return NULL;
68    }
69    Py_BEGIN_ALLOW_THREADS
70    ret = fcntl(fd, code, arg);
71    Py_END_ALLOW_THREADS
72    if (ret < 0) {
73        PyErr_SetFromErrno(PyExc_IOError);
74        return NULL;
75    }
76    return PyInt_FromLong((long)ret);
77}
78
79PyDoc_STRVAR(fcntl_doc,
80"fcntl(fd, opt, [arg])\n\
81\n\
82Perform the requested operation on file descriptor fd.  The operation\n\
83is defined by op and is operating system dependent.  These constants are\n\
84available from the fcntl module.  The argument arg is optional, and\n\
85defaults to 0; it may be an int or a string.  If arg is given as a string,\n\
86the return value of fcntl is a string of that length, containing the\n\
87resulting value put in the arg buffer by the operating system.  The length\n\
88of the arg string is not allowed to exceed 1024 bytes.  If the arg given\n\
89is an integer or if none is specified, the result value is an integer\n\
90corresponding to the return value of the fcntl call in the C code.");
91
92
93/* ioctl(fd, opt, [arg]) */
94
95static PyObject *
96fcntl_ioctl(PyObject *self, PyObject *args)
97{
98#define IOCTL_BUFSZ 1024
99    int fd;
100    /* In PyArg_ParseTuple below, we use the unsigned non-checked 'I'
101       format for the 'code' parameter because Python turns 0x8000000
102       into either a large positive number (PyLong or PyInt on 64-bit
103       platforms) or a negative number on others (32-bit PyInt)
104       whereas the system expects it to be a 32bit bit field value
105       regardless of it being passed as an int or unsigned long on
106       various platforms.  See the termios.TIOCSWINSZ constant across
107       platforms for an example of thise.
108
109       If any of the 64bit platforms ever decide to use more than 32bits
110       in their unsigned long ioctl codes this will break and need
111       special casing based on the platform being built on.
112     */
113    unsigned int code;
114    int arg;
115    int ret;
116    char *str;
117    Py_ssize_t len;
118    int mutate_arg = 1;
119    char buf[IOCTL_BUFSZ+1];  /* argument plus NUL byte */
120
121    if (PyArg_ParseTuple(args, "O&Iw#|i:ioctl",
122                         conv_descriptor, &fd, &code,
123                         &str, &len, &mutate_arg)) {
124        char *arg;
125
126        if (mutate_arg) {
127            if (len <= IOCTL_BUFSZ) {
128                memcpy(buf, str, len);
129                buf[len] = '\0';
130                arg = buf;
131            }
132            else {
133                arg = str;
134            }
135        }
136        else {
137            if (len > IOCTL_BUFSZ) {
138                PyErr_SetString(PyExc_ValueError,
139                    "ioctl string arg too long");
140                return NULL;
141            }
142            else {
143                memcpy(buf, str, len);
144                buf[len] = '\0';
145                arg = buf;
146            }
147        }
148        if (buf == arg) {
149            Py_BEGIN_ALLOW_THREADS /* think array.resize() */
150            ret = ioctl(fd, code, arg);
151            Py_END_ALLOW_THREADS
152        }
153        else {
154            ret = ioctl(fd, code, arg);
155        }
156        if (mutate_arg && (len <= IOCTL_BUFSZ)) {
157            memcpy(str, buf, len);
158        }
159        if (ret < 0) {
160            PyErr_SetFromErrno(PyExc_IOError);
161            return NULL;
162        }
163        if (mutate_arg) {
164            return PyInt_FromLong(ret);
165        }
166        else {
167            return PyString_FromStringAndSize(buf, len);
168        }
169    }
170
171    PyErr_Clear();
172    if (PyArg_ParseTuple(args, "O&Is#:ioctl",
173                         conv_descriptor, &fd, &code, &str, &len)) {
174        if (len > IOCTL_BUFSZ) {
175            PyErr_SetString(PyExc_ValueError,
176                            "ioctl string arg too long");
177            return NULL;
178        }
179        memcpy(buf, str, len);
180        buf[len] = '\0';
181        Py_BEGIN_ALLOW_THREADS
182        ret = ioctl(fd, code, buf);
183        Py_END_ALLOW_THREADS
184        if (ret < 0) {
185            PyErr_SetFromErrno(PyExc_IOError);
186            return NULL;
187        }
188        return PyString_FromStringAndSize(buf, len);
189    }
190
191    PyErr_Clear();
192    arg = 0;
193    if (!PyArg_ParseTuple(args,
194         "O&I|i;ioctl requires a file or file descriptor,"
195         " an integer and optionally an integer or buffer argument",
196                          conv_descriptor, &fd, &code, &arg)) {
197      return NULL;
198    }
199    Py_BEGIN_ALLOW_THREADS
200#ifdef __VMS
201    ret = ioctl(fd, code, (void *)arg);
202#else
203    ret = ioctl(fd, code, arg);
204#endif
205    Py_END_ALLOW_THREADS
206    if (ret < 0) {
207        PyErr_SetFromErrno(PyExc_IOError);
208        return NULL;
209    }
210    return PyInt_FromLong((long)ret);
211#undef IOCTL_BUFSZ
212}
213
214PyDoc_STRVAR(ioctl_doc,
215"ioctl(fd, opt[, arg[, mutate_flag]])\n\
216\n\
217Perform the requested operation on file descriptor fd.  The operation is\n\
218defined by opt and is operating system dependent.  Typically these codes are\n\
219retrieved from the fcntl or termios library modules.\n\
220\n\
221The argument arg is optional, and defaults to 0; it may be an int or a\n\
222buffer containing character data (most likely a string or an array). \n\
223\n\
224If the argument is a mutable buffer (such as an array) and if the\n\
225mutate_flag argument (which is only allowed in this case) is true then the\n\
226buffer is (in effect) passed to the operating system and changes made by\n\
227the OS will be reflected in the contents of the buffer after the call has\n\
228returned.  The return value is the integer returned by the ioctl system\n\
229call.\n\
230\n\
231If the argument is a mutable buffer and the mutable_flag argument is not\n\
232passed or is false, the behavior is as if a string had been passed.  This\n\
233behavior will change in future releases of Python.\n\
234\n\
235If the argument is an immutable buffer (most likely a string) then a copy\n\
236of the buffer is passed to the operating system and the return value is a\n\
237string of the same length containing whatever the operating system put in\n\
238the buffer.  The length of the arg buffer in this case is not allowed to\n\
239exceed 1024 bytes.\n\
240\n\
241If the arg given is an integer or if none is specified, the result value is\n\
242an integer corresponding to the return value of the ioctl call in the C\n\
243code.");
244
245
246/* flock(fd, operation) */
247
248static PyObject *
249fcntl_flock(PyObject *self, PyObject *args)
250{
251    int fd;
252    int code;
253    int ret;
254
255    if (!PyArg_ParseTuple(args, "O&i:flock",
256                          conv_descriptor, &fd, &code))
257        return NULL;
258
259#ifdef HAVE_FLOCK
260    Py_BEGIN_ALLOW_THREADS
261    ret = flock(fd, code);
262    Py_END_ALLOW_THREADS
263#else
264
265#ifndef LOCK_SH
266#define LOCK_SH         1       /* shared lock */
267#define LOCK_EX         2       /* exclusive lock */
268#define LOCK_NB         4       /* don't block when locking */
269#define LOCK_UN         8       /* unlock */
270#endif
271    {
272        struct flock l;
273        if (code == LOCK_UN)
274            l.l_type = F_UNLCK;
275        else if (code & LOCK_SH)
276            l.l_type = F_RDLCK;
277        else if (code & LOCK_EX)
278            l.l_type = F_WRLCK;
279        else {
280            PyErr_SetString(PyExc_ValueError,
281                            "unrecognized flock argument");
282            return NULL;
283        }
284        l.l_whence = l.l_start = l.l_len = 0;
285        Py_BEGIN_ALLOW_THREADS
286        ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
287        Py_END_ALLOW_THREADS
288    }
289#endif /* HAVE_FLOCK */
290    if (ret < 0) {
291        PyErr_SetFromErrno(PyExc_IOError);
292        return NULL;
293    }
294    Py_INCREF(Py_None);
295    return Py_None;
296}
297
298PyDoc_STRVAR(flock_doc,
299"flock(fd, operation)\n\
300\n\
301Perform the lock operation op on file descriptor fd.  See the Unix \n\
302manual page for flock(3) for details.  (On some systems, this function is\n\
303emulated using fcntl().)");
304
305
306/* lockf(fd, operation) */
307static PyObject *
308fcntl_lockf(PyObject *self, PyObject *args)
309{
310    int fd, code, ret, whence = 0;
311    PyObject *lenobj = NULL, *startobj = NULL;
312
313    if (!PyArg_ParseTuple(args, "O&i|OOi:lockf",
314                          conv_descriptor, &fd, &code,
315                          &lenobj, &startobj, &whence))
316        return NULL;
317
318#if defined(PYOS_OS2) && defined(PYCC_GCC)
319    PyErr_SetString(PyExc_NotImplementedError,
320                    "lockf not supported on OS/2 (EMX)");
321    return NULL;
322#else
323#ifndef LOCK_SH
324#define LOCK_SH         1       /* shared lock */
325#define LOCK_EX         2       /* exclusive lock */
326#define LOCK_NB         4       /* don't block when locking */
327#define LOCK_UN         8       /* unlock */
328#endif  /* LOCK_SH */
329    {
330        struct flock l;
331        if (code == LOCK_UN)
332            l.l_type = F_UNLCK;
333        else if (code & LOCK_SH)
334            l.l_type = F_RDLCK;
335        else if (code & LOCK_EX)
336            l.l_type = F_WRLCK;
337        else {
338            PyErr_SetString(PyExc_ValueError,
339                            "unrecognized lockf argument");
340            return NULL;
341        }
342        l.l_start = l.l_len = 0;
343        if (startobj != NULL) {
344#if !defined(HAVE_LARGEFILE_SUPPORT)
345            l.l_start = PyInt_AsLong(startobj);
346#else
347            l.l_start = PyLong_Check(startobj) ?
348                            PyLong_AsLongLong(startobj) :
349                    PyInt_AsLong(startobj);
350#endif
351            if (PyErr_Occurred())
352                return NULL;
353        }
354        if (lenobj != NULL) {
355#if !defined(HAVE_LARGEFILE_SUPPORT)
356            l.l_len = PyInt_AsLong(lenobj);
357#else
358            l.l_len = PyLong_Check(lenobj) ?
359                            PyLong_AsLongLong(lenobj) :
360                    PyInt_AsLong(lenobj);
361#endif
362            if (PyErr_Occurred())
363                return NULL;
364        }
365        l.l_whence = whence;
366        Py_BEGIN_ALLOW_THREADS
367        ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
368        Py_END_ALLOW_THREADS
369    }
370    if (ret < 0) {
371        PyErr_SetFromErrno(PyExc_IOError);
372        return NULL;
373    }
374    Py_INCREF(Py_None);
375    return Py_None;
376#endif  /* defined(PYOS_OS2) && defined(PYCC_GCC) */
377}
378
379PyDoc_STRVAR(lockf_doc,
380"lockf (fd, operation, length=0, start=0, whence=0)\n\
381\n\
382This is essentially a wrapper around the fcntl() locking calls.  fd is the\n\
383file descriptor of the file to lock or unlock, and operation is one of the\n\
384following values:\n\
385\n\
386    LOCK_UN - unlock\n\
387    LOCK_SH - acquire a shared lock\n\
388    LOCK_EX - acquire an exclusive lock\n\
389\n\
390When operation is LOCK_SH or LOCK_EX, it can also be bitwise ORed with\n\
391LOCK_NB to avoid blocking on lock acquisition.  If LOCK_NB is used and the\n\
392lock cannot be acquired, an IOError will be raised and the exception will\n\
393have an errno attribute set to EACCES or EAGAIN (depending on the operating\n\
394system -- for portability, check for either value).\n\
395\n\
396length is the number of bytes to lock, with the default meaning to lock to\n\
397EOF.  start is the byte offset, relative to whence, to that the lock\n\
398starts.  whence is as with fileobj.seek(), specifically:\n\
399\n\
400    0 - relative to the start of the file (SEEK_SET)\n\
401    1 - relative to the current buffer position (SEEK_CUR)\n\
402    2 - relative to the end of the file (SEEK_END)");
403
404/* List of functions */
405
406static PyMethodDef fcntl_methods[] = {
407    {"fcntl",           fcntl_fcntl, METH_VARARGS, fcntl_doc},
408    {"ioctl",           fcntl_ioctl, METH_VARARGS, ioctl_doc},
409    {"flock",           fcntl_flock, METH_VARARGS, flock_doc},
410    {"lockf",       fcntl_lockf, METH_VARARGS, lockf_doc},
411    {NULL,              NULL}           /* sentinel */
412};
413
414
415PyDoc_STRVAR(module_doc,
416"This module performs file control and I/O control on file \n\
417descriptors.  It is an interface to the fcntl() and ioctl() Unix\n\
418routines.  File descriptors can be obtained with the fileno() method of\n\
419a file or socket object.");
420
421/* Module initialisation */
422
423static int
424ins(PyObject* d, char* symbol, long value)
425{
426    PyObject* v = PyInt_FromLong(value);
427    if (!v || PyDict_SetItemString(d, symbol, v) < 0)
428        return -1;
429
430    Py_DECREF(v);
431    return 0;
432}
433
434#define INS(x) if (ins(d, #x, (long)x)) return -1
435
436static int
437all_ins(PyObject* d)
438{
439    if (ins(d, "LOCK_SH", (long)LOCK_SH)) return -1;
440    if (ins(d, "LOCK_EX", (long)LOCK_EX)) return -1;
441    if (ins(d, "LOCK_NB", (long)LOCK_NB)) return -1;
442    if (ins(d, "LOCK_UN", (long)LOCK_UN)) return -1;
443/* GNU extensions, as of glibc 2.2.4 */
444#ifdef LOCK_MAND
445    if (ins(d, "LOCK_MAND", (long)LOCK_MAND)) return -1;
446#endif
447#ifdef LOCK_READ
448    if (ins(d, "LOCK_READ", (long)LOCK_READ)) return -1;
449#endif
450#ifdef LOCK_WRITE
451    if (ins(d, "LOCK_WRITE", (long)LOCK_WRITE)) return -1;
452#endif
453#ifdef LOCK_RW
454    if (ins(d, "LOCK_RW", (long)LOCK_RW)) return -1;
455#endif
456
457#ifdef F_DUPFD
458    if (ins(d, "F_DUPFD", (long)F_DUPFD)) return -1;
459#endif
460#ifdef F_GETFD
461    if (ins(d, "F_GETFD", (long)F_GETFD)) return -1;
462#endif
463#ifdef F_SETFD
464    if (ins(d, "F_SETFD", (long)F_SETFD)) return -1;
465#endif
466#ifdef F_GETFL
467    if (ins(d, "F_GETFL", (long)F_GETFL)) return -1;
468#endif
469#ifdef F_SETFL
470    if (ins(d, "F_SETFL", (long)F_SETFL)) return -1;
471#endif
472#ifdef F_GETLK
473    if (ins(d, "F_GETLK", (long)F_GETLK)) return -1;
474#endif
475#ifdef F_SETLK
476    if (ins(d, "F_SETLK", (long)F_SETLK)) return -1;
477#endif
478#ifdef F_SETLKW
479    if (ins(d, "F_SETLKW", (long)F_SETLKW)) return -1;
480#endif
481#ifdef F_GETOWN
482    if (ins(d, "F_GETOWN", (long)F_GETOWN)) return -1;
483#endif
484#ifdef F_SETOWN
485    if (ins(d, "F_SETOWN", (long)F_SETOWN)) return -1;
486#endif
487#ifdef F_GETSIG
488    if (ins(d, "F_GETSIG", (long)F_GETSIG)) return -1;
489#endif
490#ifdef F_SETSIG
491    if (ins(d, "F_SETSIG", (long)F_SETSIG)) return -1;
492#endif
493#ifdef F_RDLCK
494    if (ins(d, "F_RDLCK", (long)F_RDLCK)) return -1;
495#endif
496#ifdef F_WRLCK
497    if (ins(d, "F_WRLCK", (long)F_WRLCK)) return -1;
498#endif
499#ifdef F_UNLCK
500    if (ins(d, "F_UNLCK", (long)F_UNLCK)) return -1;
501#endif
502/* LFS constants */
503#ifdef F_GETLK64
504    if (ins(d, "F_GETLK64", (long)F_GETLK64)) return -1;
505#endif
506#ifdef F_SETLK64
507    if (ins(d, "F_SETLK64", (long)F_SETLK64)) return -1;
508#endif
509#ifdef F_SETLKW64
510    if (ins(d, "F_SETLKW64", (long)F_SETLKW64)) return -1;
511#endif
512/* GNU extensions, as of glibc 2.2.4. */
513#ifdef FASYNC
514    if (ins(d, "FASYNC", (long)FASYNC)) return -1;
515#endif
516#ifdef F_SETLEASE
517    if (ins(d, "F_SETLEASE", (long)F_SETLEASE)) return -1;
518#endif
519#ifdef F_GETLEASE
520    if (ins(d, "F_GETLEASE", (long)F_GETLEASE)) return -1;
521#endif
522#ifdef F_NOTIFY
523    if (ins(d, "F_NOTIFY", (long)F_NOTIFY)) return -1;
524#endif
525/* Old BSD flock(). */
526#ifdef F_EXLCK
527    if (ins(d, "F_EXLCK", (long)F_EXLCK)) return -1;
528#endif
529#ifdef F_SHLCK
530    if (ins(d, "F_SHLCK", (long)F_SHLCK)) return -1;
531#endif
532
533/* OS X (and maybe others) let you tell the storage device to flush to physical media */
534#ifdef F_FULLFSYNC
535    if (ins(d, "F_FULLFSYNC", (long)F_FULLFSYNC)) return -1;
536#endif
537
538/* For F_{GET|SET}FL */
539#ifdef FD_CLOEXEC
540    if (ins(d, "FD_CLOEXEC", (long)FD_CLOEXEC)) return -1;
541#endif
542
543/* For F_NOTIFY */
544#ifdef DN_ACCESS
545    if (ins(d, "DN_ACCESS", (long)DN_ACCESS)) return -1;
546#endif
547#ifdef DN_MODIFY
548    if (ins(d, "DN_MODIFY", (long)DN_MODIFY)) return -1;
549#endif
550#ifdef DN_CREATE
551    if (ins(d, "DN_CREATE", (long)DN_CREATE)) return -1;
552#endif
553#ifdef DN_DELETE
554    if (ins(d, "DN_DELETE", (long)DN_DELETE)) return -1;
555#endif
556#ifdef DN_RENAME
557    if (ins(d, "DN_RENAME", (long)DN_RENAME)) return -1;
558#endif
559#ifdef DN_ATTRIB
560    if (ins(d, "DN_ATTRIB", (long)DN_ATTRIB)) return -1;
561#endif
562#ifdef DN_MULTISHOT
563    if (ins(d, "DN_MULTISHOT", (long)DN_MULTISHOT)) return -1;
564#endif
565
566#ifdef HAVE_STROPTS_H
567    /* Unix 98 guarantees that these are in stropts.h. */
568    INS(I_PUSH);
569    INS(I_POP);
570    INS(I_LOOK);
571    INS(I_FLUSH);
572    INS(I_FLUSHBAND);
573    INS(I_SETSIG);
574    INS(I_GETSIG);
575    INS(I_FIND);
576    INS(I_PEEK);
577    INS(I_SRDOPT);
578    INS(I_GRDOPT);
579    INS(I_NREAD);
580    INS(I_FDINSERT);
581    INS(I_STR);
582    INS(I_SWROPT);
583#ifdef I_GWROPT
584    /* despite the comment above, old-ish glibcs miss a couple... */
585    INS(I_GWROPT);
586#endif
587    INS(I_SENDFD);
588    INS(I_RECVFD);
589    INS(I_LIST);
590    INS(I_ATMARK);
591    INS(I_CKBAND);
592    INS(I_GETBAND);
593    INS(I_CANPUT);
594    INS(I_SETCLTIME);
595#ifdef I_GETCLTIME
596    INS(I_GETCLTIME);
597#endif
598    INS(I_LINK);
599    INS(I_UNLINK);
600    INS(I_PLINK);
601    INS(I_PUNLINK);
602#endif
603
604    return 0;
605}
606
607PyMODINIT_FUNC
608initfcntl(void)
609{
610    PyObject *m, *d;
611
612    /* Create the module and add the functions and documentation */
613    m = Py_InitModule3("fcntl", fcntl_methods, module_doc);
614    if (m == NULL)
615        return;
616
617    /* Add some symbolic constants to the module */
618    d = PyModule_GetDict(m);
619    all_ins(d);
620}
621