ia64/xen-unstable

view tools/python/xen/lowlevel/xs/xs.c @ 15910:c36292e83f07

Fix two memory leaks in xend.
Signed-off-by: Kouya Shimura <kouya@jp.fujitsu.com>
author kfraser@localhost.localdomain
date Fri Sep 14 16:04:33 2007 +0100 (2007-09-14)
parents 9a1809ce711b
children 26fc953a89bb
line source
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 */
22 #include <Python.h>
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>
33 #include <xenctrl.h>
34 #include "xs.h"
36 /** @file
37 * Python interface to the Xen Store Daemon (xs).
38 */
40 /* Needed for Python versions earlier than 2.3. */
41 #ifndef PyMODINIT_FUNC
42 #define PyMODINIT_FUNC DL_EXPORT(void)
43 #endif
45 #define PKG "xen.lowlevel.xs"
46 #define CLS "xs"
48 static PyObject *xs_error;
50 /** Python wrapper round an xs handle.
51 */
52 typedef struct XsHandle {
53 PyObject_HEAD;
54 struct xs_handle *xh;
55 PyObject *watches;
56 } XsHandle;
58 static void xs_set_error(int value)
59 {
60 errno = value;
61 PyErr_SetFromErrno(xs_error);
62 }
64 static 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 }
72 static void remove_watch(XsHandle *xsh, PyObject *token);
74 static PyObject *none(bool result);
76 static int parse_transaction_path(XsHandle *self, PyObject *args,
77 struct xs_handle **xh,
78 xs_transaction_t *th,
79 char **path);
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"
92 static PyObject *xspy_read(XsHandle *self, PyObject *args)
93 {
94 struct xs_handle *xh;
95 xs_transaction_t th;
96 char *path;
98 char *xsval;
99 unsigned int xsval_n;
101 if (!parse_transaction_path(self, args, &xh, &th, &path))
102 return NULL;
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 }
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"
128 static 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;
139 if (!xh)
140 return NULL;
141 if (!PyArg_ParseTuple(args, arg_spec, &thstr, &path, &data, &data_n))
142 return NULL;
144 th = strtoul(thstr, NULL, 16);
146 Py_BEGIN_ALLOW_THREADS
147 result = xs_write(xh, th, path, data, data_n);
148 Py_END_ALLOW_THREADS
150 return none(result);
151 }
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"
164 static PyObject *xspy_ls(XsHandle *self, PyObject *args)
165 {
166 struct xs_handle *xh;
167 xs_transaction_t th;
168 char *path;
170 char **xsval;
171 unsigned int xsval_n;
173 if (!parse_transaction_path(self, args, &xh, &th, &path))
174 return NULL;
176 Py_BEGIN_ALLOW_THREADS
177 xsval = xs_directory(xh, th, path, &xsval_n);
178 Py_END_ALLOW_THREADS
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 }
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"
202 static PyObject *xspy_mkdir(XsHandle *self, PyObject *args)
203 {
204 struct xs_handle *xh;
205 xs_transaction_t th;
206 char *path;
208 bool result;
210 if (!parse_transaction_path(self, args, &xh, &th, &path))
211 return NULL;
213 Py_BEGIN_ALLOW_THREADS
214 result = xs_mkdir(xh, th, path);
215 Py_END_ALLOW_THREADS
217 return none(result);
218 }
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"
230 static PyObject *xspy_rm(XsHandle *self, PyObject *args)
231 {
232 struct xs_handle *xh;
233 xs_transaction_t th;
234 char *path;
236 bool result;
238 if (!parse_transaction_path(self, args, &xh, &th, &path))
239 return NULL;
241 Py_BEGIN_ALLOW_THREADS
242 result = xs_rm(xh, th, path);
243 Py_END_ALLOW_THREADS
245 return none(result || errno == ENOENT);
246 }
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"
258 static PyObject *xspy_get_permissions(XsHandle *self, PyObject *args)
259 {
260 static char *arg_spec = "ss";
261 char *path = NULL;
263 struct xs_handle *xh = xshandle(self);
264 struct xs_permissions *perms;
265 unsigned int perms_n = 0;
266 int i;
268 xs_transaction_t th;
269 char *thstr;
271 if (!xh)
272 return NULL;
273 if (!PyArg_ParseTuple(args, arg_spec, &thstr, &path))
274 return NULL;
276 th = strtoul(thstr, NULL, 16);
278 Py_BEGIN_ALLOW_THREADS
279 perms = xs_get_permissions(xh, th, path, &perms_n);
280 Py_END_ALLOW_THREADS
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 }
293 free(perms);
294 return val;
295 }
296 else {
297 PyErr_SetFromErrno(xs_error);
298 return NULL;
299 }
300 }
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"
312 static 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";
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;
325 xs_transaction_t th;
326 char *thstr;
328 if (!xh)
329 goto exit;
330 if (!PyArg_ParseTuple(args, "ssO", &thstr, &path, &perms))
331 goto exit;
333 th = strtoul(thstr, NULL, 16);
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 }
368 free(xsperms);
369 Py_INCREF(Py_None);
370 return Py_None;
372 exit:
373 Py_XDECREF(tuple0);
374 free(xsperms);
375 return NULL;
376 }
378 #define xspy_watch_doc "\n" \
379 "Watch a path, get notifications when it changes.\n" \
380 " path [string] : xenstore path.\n" \
381 " token [string] : returned in watch notification.\n" \
382 "\n" \
383 "Returns None on success.\n" \
384 "Raises xen.lowlevel.xs.Error on error.\n" \
385 "\n"
387 /* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
388 #define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
390 static PyObject *xspy_watch(XsHandle *self, PyObject *args)
391 {
392 struct xs_handle *xh = xshandle(self);
393 char *path;
394 PyObject *token;
395 char token_str[MAX_STRLEN(unsigned long) + 1];
396 int result;
397 int i;
399 if (!xh)
400 return NULL;
401 if (!PyArg_ParseTuple(args, "sO", &path, &token))
402 return NULL;
404 /* Note that we have to store the watch token in the xs->watches list
405 before registering the watch with xs_watch, otherwise this function
406 races with xs_read_watch.
407 */
409 for (i = 0; i < PyList_Size(self->watches); i++) {
410 if (PyList_GetItem(self->watches, i) == Py_None) {
411 PySequence_SetItem(self->watches, i, token);
412 break;
413 }
414 }
415 if (i == PyList_Size(self->watches))
416 PyList_Append(self->watches, token);
418 sprintf(token_str, "%li", (unsigned long)token);
419 Py_BEGIN_ALLOW_THREADS
420 result = xs_watch(xh, path, token_str);
421 Py_END_ALLOW_THREADS
423 if (!result)
424 remove_watch(self, token);
426 return none(result);
427 }
430 #define xspy_read_watch_doc "\n" \
431 "Read a watch notification.\n" \
432 "\n" \
433 "Returns: [tuple] (path, token).\n" \
434 "Raises xen.lowlevel.xs.Error on error.\n" \
435 "\n"
437 static PyObject *xspy_read_watch(XsHandle *self, PyObject *args)
438 {
439 struct xs_handle *xh = xshandle(self);
440 PyObject *val = NULL;
441 char **xsval;
442 PyObject *token;
443 int i;
444 unsigned int num;
446 if (!xh)
447 return NULL;
449 again:
450 Py_BEGIN_ALLOW_THREADS
451 xsval = xs_read_watch(xh, &num);
452 Py_END_ALLOW_THREADS
453 if (!xsval) {
454 PyErr_SetFromErrno(xs_error);
455 goto exit;
456 }
457 if (sscanf(xsval[XS_WATCH_TOKEN], "%li", (unsigned long *)&token) != 1) {
458 xs_set_error(EINVAL);
459 goto exit;
460 }
461 for (i = 0; i < PyList_Size(self->watches); i++) {
462 if (token == PyList_GetItem(self->watches, i))
463 break;
464 }
465 if (i == PyList_Size(self->watches)) {
466 /* We do not have a registered watch for the one that has just fired.
467 Ignore this -- a watch that has been recently deregistered can still
468 have watches in transit. This is a blocking method, so go back to
469 read again.
470 */
471 free(xsval);
472 goto again;
473 }
474 /* Create tuple (path, token). */
475 val = Py_BuildValue("(sO)", xsval[XS_WATCH_PATH], token);
476 exit:
477 free(xsval);
478 return val;
479 }
481 #define xspy_unwatch_doc "\n" \
482 "Stop watching a path.\n" \
483 " path [string] : xenstore path.\n" \
484 " token [string] : token from the watch.\n" \
485 "\n" \
486 "Returns None on success.\n" \
487 "Raises xen.lowlevel.xs.Error on error.\n" \
488 "\n"
490 static PyObject *xspy_unwatch(XsHandle *self, PyObject *args)
491 {
492 struct xs_handle *xh = xshandle(self);
493 char *path;
494 PyObject *token;
495 char token_str[MAX_STRLEN(unsigned long) + 1];
496 int result;
498 if (!xh)
499 return NULL;
500 if (!PyArg_ParseTuple(args, "sO", &path, &token))
501 return NULL;
503 sprintf(token_str, "%li", (unsigned long)token);
504 Py_BEGIN_ALLOW_THREADS
505 result = xs_unwatch(xh, path, token_str);
506 Py_END_ALLOW_THREADS
508 remove_watch(self, token);
510 return none(result);
511 }
513 #define xspy_transaction_start_doc "\n" \
514 "Start a transaction.\n" \
515 "\n" \
516 "Returns transaction handle on success.\n" \
517 "Raises xen.lowlevel.xs.Error on error.\n" \
518 "\n"
520 static PyObject *xspy_transaction_start(XsHandle *self)
521 {
522 struct xs_handle *xh = xshandle(self);
523 xs_transaction_t th;
524 char thstr[MAX_STRLEN(unsigned long) + 1];
526 if (!xh)
527 return NULL;
529 Py_BEGIN_ALLOW_THREADS
530 th = xs_transaction_start(xh);
531 Py_END_ALLOW_THREADS
533 if (th == XBT_NULL) {
534 PyErr_SetFromErrno(xs_error);
535 return NULL;
536 }
538 sprintf(thstr, "%lX", (unsigned long)th);
539 return PyString_FromString(thstr);
540 }
542 #define xspy_transaction_end_doc "\n" \
543 "End the current transaction.\n" \
544 "Attempts to commit the transaction unless abort is true.\n" \
545 " abort [int]: abort flag (default 0).\n" \
546 "\n" \
547 "Returns True on success, False if you need to try again.\n" \
548 "Raises xen.lowlevel.xs.Error on error.\n" \
549 "\n"
551 static PyObject *xspy_transaction_end(XsHandle *self, PyObject *args,
552 PyObject *kwds)
553 {
554 static char *kwd_spec[] = { "transaction", "abort", NULL };
555 static char *arg_spec = "s|i";
556 int abort = 0;
558 struct xs_handle *xh = xshandle(self);
559 bool result;
561 xs_transaction_t th;
562 char *thstr;
564 if (!xh)
565 return NULL;
566 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
567 &thstr, &abort))
568 return NULL;
570 th = strtoul(thstr, NULL, 16);
572 Py_BEGIN_ALLOW_THREADS
573 result = xs_transaction_end(xh, th, abort);
574 Py_END_ALLOW_THREADS
576 if (result) {
577 Py_INCREF(Py_True);
578 return Py_True;
579 }
580 else if (errno == EAGAIN) {
581 Py_INCREF(Py_False);
582 return Py_False;
583 }
584 else {
585 PyErr_SetFromErrno(xs_error);
586 return NULL;
587 }
588 }
591 #define xspy_introduce_domain_doc "\n" \
592 "Tell xenstore about a domain so it can talk to it.\n" \
593 " dom [int] : domain id\n" \
594 " page [long] : address of domain's xenstore page\n" \
595 " port [int] : port the domain is using for xenstore\n" \
596 "\n" \
597 "Returns None on success.\n" \
598 "Raises xen.lowlevel.xs.Error on error.\n" \
599 "\n"
601 static PyObject *xspy_introduce_domain(XsHandle *self, PyObject *args)
602 {
603 uint32_t dom;
604 unsigned long page;
605 unsigned int port;
607 struct xs_handle *xh = xshandle(self);
608 bool result = 0;
610 if (!xh)
611 return NULL;
612 if (!PyArg_ParseTuple(args, "ili", &dom, &page, &port))
613 return NULL;
615 Py_BEGIN_ALLOW_THREADS
616 result = xs_introduce_domain(xh, dom, page, port);
617 Py_END_ALLOW_THREADS
619 return none(result);
620 }
622 #define xspy_resume_domain_doc "\n" \
623 "Tell xenstore to clear its shutdown flag for a domain.\n" \
624 "This ensures that a subsequent shutdown will fire the\n" \
625 "appropriate watches.\n" \
626 " dom [int]: domain id\n" \
627 "\n" \
628 "Returns None on success.\n" \
629 "Raises xen.lowlevel.xs.Error on error.\n"
631 static PyObject *xspy_resume_domain(XsHandle *self, PyObject *args)
632 {
633 uint32_t dom;
635 struct xs_handle *xh = xshandle(self);
636 bool result = 0;
638 if (!xh)
639 return NULL;
640 if (!PyArg_ParseTuple(args, "i", &dom))
641 return NULL;
643 Py_BEGIN_ALLOW_THREADS
644 result = xs_resume_domain(xh, dom);
645 Py_END_ALLOW_THREADS
647 return none(result);
648 }
650 #define xspy_release_domain_doc "\n" \
651 "Tell xenstore to release its channel to a domain.\n" \
652 "Unless this is done the domain will not be released.\n" \
653 " dom [int]: domain id\n" \
654 "\n" \
655 "Returns None on success.\n" \
656 "Raises xen.lowlevel.xs.Error on error.\n" \
657 "\n"
659 static PyObject *xspy_release_domain(XsHandle *self, PyObject *args)
660 {
661 uint32_t dom;
663 struct xs_handle *xh = xshandle(self);
664 bool result = 0;
666 if (!xh)
667 return NULL;
668 if (!PyArg_ParseTuple(args, "i", &dom))
669 return NULL;
671 Py_BEGIN_ALLOW_THREADS
672 result = xs_release_domain(xh, dom);
673 Py_END_ALLOW_THREADS
675 return none(result);
676 }
679 #define xspy_close_doc "\n" \
680 "Close the connection to xenstore.\n" \
681 "\n" \
682 "Returns None on success.\n" \
683 "Raises xen.lowlevel.xs.Error on error.\n" \
684 "\n"
686 static PyObject *xspy_close(XsHandle *self)
687 {
688 struct xs_handle *xh = xshandle(self);
689 int i;
691 if (!xh)
692 return NULL;
694 for (i = 0; i < PyList_Size(self->watches); i++) {
695 /* TODO: xs_unwatch watches */
696 PySequence_SetItem(self->watches, i, Py_None);
697 }
699 xs_daemon_close(xh);
700 self->xh = NULL;
702 Py_INCREF(Py_None);
703 return Py_None;
704 }
707 #define xspy_get_domain_path_doc "\n" \
708 "Return store path of domain, whether or not the domain exists.\n" \
709 " domid [int]: domain id\n" \
710 "\n" \
711 "Returns: [string] domain store path.\n" \
712 "Raises xen.lowlevel.xs.Error on error.\n" \
713 "\n"
715 static PyObject *xspy_get_domain_path(XsHandle *self, PyObject *args)
716 {
717 struct xs_handle *xh = xshandle(self);
718 uint32_t domid;
719 char *xsval;
721 if (!xh)
722 return NULL;
723 if (!PyArg_ParseTuple(args, "i", &domid))
724 return NULL;
726 Py_BEGIN_ALLOW_THREADS
727 xsval = xs_get_domain_path(xh, domid);
728 Py_END_ALLOW_THREADS
730 if (xsval) {
731 PyObject *val = PyString_FromString(xsval);
732 free(xsval);
733 return val;
734 }
735 else {
736 return none(errno == ENOENT);
737 }
738 }
741 /**
742 * Remove the given token from the watches list belonging to the given
743 * XsHandle, if present.
744 */
745 static void remove_watch(XsHandle *self, PyObject *token)
746 {
747 int i;
749 for (i = 0; i < PyList_Size(self->watches); i++) {
750 if (PyList_GetItem(self->watches, i) == token) {
751 PySequence_SetItem(self->watches, i, Py_None);
752 return;
753 }
754 }
755 }
758 /**
759 * Parse transaction and path arguments from the given args and kwds,
760 * convert the given self value to an xs_handle, and return all three by
761 * reference.
762 *
763 * @return 1 on success, in which case *xh, *th, and *path are valid, or 0 on
764 * failure.
765 */
766 static int parse_transaction_path(XsHandle *self, PyObject *args,
767 struct xs_handle **xh,
768 xs_transaction_t *th,
769 char **path)
770 {
771 char *thstr;
773 *xh = xshandle(self);
775 if (!xh)
776 return 0;
778 if (!PyArg_ParseTuple(args, "ss", &thstr, path))
779 return 0;
781 *th = strtoul(thstr, NULL, 16);
783 return 1;
784 }
787 static PyObject *none(bool result)
788 {
789 if (result) {
790 Py_INCREF(Py_None);
791 return Py_None;
792 }
793 else {
794 PyErr_SetFromErrno(xs_error);
795 return NULL;
796 }
797 }
800 #define XSPY_METH(_name, _args) { \
801 .ml_name = #_name, \
802 .ml_meth = (PyCFunction) xspy_ ## _name, \
803 .ml_flags = _args, \
804 .ml_doc = xspy_ ## _name ## _doc }
806 static PyMethodDef xshandle_methods[] = {
807 XSPY_METH(read, METH_VARARGS),
808 XSPY_METH(write, METH_VARARGS),
809 XSPY_METH(ls, METH_VARARGS),
810 XSPY_METH(mkdir, METH_VARARGS),
811 XSPY_METH(rm, METH_VARARGS),
812 XSPY_METH(get_permissions, METH_VARARGS),
813 XSPY_METH(set_permissions, METH_VARARGS),
814 XSPY_METH(watch, METH_VARARGS),
815 XSPY_METH(read_watch, METH_NOARGS),
816 XSPY_METH(unwatch, METH_VARARGS),
817 XSPY_METH(transaction_start, METH_NOARGS),
818 XSPY_METH(transaction_end, METH_VARARGS | METH_KEYWORDS),
819 XSPY_METH(introduce_domain, METH_VARARGS),
820 XSPY_METH(resume_domain, METH_VARARGS),
821 XSPY_METH(release_domain, METH_VARARGS),
822 XSPY_METH(close, METH_NOARGS),
823 XSPY_METH(get_domain_path, METH_VARARGS),
824 { NULL /* Sentinel. */ },
825 };
827 static PyObject *xshandle_getattr(PyObject *self, char *name)
828 {
829 return Py_FindMethod(xshandle_methods, self, name);
830 }
832 static PyObject *
833 xshandle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
834 {
835 XsHandle *self = (XsHandle *)type->tp_alloc(type, 0);
837 if (self == NULL)
838 return NULL;
840 self->xh = NULL;
841 self->watches = PyList_New(0);
842 if (!self->watches)
843 goto fail;
845 return (PyObject *)self;
846 fail:
847 /* Decreasing the object's reference to 0 will result in xshandle_dealloc
848 being called. */
849 Py_DECREF(self);
850 return NULL;
851 }
853 static int
854 xshandle_init(XsHandle *self, PyObject *args, PyObject *kwds)
855 {
856 static char *kwd_spec[] = { "readonly", NULL };
857 static char *arg_spec = "|i";
858 int readonly = 0;
860 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
861 &readonly))
862 goto fail;
864 self->xh = (readonly ? xs_daemon_open_readonly() : xs_daemon_open());
865 if (!self->xh)
866 goto fail;
868 return 0;
870 fail:
871 PyErr_SetFromErrno(xs_error);
872 return -1;
873 }
875 static void xshandle_dealloc(XsHandle *self)
876 {
877 if (self->xh) {
878 xs_daemon_close(self->xh);
879 self->xh = NULL;
880 }
882 Py_XDECREF(self->watches);
884 self->ob_type->tp_free((PyObject *)self);
885 }
887 static PyTypeObject xshandle_type = {
888 PyObject_HEAD_INIT(NULL)
889 0,
890 PKG "." CLS,
891 sizeof(XsHandle),
892 0,
893 (destructor)xshandle_dealloc, /* tp_dealloc */
894 NULL, /* tp_print */
895 xshandle_getattr, /* tp_getattr */
896 NULL, /* tp_setattr */
897 NULL, /* tp_compare */
898 NULL, /* tp_repr */
899 NULL, /* tp_as_number */
900 NULL, /* tp_as_sequence */
901 NULL, /* tp_as_mapping */
902 NULL, /* tp_hash */
903 NULL, /* tp_call */
904 NULL, /* tp_str */
905 NULL, /* tp_getattro */
906 NULL, /* tp_setattro */
907 NULL, /* tp_as_buffer */
908 Py_TPFLAGS_DEFAULT, /* tp_flags */
909 "Xenstore connections", /* tp_doc */
910 NULL, /* tp_traverse */
911 NULL, /* tp_clear */
912 NULL, /* tp_richcompare */
913 0, /* tp_weaklistoffset */
914 NULL, /* tp_iter */
915 NULL, /* tp_iternext */
916 xshandle_methods, /* tp_methods */
917 NULL, /* tp_members */
918 NULL, /* tp_getset */
919 NULL, /* tp_base */
920 NULL, /* tp_dict */
921 NULL, /* tp_descr_get */
922 NULL, /* tp_descr_set */
923 0, /* tp_dictoffset */
924 (initproc)xshandle_init, /* tp_init */
925 NULL, /* tp_alloc */
926 xshandle_new, /* tp_new */
927 };
929 static PyMethodDef xs_methods[] = { { NULL } };
931 PyMODINIT_FUNC initxs(void)
932 {
933 PyObject* m;
935 if (PyType_Ready(&xshandle_type) < 0)
936 return;
938 m = Py_InitModule(PKG, xs_methods);
940 if (m == NULL)
941 return;
943 xs_error = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL);
945 Py_INCREF(&xshandle_type);
946 PyModule_AddObject(m, CLS, (PyObject *)&xshandle_type);
948 Py_INCREF(xs_error);
949 PyModule_AddObject(m, "Error", xs_error);
950 }
953 /*
954 * Local variables:
955 * c-indent-level: 4
956 * c-basic-offset: 4
957 * End:
958 */