~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to tools/python/xen/lowlevel/xs/xs.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
48
static PyObject *xs_error;
 
49
 
 
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;
 
57
 
 
58
static void xs_set_error(int value)
 
59
{
 
60
        errno = value;
 
61
        PyErr_SetFromErrno(xs_error);
 
62
}
 
63
 
 
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
}
 
71
 
 
72
static void remove_watch(XsHandle *xsh, PyObject *token);
 
73
 
 
74
static PyObject *none(bool result);
 
75
 
 
76
static 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
 
 
92
static 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
 
 
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;
 
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
 
 
164
static 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
 
 
202
static 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
 
 
230
static 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
 
 
258
static 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
 
 
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";
 
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
    PyObject *ret = NULL;
 
328
 
 
329
    if (!xh)
 
330
        goto exit;
 
331
    if (!PyArg_ParseTuple(args, "ssO", &thstr, &path, &perms))
 
332
        goto exit;
 
333
 
 
334
    th = strtoul(thstr, NULL, 16);
 
335
 
 
336
    if (!PyList_Check(perms)) {
 
337
        xs_set_error(EINVAL);
 
338
        goto exit;
 
339
    }
 
340
 
 
341
    xsperms_n = PyList_Size(perms);
 
342
    /* NB. alloc +1 so we can change the owner if necessary. */
 
343
    xsperms = calloc(xsperms_n + 1, sizeof(struct xs_permissions));
 
344
    if (!xsperms) {
 
345
        xs_set_error(ENOMEM);
 
346
        goto exit;
 
347
    }
 
348
 
 
349
    tuple0 = PyTuple_New(0);
 
350
    if (!tuple0)
 
351
        goto exit;
 
352
 
 
353
    for (i = 0; i < xsperms_n; i++) {
 
354
        /* Read/write perms. Set these. */
 
355
        int p_read = 0, p_write = 0;
 
356
        PyObject *p = PyList_GetItem(perms, i);
 
357
        if (!PyArg_ParseTupleAndKeywords(tuple0, p, perm_spec, perm_names,
 
358
                                         &xsperms[i].id, &p_read, &p_write))
 
359
            goto exit;
 
360
        if (p_read)
 
361
            xsperms[i].perms |= XS_PERM_READ;
 
362
        if (p_write)
 
363
            xsperms[i].perms |= XS_PERM_WRITE;
 
364
    }
 
365
 
 
366
    /*
 
367
     * Is the caller trying to restrict access to the first specified
 
368
     * domain? If so then it cannot be owner, so we force dom0 as owner.
 
369
     */
 
370
    if (xsperms_n && xsperms[0].perms && xsperms[0].id) {
 
371
        memmove(&xsperms[1], &xsperms[0], xsperms_n * sizeof(*xsperms));
 
372
        xsperms[0].id = xsperms[0].perms = 0;
 
373
        xsperms_n++;
 
374
    }
 
375
 
 
376
    Py_BEGIN_ALLOW_THREADS
 
377
    result = xs_set_permissions(xh, th, path, xsperms, xsperms_n);
 
378
    Py_END_ALLOW_THREADS
 
379
    if (!result) {
 
380
        PyErr_SetFromErrno(xs_error);
 
381
        goto exit;
 
382
    }
 
383
 
 
384
    Py_INCREF(Py_None);
 
385
    ret = Py_None;
 
386
 
 
387
 exit:
 
388
    Py_XDECREF(tuple0);
 
389
    free(xsperms);
 
390
    return ret;
 
391
}
 
392
 
 
393
#define xspy_watch_doc "\n"                                             \
 
394
        "Watch a path, get notifications when it changes.\n"            \
 
395
        " path     [string] : xenstore path.\n"                         \
 
396
        " token    [string] : returned in watch notification.\n"        \
 
397
        "\n"                                                            \
 
398
        "Returns None on success.\n"                                    \
 
399
        "Raises xen.lowlevel.xs.Error on error.\n"                              \
 
400
        "\n"
 
401
 
 
402
/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
 
403
#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
 
