fcntlmodule.c revision 9bfd2bf5ede8e5d58775180d6867d81ddcdd3594
1/***********************************************************
2Copyright (c) 2000, BeOpen.com.
3Copyright (c) 1995-2000, Corporation for National Research Initiatives.
4Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
5All rights reserved.
6
7See the file "Misc/COPYRIGHT" for information on usage and
8redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
9******************************************************************/
10
11/* fcntl module */
12
13#include "Python.h"
14
15#ifdef HAVE_UNISTD_H
16#include <unistd.h>
17#endif
18
19#ifdef HAVE_SYS_FILE_H
20#include <sys/file.h>
21#endif
22
23#include <sys/ioctl.h>
24#include <fcntl.h>
25
26
27/* fcntl(fd, opt, [arg]) */
28
29static PyObject *
30fcntl_fcntl(PyObject *self, PyObject *args)
31{
32	int fd;
33	int code;
34	int arg;
35	int ret;
36	char *str;
37	int len;
38	char buf[1024];
39
40	if (PyArg_ParseTuple(args, "iis#:fcntl", &fd, &code, &str, &len)) {
41		if (len > sizeof buf) {
42			PyErr_SetString(PyExc_ValueError,
43					"fcntl string arg too long");
44			return NULL;
45		}
46		memcpy(buf, str, len);
47		Py_BEGIN_ALLOW_THREADS
48		ret = fcntl(fd, code, buf);
49		Py_END_ALLOW_THREADS
50		if (ret < 0) {
51			PyErr_SetFromErrno(PyExc_IOError);
52			return NULL;
53		}
54		return PyString_FromStringAndSize(buf, len);
55	}
56
57	PyErr_Clear();
58	arg = 0;
59	if (!PyArg_ParseTuple(args, "ii|i;fcntl requires 2 integers and optionally a third integer or a string",
60			      &fd, &code, &arg)) {
61	  return NULL;
62	}
63	Py_BEGIN_ALLOW_THREADS
64	ret = fcntl(fd, code, arg);
65	Py_END_ALLOW_THREADS
66	if (ret < 0) {
67		PyErr_SetFromErrno(PyExc_IOError);
68		return NULL;
69	}
70	return PyInt_FromLong((long)ret);
71}
72
73static char fcntl_doc [] =
74
75"fcntl(fd, opt, [arg])\n\
76\n\
77Perform the requested operation on file descriptor fd.  The operation\n\
78is defined by op and is operating system dependent.  Typically these\n\
79codes can be retrieved from the library module FCNTL.  The argument arg\n\
80is optional, and defaults to 0; it may be an int or a string. If arg is\n\
81given as a string, the return value of fcntl is a string of that length,\n\
82containing the resulting value put in the arg buffer by the operating system.\n\
83The length of the arg string is not allowed to exceed 1024 bytes. If the arg\n\
84given is an integer or if none is specified, the result value is an integer\n\
85corresponding to the return value of the fcntl call in the C code.";
86
87
88/* ioctl(fd, opt, [arg]) */
89
90static PyObject *
91fcntl_ioctl(PyObject *self, PyObject *args)
92{
93	int fd;
94	int code;
95	int arg;
96	int ret;
97	char *str;
98	int len;
99	char buf[1024];
100
101	if (PyArg_ParseTuple(args, "iis#:ioctl", &fd, &code, &str, &len)) {
102		if (len > sizeof buf) {
103			PyErr_SetString(PyExc_ValueError,
104					"ioctl string arg too long");
105			return NULL;
106		}
107		memcpy(buf, str, len);
108		Py_BEGIN_ALLOW_THREADS
109		ret = ioctl(fd, code, buf);
110		Py_END_ALLOW_THREADS
111		if (ret < 0) {
112			PyErr_SetFromErrno(PyExc_IOError);
113			return NULL;
114		}
115		return PyString_FromStringAndSize(buf, len);
116	}
117
118	PyErr_Clear();
119	arg = 0;
120	if (!PyArg_ParseTuple(args, "ii|i;ioctl requires 2 integers and optionally a third integer or a string",
121			      &fd, &code, &arg)) {
122	  return NULL;
123	}
124	Py_BEGIN_ALLOW_THREADS
125	ret = ioctl(fd, code, arg);
126	Py_END_ALLOW_THREADS
127	if (ret < 0) {
128		PyErr_SetFromErrno(PyExc_IOError);
129		return NULL;
130	}
131	return PyInt_FromLong((long)ret);
132}
133
134static char ioctl_doc [] =
135"ioctl(fd, opt, [arg])\n\
136\n\
137Perform the requested operation on file descriptor fd.  The operation\n\
138is defined by op and is operating system dependent.  Typically these\n\
139codes can be retrieved from the library module IOCTL.  The argument arg\n\
140is optional, and defaults to 0; it may be an int or a string. If arg is\n\
141given as a string, the return value of ioctl is a string of that length,\n\
142containing the resulting value put in the arg buffer by the operating system.\n\
143The length of the arg string is not allowed to exceed 1024 bytes. If the arg\n\
144given is an integer or if none is specified, the result value is an integer\n\
145corresponding to the return value of the ioctl call in the C code.";
146
147
148/* flock(fd, operation) */
149
150static PyObject *
151fcntl_flock(PyObject *self, PyObject *args)
152{
153	int fd;
154	int code;
155	int ret;
156
157	if (!PyArg_ParseTuple(args, "ii:flock", &fd, &code))
158		return NULL;
159
160#ifdef HAVE_FLOCK
161	Py_BEGIN_ALLOW_THREADS
162	ret = flock(fd, code);
163	Py_END_ALLOW_THREADS
164#else
165
166#ifndef LOCK_SH
167#define LOCK_SH		1	/* shared lock */
168#define LOCK_EX		2	/* exclusive lock */
169#define LOCK_NB		4	/* don't block when locking */
170#define LOCK_UN		8	/* unlock */
171#endif
172	{
173		struct flock l;
174		if (code == LOCK_UN)
175			l.l_type = F_UNLCK;
176		else if (code & LOCK_SH)
177			l.l_type = F_RDLCK;
178		else if (code & LOCK_EX)
179			l.l_type = F_WRLCK;
180		else {
181			PyErr_SetString(PyExc_ValueError,
182					"unrecognized flock argument");
183			return NULL;
184		}
185		l.l_whence = l.l_start = l.l_len = 0;
186		Py_BEGIN_ALLOW_THREADS
187		ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
188		Py_END_ALLOW_THREADS
189	}
190#endif /* HAVE_FLOCK */
191	if (ret < 0) {
192		PyErr_SetFromErrno(PyExc_IOError);
193		return NULL;
194	}
195	Py_INCREF(Py_None);
196	return Py_None;
197}
198
199static char flock_doc [] =
200"flock(fd, operation)\n\
201\n\
202Perform the lock operation op on file descriptor fd.  See the Unix \n\
203manual flock(3) for details.  (On some systems, this function is\n\
204emulated using fcntl().)";
205
206
207/* lockf(fd, operation) */
208static PyObject *
209fcntl_lockf(PyObject *self, PyObject *args)
210{
211	int fd, code, ret, whence = 0;
212	PyObject *lenobj = NULL, *startobj = NULL;
213
214	if (!PyArg_ParseTuple(args, "ii|OOi:lockf", &fd, &code,
215			      &lenobj, &startobj, &whence))
216	    return NULL;
217
218#ifndef LOCK_SH
219#define LOCK_SH		1	/* shared lock */
220#define LOCK_EX		2	/* exclusive lock */
221#define LOCK_NB		4	/* don't block when locking */
222#define LOCK_UN		8	/* unlock */
223#endif
224	{
225		struct flock l;
226		if (code == LOCK_UN)
227			l.l_type = F_UNLCK;
228		else if (code & LOCK_SH)
229			l.l_type = F_RDLCK;
230		else if (code & LOCK_EX)
231			l.l_type = F_WRLCK;
232		else {
233			PyErr_SetString(PyExc_ValueError,
234					"unrecognized flock argument");
235			return NULL;
236		}
237		l.l_start = l.l_len = 0;
238		if (startobj != NULL) {
239#if !defined(HAVE_LARGEFILE_SUPPORT)
240			l.l_start = PyInt_AsLong(startobj);
241#else
242			l.l_start = PyLong_Check(startobj) ?
243					PyLong_AsLongLong(startobj) :
244					PyInt_AsLong(startobj);
245#endif
246			if (PyErr_Occurred())
247				return NULL;
248		}
249		if (lenobj != NULL) {
250#if !defined(HAVE_LARGEFILE_SUPPORT)
251			l.l_len = PyInt_AsLong(lenobj);
252#else
253			l.l_len = PyLong_Check(lenobj) ?
254					PyLong_AsLongLong(lenobj) :
255					PyInt_AsLong(lenobj);
256#endif
257			if (PyErr_Occurred())
258				return NULL;
259		}
260		l.l_whence = whence;
261		Py_BEGIN_ALLOW_THREADS
262		ret = fcntl(fd, (code & LOCK_NB) ? F_SETLK : F_SETLKW, &l);
263		Py_END_ALLOW_THREADS
264	}
265	if (ret < 0) {
266		PyErr_SetFromErrno(PyExc_IOError);
267		return NULL;
268	}
269	Py_INCREF(Py_None);
270	return Py_None;
271}
272
273static char lockf_doc [] =
274"lockf (fd, operation)\n\
275\n\
276This is a wrapper around the FCNTL.F_SETLK and FCNTL.F_SETLKW fcntl()\n\
277calls.  See the Unix manual for details.";
278
279/* List of functions */
280
281static PyMethodDef fcntl_methods[] = {
282	{"fcntl",	fcntl_fcntl, METH_VARARGS, fcntl_doc},
283	{"ioctl",	fcntl_ioctl, METH_VARARGS, ioctl_doc},
284	{"flock",	fcntl_flock, METH_VARARGS, flock_doc},
285	{"lockf",       fcntl_lockf, METH_VARARGS, lockf_doc},
286	{NULL,		NULL}		/* sentinel */
287};
288
289
290static char module_doc [] =
291
292"This module performs file control and I/O control on file \n\
293descriptors.  It is an interface to the fcntl() and ioctl() Unix\n\
294routines.  File descriptors can be obtained with the fileno() method of\n\
295a file or socket object.";
296
297/* Module initialisation */
298
299static int
300ins(PyObject* d, char* symbol, long value)
301{
302        PyObject* v = PyInt_FromLong(value);
303        if (!v || PyDict_SetItemString(d, symbol, v) < 0)
304                return -1;
305
306        Py_DECREF(v);
307        return 0;
308}
309
310static int
311all_ins(PyObject* d)
312{
313        if (ins(d, "LOCK_SH", (long)LOCK_SH)) return -1;
314        if (ins(d, "LOCK_EX", (long)LOCK_EX)) return -1;
315        if (ins(d, "LOCK_NB", (long)LOCK_NB)) return -1;
316        if (ins(d, "LOCK_UN", (long)LOCK_UN)) return -1;
317	return 0;
318}
319
320DL_EXPORT(void)
321initfcntl(void)
322{
323	PyObject *m, *d;
324
325	/* Create the module and add the functions and documentation */
326	m = Py_InitModule3("fcntl", fcntl_methods, module_doc);
327
328	/* Add some symbolic constants to the module */
329	d = PyModule_GetDict(m);
330	all_ins(d);
331}
332