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