404
 
 
405
static PyObject *xspy_watch(XsHandle *self, PyObject *args)
 
406
{
 
407
    struct xs_handle *xh = xshandle(self);
 
408
    char *path;
 
409
    PyObject *token;
 
410
    char token_str[MAX_STRLEN(unsigned long) + 1];
 
411
    int result;
 
412
    int i;
 
413
 
 
414
    if (!xh)
 
415
        return NULL;
 
416
    if (!PyArg_ParseTuple(args, "sO", &path, &token))
 
417
        return NULL;
 
418
 
 
419
    /* Note that we have to store the watch token in the xs->watches list
 
420
       before registering the watch with xs_watch, otherwise this function
 
421
       races with xs_read_watch.
 
422
    */
 
423
 
 
424
    for (i = 0; i < PyList_Size(self->watches); i++) {
 
425
        if (PyList_GetItem(self->watches, i) == Py_None) {
 
426
            PySequence_SetItem(self->watches, i, token);
 
427
            break;
 
428
        }
 
429
    }
 
430
    if (i == PyList_Size(self->watches))
 
431
        PyList_Append(self->watches, token);
 
432
 
 
433
    snprintf(token_str, sizeof(token_str), "%li", (unsigned long)token);
 
434
    Py_BEGIN_ALLOW_THREADS
 
435
    result = xs_watch(xh, path, token_str);
 
436
    Py_END_ALLOW_THREADS
 
437
 
 
438
    if (!result)
 
439
        remove_watch(self, token);
 
440
 
 
441
    return none(result);
 
442
}
 
443
 
 
444
 
 
445
#define xspy_read_watch_doc "\n"                                \
 
446
        "Read a watch notification.\n"                          \
 
447
        "\n"                                                    \
 
448
        "Returns: [tuple] (path, token).\n"                     \
 
449
        "Raises xen.lowlevel.xs.Error on error.\n"                      \
 
450
        "\n"
 
451
 
 
452
static PyObject *xspy_read_watch(XsHandle *self, PyObject *args)
 
453
{
 
454
    struct xs_handle *xh = xshandle(self);
 
455
    PyObject *val = NULL;
 
456
    char **xsval;
 
457
    PyObject *token;
 
458
    int i;
 
459
    unsigned int num;
 
460
 
 
461
    if (!xh)
 
462
        return NULL;
 
463
 
 
464
again:
 
465
    Py_BEGIN_ALLOW_THREADS
 
466
    xsval = xs_read_watch(xh, &num);
 
467
    Py_END_ALLOW_THREADS
 
468
    if (!xsval) {
 
469
        PyErr_SetFromErrno(xs_error);
 
470
        goto exit;
 
471
    }
 
472
    if (sscanf(xsval[XS_WATCH_TOKEN], "%li", (unsigned long *)&token) != 1) {
 
473
        xs_set_error(EINVAL);
 
474
        goto exit;
 
475
    }
 
476
    for (i = 0; i < PyList_Size(self->watches); i++) {
 
477
        if (token == PyList_GetItem(self->watches, i))
 
478
            break;
 
479
    }
 
480
    if (i == PyList_Size(self->watches)) {
 
481
      /* We do not have a registered watch for the one that has just fired.
 
482
         Ignore this -- a watch that has been recently deregistered can still
 
483
         have watches in transit.  This is a blocking method, so go back to
 
484
         read again.
 
485
      */
 
486
      free(xsval);
 
487
      goto again;
 
488
    }
 
489
    /* Create tuple (path, token). */
 
490
    val = Py_BuildValue("(sO)", xsval[XS_WATCH_PATH], token);
 
491
 exit:
 
492
    free(xsval);
 
493
    return val;
 
494
}
 
495
 
 
496
#define xspy_unwatch_doc "\n"                           \
 
497
        "Stop watching a path.\n"                       \
 
498
        " path  [string] : xenstore path.\n"            \
 
499
        " token [string] : token from the watch.\n"     \
 
500
        "\n"                                            \
 
501
        "Returns None on success.\n"                    \
 
502
        "Raises xen.lowlevel.xs.Error on error.\n"              \
 
