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