(file) Return to fusdmodule.c CVS log (file) Jump to this file's LXR Page (dir) Up to [CENS] / emstar / fusd / python

File: [CENS] / emstar / fusd / python / fusdmodule.c (download) / (as text)
Revision: 1.3, Fri Jul 11 21:29:39 2003 UTC (6 years, 4 months ago) by cerpa
Branch: MAIN
CVS Tags: scale_radio_channel, rdd_alpha_version_1, pregeonet, nims-lab-Sep07-2004, nims-jr-Sep05-04, mote, lessgps_release, kiss_release, fusd_with_no_daemon, fusd-1_10, copyright-07-11-03, bp_scale_radio_channel, audio_server, acoustic-05-18-06, ROUTING_EXPERIMENTAL, PRE_TOSNIC_FIX, PRE_NOMEGA_MOTENIC, PRE_MOTENIC_CLEANUP, PRE_CEILING_FIX, PRE_64BIT, MOTENIC_PRE_BUGFIX_20050415, LESSGPS_1_00, LAURA_CALIBRATION_EXPERIMENTS, KISS_1_0, HOSTMOTE_V_6_EXPERIMENTAL, HOSTMOTE_PROTOCOL_VERSION_7, HOSTMOTE_PROTOCOL_VERSION_6_WITH_HOSTMOAP, HOSTMOTE_PROTOCOL_VERSION_5_WITH_HOSTMOAP, HOSTMOTE_PROTOCOL_VERSION_5, HOSTMOTE_PROTOCOL_VERSION_4, HOSTMOTE_PROTOCOL_VERSION_3, HEAD, ESS_RELEASE_3_5, ESS_RELEASE_3_4, ESS_RELEASE_3_3, ESS_RELEASE_3_2, ESS_RELEASE_3_1, ESS_RELEASE_3_0, ESS_RELEASE_2_0, ESS_CONNECTIVITY, ESS_CENTROUTE_TESTING, ESS2-CMS-V1_5_pretest, ESS2-CMS-V1_4cMergeSympathy_2, ESS2-CMS-V1_4c, ESS2-CMS-V1_4b, ESS2-CMS-V1_4a, ESS2-CMS-V1_3, ESS2-CMS-V1_2, ESS2-CMS-V1_1, ESS2-CMS-V1_0, EMSTAR_RELEASE_2_5, EMSTAR_RELEASE_2_1_BRANCH, EMSTAR_RELEASE_2_1, EMSTAR_RELEASE_2_0_beta1, EMSTAR_RELEASE_2_0, EMSTAR_RELEASE_1_3_2, EMSTAR_RELEASE_1_3_1, EMSTAR_RELEASE_1_3, EMSTAR_RELEASE_1_2, EMSTAR_RELEASE_1_1, EMSTAR_RELEASE_1_0, EMSTAR_PRE_HTML, CYCLOPS_RELEASE_CANDIDATE_2_0, CYCLOPS_PRERELEASE_STABLE, CENTROUTE_EMSTAR_SOCKETS, BG_1_0, BANGLADESH_ARSENIC_1_2, BANGLADESH_ARSENIC_1_1, AMARSS_JR_DEPLOYMENT_6_05_07
Changes since 1.2: +24 -29 lines
added the copyright notice to all the source code in the cens repository

/*
 *
 * Copyright (c) 2003 The Regents of the University of California.  All 
 * rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * - Redistributions of source code must retain the above copyright
 *   notice, this list of conditions and the following disclaimer.
 *
 * - Neither the name of the University nor the names of its
 *   contributors may be used to endorse or promote products derived
 *   from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */
 

/*
    Copyright (C) 2003  Brian Warner  <warner-fusd@lothar.com>

    This program is free software, and can be distributed under the same
    terms as the rest of FUSD (the BSD 3-clause license). See the file
    ../LICENSE for details.
*/



#include <stdio.h>
#include <Python.h>

#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>

#include "fusd.h"

typedef struct {
    PyObject_HEAD
    struct fusd_file_info *file;
    int active;
    PyObject *fp;
} RequestObject;