503
        "\n"
 
504
 
 
505
static PyObject *xspy_unwatch(XsHandle *self, PyObject *args)
 
506
{
 
507
    struct xs_handle *xh = xshandle(self);
 
508
    char *path;
 
509
    PyObject *token;
 
510
    char token_str[MAX_STRLEN(unsigned long) + 1];
 
511
    int result;
 
512
 
 
513
    if (!xh)
 
514
        return NULL;
 
515
    if (!PyArg_ParseTuple(args, "sO", &path, &token))
 
516
        return NULL;
 
517
 
 
518
    snprintf(token_str, sizeof(token_str), "%li", (unsigned long)token);
 
519
    Py_BEGIN_ALLOW_THREADS
 
520
    result = xs_unwatch(xh, path, token_str);
 
521
    Py_END_ALLOW_THREADS
 
522
 
 
523
    remove_watch(self, token);
 
524
 
 
525
    return none(result);
 
526
}
 
527
 
 
528
#define xspy_transaction_start_doc "\n"                         \
 
529
        "Start a transaction.\n"                                \
 
530
        "\n"                                                    \
 
531
        "Returns transaction handle on success.\n"              \
 
532
        "Raises xen.lowlevel.xs.Error on error.\n"                      \
 
533
        "\n"
 
534
 
 
535
static PyObject *xspy_transaction_start(XsHandle *self)
 
536
{
 
537
    struct xs_handle *xh = xshandle(self);
 
538
    xs_transaction_t th;
 
539
    char thstr[MAX_STRLEN(unsigned long) + 1];
 
540
 
 
541
    if (!xh)
 
542
        return NULL;
 
543
 
 
544
    Py_BEGIN_ALLOW_THREADS
 
545
    th = xs_transaction_start(xh);
 
546
    Py_END_ALLOW_THREADS
 
547
 
 
548
    if (th == XBT_NULL) {
 
549
        PyErr_SetFromErrno(xs_error);
 
550
        return NULL;
 
551
    }
 
552
 
 
553
    snprintf(thstr, sizeof(thstr), "%lX", (unsigned long)th);
 
554
    return PyString_FromString(thstr);
 
555
}
 
556
 
 
557
#define xspy_transaction_end_doc "\n"                                   \
 
558
        "End the current transaction.\n"                                \
 
559
        "Attempts to commit the transaction unless abort is true.\n"    \
 
560
        " abort [int]: abort flag (default 0).\n"                       \
 
561
        "\n"                                                            \
 
562
        "Returns True on success, False if you need to try again.\n"    \
 
563
        "Raises xen.lowlevel.xs.Error on error.\n"                              \
 
564
        "\n"
 
565
 
 
566
static PyObject *xspy_transaction_end(XsHandle *self, PyObject *args,
 
567
                                      PyObject *kwds)
 
568
{
 
569
    static char *kwd_spec[] = { "transaction", "abort", NULL };
 
570
    static char *arg_spec = "s|i";
 
571
    int abort = 0;
 
572
 
 
573
    struct xs_handle *xh = xshandle(self);
 
574
    bool result;
 
575
 
 
576
    xs_transaction_t th;
 
577
    char *thstr;
 
578
 
 
579
    if (!xh)
 
580
        return NULL;
 
581
    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
 
582
                                     &thstr, &abort))
 
583
        return NULL;
 
584
 
 
585
    th = strtoul(thstr, NULL, 16);
 
586
 
 
587
    Py_BEGIN_ALLOW_THREADS
 
588
    result = xs_transaction_end(xh, th, abort);
 
589
    Py_END_ALLOW_THREADS
 
590
 
 
591
    if (result) {
 
592
        Py_INCREF(Py_True);
 
593
        return Py_True;
 
594
    }
 
595
    else if (errno == EAGAIN) {
 
596
        Py_INCREF(Py_False);
 
597
        return Py_False;
 
598
    }
 
599
    else {
 
600
        PyErr_SetFromErrno(xs_error);
 
601
        return NULL;
 
602
    }
 
603
}
 
604
 
 
605
 
 
606
#define xspy_introduce_domain_doc "\n"                                  \
 
