ia64/xen-unstable

view tools/python/xen/lowlevel/xs/xs.c @ 7899:34d9095e79e3

Simplify the logic of each of the functions here, removing the many bizarre
uses of goto that reduce down to return NULL in any case, breaking the common
code out for returning values based upon the success or failure of an
operation, and the common code that parses transaction and path parameters,
used by xspy_read, xspy_ls, and xspy_mkdir. Break out also the common code
that removes a watch token from the XsHandle watches list.

Use bool rather than int for result values, where this matches the same use
by tools/xenstore/xs.c.

Added missing free in xspy_get_permissions.

Use PySequence_SetItem inside xs_watch, rather than Py_INCREF followed by
PyList_SetItem. If there is no None entry in the watches list, the code goes
on to append to the list using PyList_Append, and that call takes its own
reference rather than stealing one like PyList_SetItem. This means that we
were previously leaking a reference if the list was full and so PyList_Append
was necessary.

Use PySequence_SetItem rather than Py_INCREF/PyList_SetItem also where we are
using assigning Py_None into the list, for neatness.

Remove meaningless pipe from xspy_release_domain's arg_spec.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Thu Nov 17 20:17:50 2005 +0100 (2005-11-17)
parents a064c5804eae
children 715184c81749 e60115657823
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>
32 #include <xenctrl.h>
33 #include "xs.h"
35 /** @file
36 * Python interface to the Xen Store Daemon (xs).
37 */
39 /* Needed for Python versions earlier than 2.3. */
40 #ifndef PyMODINIT_FUNC
41 #define PyMODINIT_FUNC DL_EXPORT(void)
42 #endif
44 #define PYPKG "xen.lowlevel.xs"
46 /** Python wrapper round an xs handle.
47 */
48 typedef struct XsHandle {
49 PyObject_HEAD;
50 struct xs_handle *xh;
51 PyObject *watches;
52 } XsHandle;
54 static inline struct xs_handle *xshandle(PyObject *self)
55 {
56 struct xs_handle *xh = ((XsHandle*)self)->xh;
57 if (!xh)
58 PyErr_SetString(PyExc_RuntimeError, "invalid xenstore daemon handle");
59 return xh;
60 }
62 static inline PyObject *pyvalue_int(int val) {
63 return (val
64 ? PyInt_FromLong(val)
65 : PyErr_SetFromErrno(PyExc_RuntimeError));
66 }
68 static inline PyObject *pyvalue_str(char *val) {
69 return (val
70 ? PyString_FromString(val)
71 : PyErr_SetFromErrno(PyExc_RuntimeError));
72 }
74 static void remove_watch(XsHandle *xsh, PyObject *token);
76 static PyObject *none(bool result);
78 static int parse_transaction_path(PyObject *self, PyObject *args,
79 PyObject *kwds,
80 struct xs_handle **xh,
81 struct xs_transaction_handle **th,
82 char **path);
85 #define xspy_read_doc "\n" \
86 "Read data from a path.\n" \
87 " path [string]: xenstore path\n" \
88 "\n" \
89 "Returns: [string] data read.\n" \
90 " None if key doesn't exist.\n" \
91 "Raises RuntimeError on error.\n" \
92 "\n"
94 static PyObject *xspy_read(PyObject *self, PyObject *args, PyObject *kwds)
95 {
96 struct xs_handle *xh;
97 struct xs_transaction_handle *th;
98 char *path;
100 char *xsval;
101 unsigned int xsval_n;
103 if (!parse_transaction_path(self, args, kwds, &xh, &th, &path))
104 return NULL;
106 Py_BEGIN_ALLOW_THREADS
107 xsval = xs_read(xh, th, path, &xsval_n);
108 Py_END_ALLOW_THREADS
109 if (xsval) {
110 PyObject *val = PyString_FromStringAndSize(xsval, xsval_n);
111 free(xsval);
112 return val;
113 }
114 else {
115 return none(errno == ENOENT);
116 }
117 }
120 #define xspy_write_doc "\n" \
121 "Write data to a path.\n" \
122 " path [string] : xenstore path to write to\n." \
123 " data [string] : data to write.\n" \
124 "\n" \
125 "Returns None on success.\n" \
126 "Raises RuntimeError on error.\n" \
127 "\n"
129 static PyObject *xspy_write(PyObject *self, PyObject *args, PyObject *kwds)
130 {
131 static char *kwd_spec[] = { "transaction", "path", "data", NULL };
132 static char *arg_spec = "sss#";
133 char *path = NULL;
134 char *data = NULL;
135 int data_n = 0;
137 struct xs_handle *xh = xshandle(self);
138 bool result;
140 struct xs_transaction_handle *th;
141 char *thstr;
143 if (!xh)
144 return NULL;
145 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
146 &thstr, &path, &data, &data_n))
147 return NULL;
149 th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
151 Py_BEGIN_ALLOW_THREADS
152 result = xs_write(xh, th, path, data, data_n);
153 Py_END_ALLOW_THREADS
155 return none(result);
156 }
159 #define xspy_ls_doc "\n" \
160 "List a directory.\n" \
161 " path [string]: path to list.\n" \
162 "\n" \
163 "Returns: [string array] list of subdirectory names.\n" \
164 " None if key doesn't exist.\n" \
165 "Raises RuntimeError on error.\n" \
166 "\n"
168 static PyObject *xspy_ls(PyObject *self, PyObject *args, PyObject *kwds)
169 {
170 struct xs_handle *xh;
171 struct xs_transaction_handle *th;
172 char *path;
174 char **xsval;
175 int xsval_n;
177 if (!parse_transaction_path(self, args, kwds, &xh, &th, &path))
178 return NULL;
180 Py_BEGIN_ALLOW_THREADS
181 xsval = xs_directory(xh, th, path, &xsval_n);
182 Py_END_ALLOW_THREADS
184 if (xsval) {
185 int i;
186 PyObject *val = PyList_New(xsval_n);
187 for (i = 0; i < xsval_n; i++)
188 PyList_SetItem(val, i, PyString_FromString(xsval[i]));
189 free(xsval);
190 return val;
191 }
192 else {
193 return none(errno == ENOENT);
194 }
195 }
198 #define xspy_mkdir_doc "\n" \
199 "Make a directory.\n" \
200 " path [string]: path to directory to create.\n" \
201 "\n" \
202 "Returns None on success.\n" \
203 "Raises RuntimeError on error.\n" \
204 "\n"
206 static PyObject *xspy_mkdir(PyObject *self, PyObject *args, PyObject *kwds)
207 {
208 struct xs_handle *xh;
209 struct xs_transaction_handle *th;
210 char *path;
212 bool result;
214 if (!parse_transaction_path(self, args, kwds, &xh, &th, &path))
215 return NULL;
217 Py_BEGIN_ALLOW_THREADS
218 result = xs_mkdir(xh, th, path);
219 Py_END_ALLOW_THREADS
221 return none(result);
222 }
225 #define xspy_rm_doc "\n" \
226 "Remove a path.\n" \
227 " path [string] : path to remove\n" \
228 "\n" \
229 "Returns None on success.\n" \
230 "Raises RuntimeError on error.\n" \
231 "\n"
233 static PyObject *xspy_rm(PyObject *self, PyObject *args, PyObject *kwds)
234 {
235 struct xs_handle *xh;
236 struct xs_transaction_handle *th;
237 char *path;
239 bool result;
241 if (!parse_transaction_path(self, args, kwds, &xh, &th, &path))
242 return NULL;
244 Py_BEGIN_ALLOW_THREADS
245 result = xs_rm(xh, th, path);
246 Py_END_ALLOW_THREADS
248 return none(result || errno == ENOENT);
249 }
252 #define xspy_get_permissions_doc "\n" \
253 "Get the permissions for a path\n" \
254 " path [string]: xenstore path.\n" \
255 "\n" \
256 "Returns: permissions array.\n" \
257 "Raises RuntimeError on error.\n" \
258 "\n"
260 static PyObject *xspy_get_permissions(PyObject *self, PyObject *args,
261 PyObject *kwds)
262 {
263 static char *kwd_spec[] = { "transaction", "path", NULL };
264 static char *arg_spec = "ss";
265 char *path = NULL;
267 struct xs_handle *xh = xshandle(self);
268 struct xs_permissions *perms;
269 unsigned int perms_n = 0;
270 int i;
272 struct xs_transaction_handle *th;
273 char *thstr;
275 if (!xh)
276 return NULL;
277 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
278 &thstr, &path))
279 return NULL;
281 th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
283 Py_BEGIN_ALLOW_THREADS
284 perms = xs_get_permissions(xh, th, path, &perms_n);
285 Py_END_ALLOW_THREADS
287 if (perms) {
288 PyObject *val = PyList_New(perms_n);
289 for (i = 0; i < perms_n; i++, perms++) {
290 PyObject *p = Py_BuildValue("{s:i,s:i,s:i}",
291 "dom", perms->id,
292 "read", perms->perms & XS_PERM_READ,
293 "write",perms->perms & XS_PERM_WRITE);
294 PyList_SetItem(val, i, p);
295 }
297 free(perms);
298 return val;
299 }
300 else {
301 PyErr_SetFromErrno(PyExc_RuntimeError);
302 return NULL;
303 }
304 }
306 #define xspy_set_permissions_doc "\n" \
307 "Set the permissions for a path\n" \
308 " path [string] : xenstore path.\n" \
309 " perms : permissions.\n" \
310 "\n" \
311 "Returns None on success.\n" \
312 "Raises RuntimeError on error.\n" \
313 "\n"
315 static PyObject *xspy_set_permissions(PyObject *self, PyObject *args,
316 PyObject *kwds)
317 {
318 static char *kwd_spec[] = { "transaction", "path", "perms", NULL };
319 static char *arg_spec = "ssO";
320 char *path = NULL;
321 PyObject *perms = NULL;
322 static char *perm_names[] = { "dom", "read", "write", NULL };
323 static char *perm_spec = "i|iiii";
325 struct xs_handle *xh = xshandle(self);
326 int i, result;
327 struct xs_permissions *xsperms = NULL;
328 int xsperms_n = 0;
329 PyObject *tuple0 = NULL;
330 PyObject *val = NULL;
332 struct xs_transaction_handle *th;
333 char *thstr;
335 if (!xh)
336 goto exit;
337 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
338 &thstr, &path, &perms))
339 goto exit;
341 th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
343 if (!PyList_Check(perms)) {
344 PyErr_SetString(PyExc_RuntimeError, "perms must be a list");
345 goto exit;
346 }
347 xsperms_n = PyList_Size(perms);
348 xsperms = calloc(xsperms_n, sizeof(struct xs_permissions));
349 if (!xsperms) {
350 PyErr_SetString(PyExc_RuntimeError, "out of memory");
351 goto exit;
352 }
353 tuple0 = PyTuple_New(0);
354 if (!tuple0)
355 goto exit;
356 for (i = 0; i < xsperms_n; i++) {
357 /* Domain the permissions apply to. */
358 int dom = 0;
359 /* Read/write perms. Set these. */
360 int p_read = 0, p_write = 0;
361 PyObject *p = PyList_GetItem(perms, i);
362 if (!PyArg_ParseTupleAndKeywords(tuple0, p, perm_spec, perm_names,
363 &dom, &p_read, &p_write))
364 goto exit;
365 xsperms[i].id = dom;
366 if (p_read)
367 xsperms[i].perms |= XS_PERM_READ;
368 if (p_write)
369 xsperms[i].perms |= XS_PERM_WRITE;
370 }
371 Py_BEGIN_ALLOW_THREADS
372 result = xs_set_permissions(xh, th, path, xsperms, xsperms_n);
373 Py_END_ALLOW_THREADS
374 if (!result) {
375 PyErr_SetFromErrno(PyExc_RuntimeError);
376 goto exit;
377 }
378 Py_INCREF(Py_None);
379 val = Py_None;
380 exit:
381 Py_XDECREF(tuple0);
382 free(xsperms);
383 return val;
384 }
386 #define xspy_watch_doc "\n" \
387 "Watch a path, get notifications when it changes.\n" \
388 " path [string] : xenstore path.\n" \
389 " token [string] : returned in watch notification.\n" \
390 "\n" \
391 "Returns None on success.\n" \
392 "Raises RuntimeError on error.\n" \
393 "\n"
395 /* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
396 #define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
398 static PyObject *xspy_watch(PyObject *self, PyObject *args, PyObject *kwds)
399 {
400 static char *kwd_spec[] = { "path", "token", NULL };
401 static char *arg_spec = "sO";
402 char *path = NULL;
403 PyObject *token;
404 char token_str[MAX_STRLEN(unsigned long) + 1];
405 int i;
407 XsHandle *xsh = (XsHandle *)self;
408 struct xs_handle *xh = xshandle(self);
409 int result = 0;
411 if (!xh)
412 return NULL;
413 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
414 &path, &token))
415 return NULL;
417 /* Note that we have to store the watch token in the xs->watches list
418 before registering the watch with xs_watch, otherwise this function
419 races with xs_read_watch.
420 */
422 for (i = 0; i < PyList_Size(xsh->watches); i++) {
423 if (PyList_GetItem(xsh->watches, i) == Py_None) {
424 PySequence_SetItem(xsh->watches, i, token);
425 break;
426 }
427 }
428 if (i == PyList_Size(xsh->watches))
429 PyList_Append(xsh->watches, token);
431 sprintf(token_str, "%li", (unsigned long)token);
432 Py_BEGIN_ALLOW_THREADS
433 result = xs_watch(xh, path, token_str);
434 Py_END_ALLOW_THREADS
436 if (!result)
437 remove_watch(xsh, token);
439 return none(result);
440 }
443 #define xspy_read_watch_doc "\n" \
444 "Read a watch notification.\n" \
445 "\n" \
446 "Returns: [tuple] (path, token).\n" \
447 "Raises RuntimeError on error.\n" \
448 "\n"
450 static PyObject *xspy_read_watch(PyObject *self, PyObject *args,
451 PyObject *kwds)
452 {
453 static char *kwd_spec[] = { NULL };
454 static char *arg_spec = "";
456 XsHandle *xsh = (XsHandle *)self;
457 struct xs_handle *xh = xshandle(self);
458 PyObject *val = NULL;
459 char **xsval = NULL;
460 PyObject *token;
461 int i;
462 unsigned int num;
464 if (!xh)
465 return NULL;
466 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
467 return NULL;
469 again:
470 Py_BEGIN_ALLOW_THREADS
471 xsval = xs_read_watch(xh, &num);
472 Py_END_ALLOW_THREADS
473 if (!xsval) {
474 PyErr_SetFromErrno(PyExc_RuntimeError);
475 goto exit;
476 }
477 if (sscanf(xsval[XS_WATCH_TOKEN], "%li", (unsigned long *)&token) != 1) {
478 PyErr_SetString(PyExc_RuntimeError, "invalid token");
479 goto exit;
480 }
481 for (i = 0; i < PyList_Size(xsh->watches); i++) {
482 if (token == PyList_GetItem(xsh->watches, i))
483 break;
484 }
485 if (i == PyList_Size(xsh->watches)) {
486 /* We do not have a registered watch for the one that has just fired.
487 Ignore this -- a watch that has been recently deregistered can still
488 have watches in transit. This is a blocking method, so go back to
489 read again.
490 */
491 free(xsval);
492 goto again;
493 }
494 /* Create tuple (path, token). */
495 val = Py_BuildValue("(sO)", xsval[XS_WATCH_PATH], token);
496 exit:
497 free(xsval);
498 return val;
499 }
501 #define xspy_unwatch_doc "\n" \
502 "Stop watching a path.\n" \
503 " path [string] : xenstore path.\n" \
504 " token [string] : token from the watch.\n" \
505 "\n" \
506 "Returns None on success.\n" \
507 "Raises RuntimeError on error.\n" \
508 "\n"
510 static PyObject *xspy_unwatch(PyObject *self, PyObject *args, PyObject *kwds)
511 {
512 static char *kwd_spec[] = { "path", "token", NULL };
513 static char *arg_spec = "sO";
514 char *path = NULL;
515 PyObject *token;
516 char token_str[MAX_STRLEN(unsigned long) + 1];
518 XsHandle *xsh = (XsHandle *)self;
519 struct xs_handle *xh = xshandle(self);
520 int result = 0;
522 if (!xh)
523 return NULL;
524 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path,
525 &token))
526 return NULL;
528 sprintf(token_str, "%li", (unsigned long)token);
529 Py_BEGIN_ALLOW_THREADS
530 result = xs_unwatch(xh, path, token_str);
531 Py_END_ALLOW_THREADS
533 remove_watch(xsh, token);
535 return none(result);
536 }
538 #define xspy_transaction_start_doc "\n" \
539 "Start a transaction.\n" \
540 "\n" \
541 "Returns transaction handle on success.\n" \
542 "Raises RuntimeError on error.\n" \
543 "\n"
545 static PyObject *xspy_transaction_start(PyObject *self, PyObject *args,
546 PyObject *kwds)
547 {
548 static char *kwd_spec[] = { NULL };
549 static char *arg_spec = "";
550 char *path = NULL;
552 struct xs_handle *xh = xshandle(self);
553 struct xs_transaction_handle *th;
554 char thstr[20];
556 if (!xh)
557 return NULL;
558 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec, &path))
559 return NULL;
561 Py_BEGIN_ALLOW_THREADS
562 th = xs_transaction_start(xh);
563 Py_END_ALLOW_THREADS
565 if (th == NULL) {
566 PyErr_SetFromErrno(PyExc_RuntimeError);
567 return NULL;
568 }
570 sprintf(thstr, "%lX", (unsigned long)th);
571 return PyString_FromString(thstr);
572 }
574 #define xspy_transaction_end_doc "\n" \
575 "End the current transaction.\n" \
576 "Attempts to commit the transaction unless abort is true.\n" \
577 " abort [int]: abort flag (default 0).\n" \
578 "\n" \
579 "Returns True on success, False if you need to try again.\n" \
580 "Raises RuntimeError on error.\n" \
581 "\n"
583 static PyObject *xspy_transaction_end(PyObject *self, PyObject *args,
584 PyObject *kwds)
585 {
586 static char *kwd_spec[] = { "transaction", "abort", NULL };
587 static char *arg_spec = "s|i";
588 int abort = 0;
590 struct xs_handle *xh = xshandle(self);
591 bool result;
593 struct xs_transaction_handle *th;
594 char *thstr;
596 if (!xh)
597 return NULL;
598 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
599 &thstr, &abort))
600 return NULL;
602 th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
604 Py_BEGIN_ALLOW_THREADS
605 result = xs_transaction_end(xh, th, abort);
606 Py_END_ALLOW_THREADS
608 if (result) {
609 Py_INCREF(Py_True);
610 return Py_True;
611 }
612 else if (errno == EAGAIN) {
613 Py_INCREF(Py_False);
614 return Py_False;
615 }
616 else {
617 PyErr_SetFromErrno(PyExc_RuntimeError);
618 return NULL;
619 }
620 }
623 #define xspy_introduce_domain_doc "\n" \
624 "Tell xenstore about a domain so it can talk to it.\n" \
625 " dom [int] : domain id\n" \
626 " page [long] : address of domain's xenstore page\n" \
627 " port [int] : port the domain is using for xenstore\n" \
628 "\n" \
629 "Returns None on success.\n" \
630 "Raises RuntimeError on error.\n" \
631 "\n"
633 static PyObject *xspy_introduce_domain(PyObject *self, PyObject *args,
634 PyObject *kwds)
635 {
636 static char *kwd_spec[] = { "dom", "page", "port", NULL };
637 static char *arg_spec = "ili";
638 domid_t dom = 0;
639 unsigned long page = 0;
640 unsigned int port = 0;
642 struct xs_handle *xh = xshandle(self);
643 bool result = 0;
645 if (!xh)
646 return NULL;
647 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
648 &dom, &page, &port))
649 return NULL;
651 Py_BEGIN_ALLOW_THREADS
652 result = xs_introduce_domain(xh, dom, page, port);
653 Py_END_ALLOW_THREADS
655 return none(result);
656 }
659 #define xspy_release_domain_doc "\n" \
660 "Tell xenstore to release its channel to a domain.\n" \
661 "Unless this is done the domain will not be released.\n" \
662 " dom [int]: domain id\n" \
663 "\n" \
664 "Returns None on success.\n" \
665 "Raises RuntimeError on error.\n" \
666 "\n"
668 static PyObject *xspy_release_domain(PyObject *self, PyObject *args,
669 PyObject *kwds)
670 {
671 static char *kwd_spec[] = { "dom", NULL };
672 static char *arg_spec = "i";
673 domid_t dom;
675 struct xs_handle *xh = xshandle(self);
676 bool result = 0;
678 if (!xh)
679 return NULL;
680 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
681 &dom))
682 return NULL;
684 Py_BEGIN_ALLOW_THREADS
685 result = xs_release_domain(xh, dom);
686 Py_END_ALLOW_THREADS
688 return none(result);
689 }
692 #define xspy_close_doc "\n" \
693 "Close the connection to xenstore.\n" \
694 "\n" \
695 "Returns None on success.\n" \
696 "Raises RuntimeError on error.\n" \
697 "\n"
699 static PyObject *xspy_close(PyObject *self, PyObject *args, PyObject *kwds)
700 {
701 static char *kwd_spec[] = { NULL };
702 static char *arg_spec = "";
703 int i;
705 XsHandle *xsh = (XsHandle *)self;
706 struct xs_handle *xh = xshandle(self);
708 if (!xh)
709 return NULL;
710 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec))
711 return NULL;
713 for (i = 0; i < PyList_Size(xsh->watches); i++) {
714 /* TODO: xs_unwatch watches */
715 PySequence_SetItem(xsh->watches, i, Py_None);
716 }
718 xs_daemon_close(xh);
719 xsh->xh = NULL;
721 Py_INCREF(Py_None);
722 return Py_None;
723 }
726 #define xspy_get_domain_path_doc "\n" \
727 "Return store path of domain, whether or not the domain exists.\n" \
728 " domid [int]: domain id\n" \
729 "\n" \
730 "Returns: [string] domain store path.\n" \
731 "Raises RuntimeError on error.\n" \
732 "\n"
734 static PyObject *xspy_get_domain_path(PyObject *self, PyObject *args,
735 PyObject *kwds)
736 {
737 static char *kwd_spec[] = { "domid", NULL };
738 static char *arg_spec = "i";
739 int domid = 0;
741 struct xs_handle *xh = xshandle(self);
742 char *xsval = NULL;
744 if (!xh)
745 return NULL;
746 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
747 &domid))
748 return NULL;
750 Py_BEGIN_ALLOW_THREADS
751 xsval = xs_get_domain_path(xh, domid);
752 Py_END_ALLOW_THREADS
754 if (xsval) {
755 PyObject *val = PyString_FromString(xsval);
756 free(xsval);
757 return val;
758 }
759 else {
760 return none(errno == ENOENT);
761 }
762 }
765 /**
766 * Remove the given token from the watches list belonging to the given
767 * XsHandle, if present.
768 */
769 static void remove_watch(XsHandle *xsh, PyObject *token)
770 {
771 int i;
773 for (i = 0; i < PyList_Size(xsh->watches); i++) {
774 if (PyList_GetItem(xsh->watches, i) == token) {
775 PySequence_SetItem(xsh->watches, i, Py_None);
776 return;
777 }
778 }
779 }
782 /**
783 * Parse transaction and path arguments from the given args and kwds,
784 * convert the given self value to an xs_handle, and return all three by
785 * reference.
786 *
787 * @return 1 on success, in which case *xh, *th, and *path are valid, or 0 on
788 * failure.
789 */
790 static int parse_transaction_path(PyObject *self, PyObject *args,
791 PyObject *kwds,
792 struct xs_handle **xh,
793 struct xs_transaction_handle **th,
794 char **path)
795 {
796 static char *arg_spec = "ss";
797 static char *kwd_spec[] = { "transaction", "path", NULL };
798 char *thstr;
800 *xh = xshandle(self);
802 if (!xh)
803 return 0;
805 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
806 &thstr, path))
807 return 0;
809 *th = (struct xs_transaction_handle *)strtoul(thstr, NULL, 16);
811 return 1;
812 }
815 static PyObject *none(bool result)
816 {
817 if (result) {
818 Py_INCREF(Py_None);
819 return Py_None;
820 }
821 else {
822 PyErr_SetFromErrno(PyExc_RuntimeError);
823 return NULL;
824 }
825 }
828 #define XSPY_METH(_name) { \
829 .ml_name = #_name, \
830 .ml_meth = (PyCFunction) xspy_ ## _name, \
831 .ml_flags = (METH_VARARGS | METH_KEYWORDS), \
832 .ml_doc = xspy_ ## _name ## _doc }
834 static PyMethodDef xshandle_methods[] = {
835 XSPY_METH(read),
836 XSPY_METH(write),
837 XSPY_METH(ls),
838 XSPY_METH(mkdir),
839 XSPY_METH(rm),
840 XSPY_METH(get_permissions),
841 XSPY_METH(set_permissions),
842 XSPY_METH(watch),
843 XSPY_METH(read_watch),
844 XSPY_METH(unwatch),
845 XSPY_METH(transaction_start),
846 XSPY_METH(transaction_end),
847 XSPY_METH(introduce_domain),
848 XSPY_METH(release_domain),
849 XSPY_METH(close),
850 XSPY_METH(get_domain_path),
851 { /* Terminator. */ },
852 };
854 static PyObject *xshandle_getattr(PyObject *self, char *name)
855 {
856 return Py_FindMethod(xshandle_methods, self, name);
857 }
859 static void xshandle_dealloc(PyObject *self)
860 {
861 XsHandle *xh = (XsHandle*)self;
862 if (xh->xh) {
863 xs_daemon_close(xh->xh);
864 xh->xh = NULL;
865 }
866 PyObject_Del(self);
867 }
869 static PyTypeObject xshandle_type = {
870 PyObject_HEAD_INIT(&PyType_Type)
871 0,
872 "xshandle",
873 sizeof(XsHandle),
874 0,
875 xshandle_dealloc, /* tp_dealloc */
876 NULL, /* tp_print */
877 xshandle_getattr, /* tp_getattr */
878 NULL, /* tp_setattr */
879 NULL, /* tp_compare */
880 NULL, /* tp_repr */
881 NULL, /* tp_as_number */
882 NULL, /* tp_as_sequence */
883 NULL, /* tp_as_mapping */
884 NULL /* tp_hash */
885 };
887 static PyObject *xshandle_open(PyObject *self, PyObject *args, PyObject *kwds)
888 {
889 static char *kwd_spec[] = { "readonly", NULL };
890 static char *arg_spec = "|i";
891 int readonly = 0;
893 XsHandle *xsh = NULL;
894 PyObject *val = NULL;
896 if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
897 &readonly))
898 return NULL;
900 xsh = PyObject_New(XsHandle, &xshandle_type);
901 if (!xsh)
902 return NULL;
903 xsh->watches = PyList_New(0);
904 if (!xsh->watches)
905 goto exit;
906 xsh->xh = (readonly ? xs_daemon_open_readonly() : xs_daemon_open());
907 if (!xsh->xh) {
908 Py_DECREF(xsh->watches);
909 PyErr_SetFromErrno(PyExc_RuntimeError);
910 goto exit;
911 }
912 val = (PyObject *)xsh;
913 return val;
914 exit:
915 PyObject_Del(xsh);
916 return NULL;
917 }
919 static PyMethodDef xs_methods[] = {
920 { .ml_name = "open",
921 .ml_meth = (PyCFunction)xshandle_open,
922 .ml_flags = (METH_VARARGS | METH_KEYWORDS),
923 .ml_doc = "\n"
924 "Open a connection to the xenstore daemon.\n"
925 "Returns: xs connection object.\n"
926 "Raises RuntimeError on error.\n"
927 "\n"
928 },
929 { /* Terminator. */ }
930 };
932 PyMODINIT_FUNC initxs (void)
933 {
934 PyObject *module;
936 module = Py_InitModule(PYPKG, xs_methods);
937 }
940 /*
941 * Local variables:
942 * c-indent-level: 4
943 * c-basic-offset: 4
944 * End:
945 */