staticforward PyTypeObject ReadRequest_Type;
staticforward PyTypeObject WriteRequest_Type;
staticforward PyTypeObject IoctlRequest_Type;
staticforward PyTypeObject PollDiffRequest_Type;

#define ReadRequestObject_Check(v) ((v)->ob_type == &ReadRequest_Type)
#define WriteRequestObject_Check(v) ((v)->ob_type == &WriteRequest_Type)
#define IoctlRequestObject_Check(v) ((v)->ob_type == &IoctlRequest_Type)
#define PollDiffRequestObject_Check(v) ((v)->ob_type == &PollDiffRequest_Type)

static RequestObject *
newReadRequestObject(struct fusd_file_info *file, PyObject *fp)
{
    RequestObject *self;
    self = PyObject_New(RequestObject, &ReadRequest_Type);
    if (self == NULL)
        return NULL;
    self->file = file;
    self->active = 1;
    self->fp = fp;
    return self;
}

static RequestObject *
newWriteRequestObject(struct fusd_file_info *file, PyObject *fp)
{
    RequestObject *self;
    self = PyObject_New(RequestObject, &WriteRequest_Type);
    if (self == NULL)
        return NULL;
    self->file = file;
    self->active = 1;
    self->fp = fp;
    return self;
}

static RequestObject *
newIoctlRequestObject(struct fusd_file_info *file, PyObject *fp)
{
    RequestObject *self;
    self = PyObject_New(RequestObject, &IoctlRequest_Type);
    if (self == NULL)
        return NULL;
    self->file = file;
    self->active = 1;
    self->fp = fp;
    return self;
}

static RequestObject *
newPollDiffRequestObject(struct fusd_file_info *file, PyObject *fp)
{
    RequestObject *self;
    self = PyObject_New(RequestObject, &PollDiffRequest_Type);
    if (self == NULL)
        return NULL;
    self->file = file;
    self->active = 1;
    self->fp = fp;
    return self;
}

static void
Request_dealloc(RequestObject *self)
{
    if (self->active) {
        /* the python code should not let active requests fall out of scope.
           They should all be explicitly .finish()ed or .destroy()ed */
        fprintf(stderr, "Warning: Active Request <%s> being destroyed\n",
                self->ob_type->tp_name);
        self->active = 0;
        fusd_destroy(self->file);
    }
    PyObject_Del(self);
}

static PyObject *
Request_finish(RequestObject *self, PyObject *args)
{
    int retval; /* really ssize_t */
    int rc;

    if (!PyArg_ParseTuple(args, "i:finish", &retval))
        return NULL;
    if (!self->active) {
        PyErr_SetString(PyExc_RuntimeError, "duplicate request->return");
        return NULL;
    }
    rc = fusd_return(self->file, retval);
    self->active = 0;
    return PyInt_FromLong(rc);
}