607
        "Tell xenstore about a domain so it can talk to it.\n"          \
 
608
        " dom  [int]   : domain id\n"                                   \
 
609
        " page [long]  : address of domain's xenstore page\n"           \
 
610
        " port [int]   : port the domain is using for xenstore\n"       \
 
611
        "\n"                                                            \
 
612
        "Returns None on success.\n"                                    \
 
613
        "Raises xen.lowlevel.xs.Error on error.\n"                              \
 
614
        "\n"
 
615
 
 
616
static PyObject *xspy_introduce_domain(XsHandle *self, PyObject *args)
 
617
{
 
618
    uint32_t dom;
 
619
    unsigned long page;
 
620
    unsigned int port;
 
621
 
 
622
    struct xs_handle *xh = xshandle(self);
 
623
    bool result = 0;
 
624
 
 
625
    if (!xh)
 
626
        return NULL;
 
627
    if (!PyArg_ParseTuple(args, "ili", &dom, &page, &port))
 
628
        return NULL;
 
629
 
 
630
    Py_BEGIN_ALLOW_THREADS
 
631
    result = xs_introduce_domain(xh, dom, page, port);
 
632
    Py_END_ALLOW_THREADS
 
633
 
 
634
    return none(result);
 
635
}
 
636
 
 
637
#define xspy_set_target_doc "\n"                                        \
 
638
        "Tell xenstore that a domain is targetting another one so it\n" \
 
639
        "should let it tinker with it.\n"                               \
 
640
        " dom    [int]   : domain id\n"                                 \
 
641
        " target [int]   : domain id of the target\n"                   \
 
642
        "\n"                                                            \
 
643
        "Returns None on success.\n"                                    \
 
644
        "Raises xen.lowlevel.xs.Error on error.\n"                      \
 
645
        "\n"
 
646
 
 
647
static PyObject *xspy_set_target(XsHandle *self, PyObject *args)
 
648
{
 
649
    uint32_t dom;
 
650
    uint32_t target;
 
651
 
 
652
    struct xs_handle *xh = xshandle(self);
 
653
    bool result = 0;
 
654
 
 
655
    if (!xh)
 
656
        return NULL;
 
657
    if (!PyArg_ParseTuple(args, "ii", &dom, &target))
 
658
        return NULL;
 
659
 
 
660
    Py_BEGIN_ALLOW_THREADS
 
661
    result = xs_set_target(xh, dom, target);
 
662
    Py_END_ALLOW_THREADS
 
663
 
 
664
    return none(result);
 
665
}
 
666
 
 
667
#define xspy_resume_domain_doc "\n"                                \
 
668
        "Tell xenstore to clear its shutdown flag for a domain.\n" \
 
669
        "This ensures that a subsequent shutdown will fire the\n"  \
 
670
        "appropriate watches.\n"                                   \
 
671
        " dom [int]: domain id\n"                                  \
 
672
        "\n"                                                       \
 
673
        "Returns None on success.\n"                               \
 
674
        "Raises xen.lowlevel.xs.Error on error.\n"
 
675
 
 
676
static PyObject *xspy_resume_domain(XsHandle *self, PyObject *args)
 
677
{
 
678
    uint32_t dom;
 
679
 
 
680
    struct xs_handle *xh = xshandle(self);
 
681
    bool result = 0;
 
682
 
 
683
    if (!xh)
 
684
        return NULL;
 
685
    if (!PyArg_ParseTuple(args, "i", &dom))
 
686
        return NULL;
 
687
 
 
688
    Py_BEGIN_ALLOW_THREADS
 
689
    result = xs_resume_domain(xh, dom);
 
690
    Py_END_ALLOW_THREADS
 
691
 
 
692
    return none(result);
 
693
}
 
694
 
 
695
#define xspy_release_domain_doc "\n"                                    \
 
696
        "Tell xenstore to release its channel to a domain.\n"           \
 
697
        "Unless this is done the domain will not be released.\n"        \
 
698
        " dom [int]: domain id\n"                                       \
 
699
        "\n"                                                            \
 
