/*
* Python interface to the Xen Store Daemon.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of version 2.1 of the GNU Lesser General Public
* License as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; If not, see .
*
* Copyright (C) 2005 Mike Wray Hewlett-Packard
* Copyright (C) 2005 Christian Limpach
* Copyright (C) 2005 XenSource Ltd.
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/** @file
* Python interface to the Xen Store Daemon (xs).
*/
/* Needed for Python versions earlier than 2.3. */
#ifndef PyMODINIT_FUNC
#define PyMODINIT_FUNC DL_EXPORT(void)
#endif
#define PKG "xen.lowlevel.xs"
#define CLS "xs"
#if PY_MAJOR_VERSION < 3
/* Python 2 compatibility */
#define PyLong_FromLong PyInt_FromLong
#undef PyLong_Check
#define PyLong_Check PyInt_Check
#define PyLong_AsLong PyInt_AsLong
#endif
static PyObject *xs_error;
/** Python wrapper round an xs handle.
*/
typedef struct XsHandle {
PyObject_HEAD;
struct xs_handle *xh;
PyObject *watches;
} XsHandle;
static void xs_set_error(int value)
{
errno = value;
PyErr_SetFromErrno(xs_error);
}
static inline struct xs_handle *xshandle(XsHandle *self)
{
struct xs_handle *xh = self->xh;
if (!xh)
xs_set_error(EINVAL);
return xh;
}
static void remove_watch(XsHandle *xsh, PyObject *token);
static PyObject *match_watch_by_token(XsHandle *self, char **xsval);
static PyObject *none(bool result);
static int parse_transaction_path(XsHandle *self, PyObject *args,
struct xs_handle **xh,
xs_transaction_t *th,
char **path);
#define xspy_read_doc "\n" \
"Read data from a path.\n" \
" transaction [string]: transaction handle\n" \
" path [string]: xenstore path\n" \
"\n" \
"Returns: [string] data read.\n" \
" None if key doesn't exist.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_read(XsHandle *self, PyObject *args)
{
struct xs_handle *xh;
xs_transaction_t th;
char *path;
char *xsval;
unsigned int xsval_n;
if (!parse_transaction_path(self, args, &xh, &th, &path))
return NULL;
Py_BEGIN_ALLOW_THREADS
xsval = xs_read(xh, th, path, &xsval_n);
Py_END_ALLOW_THREADS
if (xsval) {
PyObject *val = PyBytes_FromStringAndSize(xsval, xsval_n);
free(xsval);
return val;
}
else {
return none(errno == ENOENT);
}
}
#define xspy_write_doc "\n" \
"Write data to a path.\n" \
" transaction [string]: transaction handle\n" \
" path [string] : xenstore path to write to\n." \
" data [string] : data to write.\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_write(XsHandle *self, PyObject *args)
{
static char *arg_spec = "sss#";
struct xs_handle *xh = xshandle(self);
xs_transaction_t th;
char *thstr;
char *path;
char *data;
int data_n;
bool result;
if (!xh)
return NULL;
if (!PyArg_ParseTuple(args, arg_spec, &thstr, &path, &data, &data_n))
return NULL;
th = strtoul(thstr, NULL, 16);
Py_BEGIN_ALLOW_THREADS
result = xs_write(xh, th, path, data, data_n);
Py_END_ALLOW_THREADS
return none(result);
}
#define xspy_ls_doc "\n" \
"List a directory.\n" \
" transaction [string]: transaction handle\n" \
" path [string]: path to list.\n" \
"\n" \
"Returns: [string array] list of subdirectory names.\n" \
" None if key doesn't exist.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_ls(XsHandle *self, PyObject *args)
{
struct xs_handle *xh;
xs_transaction_t th;
char *path;
char **xsval;
unsigned int xsval_n;
if (!parse_transaction_path(self, args, &xh, &th, &path))
return NULL;
Py_BEGIN_ALLOW_THREADS
xsval = xs_directory(xh, th, path, &xsval_n);
Py_END_ALLOW_THREADS
if (xsval) {
int i;
PyObject *val = PyList_New(xsval_n);
for (i = 0; i < xsval_n; i++)
#if PY_MAJOR_VERSION >= 3
PyList_SetItem(val, i, PyUnicode_FromString(xsval[i]));
#else
PyList_SetItem(val, i, PyBytes_FromString(xsval[i]));
#endif
free(xsval);
return val;
}
else {
return none(errno == ENOENT);
}
}
#define xspy_mkdir_doc "\n" \
"Make a directory.\n" \
" transaction [string]: transaction handle.\n" \
" path [string] : path to directory to create.\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_mkdir(XsHandle *self, PyObject *args)
{
struct xs_handle *xh;
xs_transaction_t th;
char *path;
bool result;
if (!parse_transaction_path(self, args, &xh, &th, &path))
return NULL;
Py_BEGIN_ALLOW_THREADS
result = xs_mkdir(xh, th, path);
Py_END_ALLOW_THREADS
return none(result);
}
#define xspy_rm_doc "\n" \
"Remove a path.\n" \
" transaction [string]: transaction handle\n" \
" path [string] : path to remove\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_rm(XsHandle *self, PyObject *args)
{
struct xs_handle *xh;
xs_transaction_t th;
char *path;
bool result;
if (!parse_transaction_path(self, args, &xh, &th, &path))
return NULL;
Py_BEGIN_ALLOW_THREADS
result = xs_rm(xh, th, path);
Py_END_ALLOW_THREADS
return none(result || errno == ENOENT);
}
#define xspy_get_permissions_doc "\n" \
"Get the permissions for a path\n" \
" transaction [string]: transaction handle\n" \
" path [string]: xenstore path.\n" \
"\n" \
"Returns: permissions array.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_get_permissions(XsHandle *self, PyObject *args)
{
static char *arg_spec = "ss";
char *path = NULL;
struct xs_handle *xh = xshandle(self);
struct xs_permissions *perms;
unsigned int perms_n = 0;
int i;
xs_transaction_t th;
char *thstr;
if (!xh)
return NULL;
if (!PyArg_ParseTuple(args, arg_spec, &thstr, &path))
return NULL;
th = strtoul(thstr, NULL, 16);
Py_BEGIN_ALLOW_THREADS
perms = xs_get_permissions(xh, th, path, &perms_n);
Py_END_ALLOW_THREADS
if (perms) {
PyObject *val = PyList_New(perms_n);
for (i = 0; i < perms_n; i++) {
PyObject *p =
Py_BuildValue("{s:i,s:i,s:i}",
"dom", perms[i].id,
"read", perms[i].perms & XS_PERM_READ,
"write", perms[i].perms & XS_PERM_WRITE);
PyList_SetItem(val, i, p);
}
free(perms);
return val;
}
else {
PyErr_SetFromErrno(xs_error);
return NULL;
}
}
#define xspy_set_permissions_doc "\n" \
"Set the permissions for a path\n" \
" transaction [string]: transaction handle\n" \
" path [string] : xenstore path.\n" \
" perms : permissions.\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_set_permissions(XsHandle *self, PyObject *args)
{
char *path;
PyObject *perms;
static char *perm_names[] = { "dom", "read", "write", NULL };
static char *perm_spec = "i|ii";
struct xs_handle *xh = xshandle(self);
int i, result;
struct xs_permissions *xsperms = NULL;
int xsperms_n;
PyObject *tuple0 = NULL;
xs_transaction_t th;
char *thstr;
PyObject *ret = NULL;
if (!xh)
goto exit;
if (!PyArg_ParseTuple(args, "ssO", &thstr, &path, &perms))
goto exit;
th = strtoul(thstr, NULL, 16);
if (!PyList_Check(perms)) {
xs_set_error(EINVAL);
goto exit;
}
xsperms_n = PyList_Size(perms);
/* NB. alloc +1 so we can change the owner if necessary. */
xsperms = calloc(xsperms_n + 1, sizeof(struct xs_permissions));
if (!xsperms) {
xs_set_error(ENOMEM);
goto exit;
}
tuple0 = PyTuple_New(0);
if (!tuple0)
goto exit;
for (i = 0; i < xsperms_n; i++) {
/* Read/write perms. Set these. */
int p_read = 0, p_write = 0;
PyObject *p = PyList_GetItem(perms, i);
if (!PyArg_ParseTupleAndKeywords(tuple0, p, perm_spec, perm_names,
&xsperms[i].id, &p_read, &p_write))
goto exit;
if (p_read)
xsperms[i].perms |= XS_PERM_READ;
if (p_write)
xsperms[i].perms |= XS_PERM_WRITE;
}
/*
* Is the caller trying to restrict access to the first specified
* domain? If so then it cannot be owner, so we force dom0 as owner.
*/
if (xsperms_n && xsperms[0].perms && xsperms[0].id) {
memmove(&xsperms[1], &xsperms[0], xsperms_n * sizeof(*xsperms));
xsperms[0].id = xsperms[0].perms = 0;
xsperms_n++;
}
Py_BEGIN_ALLOW_THREADS
result = xs_set_permissions(xh, th, path, xsperms, xsperms_n);
Py_END_ALLOW_THREADS
if (!result) {
PyErr_SetFromErrno(xs_error);
goto exit;
}
Py_INCREF(Py_None);
ret = Py_None;
exit:
Py_XDECREF(tuple0);
free(xsperms);
return ret;
}
#define xspy_watch_doc "\n" \
"Watch a path, get notifications when it changes.\n" \
" path [string] : xenstore path.\n" \
" token [string] : returned in watch notification.\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
/* Each 10 bits takes ~ 3 digits, plus one, plus one for nul terminator. */
#define MAX_STRLEN(x) ((sizeof(x) * CHAR_BIT + CHAR_BIT-1) / 10 * 3 + 2)
static PyObject *xspy_watch(XsHandle *self, PyObject *args)
{
struct xs_handle *xh = xshandle(self);
char *path;
PyObject *token;
char token_str[MAX_STRLEN(unsigned long) + 1];
int result;
int i;
if (!xh)
return NULL;
if (!PyArg_ParseTuple(args, "sO", &path, &token))
return NULL;
/* Note that we have to store the watch token in the xs->watches list
before registering the watch with xs_watch, otherwise this function
races with xs_read_watch.
*/
for (i = 0; i < PyList_Size(self->watches); i++) {
if (PyList_GetItem(self->watches, i) == Py_None) {
PySequence_SetItem(self->watches, i, token);
break;
}
}
if (i == PyList_Size(self->watches))
PyList_Append(self->watches, token);
snprintf(token_str, sizeof(token_str), "%li", (unsigned long)token);
Py_BEGIN_ALLOW_THREADS
result = xs_watch(xh, path, token_str);
Py_END_ALLOW_THREADS
if (!result)
remove_watch(self, token);
return none(result);
}
#define xspy_fileno_doc "\n" \
"Return the FD to poll for notifications when watches fire.\n" \
"Returns: [int] file descriptor.\n" \
"\n"
static PyObject *xspy_fileno(XsHandle *self)
{
struct xs_handle *xh = xshandle(self);
int fd;
if (!xh)
return NULL;
fd = xs_fileno(xh);
return PyLong_FromLong(fd);
}
#define xspy_check_watch_doc "\n" \
"Check for watch notifications without blocking.\n" \
"\n" \
"Returns: [tuple] (path, token).\n" \
" None if no watches have fired.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_check_watch(XsHandle *self, PyObject *args)
{
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
char **xsval;
if (!xh)
return NULL;
xsval = xs_check_watch(xh);
if (!xsval) {
return none(errno == EAGAIN);
}
val = match_watch_by_token(self, xsval);
free(xsval);
return val;
}
#define xspy_read_watch_doc "\n" \
"Read a watch notification.\n" \
"\n" \
"Returns: [tuple] (path, token).\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_read_watch(XsHandle *self, PyObject *args)
{
struct xs_handle *xh = xshandle(self);
PyObject *val = NULL;
char **xsval;
unsigned int num;
if (!xh)
return NULL;
again:
Py_BEGIN_ALLOW_THREADS
xsval = xs_read_watch(xh, &num);
Py_END_ALLOW_THREADS
if (!xsval) {
PyErr_SetFromErrno(xs_error);
return val;
}
val = match_watch_by_token(self, xsval);
free(xsval);
if (!val && errno == EAGAIN) {
goto again;
}
return val;
}
#define xspy_unwatch_doc "\n" \
"Stop watching a path.\n" \
" path [string] : xenstore path.\n" \
" token [string] : token from the watch.\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_unwatch(XsHandle *self, PyObject *args)
{
struct xs_handle *xh = xshandle(self);
char *path;
PyObject *token;
char token_str[MAX_STRLEN(unsigned long) + 1];
int result;
if (!xh)
return NULL;
if (!PyArg_ParseTuple(args, "sO", &path, &token))
return NULL;
snprintf(token_str, sizeof(token_str), "%li", (unsigned long)token);
Py_BEGIN_ALLOW_THREADS
result = xs_unwatch(xh, path, token_str);
Py_END_ALLOW_THREADS
remove_watch(self, token);
return none(result);
}
#define xspy_transaction_start_doc "\n" \
"Start a transaction.\n" \
"\n" \
"Returns transaction handle on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_transaction_start(XsHandle *self)
{
struct xs_handle *xh = xshandle(self);
xs_transaction_t th;
char thstr[MAX_STRLEN(unsigned long) + 1];
if (!xh)
return NULL;
Py_BEGIN_ALLOW_THREADS
th = xs_transaction_start(xh);
Py_END_ALLOW_THREADS
if (th == XBT_NULL) {
PyErr_SetFromErrno(xs_error);
return NULL;
}
snprintf(thstr, sizeof(thstr), "%lX", (unsigned long)th);
#if PY_MAJOR_VERSION >= 3
return PyUnicode_FromString(thstr);
#else
return PyBytes_FromString(thstr);
#endif
}
#define xspy_transaction_end_doc "\n" \
"End the current transaction.\n" \
"Attempts to commit the transaction unless abort is true.\n" \
" transaction [string] : transaction handle.\n" \
" abort [int] : abort flag (default 0).\n" \
"\n" \
"Returns True on success, False if you need to try again.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_transaction_end(XsHandle *self, PyObject *args,
PyObject *kwds)
{
static char *kwd_spec[] = { "transaction", "abort", NULL };
static char *arg_spec = "s|i";
int abort = 0;
struct xs_handle *xh = xshandle(self);
bool result;
xs_transaction_t th;
char *thstr;
if (!xh)
return NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&thstr, &abort))
return NULL;
th = strtoul(thstr, NULL, 16);
Py_BEGIN_ALLOW_THREADS
result = xs_transaction_end(xh, th, abort);
Py_END_ALLOW_THREADS
if (result) {
Py_INCREF(Py_True);
return Py_True;
}
else if (errno == EAGAIN) {
Py_INCREF(Py_False);
return Py_False;
}
else {
PyErr_SetFromErrno(xs_error);
return NULL;
}
}
#define xspy_introduce_domain_doc "\n" \
"Tell xenstore about a domain so it can talk to it.\n" \
" dom [int] : domain id\n" \
" page [long] : address of domain's xenstore page\n" \
" port [int] : port the domain is using for xenstore\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_introduce_domain(XsHandle *self, PyObject *args)
{
uint32_t dom;
unsigned long page;
unsigned int port;
struct xs_handle *xh = xshandle(self);
bool result = 0;
if (!xh)
return NULL;
if (!PyArg_ParseTuple(args, "ili", &dom, &page, &port))
return NULL;
Py_BEGIN_ALLOW_THREADS
result = xs_introduce_domain(xh, dom, page, port);
Py_END_ALLOW_THREADS
return none(result);
}
#define xspy_set_target_doc "\n" \
"Tell xenstore that a domain is targetting another one so it\n" \
"should let it tinker with it.\n" \
" dom [int] : domain id\n" \
" target [int] : domain id of the target\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_set_target(XsHandle *self, PyObject *args)
{
uint32_t dom;
uint32_t target;
struct xs_handle *xh = xshandle(self);
bool result = 0;
if (!xh)
return NULL;
if (!PyArg_ParseTuple(args, "ii", &dom, &target))
return NULL;
Py_BEGIN_ALLOW_THREADS
result = xs_set_target(xh, dom, target);
Py_END_ALLOW_THREADS
return none(result);
}
#define xspy_resume_domain_doc "\n" \
"Tell xenstore to clear its shutdown flag for a domain.\n" \
"This ensures that a subsequent shutdown will fire the\n" \
"appropriate watches.\n" \
" dom [int]: domain id\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n"
static PyObject *xspy_resume_domain(XsHandle *self, PyObject *args)
{
uint32_t dom;
struct xs_handle *xh = xshandle(self);
bool result = 0;
if (!xh)
return NULL;
if (!PyArg_ParseTuple(args, "i", &dom))
return NULL;
Py_BEGIN_ALLOW_THREADS
result = xs_resume_domain(xh, dom);
Py_END_ALLOW_THREADS
return none(result);
}
#define xspy_release_domain_doc "\n" \
"Tell xenstore to release its channel to a domain.\n" \
"Unless this is done the domain will not be released.\n" \
" dom [int]: domain id\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_release_domain(XsHandle *self, PyObject *args)
{
uint32_t dom;
struct xs_handle *xh = xshandle(self);
bool result = 0;
if (!xh)
return NULL;
if (!PyArg_ParseTuple(args, "i", &dom))
return NULL;
Py_BEGIN_ALLOW_THREADS
result = xs_release_domain(xh, dom);
Py_END_ALLOW_THREADS
return none(result);
}
#define xspy_close_doc "\n" \
"Close the connection to xenstore.\n" \
"\n" \
"Returns None on success.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_close(XsHandle *self)
{
struct xs_handle *xh = xshandle(self);
int i;
if (!xh)
return NULL;
for (i = 0; i < PyList_Size(self->watches); i++) {
/* TODO: xs_unwatch watches */
PySequence_SetItem(self->watches, i, Py_None);
}
xs_daemon_close(xh);
self->xh = NULL;
Py_INCREF(Py_None);
return Py_None;
}
#define xspy_get_domain_path_doc "\n" \
"Return store path of domain, whether or not the domain exists.\n" \
" domid [int]: domain id\n" \
"\n" \
"Returns: [string] domain store path.\n" \
"Raises xen.lowlevel.xs.Error on error.\n" \
"\n"
static PyObject *xspy_get_domain_path(XsHandle *self, PyObject *args)
{
struct xs_handle *xh = xshandle(self);
uint32_t domid;
char *xsval;
if (!xh)
return NULL;
if (!PyArg_ParseTuple(args, "i", &domid))
return NULL;
Py_BEGIN_ALLOW_THREADS
xsval = xs_get_domain_path(xh, domid);
Py_END_ALLOW_THREADS
if (xsval) {
#if PY_MAJOR_VERSION >= 3
PyObject *val = PyUnicode_FromString(xsval);
#else
PyObject *val = PyBytes_FromString(xsval);
#endif
free(xsval);
return val;
}
else {
return none(errno == ENOENT);
}
}
/**
* Remove the given token from the watches list belonging to the given
* XsHandle, if present.
*/
static void remove_watch(XsHandle *self, PyObject *token)
{
int i;
for (i = 0; i < PyList_Size(self->watches); i++) {
if (PyList_GetItem(self->watches, i) == token) {
PySequence_SetItem(self->watches, i, Py_None);
return;
}
}
}
/**
* Parse transaction and path arguments from the given args and kwds,
* convert the given self value to an xs_handle, and return all three by
* reference.
*
* @return 1 on success, in which case *xh, *th, and *path are valid, or 0 on
* failure.
*/
static int parse_transaction_path(XsHandle *self, PyObject *args,
struct xs_handle **xh,
xs_transaction_t *th,
char **path)
{
char *thstr;
*xh = xshandle(self);
if (!*xh)
return 0;
if (!PyArg_ParseTuple(args, "ss", &thstr, path))
return 0;
*th = strtoul(thstr, NULL, 16);
return 1;
}
static PyObject *match_watch_by_token(XsHandle *self, char **xsval)
{
PyObject *token;
int i;
if (sscanf(xsval[XS_WATCH_TOKEN], "%li", (unsigned long *)&token) != 1) {
xs_set_error(EINVAL);
return NULL;
}
for (i = 0; i < PyList_Size(self->watches); i++) {
if (token == PyList_GetItem(self->watches, i))
break;
}
if (i == PyList_Size(self->watches)) {
/* We do not have a registered watch for the one that has just fired.
Ignore this -- a watch that has been recently deregistered can still
have watches in transit.
*/
xs_set_error(EAGAIN);
return NULL;
}
/* Create tuple (path, token). */
return Py_BuildValue("(sO)", xsval[XS_WATCH_PATH], token);
}
static PyObject *none(bool result)
{
if (result) {
Py_INCREF(Py_None);
return Py_None;
}
else {
PyErr_SetFromErrno(xs_error);
return NULL;
}
}
#define XSPY_METH(_name, _args) { \
.ml_name = #_name, \
.ml_meth = (PyCFunction) xspy_ ## _name, \
.ml_flags = _args, \
.ml_doc = xspy_ ## _name ## _doc }
static PyMethodDef xshandle_methods[] = {
XSPY_METH(read, METH_VARARGS),
XSPY_METH(write, METH_VARARGS),
XSPY_METH(ls, METH_VARARGS),
XSPY_METH(mkdir, METH_VARARGS),
XSPY_METH(rm, METH_VARARGS),
XSPY_METH(get_permissions, METH_VARARGS),
XSPY_METH(set_permissions, METH_VARARGS),
XSPY_METH(watch, METH_VARARGS),
XSPY_METH(read_watch, METH_NOARGS),
XSPY_METH(check_watch, METH_NOARGS),
XSPY_METH(unwatch, METH_VARARGS),
XSPY_METH(transaction_start, METH_NOARGS),
XSPY_METH(transaction_end, METH_VARARGS | METH_KEYWORDS),
XSPY_METH(introduce_domain, METH_VARARGS),
XSPY_METH(set_target, METH_VARARGS),
XSPY_METH(resume_domain, METH_VARARGS),
XSPY_METH(release_domain, METH_VARARGS),
XSPY_METH(close, METH_NOARGS),
XSPY_METH(get_domain_path, METH_VARARGS),
XSPY_METH(fileno, METH_NOARGS),
{ NULL /* Sentinel. */ },
};
static PyObject *
xshandle_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
XsHandle *self = (XsHandle *)type->tp_alloc(type, 0);
if (self == NULL)
return NULL;
self->xh = NULL;
self->watches = PyList_New(0);
if (!self->watches)
goto fail;
return (PyObject *)self;
fail:
/* Decreasing the object's reference to 0 will result in xshandle_dealloc
being called. */
Py_DECREF(self);
return NULL;
}
static int
xshandle_init(XsHandle *self, PyObject *args, PyObject *kwds)
{
static char *kwd_spec[] = { "readonly", NULL };
static char *arg_spec = "|i";
int readonly = 0;
if (!PyArg_ParseTupleAndKeywords(args, kwds, arg_spec, kwd_spec,
&readonly))
goto fail;
self->xh = (readonly ? xs_daemon_open_readonly() : xs_daemon_open());
if (!self->xh)
goto fail;
return 0;
fail:
PyErr_SetFromErrno(xs_error);
return -1;
}
static void xshandle_dealloc(XsHandle *self)
{
if (self->xh) {
xs_daemon_close(self->xh);
self->xh = NULL;
}
Py_XDECREF(self->watches);
Py_TYPE(self)->tp_free((PyObject *)self);
}
static PyTypeObject xshandle_type = {
#if PY_MAJOR_VERSION >= 3
.ob_base = { PyObject_HEAD_INIT(NULL) },
#else
PyObject_HEAD_INIT(NULL)
#endif
.tp_name = PKG "." CLS,
.tp_basicsize = sizeof(XsHandle),
.tp_itemsize = 0,
.tp_dealloc = (destructor)xshandle_dealloc,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "Xenstore connections",
.tp_methods = xshandle_methods,
.tp_init = (initproc)xshandle_init,
.tp_new = xshandle_new,
};
static PyMethodDef xs_methods[] = { { NULL } };
#if PY_MAJOR_VERSION >= 3
static PyModuleDef xs_module = {
PyModuleDef_HEAD_INIT,
PKG, /* name */
NULL, /* docstring */
-1, /* size of per-interpreter state, -1 means the module use global
variables */
xs_methods
};
#endif
#if PY_MAJOR_VERSION >= 3
#define INITERROR return NULL
PyMODINIT_FUNC PyInit_xs(void)
#else
#define INITERROR return
PyMODINIT_FUNC initxs(void)
#endif
{
PyObject* m;
if (PyType_Ready(&xshandle_type) < 0)
INITERROR;
#if PY_MAJOR_VERSION >= 3
m = PyModule_Create(&xs_module);
#else
m = Py_InitModule(PKG, xs_methods);
#endif
if (m == NULL)
INITERROR;
xs_error = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL);
if (xs_error == NULL) {
Py_DECREF(m);
INITERROR;
}
Py_INCREF(&xshandle_type);
PyModule_AddObject(m, CLS, (PyObject *)&xshandle_type);
Py_INCREF(xs_error);
PyModule_AddObject(m, "Error", xs_error);
#if PY_MAJOR_VERSION >= 3
return m;
#endif
}
/*
* Local variables:
* c-indent-level: 4
* c-basic-offset: 4
* End:
*/