static PyObject *
Request_destroy(RequestObject *self, PyObject *args)
{
    if (!PyArg_ParseTuple(args, ":destroy"))
        return NULL;
    if (!self->active) {
        PyErr_SetString(PyExc_RuntimeError,
                        "can only destroy active requests");
        return NULL;
    }
    fusd_destroy(self->file);
    self->active = 0;

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
ReadRequest_setdata(RequestObject *self, PyObject *args)
{
    int offset;
    char *data;
    int datalen;

    if (!self->active) {
        PyErr_SetString(PyExc_RuntimeError, "setdata on inactive request");
        return NULL;
    }

    if (!PyArg_ParseTuple(args, "is#:setdata", &offset, &data, &datalen))
        return NULL;

    if ((offset < 0) || (offset+datalen > fusd_get_length(self->file))) {
        PyErr_SetString(PyExc_IndexError, "writing beyond buffer");
        return NULL;
    }

    memcpy(fusd_get_read_buffer(self->file), data, datalen);

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
WriteRequest_getdata(RequestObject *self, PyObject *args)
{
    int offset = 0;
    int datalen = fusd_get_length(self->file);
    int reqlen = datalen;
    PyObject *ret;

    if (!self->active) {
        PyErr_SetString(PyExc_RuntimeError, "getdata on inactive request");
        return NULL;
    }
    if (!PyArg_ParseTuple(args, "|ii:getdata", &offset, &reqlen))
        return NULL;

    if ((offset < 0) || (reqlen < 0 ) || (offset+reqlen > datalen)) {
        PyErr_SetString(PyExc_IndexError, "reading beyond buffer");
        return NULL;
    }

    ret = Py_BuildValue("s#", fusd_get_write_buffer(self->file) + offset,
                        reqlen);
    return ret;
}

static PyObject *
IoctlRequest_getdata(RequestObject *self, PyObject *args)
{

    if (!self->active) {
        PyErr_SetString(PyExc_RuntimeError, "getdata on inactive request");
        return NULL;
    }

    // IO_W or IO_WR will have a data pointer
    if (fusd_get_ioctl_buffer(self->file)) {
        return Py_BuildValue("s#", fusd_get_ioctl_buffer(self->file),
                             fusd_get_length(self->file));
    }
    // IO will have an int, IO_R will probably have a zero
    return PyInt_FromLong(fusd_get_ioctl_arg(self->file));
}

static PyObject *
IoctlRequest_setdata(RequestObject *self, PyObject *args)
{
    char *data;
    int datalen;
    int cmd = fusd_get_ioctl_request(self->file);

    if (!self->active) {
        PyErr_SetString(PyExc_RuntimeError, "getdata on inactive request");
        return NULL;
    }

    // IO_R will have a data pointer. IO_W will to, but it isn't used
    if ((_IOC_DIR(cmd) & _IOC_READ) && fusd_get_ioctl_buffer(self->file))
    {
        if (!PyArg_ParseTuple(args, "s#:setdata", &data, &datalen))
            return NULL;
        if (datalen > fusd_get_length(self->file)) {
            PyErr_Format(PyExc_IndexError,
                         "too much data: ioctl accepts %d bytes, given %d",
                         fusd_get_length(self->file), datalen);
            return NULL;
        }
        memcpy(fusd_get_ioctl_buffer(self->file), data, datalen);
        Py_INCREF(Py_None);
        return Py_None;
    }

    PyErr_SetString(PyExc_TypeError, "this ioctl is read only");
    return NULL;
}


static PyMethodDef ReadRequest_methods[] = {
    {"setdata", (PyCFunction)ReadRequest_setdata, METH_VARARGS},
    {"destroy", (PyCFunction)Request_destroy, METH_VARARGS},
    {"finish", (PyCFunction)Request_finish, METH_VARARGS},
    {NULL, NULL} /* sentinel */
};

static PyMethodDef WriteRequest_methods[] = {
    {"getdata", (PyCFunction)WriteRequest_getdata, METH_VARARGS},
    {"destroy", (PyCFunction)Request_destroy, METH_VARARGS},
    {"finish", (PyCFunction)Request_finish, METH_VARARGS},
    {NULL, NULL} /* sentinel */
};

static PyMethodDef IoctlRequest_methods[] = {
    {"getdata", (PyCFunction)IoctlRequest_getdata, METH_VARARGS},
    {"setdata", (PyCFunction)IoctlRequest_setdata, METH_VARARGS},
    {"destroy", (PyCFunction)Request_destroy, METH_VARARGS},
    {"finish", (PyCFunction)Request_finish, METH_VARARGS},
    {NULL, NULL} /* sentinel */
};

static PyMethodDef PollDiffRequest_methods[] = {
    {"destroy", (PyCFunction)Request_destroy, METH_VARARGS},
    {"finish", (PyCFunction)Request_finish, METH_VARARGS},
    {NULL, NULL} /* sentinel */
};

static int
Request_getparm(RequestObject *self, char *name, int *valid)
{
    *valid = 1;
    if (strcmp(name, "length") == 0)
        return fusd_get_length(self->file);
    if (strcmp(name, "fd") == 0)
        return self->file->fd;
    if (strcmp(name, "flags") == 0)
        return self->file->flags;
    if (strcmp(name, "pid") == 0)
        return self->file->pid;
    if (strcmp(name, "uid") == 0)
        return self->file->uid;
    if (strcmp(name, "gid") == 0)
        return self->file->gid;
    if (strcmp(name, "offset") == 0) {
        int offset = *(fusd_get_offset(self->file)); /* loff_t */
        return offset;
    }
            
    *valid = 0;
    return 0;
}

static PyObject *
ReadRequest_getattr(RequestObject *self, char *name)
{
    int parm, valid;

    parm = Request_getparm(self, name, &valid);
    if (valid)
        return PyInt_FromLong(parm);
    return Py_FindMethod(ReadRequest_methods, (PyObject *)self, name);
}

static PyObject *
WriteRequest_getattr(RequestObject *self, char *name)
{
    int parm, valid;

    parm = Request_getparm(self, name, &valid);
    if (valid)
        return PyInt_FromLong(parm);
    return Py_FindMethod(WriteRequest_methods, (PyObject *)self, name);
}

static PyObject *
IoctlRequest_getattr(RequestObject *self, char *name)
{
    int parm, valid;
    int cmd = fusd_get_ioctl_request(self->file);

    parm = Request_getparm(self, name, &valid);
    if (valid)
        return PyInt_FromLong(parm);
    if (strcmp(name, "cmd") == 0)
        return PyInt_FromLong(cmd);
    if (strcmp(name, "nr") == 0)
        return PyInt_FromLong(_IOC_NR(cmd));
    if (strcmp(name, "type") == 0)
        return PyInt_FromLong(_IOC_TYPE(cmd));
    if (strcmp(name, "size") == 0)
        return PyInt_FromLong(_IOC_SIZE(cmd));
    if (strcmp(name, "direction") == 0)
        return PyInt_FromLong(_IOC_DIR(cmd));
    if (strcmp(name, "dir_string") == 0) {
        int dir = _IOC_DIR(cmd);
        switch (dir) {
          case _IOC_NONE:
            return PyString_FromString("none");
          case _IOC_WRITE:
            return PyString_FromString("write");
          case _IOC_READ:
            return PyString_FromString("read");
          case (_IOC_READ | _IOC_WRITE):
            return PyString_FromString("readwrite");
        }
    }

    return Py_FindMethod(IoctlRequest_methods, (PyObject *)self, name);
}

static PyObject *
PollDiffRequest_getattr(RequestObject *self, char *name)
{
    return Py_FindMethod(PollDiffRequest_methods, (PyObject *)self, name);
}


static int
Request_setattr(RequestObject *self, char *name, PyObject *v)
{
    if (strcmp(name, "offset") == 0) {
        int offset;
        offset = PyInt_AsLong(v);
        if (PyErr_Occurred())
            return -1;
        *(fusd_get_offset(self->file)) = offset; /* loff_t */
        return 0;
    }
    if (strcmp(name, "flags") == 0) {
        int flags;
        flags = PyInt_AsLong(v);
        if (PyErr_Occurred())
            return -1;
        self->file->flags = flags;
        return 0;
    }

    PyErr_Format(PyExc_AttributeError,
                 "cannot set Request attribute '%s'", name);
    return -1;
}

statichere PyTypeObject ReadRequest_Type = {
    /* The ob_type field must be initialized in the module init function
     * to be portable to Windows without using C++. */
    PyObject_HEAD_INIT(NULL)
    0,                              /*ob_size*/
    "fusdmodule.ReadRequest",       /*tp_name*/
    sizeof(RequestObject),          /*tp_basicsize*/
    0,                              /*tp_itemsize*/
    /* methods */
    (destructor)Request_dealloc,    /*tp_dealloc*/
    0,                                     /*tp_print*/
    (getattrfunc)ReadRequest_getattr,      /*tp_getattr*/
    (setattrfunc)Request_setattr,          /*tp_setattr*/
};

statichere PyTypeObject WriteRequest_Type = {
    /* The ob_type field must be initialized in the module init function
     * to be portable to Windows without using C++. */
    PyObject_HEAD_INIT(NULL)
    0,                              /*ob_size*/
    "fusdmodule.WriteRequest",      /*tp_name*/
    sizeof(RequestObject),          /*tp_basicsize*/
    0,                              /*tp_itemsize*/
    /* methods */
    (destructor)Request_dealloc,    /*tp_dealloc*/
    0,                                     /*tp_print*/
    (getattrfunc)WriteRequest_getattr,     /*tp_getattr*/
    (setattrfunc)Request_setattr,          /*tp_setattr*/
};

statichere PyTypeObject IoctlRequest_Type = {
    /* The ob_type field must be initialized in the module init function
     * to be portable to Windows without using C++. */
    PyObject_HEAD_INIT(NULL)
    0,                              /*ob_size*/
    "fusdmodule.IoctlRequest",      /*tp_name*/
    sizeof(RequestObject),          /*tp_basicsize*/
    0,                              /*tp_itemsize*/
    /* methods */
    (destructor)Request_dealloc,    /*tp_dealloc*/
    0,                                     /*tp_print*/
    (getattrfunc)IoctlRequest_getattr,     /*tp_getattr*/
    (setattrfunc)Request_setattr,          /*tp_setattr*/
};

statichere PyTypeObject PollDiffRequest_Type = {
    /* The ob_type field must be initialized in the module init function
     * to be portable to Windows without using C++. */
    PyObject_HEAD_INIT(NULL)
    0,                              /*ob_size*/
    "fusdmodule.PollDiffRequest",   /*tp_name*/
    sizeof(RequestObject),          /*tp_basicsize*/
    0,                              /*tp_itemsize*/
    /* methods */
    (destructor)Request_dealloc,    /*tp_dealloc*/
    0,                                     /*tp_print*/
    (getattrfunc)PollDiffRequest_getattr,  /*tp_getattr*/
    0,                                     /*tp_setattr*/
};


static int
client_open(struct fusd_file_info *file)
{
    PyObject *ret, *device;
    int retval;
    unsigned int flags;
    PyObject *fp;

    device = file->device_info;
    ret = PyObject_CallMethod(device, "do_open",
                              "iiii", file->flags, file->pid,
                              file->uid, file->gid);
    if (!ret) {
        /* print and clear the exception */
        PyErr_Print();
        return -EIO;
    }
    if (!PyArg_ParseTuple(ret, "iiO", &retval, &flags, &fp))
    {
        PyErr_Print();
        return -EIO;
    }
    file->flags = flags;
    file->private_data = fp;
    return retval;
}

static int
client_close(struct fusd_file_info *file)
{
    PyObject *ret, *device, *fp;
    int retval;

    device = file->device_info;
    fp = file->private_data;
    ret = PyObject_CallMethod(device, "do_close", "Oiiii",
                              fp, file->flags, file->pid,
                              file->uid, file->gid);
    if (!ret) {
        /* print and clear the exception */
        PyErr_Print();
        return -EIO;
    }
    if (!PyArg_ParseTuple(ret, "i", &retval))
    {
        PyErr_Print();
        return -EIO;
    }
    return retval;
}

static ssize_t
client_read(struct fusd_file_info *file, char *buffer, size_t length,
            loff_t *offset)
{
    PyObject *ret, *fp;
    RequestObject *req;
    int newoffset;

    fp = file->private_data;

    newoffset = *offset; /* loff_t */
    if (newoffset != *offset) {
        fprintf(stderr, "Ack! offset is too large, loff_t is too big\n");
        fprintf(stderr, "client_read() failing..\n");
        return -EIO;
    }

    req = newReadRequestObject(file, fp);
    if (!req) {
        fprintf(stderr, "client_read: unable to allocate RequestObject\n");
        return -EIO;
    }

    ret = PyObject_CallMethod(fp, "do_read", "O", req);

    if (ret == Py_None) {
        /* this is the normal case. They might have called req.finish, or
           they may defer it until later. */
        Py_DECREF(req);
        return -FUSD_NOREPLY;
    }

    /* something went wrong */

    if (ret) {
        fprintf(stderr,
                "do_read should not return anything (returned <%s>)\n",
                ret->ob_type->tp_name);
    } else {
        /* print and clear the exception */
        PyErr_Print();
    }

    if (req->active) {
        /* they didn't do .finish, so free the Request (preserving the .file
           struct) and return an error. */
        req->active = 0;
        Py_DECREF(req);
        return -EIO;
    }
    /* they did do .finish, so an error code was already sent */
    Py_DECREF(req);
    return -FUSD_NOREPLY;
}

static ssize_t
client_write(struct fusd_file_info *file, const char *buffer,
             size_t length, loff_t *offset)
{
    PyObject *ret, *fp;
    int newoffset;
    RequestObject *req;

    /* N.B.: loff_t is larger than an int, so you can't pass *offset to a
     varargs function because everything after that argument will be taken
     from the wrong place. Downgrade it to an int before handing it to
     Py_BuildValue. This also means we can't deal with >2GB files yet. */

    fp = file->private_data;
    newoffset = *offset;

    if (newoffset != *offset) {
        fprintf(stderr, "Ack! offset is too large, loff_t is too big\n");
        fprintf(stderr, "client_write() failing..\n");
        return -EIO;
    }

    req = newWriteRequestObject(file, fp);
    if (!req) {
        fprintf(stderr, "client_write: unable to allocate RequestObject\n");
        return -EIO;
    }
    
    ret = PyObject_CallMethod(fp, "do_write", "O", req);

    if (ret == Py_None) {
        /* this is the normal case. They might have called req.finish, or
           they may defer it until later. */
        Py_DECREF(req);
        return -FUSD_NOREPLY;
    }

    /* something went wrong */

    if (ret) {
        fprintf(stderr,
                "do_write should not return anything (returned <%s>)\n",
                ret->ob_type->tp_name);
    } else {
        /* print and clear the exception */
        PyErr_Print();
    }

    if (req->active) {
        /* they didn't do .finish, so free the Request (preserving the .file
           struct) and return an error. */
        req->active = 0;
        Py_DECREF(req);
        return -EIO;
    }
    /* they did do .finish, so an error code was already sent */
    Py_DECREF(req);
    return -FUSD_NOREPLY;
}

static int
client_ioctl(struct fusd_file_info *file, int request, void *data)
{
    PyObject *ret, *fp;
    RequestObject *req;

    fp = file->private_data;

    req = newIoctlRequestObject(file, fp);
    if (!req) {
        fprintf(stderr, "client_ioctl: unable to allocate RequestObject\n");
        return -EIO;
    }

    ret = PyObject_CallMethod(fp, "do_ioctl", "O", req);

    if (ret == Py_None) {
        /* this is the normal case. They might have called req.finish, or
           they may defer it until later. */
        Py_DECREF(req);
        return -FUSD_NOREPLY;
    }

    /* something went wrong */

    if (ret) {
        fprintf(stderr,
                "do_ioctl should not return anything (returned <%s>)\n",
                ret->ob_type->tp_name);
    } else {
        /* print and clear the exception */
        PyErr_Print();
    }

    if (req->active) {
        /* they didn't do .finish, so free the Request (preserving the .file
           struct) and return an error. */
        req->active = 0;
        Py_DECREF(req);
        return -EIO;
    }
    /* they did do .finish, so an error code was already sent */
    Py_DECREF(req);
    return -FUSD_NOREPLY;
}

static int
client_poll_diff(struct fusd_file_info *file, unsigned int cached_state)
{
    PyObject *ret, *fp;
    RequestObject *req;

    fp = file->private_data;

    req = newPollDiffRequestObject(file, fp);
    if (!req) {
        fprintf(stderr,
                "client_poll_diff: unable to allocate RequestObject\n");
        return -EIO;
    }

    ret = PyObject_CallMethod(fp, "do_poll_diff", "Oi", req, cached_state);

    if (ret == Py_None) {
        /* this is the normal case. They might have called req.finish, or
           they may defer it until later. */
        Py_DECREF(req);
        return -FUSD_NOREPLY;
    }

    /* something went wrong */

    if (ret) {
        fprintf(stderr,
                "do_poll_diff should not return anything (returned <%s>)\n",
                ret->ob_type->tp_name);
    } else {
        /* print and clear the exception */
        PyErr_Print();
    }

    if (req->active) {
        /* they didn't do .finish, so free the Request (preserving the .file
           struct) and return an error. */
        req->active = 0;
        Py_DECREF(req);
        return -EIO;
    }
    /* they did do .finish, so an error code was already sent */
    Py_DECREF(req);
    return -FUSD_NOREPLY;
}

static struct fusd_file_operations fops = {
    open: client_open,
    close: client_close,
    read: client_read,
    write: client_write,
    ioctl: client_ioctl,
    poll_diff: client_poll_diff,
};


static PyObject *
do_register(PyObject *self, PyObject *args)
{
    const char *name;
    PyObject *device_info;
    int mode; /* permissions for the /dev/NAME device, like 0666 */
    mode_t realmode;
    int handle;

    if (!PyArg_ParseTuple(args, "siO", &name, &mode, &device_info))
        return NULL;

    realmode = mode;
    handle = fusd_register(name, realmode, device_info, &fops);
    if (handle < 0) {
        /* errno will be ENOPKG if the kernel module isn't installed */
        return PyErr_SetFromErrno(PyExc_RuntimeError);
    }
    Py_INCREF(device_info);
    return PyInt_FromLong(handle);
}

static PyObject *
do_unregister(PyObject *self, PyObject *args)
{
    PyObject *device_info;
    int rc, fd;

    if (!PyArg_ParseTuple(args, "iO", &fd, &device_info))
        return NULL;

    rc = fusd_unregister(fd);
    Py_DECREF(device_info);
    if (rc < 0) {
        return PyErr_SetFromErrno(PyExc_RuntimeError);
    }
    return PyInt_FromLong(rc);
}

static PyObject *
do_dispatch(PyObject *self, PyObject *args)
{
    int fd;

    if (!PyArg_ParseTuple(args, "i", &fd))
        return NULL;

    fusd_dispatch(fd);

    Py_INCREF(Py_None);
    return Py_None;
}

static PyObject *
do_run(PyObject *self, PyObject *args)
{
    if (!PyArg_ParseTuple(args, ""))
        return NULL;

    fusd_run(); /* runs forever */

    Py_INCREF(Py_None);
    return Py_None; /* but just in case */
}

static
struct PyMethodDef Methods[] =
{
    {"register",  do_register, METH_VARARGS },
    {"unregister",  do_unregister, METH_VARARGS },
    {"dispatch",  do_dispatch, METH_VARARGS },
    {"run",  do_run, METH_VARARGS },
    {NULL, NULL },
};

DL_EXPORT(void)
init_fusd(void)
{
    PyObject *module, *d;

    ReadRequest_Type.ob_type = &PyType_Type;
    WriteRequest_Type.ob_type = &PyType_Type;
    IoctlRequest_Type.ob_type = &PyType_Type;

    module = Py_InitModule("_fusd", Methods);

    /* constants */
    d = PyModule_GetDict(module);
    PyDict_SetItemString(d, "NOREPLY", PyInt_FromLong(FUSD_NOREPLY));
    PyDict_SetItemString(d, "NOTIFY_INPUT",
                         PyInt_FromLong(FUSD_NOTIFY_INPUT));
    PyDict_SetItemString(d, "NOTIFY_OUTPUT",
                         PyInt_FromLong(FUSD_NOTIFY_OUTPUT));
    PyDict_SetItemString(d, "NOTIFY_EXCEPT",
                         PyInt_FromLong(FUSD_NOTIFY_EXCEPT));
}

CENS CVS Mailing List
Powered by
ViewCVS 0.9.2