700
        "Returns None on success.\n"                                    \
 
701
        "Raises xen.lowlevel.xs.Error on error.\n"                              \
 
702
        "\n"
 
703
 
 
704
static PyObject *xspy_release_domain(XsHandle *self, PyObject *args)
 
705
{
 
706
    uint32_t dom;
 
707
 
 
708
    struct xs_handle *xh = xshandle(self);
 
709
    bool result = 0;
 
710
 
 
711
    if (!xh)
 
712
        return NULL;
 
713
    if (!PyArg_ParseTuple(args, "i", &dom))
 
714
        return NULL;
 
715
 
 
716
    Py_BEGIN_ALLOW_THREADS
 
717
    result = xs_release_domain(xh, dom);
 
718
    Py_END_ALLOW_THREADS
 
719
 
 
720
    return none(result);
 
721
}
 
722
 
 
723
 
 
724
#define xspy_close_doc "\n"                     \
 
725
        "Close the connection to xenstore.\n"   \
 
726
        "\n"                                    \
 
727
        "Returns None on success.\n"            \
 
728
        "Raises xen.lowlevel.xs.Error on error.\n"      \
 
729
        "\n"
 
730
 
 
731
static PyObject *xspy_close(XsHandle *self)
 
732
{
 
733
    struct xs_handle *xh = xshandle(self);
 
734
    int i;
 
735
 
 
736
    if (!xh)
 
737
        return NULL;
 
738
 
 
739
    for (i = 0; i < PyList_Size(self->watches); i++) {
 
740
        /* TODO: xs_unwatch watches */
 
741
        PySequence_SetItem(self->watches, i, Py_None);
 
742
    }
 
743
 
 
744
    xs_daemon_close(xh);
 
745
    self->xh = NULL;
 
746
 
 
747
    Py_INCREF(Py_None);
 
748
    return Py_None;
 
749
}
 
750
 
 
751
 
 
752
#define xspy_get_domain_path_doc "\n"                   \
 
753
        "Return store path of domain, whether or not the domain exists.\n" \
 
754
        " domid [int]: domain id\n"                     \
 
755
        "\n"                                            \
 
756
        "Returns: [string] domain store path.\n"        \
 
757
        "Raises xen.lowlevel.xs.Error on error.\n"              \
 
758
        "\n"
 
759
 
 
760
static PyObject *xspy_get_domain_path(XsHandle *self, PyObject *args)
 
761
{
 
762
    struct xs_handle *xh = xshandle(self);
 
763
    uint32_t domid;
 
764
    char *xsval;
 
765
 
 
766
    if (!xh)
 
767
        return NULL;
 
768
    if (!PyArg_ParseTuple(args, "i", &domid))
 
769
        return NULL;
 
770
 
 
771
    Py_BEGIN_ALLOW_THREADS
 
772
    xsval = xs_get_domain_path(xh, domid);
 
773
    Py_END_ALLOW_THREADS
 
774
 
 
775
    if (xsval) {
 
776
        PyObject *val = PyString_FromString(xsval);
 
777
        free(xsval);
 
778
        return val;
 
779
    }
 
780
    else {
 
781
        return none(errno == ENOENT);
 
782
    }
 
783
}
 
784
 
 
785
 
 
786
/**
 
787
 * Remove the given token from the watches list belonging to the given
 
788
 * XsHandle, if present.
 
789
 */
 
790
static void remove_watch(XsHandle *self, PyObject *token)
 
791
{
 
792
    int i;
 
793
 
 
794
    for (i = 0; i < PyList_Size(self->watches); i++) {
 
795
        if (PyList_GetItem(self->watches, i) == token) {
 
796
            PySequence_SetItem(self->watches, i, Py_None);
 
797
            return;
 
798
        }
 
799
    }
 
800
}
 
801
 
 
802
 
 
803
/**
 
804
 * Parse transaction and path arguments from the given args and kwds,
 
805
 * convert the given self value to an xs_handle, and return all three by
 
806
 * reference.
 
807
 * 
 
808
 * @return 1 on success, in which case *xh, *th, and *path are valid, or 0 on
 
809
 * failure.
 
810
 */
 
