1 /*
2 *
3 * Copyright (c) 2003 The Regents of the University of California. All
4 * rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * - Neither the name of the University nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
18 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
19 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 */
30
31
32 /*
33 Copyright (C) 2003 Brian Warner <warner-fusd@lothar.com>
34
35 This program is free software, and can be distributed under the same
36 terms as the rest of FUSD (the BSD 3-clause license). See the file
37 ../LICENSE for details.
38 */
39
40
41
42 #include <stdio.h>
43 #include <Python.h>
44
45 #include <sys/types.h>
46 #include <sys/ioctl.h>
47 #include <errno.h>
48
49 #include "fusd.h"
50
51 typedef struct {
52 PyObject_HEAD
53 struct fusd_file_info *file;
54 int active;
55 PyObject *fp;
56 } RequestObject;
57
58 staticforward PyTypeObject ReadRequest_Type;
59 staticforward PyTypeObject WriteRequest_Type;
60 staticforward PyTypeObject IoctlRequest_Type;
61 staticforward PyTypeObject PollDiffRequest_Type;
62
63 #define ReadRequestObject_Check(v) ((v)->ob_type == &ReadRequest_Type)
64 #define WriteRequestObject_Check(v) ((v)->ob_type == &WriteRequest_Type)
65 #define IoctlRequestObject_Check(v) ((v)->ob_type == &IoctlRequest_Type)
66 #define PollDiffRequestObject_Check(v) ((v)->ob_type == &PollDiffRequest_Type)
67
68 static RequestObject *
69 newReadRequestObject(struct fusd_file_info *file, PyObject *fp)
70 {
71 RequestObject *self;
72 self = PyObject_New(RequestObject, &ReadRequest_Type);
73 if (self == NULL)
74 return NULL;
75 self->file = file;
76 self->active = 1;
77 self->fp = fp;
78 return self;
79 }
80
81 static RequestObject *
82 newWriteRequestObject(struct fusd_file_info *file, PyObject *fp)
83 {
84 RequestObject *self;
85 self = PyObject_New(RequestObject, &WriteRequest_Type);
86 if (self == NULL)
87 return NULL;
88 self->file = file;
89 self->active = 1;
90 self->fp = fp;
91 return self;
92 }
93
94 static RequestObject *
95 newIoctlRequestObject(struct fusd_file_info *file, PyObject *fp)
96 {
97 RequestObject *self;
98 self = PyObject_New(RequestObject, &IoctlRequest_Type);
99 if (self == NULL)
100 return NULL;
101 self->file = file;
102 self->active = 1;
103 self->fp = fp;
104 return self;
105 }
106
107 static RequestObject *
108 newPollDiffRequestObject(struct fusd_file_info *file, PyObject *fp)
109 {
110 RequestObject *self;
111 self = PyObject_New(RequestObject, &PollDiffRequest_Type);
112 if (self == NULL)
113 return NULL;
114 self->file = file;
115 self->active = 1;
116 self->fp = fp;
117 return self;
118 }
119
120 static void
121 Request_dealloc(RequestObject *self)
122 {
123 if (self->active) {
124 /* the python code should not let active requests fall out of scope.
125 They should all be explicitly .finish()ed or .destroy()ed */
126 fprintf(stderr, "Warning: Active Request <%s> being destroyed\n",
127 self->ob_type->tp_name);
128 self->active = 0;
129 fusd_destroy(self->file);
130 }
131 PyObject_Del(self);
132 }
133
134 static PyObject *
135 Request_finish(RequestObject *self, PyObject *args)
136 {
137 int retval; /* really ssize_t */
138 int rc;
139
140 if (!PyArg_ParseTuple(args, "i:finish", &retval))
141 return NULL;
142 if (!self->active) {
143 PyErr_SetString(PyExc_RuntimeError, "duplicate request->return");
144 return NULL;
145 }
146 rc = fusd_return(self->file, retval);
147 self->active = 0;
148 return PyInt_FromLong(rc);
149 }
150
151 static PyObject *
152 Request_destroy(RequestObject *self, PyObject *args)
153 {
154 if (!PyArg_ParseTuple(args, ":destroy"))
155 return NULL;
156 if (!self->active) {
157 PyErr_SetString(PyExc_RuntimeError,
158 "can only destroy active requests");
159 return NULL;
160 }
161 fusd_destroy(self->file);
162 self->active = 0;
163
164 Py_INCREF(Py_None);
165 return Py_None;
166 }
167
168 static PyObject *
169 ReadRequest_setdata(RequestObject *self, PyObject *args)
170 {
171 int offset;
172 char *data;
173 int datalen;
174
175 if (!self->active) {
176 PyErr_SetString(PyExc_RuntimeError, "setdata on inactive request");
177 return NULL;
178 }
179
180 if (!PyArg_ParseTuple(args, "is#:setdata", &offset, &data, &datalen))
181 return NULL;
182
183 if ((offset < 0) || (offset+datalen > fusd_get_length(self->file))) {
184 PyErr_SetString(PyExc_IndexError, "writing beyond buffer");
185 return NULL;
186 }
187
188 memcpy(fusd_get_read_buffer(self->file), data, datalen);
189
190 Py_INCREF(Py_None);
191 return Py_None;
192 }
193
194 static PyObject *
195 WriteRequest_getdata(RequestObject *self, PyObject *args)
196 {
197 int offset = 0;
198 int datalen = fusd_get_length(self->file);
199 int reqlen = datalen;
200 PyObject *ret;
201
202 if (!self->active) {
203 PyErr_SetString(PyExc_RuntimeError, "getdata on inactive request");
204 return NULL;
205 }
206 if (!PyArg_ParseTuple(args, "|ii:getdata", &offset, &reqlen))
207 return NULL;
208
209 if ((offset < 0) || (reqlen < 0 ) || (offset+reqlen > datalen)) {
210 PyErr_SetString(PyExc_IndexError, "reading beyond buffer");
211 return NULL;
212 }
213
214 ret = Py_BuildValue("s#", fusd_get_write_buffer(self->file) + offset,
215 reqlen);
216 return ret;
217 }
218
219 static PyObject *
220 IoctlRequest_getdata(RequestObject *self, PyObject *args)
221 {
222
223 if (!self->active) {
224 PyErr_SetString(PyExc_RuntimeError, "getdata on inactive request");
225 return NULL;
226 }
227
228 // IO_W or IO_WR will have a data pointer
229 if (fusd_get_ioctl_buffer(self->file)) {
230 return Py_BuildValue("s#", fusd_get_ioctl_buffer(self->file),
231 fusd_get_length(self->file));
232 }
233 // IO will have an int, IO_R will probably have a zero
234 return PyInt_FromLong(fusd_get_ioctl_arg(self->file));
235 }
236
237 static PyObject *
238 IoctlRequest_setdata(RequestObject *self, PyObject *args)
239 {
240 char *data;
241 int datalen;
242 int cmd = fusd_get_ioctl_request(self->file);
243
244 if (!self->active) {
245 PyErr_SetString(PyExc_RuntimeError, "getdata on inactive request");
246 return NULL;
247 }
248
249 // IO_R will have a data pointer. IO_W will to, but it isn't used
250 if ((_IOC_DIR(cmd) & _IOC_READ) && fusd_get_ioctl_buffer(self->file))
251 {
252 if (!PyArg_ParseTuple(args, "s#:setdata", &data, &datalen))
253 return NULL;
254 if (datalen > fusd_get_length(self->file)) {
255 PyErr_Format(PyExc_IndexError,
256 "too much data: ioctl accepts %d bytes, given %d",
257 fusd_get_length(self->file), datalen);
258 return NULL;
259 }
260 memcpy(fusd_get_ioctl_buffer(self->file), data, datalen);
261 Py_INCREF(Py_None);
262 return Py_None;
263 }
264
265 PyErr_SetString(PyExc_TypeError, "this ioctl is read only");
266 return NULL;
267 }
268
269
270 static PyMethodDef ReadRequest_methods[] = {
271 {"setdata", (PyCFunction)ReadRequest_setdata, METH_VARARGS},
272 {"destroy", (PyCFunction)Request_destroy, METH_VARARGS},
273 {"finish", (PyCFunction)Request_finish, METH_VARARGS},
274 {NULL, NULL} /* sentinel */
275 };
276
277 static PyMethodDef WriteRequest_methods[] = {
278 {"getdata", (PyCFunction)WriteRequest_getdata, METH_VARARGS},
279 {"destroy", (PyCFunction)Request_destroy, METH_VARARGS},
280 {"finish", (PyCFunction)Request_finish, METH_VARARGS},
281 {NULL, NULL} /* sentinel */
282 };
283
284 static PyMethodDef IoctlRequest_methods[] = {
285 {"getdata", (PyCFunction)IoctlRequest_getdata, METH_VARARGS},
286 {"setdata", (PyCFunction)IoctlRequest_setdata, METH_VARARGS},
287 {"destroy", (PyCFunction)Request_destroy, METH_VARARGS},
288 {"finish", (PyCFunction)Request_finish, METH_VARARGS},
289 {NULL, NULL} /* sentinel */
290 };
291
292 static PyMethodDef PollDiffRequest_methods[] = {
293 {"destroy", (PyCFunction)Request_destroy, METH_VARARGS},
294 {"finish", (PyCFunction)Request_finish, METH_VARARGS},
295 {NULL, NULL} /* sentinel */
296 };
297
298 static int
299 Request_getparm(RequestObject *self, char *name, int *valid)
300 {
301 *valid = 1;
302 if (strcmp(name, "length") == 0)
303 return fusd_get_length(self->file);
304 if (strcmp(name, "fd") == 0)
305 return self->file->fd;
306 if (strcmp(name, "flags") == 0)
307 return self->file->flags;
308 if (strcmp(name, "pid") == 0)
309 return self->file->pid;
310 if (strcmp(name, "uid") == 0)
311 return self->file->uid;
312 if (strcmp(name, "gid") == 0)
313 return self->file->gid;
314 if (strcmp(name, "offset") == 0) {
315 int offset = *(fusd_get_offset(self->file)); /* loff_t */
316 return offset;
317 }
318
319 *valid = 0;
320 return 0;
321 }
322
323 static PyObject *
324 ReadRequest_getattr(RequestObject *self, char *name)
325 {
326 int parm, valid;
327
328 parm = Request_getparm(self, name, &valid);
329 if (valid)
330 return PyInt_FromLong(parm);
331 return Py_FindMethod(ReadRequest_methods, (PyObject *)self, name);
332 }
333
334 static PyObject *
335 WriteRequest_getattr(RequestObject *self, char *name)
336 {
337 int parm, valid;
338
339 parm = Request_getparm(self, name, &valid);
340 if (valid)
341 return PyInt_FromLong(parm);
342 return Py_FindMethod(WriteRequest_methods, (PyObject *)self, name);
343 }
344
345 static PyObject *
346 IoctlRequest_getattr(RequestObject *self, char *name)
347 {
348 int parm, valid;
349 int cmd = fusd_get_ioctl_request(self->file);
350
351 parm = Request_getparm(self, name, &valid);
352 if (valid)
353 return PyInt_FromLong(parm);
354 if (strcmp(name, "cmd") == 0)
355 return PyInt_FromLong(cmd);
356 if (strcmp(name, "nr") == 0)
357 return PyInt_FromLong(_IOC_NR(cmd));
358 if (strcmp(name, "type") == 0)
359 return PyInt_FromLong(_IOC_TYPE(cmd));
360 if (strcmp(name, "size") == 0)
361 return PyInt_FromLong(_IOC_SIZE(cmd));
362 if (strcmp(name, "direction") == 0)
363 return PyInt_FromLong(_IOC_DIR(cmd));
364 if (strcmp(name, "dir_string") == 0) {
365 int dir = _IOC_DIR(cmd);
366 switch (dir) {
367 case _IOC_NONE:
368 return PyString_FromString("none");
369 case _IOC_WRITE:
370 return PyString_FromString("write");
371 case _IOC_READ:
372 return PyString_FromString("read");
373 case (_IOC_READ | _IOC_WRITE):
374 return PyString_FromString("readwrite");
375 }
376 }
377
378 return Py_FindMethod(IoctlRequest_methods, (PyObject *)self, name);
379 }
380
381 static PyObject *
382 PollDiffRequest_getattr(RequestObject *self, char *name)
383 {
384 return Py_FindMethod(PollDiffRequest_methods, (PyObject *)self, name);
385 }
386
387
388 static int
389 Request_setattr(RequestObject *self, char *name, PyObject *v)
390 {
391 if (strcmp(name, "offset") == 0) {
392 int offset;
393 offset = PyInt_AsLong(v);
394 if (PyErr_Occurred())
395 return -1;
396 *(fusd_get_offset(self->file)) = offset; /* loff_t */
397 return 0;
398 }
399 if (strcmp(name, "flags") == 0) {
400 int flags;
401 flags = PyInt_AsLong(v);
402 if (PyErr_Occurred())
403 return -1;
404 self->file->flags = flags;
405 return 0;
406 }
407
408 PyErr_Format(PyExc_AttributeError,
409 "cannot set Request attribute '%s'", name);
410 return -1;
411 }
412
413 statichere PyTypeObject ReadRequest_Type = {
414 /* The ob_type field must be initialized in the module init function
415 * to be portable to Windows without using C++. */
416 PyObject_HEAD_INIT(NULL)
417 0, /*ob_size*/
418 "fusdmodule.ReadRequest", /*tp_name*/
419 sizeof(RequestObject), /*tp_basicsize*/
420 0, /*tp_itemsize*/
421 /* methods */
422 (destructor)Request_dealloc, /*tp_dealloc*/
423 0, /*tp_print*/
424 (getattrfunc)ReadRequest_getattr, /*tp_getattr*/
425 (setattrfunc)Request_setattr, /*tp_setattr*/
426 };
427
428 statichere PyTypeObject WriteRequest_Type = {
429 /* The ob_type field must be initialized in the module init function
430 * to be portable to Windows without using C++. */
431 PyObject_HEAD_INIT(NULL)
432 0, /*ob_size*/
433 "fusdmodule.WriteRequest", /*tp_name*/
434 sizeof(RequestObject), /*tp_basicsize*/
435 0, /*tp_itemsize*/
436 /* methods */
437 (destructor)Request_dealloc, /*tp_dealloc*/
438 0, /*tp_print*/
439 (getattrfunc)WriteRequest_getattr, /*tp_getattr*/
440 (setattrfunc)Request_setattr, /*tp_setattr*/
441 };
442
443 statichere PyTypeObject IoctlRequest_Type = {
444 /* The ob_type field must be initialized in the module init function
445 * to be portable to Windows without using C++. */
446 PyObject_HEAD_INIT(NULL)
447 0, /*ob_size*/
448 "fusdmodule.IoctlRequest", /*tp_name*/
449 sizeof(RequestObject), /*tp_basicsize*/
450 0, /*tp_itemsize*/
451 /* methods */
452 (destructor)Request_dealloc, /*tp_dealloc*/
453 0, /*tp_print*/
454 (getattrfunc)IoctlRequest_getattr, /*tp_getattr*/
455 (setattrfunc)Request_setattr, /*tp_setattr*/
456 };
457
458 statichere PyTypeObject PollDiffRequest_Type = {
459 /* The ob_type field must be initialized in the module init function
460 * to be portable to Windows without using C++. */
461 PyObject_HEAD_INIT(NULL)
462 0, /*ob_size*/
463 "fusdmodule.PollDiffRequest", /*tp_name*/
464 sizeof(RequestObject), /*tp_basicsize*/
465 0, /*tp_itemsize*/
466 /* methods */
467 (destructor)Request_dealloc, /*tp_dealloc*/
468 0, /*tp_print*/
469 (getattrfunc)PollDiffRequest_getattr, /*tp_getattr*/
470 0, /*tp_setattr*/
471 };
472
473
474 static int
475 client_open(struct fusd_file_info *file)
476 {
477 PyObject *ret, *device;
478 int retval;
479 unsigned int flags;
480 PyObject *fp;
481
482 device = file->device_info;
483 ret = PyObject_CallMethod(device, "do_open",
484 "iiii", file->flags, file->pid,
485 file->uid, file->gid);
486 if (!ret) {
487 /* print and clear the exception */
488 PyErr_Print();
489 return -EIO;
490 }
491 if (!PyArg_ParseTuple(ret, "iiO", &retval, &flags, &fp))
492 {
493 PyErr_Print();
494 return -EIO;
495 }
496 file->flags = flags;
497 file->private_data = fp;
498 return retval;
499 }
500
501 static int
502 client_close(struct fusd_file_info *file)
503 {
504 PyObject *ret, *device, *fp;
505 int retval;
506
507 device = file->device_info;
508 fp = file->private_data;
509 ret = PyObject_CallMethod(device, "do_close", "Oiiii",
510 fp, file->flags, file->pid,
511 file->uid, file->gid);
512 if (!ret) {
513 /* print and clear the exception */
514 PyErr_Print();
515 return -EIO;
516 }
517 if (!PyArg_ParseTuple(ret, "i", &retval))
518 {
519 PyErr_Print();
520 return -EIO;
521 }
522 return retval;
523 }
524
525 static ssize_t
526 client_read(struct fusd_file_info *file, char *buffer, size_t length,
527 loff_t *offset)
528 {
529 PyObject *ret, *fp;
530 RequestObject *req;
531 int newoffset;
532
533 fp = file->private_data;
534
535 newoffset = *offset; /* loff_t */
536 if (newoffset != *offset) {
537 fprintf(stderr, "Ack! offset is too large, loff_t is too big\n");
538 fprintf(stderr, "client_read() failing..\n");
539 return -EIO;
540 }
541
542 req = newReadRequestObject(file, fp);
543 if (!req) {
544 fprintf(stderr, "client_read: unable to allocate RequestObject\n");
545 return -EIO;
546 }
547
548 ret = PyObject_CallMethod(fp, "do_read", "O", req);
549
550 if (ret == Py_None) {
551 /* this is the normal case. They might have called req.finish, or
552 they may defer it until later. */
553 Py_DECREF(req);
554 return -FUSD_NOREPLY;
555 }
556
557 /* something went wrong */
558
559 if (ret) {
560 fprintf(stderr,
561 "do_read should not return anything (returned <%s>)\n",
562 ret->ob_type->tp_name);
563 } else {
564 /* print and clear the exception */
565 PyErr_Print();
566 }
567
568 if (req->active) {
569 /* they didn't do .finish, so free the Request (preserving the .file
570 struct) and return an error. */
571 req->active = 0;
572 Py_DECREF(req);
573 return -EIO;
574 }
575 /* they did do .finish, so an error code was already sent */
576 Py_DECREF(req);
577 return -FUSD_NOREPLY;
578 }
579
580 static ssize_t
581 client_write(struct fusd_file_info *file, const char *buffer,
582 size_t length, loff_t *offset)
583 {
584 PyObject *ret, *fp;
585 int newoffset;
586 RequestObject *req;
587
588 /* N.B.: loff_t is larger than an int, so you can't pass *offset to a
589 varargs function because everything after that argument will be taken
590 from the wrong place. Downgrade it to an int before handing it to
591 Py_BuildValue. This also means we can't deal with >2GB files yet. */
592
593 fp = file->private_data;
594 newoffset = *offset;
595
596 if (newoffset != *offset) {
597 fprintf(stderr, "Ack! offset is too large, loff_t is too big\n");
598 fprintf(stderr, "client_write() failing..\n");
599 return -EIO;
600 }
601
602 req = newWriteRequestObject(file, fp);
603 if (!req) {
604 fprintf(stderr, "client_write: unable to allocate RequestObject\n");
605 return -EIO;
606 }
607
608 ret = PyObject_CallMethod(fp, "do_write", "O", req);
609
610 if (ret == Py_None) {
611 /* this is the normal case. They might have called req.finish, or
612 they may defer it until later. */
613 Py_DECREF(req);
614 return -FUSD_NOREPLY;
615 }
616
617 /* something went wrong */
618
619 if (ret) {
620 fprintf(stderr,
621 "do_write should not return anything (returned <%s>)\n",
622 ret->ob_type->tp_name);
623 } else {
624 /* print and clear the exception */
625 PyErr_Print();
626 }
627
628 if (req->active) {
629 /* they didn't do .finish, so free the Request (preserving the .file
630 struct) and return an error. */
631 req->active = 0;
632 Py_DECREF(req);
633 return -EIO;
634 }
635 /* they did do .finish, so an error code was already sent */
636 Py_DECREF(req);
637 return -FUSD_NOREPLY;
638 }
639
640 static int
641 client_ioctl(struct fusd_file_info *file, int request, void *data)
642 {
643 PyObject *ret, *fp;
644 RequestObject *req;
645
646 fp = file->private_data;
647
648 req = newIoctlRequestObject(file, fp);
649 if (!req) {
650 fprintf(stderr, "client_ioctl: unable to allocate RequestObject\n");
651 return -EIO;
652 }
653
654 ret = PyObject_CallMethod(fp, "do_ioctl", "O", req);
655
656 if (ret == Py_None) {
657 /* this is the normal case. They might have called req.finish, or
658 they may defer it until later. */
659 Py_DECREF(req);
660 return -FUSD_NOREPLY;
661 }
662
663 /* something went wrong */
664
665 if (ret) {
666 fprintf(stderr,
667 "do_ioctl should not return anything (returned <%s>)\n",
668 ret->ob_type->tp_name);
669 } else {
670 /* print and clear the exception */
671 PyErr_Print();
672 }
673
674 if (req->active) {
675 /* they didn't do .finish, so free the Request (preserving the .file
676 struct) and return an error. */
677 req->active = 0;
678 Py_DECREF(req);
679 return -EIO;
680 }
681 /* they did do .finish, so an error code was already sent */
682 Py_DECREF(req);
683 return -FUSD_NOREPLY;
684 }
685
686 static int
687 client_poll_diff(struct fusd_file_info *file, unsigned int cached_state)
688 {
689 PyObject *ret, *fp;
690 RequestObject *req;
691
692 fp = file->private_data;
693
694 req = newPollDiffRequestObject(file, fp);
695 if (!req) {
696 fprintf(stderr,
697 "client_poll_diff: unable to allocate RequestObject\n");
698 return -EIO;
699 }
700
701 ret = PyObject_CallMethod(fp, "do_poll_diff", "Oi", req, cached_state);
702
703 if (ret == Py_None) {
704 /* this is the normal case. They might have called req.finish, or
705 they may defer it until later. */
706 Py_DECREF(req);
707 return -FUSD_NOREPLY;
708 }
709
710 /* something went wrong */
711
712 if (ret) {
713 fprintf(stderr,
714 "do_poll_diff should not return anything (returned <%s>)\n",
715 ret->ob_type->tp_name);
716 } else {
717 /* print and clear the exception */
718 PyErr_Print();
719 }
720
721 if (req->active) {
722 /* they didn't do .finish, so free the Request (preserving the .file
723 struct) and return an error. */
724 req->active = 0;
725 Py_DECREF(req);
726 return -EIO;
727 }
728 /* they did do .finish, so an error code was already sent */
729 Py_DECREF(req);
730 return -FUSD_NOREPLY;
731 }
732
733 static struct fusd_file_operations fops = {
734 open: client_open,
735 close: client_close,
736 read: client_read,
737 write: client_write,
738 ioctl: client_ioctl,
739 poll_diff: client_poll_diff,
740 };
741
742
743 static PyObject *
744 do_register(PyObject *self, PyObject *args)
745 {
746 const char *name;
747 PyObject *device_info;
748 int mode; /* permissions for the /dev/NAME device, like 0666 */
749 mode_t realmode;
750 int handle;
751
752 if (!PyArg_ParseTuple(args, "siO", &name, &mode, &device_info))
753 return NULL;
754
755 realmode = mode;
756 handle = fusd_register(name, realmode, device_info, &fops);
757 if (handle < 0) {
758 /* errno will be ENOPKG if the kernel module isn't installed */
759 return PyErr_SetFromErrno(PyExc_RuntimeError);
760 }
761 Py_INCREF(device_info);
762 return PyInt_FromLong(handle);
763 }
764
765 static PyObject *
766 do_unregister(PyObject *self, PyObject *args)
767 {
768 PyObject *device_info;
769 int rc, fd;
770
771 if (!PyArg_ParseTuple(args, "iO", &fd, &device_info))
772 return NULL;
773
774 rc = fusd_unregister(fd);
775 Py_DECREF(device_info);
776 if (rc < 0) {
777 return PyErr_SetFromErrno(PyExc_RuntimeError);
778 }
779 return PyInt_FromLong(rc);
780 }
781
782 static PyObject *
783 do_dispatch(PyObject *self, PyObject *args)
784 {
785 int fd;
786
787 if (!PyArg_ParseTuple(args, "i", &fd))
788 return NULL;
789
790 fusd_dispatch(fd);
791
792 Py_INCREF(Py_None);
793 return Py_None;
794 }
795
796 static PyObject *
797 do_run(PyObject *self, PyObject *args)
798 {
799 if (!PyArg_ParseTuple(args, ""))
800 return NULL;
801
802 fusd_run(); /* runs forever */
803
804 Py_INCREF(Py_None);
805 return Py_None; /* but just in case */
806 }
807
808 static
809 struct PyMethodDef Methods[] =
810 {
811 {"register", do_register, METH_VARARGS },
812 {"unregister", do_unregister, METH_VARARGS },
813 {"dispatch", do_dispatch, METH_VARARGS },
814 {"run", do_run, METH_VARARGS },
815 {NULL, NULL },
816 };
817
818 DL_EXPORT(void)
819 init_fusd(void)
820 {
821 PyObject *module, *d;
822
823 ReadRequest_Type.ob_type = &PyType_Type;
824 WriteRequest_Type.ob_type = &PyType_Type;
825 IoctlRequest_Type.ob_type = &PyType_Type;
826
827 module = Py_InitModule("_fusd", Methods);
828
829 /* constants */
830 d = PyModule_GetDict(module);
831 PyDict_SetItemString(d, "NOREPLY", PyInt_FromLong(FUSD_NOREPLY));
832 PyDict_SetItemString(d, "NOTIFY_INPUT",
833 PyInt_FromLong(FUSD_NOTIFY_INPUT));
834 PyDict_SetItemString(d, "NOTIFY_OUTPUT",
835 PyInt_FromLong(FUSD_NOTIFY_OUTPUT));
836 PyDict_SetItemString(d, "NOTIFY_EXCEPT",
837 PyInt_FromLong(FUSD_NOTIFY_EXCEPT));
838 }
839
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.