source: trunk/packages/xen-3.1/xen-3.1/tools/python/xen/lowlevel/xs/xs.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 24.8 KB
Line 
1/*
2 * Python interface to the Xen Store Daemon.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of version 2.1 of the GNU Lesser General Public
6 * License as published by the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16 *
17 * Copyright (C) 2005 Mike Wray Hewlett-Packard
18 * Copyright (C) 2005 Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
19 * Copyright (C) 2005 XenSource Ltd.
20 */
21
22#include <Python.h>
23
24#include <stdbool.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <unistd.h>
28#include <sys/types.h>
29#include <sys/stat.h>
30#include <fcntl.h>
31#include <errno.h>
32
33#include <xenctrl.h>
34#include "xs.h"
35
36/** @file
37 * Python interface to the Xen Store Daemon (xs).
38 */
39
40/* Needed for Python versions earlier than 2.3. */
41#ifndef PyMODINIT_FUNC
42#define PyMODINIT_FUNC DL_EXPORT(void)
43#endif
44
45#define PKG "xen.lowlevel.xs"
46#define CLS "xs"
47
48static PyObject *xs_error;
49
50/** Python wrapper round an xs handle.
51 */
52typedef struct XsHandle {
53    PyObject_HEAD;
54    struct xs_handle *xh;
55    PyObject *watches;
56} XsHandle;
57
58static void xs_set_error(int value)
59{
60        errno = value;
61        PyErr_SetFromErrno(xs_error);
62}
63
64static inline struct xs_handle *xshandle(XsHandle *self)
65{
66    struct xs_handle *xh = self->xh;
67    if (!xh)
68        xs_set_error(EINVAL);
69    return xh;
70}
71
72static void remove_watch(XsHandle *xsh, PyObject *token);
73
74static PyObject *none(bool result);
75
76static int parse_transaction_path(XsHandle *self, PyObject *args,
77                                  struct xs_handle **xh,
78                                  xs_transaction_t *th,
79                                  char **path);
80
81
82#define xspy_read_doc "\n"                              \
83        "Read data from a path.\n"                      \
84        " transaction [string]: transaction handle\n"   \
85        " path [string]:        xenstore path\n"        \
86        "\n"                                            \
87        "Returns: [string] data read.\n"                \
88        "         None if key doesn't exist.\n"         \
89        "Raises xen.lowlevel.xs.Error on error.\n"               \
90        "\n"
91
92static PyObject *xspy_read(XsHandle *self, PyObject *args)
93{
94    struct xs_handle *xh;
95    xs_transaction_t th;
96    char *path;
97
98    char *xsval;
99    unsigned int xsval_n;
100
101    if (!parse_transaction_path(self, args, &xh, &th, &path))
102        return NULL;
103
104    Py_BEGIN_ALLOW_THREADS
105    xsval = xs_read(xh, th, path, &xsval_n);
106    Py_END_ALLOW_THREADS
107    if (xsval) {
108        PyObject *val = PyString_FromStringAndSize(xsval, xsval_n);
109        free(xsval);
110        return val;
111    }
112    else {
113        return none(errno == ENOENT);
114    }
115}
116
117
118#define xspy_write_doc "\n"                                     \
119        "Write data to a path.\n"                               \
120        " transaction [string]: transaction handle\n"           \
121        " path   [string] : xenstore path to write to\n."       \
122        " data   [string] : data to write.\n"                   \
123        "\n"                                                    \
124        "Returns None on success.\n"                            \
125        "Raises xen.lowlevel.xs.Error on error.\n"                      \
126        "\n"
127
128static PyObject *xspy_write(XsHandle *self, PyObject *args)
129{
130    static char *arg_spec = "sss#";
131    struct xs_handle *xh = xshandle(self);
132    xs_transaction_t th;
133    char *thstr;
134    char *path;
135    char *data;
136    int data_n;
137    bool result;
138
139    if (!xh)
140        return NULL;
141    if (!PyArg_ParseTuple(args, arg_spec, &thstr, &path, &data, &data_n))
142        return NULL;
143
144    th = strtoul(thstr, NULL, 16);
145
146    Py_BEGIN_ALLOW_THREADS
147    result = xs_write(xh, th, path, data, data_n);
148    Py_END_ALLOW_THREADS
149
150    return none(result);
151}
152
153
154#define xspy_ls_doc "\n"                                        \
155        "List a directory.\n"                                   \
156        " transaction [string]: transaction handle\n"           \
157        " path [string]:        path to list.\n"                \
158        "\n"                                                    \
159        "Returns: [string array] list of subdirectory names.\n" \
160        "         None if key doesn't exist.\n"                 \
161        "Raises xen.lowlevel.xs.Error on error.\n"                      \
162        "\n"
163
164static PyObject *xspy_ls(XsHandle *self, PyObject *args)
165{
166    struct xs_handle *xh;
167    xs_transaction_t th;
168    char *path;
169
170    char **xsval;
171    unsigned int xsval_n;
172
173    if (!parse_transaction_path(self, args, &xh, &th, &path))
174        return NULL;
175
176    Py_BEGIN_ALLOW_THREADS
177    xsval = xs_directory(xh, th, path, &xsval_n);
178    Py_END_ALLOW_THREADS
179
180    if (xsval) {
181        int i;
182        PyObject *val = PyList_New(xsval_n);
183        for (i = 0; i < xsval_n; i++)
184            PyList_SetItem(val, i, PyString_FromString(xsval[i]));
185        free(xsval);
186        return val;
187    }
188    else {
189        return none(errno == ENOENT);
190    }
191}
192
193
194#define xspy_mkdir_doc "\n"                                     \
195        "Make a directory.\n"                                   \
196        " path [string]: path to directory to create.\n"        \
197        "\n"                                                    \
198        "Returns None on success.\n"                            \
199        "Raises xen.lowlevel.xs.Error on error.\n"                      \
200        "\n"
201
202static PyObject *xspy_mkdir(XsHandle *self, PyObject *args)
203{
204    struct xs_handle *xh;
205    xs_transaction_t th;
206    char *path;
207
208    bool result;
209
210    if (!parse_transaction_path(self, args, &xh, &th, &path))
211        return NULL;
212
213    Py_BEGIN_ALLOW_THREADS
214    result = xs_mkdir(xh, th, path);
215    Py_END_ALLOW_THREADS
216
217    return none(result);
218}
219
220
221#define xspy_rm_doc "\n"                                \
222        "Remove a path.\n"                              \
223        " transaction [string]: transaction handle\n"   \
224        " path [string] : path to remove\n"             \
225        "\n"                                            \
226        "Returns None on success.\n"                    \
227        "Raises xen.lowlevel.xs.Error on error.\n"               \
228        "\n"
229
230static PyObject *xspy_rm(XsHandle *self, PyObject *args)
231{
232    struct xs_handle *xh;
233    xs_transaction_t th;
234    char *path;
235
236    bool result;
237
238    if (!parse_transaction_path(self, args, &xh, &th, &path))
239        return NULL;
240
241    Py_BEGIN_ALLOW_THREADS
242    result = xs_rm(xh, th, path);
243    Py_END_ALLOW_THREADS
244
245    return none(result || errno == ENOENT);
246}
247
248
249#define xspy_get_permissions_doc "\n"                   \
250        "Get the permissions for a path\n"              \
251        " transaction [string]: transaction handle\n"   \
252        " path [string]:        xenstore path.\n"       \
253        "\n"                                            \
254        "Returns: permissions array.\n"                 \
255        "Raises xen.lowlevel.xs.Error on error.\n"               \
256        "\n"
257
258static PyObject *xspy_get_permissions(XsHandle *self, PyObject *args)
259{
260    static char *arg_spec = "ss";
261    char *path = NULL;
262
263    struct xs_handle *xh = xshandle(self);
264    struct xs_permissions *perms;
265    unsigned int perms_n = 0;
266    int i;
267
268    xs_transaction_t th;
269    char *thstr;
270
271    if (!xh)
272        return NULL;
273    if (!PyArg_ParseTuple(args, arg_spec, &thstr, &path))
274        return NULL;
275
276    th = strtoul(thstr, NULL, 16);
277
278    Py_BEGIN_ALLOW_THREADS
279    perms = xs_get_permissions(xh, th, path, &perms_n);
280    Py_END_ALLOW_THREADS
281
282    if (perms) {
283        PyObject *val = PyList_New(perms_n);
284        for (i = 0; i < perms_n; i++) {
285            PyObject *p =
286                Py_BuildValue("{s:i,s:i,s:i}",
287                              "dom",   perms[i].id,
288                              "read",  perms[i].perms & XS_PERM_READ,
289                              "write", perms[i].perms & XS_PERM_WRITE);
290            PyList_SetItem(val, i, p);
291        }
292
293        free(perms);
294        return val;
295    }
296    else {
297        PyErr_SetFromErrno(xs_error);
298        return NULL;
299    }
300}
301
302#define xspy_set_permissions_doc "\n"                   \
303        "Set the permissions for a path\n"              \
304        " transaction [string]: transaction handle\n"   \
305        " path  [string]      : xenstore path.\n"       \
306        " perms               : permissions.\n"         \
307        "\n"                                            \
308        "Returns None on success.\n"                    \
309        "Raises xen.lowlevel.xs.Error on error.\n"               \
310        "\n"
311
312static PyObject *xspy_set_permissions(XsHandle *self, PyObject *args)
313{
314    char *path;
315    PyObject *perms;
316    static char *perm_names[] = { "dom", "read", "write", NULL };
317    static char *perm_spec = "i|ii";
318
319    struct xs_handle *xh = xshandle(self);
320    int i, result;
321    struct xs_permissions *xsperms = NULL;
322    int xsperms_n;
323    PyObject *tuple0 = NULL;
324
325    xs_transaction_t th;
326    char *thstr;
327
328    if (!xh)
329        goto exit;
330    if (!PyArg_ParseTuple(args, "ssO", &thstr, &path, &perms))
331        goto exit;
332
333    th = strtoul(thstr, NULL, 16);
334
335    if (!PyList_Check(perms)) {
336        xs_set_error(EINVAL);
337        goto exit;
338    }
339    xsperms_n = PyList_Size(perms);
340    xsperms = calloc(xsperms_n, sizeof(struct xs_permissions));
341    if (!xsperms) {
342        xs_set_error(ENOMEM);
343        goto exit;
344    }
345    tuple0 = PyTuple_New(0);
346    if (!tuple0)
347        goto exit;
348    for (i = 0; i < xsperms_n; i++) {
349        /* Read/write perms. Set these. */
350        int p_read = 0, p_write = 0;
351        PyObject *p = PyList_GetItem(perms, i);
352        if (!PyArg_ParseTupleAndKeywords(tuple0, p, perm_spec, perm_names,
353                                         &xsperms[i].id, &p_read, &p_write))
354            goto exit;
355        if (p_read)
356            xsperms[i].perms |= XS_PERM_READ;
357        if (p_write)
358            xsperms[i].perms |= XS_PERM_WRITE;
359    }
360    Py_BEGIN_ALLOW_THREADS
361    result = xs_set_permissions(xh, th, path, xsperms, xsperms_n);
362    Py_END_ALLOW_THREADS
363    if (!result) {
364        PyErr_SetFromErrno(xs_error);
365        goto exit;
366    }
367
368    Py_INCREF(Py_None);
369    return Py_None;
370
371 exit:
372    Py_XDECREF(tuple0);
373    free(xsperms);
374    return NULL;
375}
376
377#define xspy_watch_doc "\n"                                             \
378        "Watch a path, get notifications when it changes.\n"            \
379        " path     [string] : xenstore path.\n"                         \
380        " token    [string] : returned in watch notification.\n"        \
381        "\n"                                                            \
382        "Returns None on success.\n"                                    \
383        "Raises xen.lowlevel.xs.Error on error.\n"                              \
384        "\n"
385
386/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
387#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
388
389static PyObject *xspy_watch(XsHandle *self, PyObject *args)
390{
391    struct xs_handle *xh = xshandle(self);
392    char *path;
393    PyObject *token;
394    char token_str[MAX_STRLEN(unsigned long) + 1];
395    int result;
396    int i;
397
398    if (!xh)
399        return NULL;
400    if (!PyArg_ParseTuple(args, "sO", &path, &token))
401        return NULL;
402
403    /* Note that we have to store the watch token in the xs->watches list
404       before registering the watch with xs_watch, otherwise this function
405       races with xs_read_watch.
406    */
407
408    for (i = 0; i < PyList_Size(self->watches); i++) {
409        if (PyList_GetItem(self->watches, i) == Py_None) {
410            PySequence_SetItem(self->watches, i, token);
411            break;
412        }
413    }
414    if (i == PyList_Size(self->watches))
415        PyList_Append(self->watches, token);
416
417    sprintf(token_str, "%li", (unsigned long)token);
418    Py_BEGIN_ALLOW_THREADS
419    result = xs_watch(xh, path, token_str);
420    Py_END_ALLOW_THREADS
421
422    if (!result)
423        remove_watch(self, token);
424
425    return none(result);
426}
427
428
429#define xspy_read_watch_doc "\n"                                \
430        "Read a watch notification.\n"                          \
431        "\n"                                                    \
432        "Returns: [tuple] (path, token).\n"                     \
433        "Raises xen.lowlevel.xs.Error on error.\n"                      \
434        "\n"
435
436static PyObject *xspy_read_watch(XsHandle *self, PyObject *args)
437{
438    struct xs_handle *xh = xshandle(self);
439    PyObject *val = NULL;
440    char **xsval;
441    PyObject *token;
442    int i;
443    unsigned int num;
444
445    if (!xh)
446        return NULL;
447
448again:
449    Py_BEGIN_ALLOW_THREADS
450    xsval = xs_read_watch(xh, &num);
451    Py_END_ALLOW_THREADS
452    if (!xsval) {
453        PyErr_SetFromErrno(xs_error);
454        goto exit;
455    }
456    if (sscanf(xsval[XS_WATCH_TOKEN], "%li", (unsigned long *)&token) != 1) {
457        xs_set_error(EINVAL);
458        goto exit;
459    }
460    for (i = 0; i < PyList_Size(self->watches); i++) {
461        if (token == PyList_GetItem(self->watches, i))
462            break;
463    }
464    if (i == PyList_Size(self->watches)) {
465      /* We do not have a registered watch for the one that has just fired.
466         Ignore this -- a watch that has been recently deregistered can still
467         have watches in transit.  This is a blocking method, so go back to
468         read again.
469      */
470      free(xsval);
471      goto again;
472    }
473    /* Create tuple (path, token). */
474    val = Py_BuildValue("(sO)", xsval[XS_WATCH_PATH], token);
475 exit:
476    free(xsval);
477    return val;
478}
479
480#define xspy_unwatch_doc "\n"                           \
481        "Stop watching a path.\n"                       \
482        " path  [string] : xenstore path.\n"            \
483        " token [string] : token from the watch.\n"     \
484        "\n"                                            \
485        "Returns None on success.\n"                    \
486        "Raises xen.lowlevel.xs.Error on error.\n"              \
487        "\n"
488
489static PyObject *xspy_unwatch(XsHandle *self, PyObject *args)
490{
491    struct xs_handle *xh = xshandle(self);
492    char *path;
493    PyObject *token;
494    char token_str[MAX_STRLEN(unsigned long) + 1];
495    int result;
496
497    if (!xh)
498        return NULL;
499    if (!PyArg_ParseTuple(args, "sO", &path, &token))
500        return NULL;
501
502    sprintf(token_str, "%li", (unsigned long)token);
503    Py_BEGIN_ALLOW_THREADS
504    result = xs_unwatch(xh, path, token_str);
505    Py_END_ALLOW_THREADS
506
507    remove_watch(self, token);
508
509    return none(result);
510}
511
512#define xspy_transaction_start_doc "\n"                         \
513        "Start a transaction.\n"                                \
514        "\n"                                                    \
515        "Returns transaction handle on success.\n"              \
516        "Raises xen.lowlevel.xs.Error on error.\n"                      \
517        "\n"
518
519static PyObject *xspy_transaction_start(XsHandle *self)
520{
521    struct xs_handle *xh = xshandle(self);
522    xs_transaction_t th;
523    char thstr[MAX_STRLEN(unsigned long) + 1];
524
525    if (!xh)
526        return NULL;
527
528    Py_BEGIN_ALLOW_THREADS
529    th = xs_transaction_start(xh);
530    Py_END_ALLOW_THREADS
531
532    if (th == XBT_NULL) {
533        PyErr_SetFromErrno(xs_error);
534        return NULL;
535    }
536
537    sprintf(thstr, "%lX", (unsigned long)th);
538    return PyString_FromString(thstr);
539}
540
541#define xspy_transaction_end_doc "\n"                                   \
542        "End the current transaction.\n"                                \
543        "Attempts to commit the transaction unless abort is true.\n"    \
544        " abort [int]: abort flag (default 0).\n"                       \
545        "\n"                                                            \
546        "Returns True on success, False if you need to try again.\n"    \
547        "Raises xen.lowlevel.xs.Error on error.\n"                              \
548        "\n"
549
550static PyObject *xspy_transaction_end(XsHandle *self, PyObject *args,
551                                      PyObject *kwds)
552{
553    static char *kwd_spec[] = { "transaction", "abort", NULL };
554    static char *arg_spec = "s|i";
555    int abort = 0;
556
557    struct xs_handle *xh = xshandle(self);
558    bool result;
559
560    xs_transaction_t th;
561    char *thstr;
562
563    if (!xh)
564        return NULL;
565    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
566                                     &thstr, &abort))
567        return NULL;
568
569    th = strtoul(thstr, NULL, 16);
570
571    Py_BEGIN_ALLOW_THREADS
572    result = xs_transaction_end(xh, th, abort);
573    Py_END_ALLOW_THREADS
574
575    if (result) {
576        Py_INCREF(Py_True);
577        return Py_True;
578    }
579    else if (errno == EAGAIN) {
580        Py_INCREF(Py_False);
581        return Py_False;
582    }
583    else {
584        PyErr_SetFromErrno(xs_error);
585        return NULL;
586    }
587}
588
589
590#define xspy_introduce_domain_doc "\n"                                  \
591        "Tell xenstore about a domain so it can talk to it.\n"          \
592        " dom  [int]   : domain id\n"                                   \
593        " page [long]  : address of domain's xenstore page\n"           \
594        " port [int]   : port the domain is using for xenstore\n"       \
595        "\n"                                                            \
596        "Returns None on success.\n"                                    \
597        "Raises xen.lowlevel.xs.Error on error.\n"                              \
598        "\n"
599
600static PyObject *xspy_introduce_domain(XsHandle *self, PyObject *args)
601{
602    uint32_t dom;
603    unsigned long page;
604    unsigned int port;
605
606    struct xs_handle *xh = xshandle(self);
607    bool result = 0;
608
609    if (!xh)
610        return NULL;
611    if (!PyArg_ParseTuple(args, "ili", &dom, &page, &port))
612        return NULL;
613
614    Py_BEGIN_ALLOW_THREADS
615    result = xs_introduce_domain(xh, dom, page, port);
616    Py_END_ALLOW_THREADS
617
618    return none(result);
619}
620
621#define xspy_resume_domain_doc "\n"                                \
622        "Tell xenstore to clear its shutdown flag for a domain.\n" \
623        "This ensures that a subsequent shutdown will fire the\n"  \
624        "appropriate watches.\n"                                   \
625        " dom [int]: domain id\n"                                  \
626        "\n"                                                       \
627        "Returns None on success.\n"                               \
628        "Raises xen.lowlevel.xs.Error on error.\n"
629
630static PyObject *xspy_resume_domain(XsHandle *self, PyObject *args)
631{
632    uint32_t dom;
633
634    struct xs_handle *xh = xshandle(self);
635    bool result = 0;
636
637    if (!xh)
638        return NULL;
639    if (!PyArg_ParseTuple(args, "i", &dom))
640        return NULL;
641
642    Py_BEGIN_ALLOW_THREADS
643    result = xs_resume_domain(xh, dom);
644    Py_END_ALLOW_THREADS
645
646    return none(result);
647}
648
649#define xspy_release_domain_doc "\n"                                    \
650        "Tell xenstore to release its channel to a domain.\n"           \
651        "Unless this is done the domain will not be released.\n"        \
652        " dom [int]: domain id\n"                                       \
653        "\n"                                                            \
654        "Returns None on success.\n"                                    \
655        "Raises xen.lowlevel.xs.Error on error.\n"                              \
656        "\n"
657
658static PyObject *xspy_release_domain(XsHandle *self, PyObject *args)
659{
660    uint32_t dom;
661
662    struct xs_handle *xh = xshandle(self);
663    bool result = 0;
664
665    if (!xh)
666        return NULL;
667    if (!PyArg_ParseTuple(args, "i", &dom))
668        return NULL;
669
670    Py_BEGIN_ALLOW_THREADS
671    result = xs_release_domain(xh, dom);
672    Py_END_ALLOW_THREADS
673
674    return none(result);
675}
676
677
678#define xspy_close_doc "\n"                     \
679        "Close the connection to xenstore.\n"   \
680        "\n"                                    \
681        "Returns None on success.\n"            \
682        "Raises xen.lowlevel.xs.Error on error.\n"      \
683        "\n"
684
685static PyObject *xspy_close(XsHandle *self)
686{
687    struct xs_handle *xh = xshandle(self);
688    int i;
689
690    if (!xh)
691        return NULL;
692
693    for (i = 0; i < PyList_Size(self->watches); i++) {
694        /* TODO: xs_unwatch watches */
695        PySequence_SetItem(self->watches, i, Py_None);
696    }
697
698    xs_daemon_close(xh);
699    self->xh = NULL;
700
701    Py_INCREF(Py_None);
702    return Py_None;
703}
704
705
706#define xspy_get_domain_path_doc "\n"                   \
707        "Return store path of domain, whether or not the domain exists.\n" \
708        " domid [int]: domain id\n"                     \
709        "\n"                                            \
710        "Returns: [string] domain store path.\n"        \
711        "Raises xen.lowlevel.xs.Error on error.\n"              \
712        "\n"
713
714static PyObject *xspy_get_domain_path(XsHandle *self, PyObject *args)
715{
716    struct xs_handle *xh = xshandle(self);
717    uint32_t domid;
718    char *xsval;
719
720    if (!xh)
721        return NULL;
722    if (!PyArg_ParseTuple(args, "i", &domid))
723        return NULL;
724
725    Py_BEGIN_ALLOW_THREADS
726    xsval = xs_get_domain_path(xh, domid);
727    Py_END_ALLOW_THREADS
728
729    if (xsval) {
730        PyObject *val = PyString_FromString(xsval);
731        free(xsval);
732        return val;
733    }
734    else {
735        return none(errno == ENOENT);
736    }
737}
738
739
740/**
741 * Remove the given token from the watches list belonging to the given
742 * XsHandle, if present.
743 */
744static void remove_watch(XsHandle *self, PyObject *token)
745{
746    int i;
747
748    for (i = 0; i < PyList_Size(self->watches); i++) {
749        if (PyList_GetItem(self->watches, i) == token) {
750            PySequence_SetItem(self->watches, i, Py_None);
751            return;
752        }
753    }
754}
755
756
757/**
758 * Parse transaction and path arguments from the given args and kwds,
759 * convert the given self value to an xs_handle, and return all three by
760 * reference.
761 *
762 * @return 1 on success, in which case *xh, *th, and *path are valid, or 0 on
763 * failure.
764 */
765static int parse_transaction_path(XsHandle *self, PyObject *args,
766                                  struct xs_handle **xh,
767                                  xs_transaction_t *th,
768                                  char **path)
769{
770    char *thstr;
771
772    *xh = xshandle(self);
773
774    if (!xh)
775        return 0;
776
777    if (!PyArg_ParseTuple(args, "ss", &thstr, path))
778        return 0;
779
780    *th = strtoul(thstr, NULL, 16);
781
782    return 1;
783}
784
785
786static PyObject *none(bool result)
787{
788    if (result) {
789        Py_INCREF(Py_None);
790        return Py_None;
791    }
792    else {
793        PyErr_SetFromErrno(xs_error);
794        return NULL;
795    }
796}
797
798
799#define XSPY_METH(_name, _args) {               \
800    .ml_name  = #_name,                         \
801    .ml_meth  = (PyCFunction) xspy_ ## _name,   \
802    .ml_flags = _args,                          \
803    .ml_doc   = xspy_ ## _name ## _doc }
804
805static PyMethodDef xshandle_methods[] = {
806    XSPY_METH(read,              METH_VARARGS),
807    XSPY_METH(write,             METH_VARARGS),
808    XSPY_METH(ls,                METH_VARARGS),
809    XSPY_METH(mkdir,             METH_VARARGS),
810    XSPY_METH(rm,                METH_VARARGS),
811    XSPY_METH(get_permissions,   METH_VARARGS),
812    XSPY_METH(set_permissions,   METH_VARARGS),
813    XSPY_METH(watch,             METH_VARARGS),
814    XSPY_METH(read_watch,        METH_NOARGS),
815    XSPY_METH(unwatch,           METH_VARARGS),
816    XSPY_METH(transaction_start, METH_NOARGS),
817    XSPY_METH(transaction_end,   METH_VARARGS | METH_KEYWORDS),
818    XSPY_METH(introduce_domain,  METH_VARARGS),
819    XSPY_METH(resume_domain,     METH_VARARGS),
820    XSPY_METH(release_domain,    METH_VARARGS),
821    XSPY_METH(close,             METH_NOARGS),
822    XSPY_METH(get_domain_path,   METH_VARARGS),
823    { NULL /* Sentinel. */ },
824};
825
826static PyObject *xshandle_getattr(PyObject *self, char *name)
827{
828    return Py_FindMethod(xshandle_methods, self, name);
829}
830
831static PyObject *
832xshandle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
833{
834    XsHandle *self = (XsHandle *)type->tp_alloc(type, 0);
835
836    if (self == NULL)
837        return NULL;
838
839    self->xh = NULL;
840    self->watches = PyList_New(0);
841    if (!self->watches)
842        goto fail;
843
844    return (PyObject *)self;
845fail:
846    /* Decreasing the object's reference to 0 will result in xshandle_dealloc
847       being called. */
848    Py_DECREF(self);
849    return NULL;
850}
851
852static int
853xshandle_init(XsHandle *self, PyObject *args, PyObject *kwds)
854{
855    static char *kwd_spec[] = { "readonly", NULL };
856    static char *arg_spec = "|i";
857    int readonly = 0;
858
859    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
860                                     &readonly))
861        goto fail;
862
863    self->xh = (readonly ? xs_daemon_open_readonly() : xs_daemon_open());
864    if (!self->xh)
865        goto fail;
866
867    return 0;
868
869 fail:
870    PyErr_SetFromErrno(xs_error);
871    return -1;
872}
873
874static void xshandle_dealloc(XsHandle *self)
875{
876    if (self->xh) {
877        xs_daemon_close(self->xh);
878        self->xh = NULL;
879    }
880
881    Py_XDECREF(self->watches);
882
883    self->ob_type->tp_free((PyObject *)self);
884}
885
886static PyTypeObject xshandle_type = {
887    PyObject_HEAD_INIT(NULL)
888    0,
889    PKG "." CLS,
890    sizeof(XsHandle),
891    0,
892    (destructor)xshandle_dealloc, /* tp_dealloc        */
893    NULL,                         /* tp_print          */
894    xshandle_getattr,             /* tp_getattr        */
895    NULL,                         /* tp_setattr        */
896    NULL,                         /* tp_compare        */
897    NULL,                         /* tp_repr           */
898    NULL,                         /* tp_as_number      */
899    NULL,                         /* tp_as_sequence    */
900    NULL,                         /* tp_as_mapping     */
901    NULL,                         /* tp_hash           */
902    NULL,                         /* tp_call           */
903    NULL,                         /* tp_str            */
904    NULL,                         /* tp_getattro       */
905    NULL,                         /* tp_setattro       */
906    NULL,                         /* tp_as_buffer      */
907    Py_TPFLAGS_DEFAULT,           /* tp_flags          */
908    "Xenstore connections",       /* tp_doc            */
909    NULL,                         /* tp_traverse       */
910    NULL,                         /* tp_clear          */
911    NULL,                         /* tp_richcompare    */
912    0,                            /* tp_weaklistoffset */
913    NULL,                         /* tp_iter           */
914    NULL,                         /* tp_iternext       */
915    xshandle_methods,             /* tp_methods        */
916    NULL,                         /* tp_members        */
917    NULL,                         /* tp_getset         */
918    NULL,                         /* tp_base           */
919    NULL,                         /* tp_dict           */
920    NULL,                         /* tp_descr_get      */
921    NULL,                         /* tp_descr_set      */
922    0,                            /* tp_dictoffset     */
923    (initproc)xshandle_init,      /* tp_init           */
924    NULL,                         /* tp_alloc          */
925    xshandle_new,                 /* tp_new            */
926};
927
928static PyMethodDef xs_methods[] = { { NULL } };
929
930PyMODINIT_FUNC initxs(void)
931{
932    PyObject* m;
933
934    if (PyType_Ready(&xshandle_type) < 0)
935        return;
936
937    m = Py_InitModule(PKG, xs_methods);
938
939    if (m == NULL)
940      return;
941
942    xs_error = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL);
943
944    Py_INCREF(&xshandle_type);
945    PyModule_AddObject(m, CLS, (PyObject *)&xshandle_type);
946
947    Py_INCREF(xs_error);
948    PyModule_AddObject(m, "Error", xs_error);
949}
950
951
952/*
953 * Local variables:
954 *  c-indent-level: 4
955 *  c-basic-offset: 4
956 * End:
957 */
Note: See TracBrowser for help on using the repository browser.