811
static int parse_transaction_path(XsHandle *self, PyObject *args,
 
812
                                  struct xs_handle **xh,
 
813
                                  xs_transaction_t *th,
 
814
                                  char **path)
 
815
{
 
816
    char *thstr;
 
817
 
 
818
    *xh = xshandle(self);
 
819
 
 
820
    if (!xh)
 
821
        return 0;
 
822
 
 
823
    if (!PyArg_ParseTuple(args, "ss", &thstr, path))
 
824
        return 0;
 
825
 
 
826
    *th = strtoul(thstr, NULL, 16);
 
827
 
 
828
    return 1;
 
829
}
 
830
 
 
831
 
 
832
static PyObject *none(bool result)
 
833
{
 
834
    if (result) {
 
835
        Py_INCREF(Py_None);
 
836
        return Py_None;
 
837
    }
 
838
    else {
 
839
        PyErr_SetFromErrno(xs_error);
 
840
        return NULL;
 
841
    }
 
842
}
 
843
 
 
844
 
 
845
#define XSPY_METH(_name, _args) {               \
 
846
    .ml_name  = #_name,                         \
 
847
    .ml_meth  = (PyCFunction) xspy_ ## _name,   \
 
848
    .ml_flags = _args,                          \
 
849
    .ml_doc   = xspy_ ## _name ## _doc }
 
850
 
 
851
static PyMethodDef xshandle_methods[] = {
 
852
    XSPY_METH(read,              METH_VARARGS),
 
853
    XSPY_METH(write,             METH_VARARGS),
 
854
    XSPY_METH(ls,                METH_VARARGS),
 
855
    XSPY_METH(mkdir,             METH_VARARGS),
 
856
    XSPY_METH(rm,                METH_VARARGS),
 
857
    XSPY_METH(get_permissions,   METH_VARARGS),
 
858
    XSPY_METH(set_permissions,   METH_VARARGS),
 
859
    XSPY_METH(watch,             METH_VARARGS),
 
860
    XSPY_METH(read_watch,        METH_NOARGS),
 
861
    XSPY_METH(unwatch,           METH_VARARGS),
 
862
    XSPY_METH(transaction_start, METH_NOARGS),
 
863
    XSPY_METH(transaction_end,   METH_VARARGS | METH_KEYWORDS),
 
864
    XSPY_METH(introduce_domain,  METH_VARARGS),
 
865
    XSPY_METH(set_target,        METH_VARARGS),
 
866
    XSPY_METH(resume_domain,     METH_VARARGS),
 
867
    XSPY_METH(release_domain,    METH_VARARGS),
 
868
    XSPY_METH(close,             METH_NOARGS),
 
869
    XSPY_METH(get_domain_path,   METH_VARARGS),
 
870
    { NULL /* Sentinel. */ },
 
871
};
 
872
 
 
873
static PyObject *xshandle_getattr(PyObject *self, char *name)
 
874
{
 
875
    return Py_FindMethod(xshandle_methods, self, name);
 
876
}
 
877
 
 
878
static PyObject *
 
879
xshandle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
880
{
 
881
    XsHandle *self = (XsHandle *)type->tp_alloc(type, 0);
 
882
 
 
883
    if (self == NULL)
 
884
        return NULL;
 
885
 
 
886
    self->xh = NULL;
 
887
    self->watches = PyList_New(0);
 
888
    if (!self->watches)
 
889
        goto fail;
 
890
 
 
891
    return (PyObject *)self;
 
892
fail:
 
893
    /* Decreasing the object's reference to 0 will result in xshandle_dealloc
 
894
       being called. */
 
895
    Py_DECREF(self);
 
896
    return NULL;
 
897
}
 
898
 
 
899
static int
 
900
xshandle_init(XsHandle *self, PyObject *args, PyObject *kwds)
 
901
{
 
902
    static char *kwd_spec[] = { "readonly", NULL };
 
903
    static char *arg_spec = "|i";
 
904
    int readonly = 0;
 
905
 
 
906
    if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
 
907
                                     &readonly))
 
908
        goto fail;
 
909
 
 
910
    self->xh = (readonly ? xs_daemon_open_readonly() : xs_daemon_open());
 
911
    if (!self->xh)
 
912
        goto fail;
 
913
 
 
914
    return 0;
 
915
 
 
916
 fail:
 
917
    PyErr_SetFromErrno(xs_error);
 
918
    return -1;
 
919
}
 
920
 
 
921
static void xshandle_dealloc(XsHandle *self)
 
922
{
 
923
    if (self->xh) {
 
924
        xs_daemon_close(self->xh);
 
925
        self->xh = NULL;
 
926
    }
 
927
 
 
928
    Py_XDECREF(self->watches);
 
929
 
 
930
    self->ob_type->tp_free((PyObject *)self);
 
931
}
 
932
 
 
933
static PyTypeObject xshandle_type = {
 
934
    PyObject_HEAD_INIT(NULL)
 
935
    0,
 
936
    PKG "." CLS,
 
937
    sizeof(XsHandle),
 
938
    0,
 
939
    (destructor)xshandle_dealloc, /* tp_dealloc        */
 
940
    NULL,                         /* tp_print          */
 
941
    xshandle_getattr,             /* tp_getattr        */
 
942
    NULL,                         /* tp_setattr        */
 
943
    NULL,                         /* tp_compare        */
 
944
    NULL,                         /* tp_repr           */
 
945
    NULL,                         /* tp_as_number      */
 
946
    NULL,                         /* tp_as_sequence    */
 
947
    NULL,                         /* tp_as_mapping     */
 
948
    NULL,                         /* tp_hash           */
 
949
    NULL,                         /* tp_call           */
 
950
    NULL,                         /* tp_str            */
 
951
    NULL,                         /* tp_getattro       */
 
952
    NULL,                         /* tp_setattro       */
 
953
    NULL,                         /* tp_as_buffer      */
 
954
    Py_TPFLAGS_DEFAULT,           /* tp_flags          */
 
955
    "Xenstore connections",       /* tp_doc            */
 
956
    NULL,                         /* tp_traverse       */
 
957
    NULL,                         /* tp_clear          */
 
958
    NULL,                         /* tp_richcompare    */
 
959
    0,                            /* tp_weaklistoffset */
 
960
    NULL,                         /* tp_iter           */
 
961
    NULL,                         /* tp_iternext       */
 
962
    xshandle_methods,             /* tp_methods        */
 
963
    NULL,                         /* tp_members        */
 
964
    NULL,                         /* tp_getset         */
 
965
    NULL,                         /* tp_base           */
 
966
    NULL,                         /* tp_dict           */
 
967
    NULL,                         /* tp_descr_get      */
 
968
    NULL,                         /* tp_descr_set      */
 
969
    0,                            /* tp_dictoffset     */
 
970
    (initproc)xshandle_init,      /* tp_init           */
 
971
    NULL,                         /* tp_alloc          */
 
972
    xshandle_new,                 /* tp_new            */
 
973
};
 
974
 
 
975
static PyMethodDef xs_methods[] = { { NULL } };
 
976
 
 
977
PyMODINIT_FUNC initxs(void)
 
978
{
 
979
    PyObject* m;
 
980
 
 
981
    if (PyType_Ready(&xshandle_type) < 0)
 
982
        return;
 
983
 
 
984
    m = Py_InitModule(PKG, xs_methods);
 
985
 
 
986
    if (m == NULL)
 
987
      return;
 
988
 
 
989
    xs_error = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL);
 
990
 
 
991
    Py_INCREF(&xshandle_type);
 
992
    PyModule_AddObject(m, CLS, (PyObject *)&xshandle_type);
 
993
 
 
994
    Py_INCREF(xs_error);
 
995
    PyModule_AddObject(m, "Error", xs_error);
 
996
}
 
997
 
 
998
 
 
999
/*
 
1000
 * Local variables:
 
1001
 *  c-indent-level: 4
 
1002
 *  c-basic-offset: 4
 
1003
 * End:
 
1004
 */