29be83b7a5f5f35b9834caf467aef98ea73423cb
[libguestfs.git] / python / guestfs-py-byhand.c
1 /* libguestfs python bindings
2  * Copyright (C) 2009-2011 Red Hat Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 /* This file contains a small number of functions that are written by
20  * hand.  The majority of the bindings are generated (see
21  * guestfs-py.c).
22  */
23
24 #include <config.h>
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <assert.h>
29
30 #include "guestfs-py.h"
31
32 static PyObject **get_all_event_callbacks (guestfs_h *g, size_t *len_rtn);
33
34 PyObject *
35 py_guestfs_create (PyObject *self, PyObject *args)
36 {
37   guestfs_h *g;
38
39   g = guestfs_create ();
40   if (g == NULL) {
41     PyErr_SetString (PyExc_RuntimeError,
42                      "guestfs.create: failed to allocate handle");
43     return NULL;
44   }
45   guestfs_set_error_handler (g, NULL, NULL);
46   /* This can return NULL, but in that case put_handle will have
47    * set the Python error string.
48    */
49   return put_handle (g);
50 }
51
52 PyObject *
53 py_guestfs_close (PyObject *self, PyObject *args)
54 {
55   PyThreadState *py_save = NULL;
56   PyObject *py_g;
57   guestfs_h *g;
58   size_t i, len;
59   PyObject **callbacks;
60
61   if (!PyArg_ParseTuple (args, (char *) "O:guestfs_close", &py_g))
62     return NULL;
63   g = get_handle (py_g);
64
65   /* As in the OCaml bindings, there is a hard to solve case where the
66    * caller can delete a callback from within the callback, resulting
67    * in a double-free here.  XXX
68    */
69   callbacks = get_all_event_callbacks (g, &len);
70
71   if (PyEval_ThreadsInitialized ())
72     py_save = PyEval_SaveThread ();
73   guestfs_close (g);
74   if (PyEval_ThreadsInitialized ())
75     PyEval_RestoreThread (py_save);
76
77   for (i = 0; i < len; ++i)
78     Py_XDECREF (callbacks[i]);
79
80   Py_INCREF (Py_None);
81   return Py_None;
82 }
83
84 /* http://docs.python.org/release/2.5.2/ext/callingPython.html */
85 static void
86 py_guestfs_event_callback_wrapper (guestfs_h *g,
87                                    void *callback,
88                                    uint64_t event,
89                                    int event_handle,
90                                    int flags,
91                                    const char *buf, size_t buf_len,
92                                    const uint64_t *array, size_t array_len)
93 {
94   PyGILState_STATE py_save = PyGILState_UNLOCKED;
95   PyObject *py_callback = callback;
96   PyObject *py_array;
97   PyObject *args;
98   PyObject *a;
99   size_t i;
100   PyObject *py_r;
101
102   py_array = PyList_New (array_len);
103   for (i = 0; i < array_len; ++i) {
104     a = PyLong_FromLongLong (array[i]);
105     PyList_SET_ITEM (py_array, i, a);
106   }
107
108   /* XXX As with Perl we don't pass the guestfs_h handle here. */
109   args = Py_BuildValue ("(Kis#O)",
110                         (unsigned PY_LONG_LONG) event, event_handle,
111                         buf, buf_len, py_array);
112
113   if (PyEval_ThreadsInitialized ())
114     py_save = PyGILState_Ensure ();
115
116   py_r = PyEval_CallObject (py_callback, args);
117
118   if (PyEval_ThreadsInitialized ())
119     PyGILState_Release (py_save);
120
121   Py_DECREF (args);
122
123   if (py_r != NULL)
124     Py_DECREF (py_r);
125   else
126     /* Callback threw an exception: print it. */
127     PyErr_PrintEx (0);
128 }
129
130 PyObject *
131 py_guestfs_set_event_callback (PyObject *self, PyObject *args)
132 {
133   PyObject *py_g;
134   guestfs_h *g;
135   PyObject *py_callback;
136   unsigned PY_LONG_LONG events;
137   int eh;
138   PyObject *py_eh;
139   char key[64];
140
141   if (!PyArg_ParseTuple (args, (char *) "OOK:guestfs_set_event_callback",
142                          &py_g, &py_callback, &events))
143     return NULL;
144
145   if (!PyCallable_Check (py_callback)) {
146     PyErr_SetString (PyExc_TypeError,
147                      "callback parameter is not callable "
148                      "(eg. lambda or function)");
149     return NULL;
150   }
151
152   g = get_handle (py_g);
153
154   eh = guestfs_set_event_callback (g, py_guestfs_event_callback_wrapper,
155                                    events, 0, py_callback);
156   if (eh == -1) {
157     PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));
158     return NULL;
159   }
160
161   /* Increase the refcount for this callback since we are storing it
162    * in the opaque C libguestfs handle.  We need to remember that we
163    * did this, so we can decrease the refcount for all undeleted
164    * callbacks left around at close time (see py_guestfs_close).
165    */
166   Py_XINCREF (py_callback);
167
168   snprintf (key, sizeof key, "_python_event_%d", eh);
169   guestfs_set_private (g, key, py_callback);
170
171   py_eh = PyInt_FromLong ((long) eh);
172   return py_eh;
173 }
174
175 PyObject *
176 py_guestfs_delete_event_callback (PyObject *self, PyObject *args)
177 {
178   PyObject *py_g;
179   guestfs_h *g;
180   int eh;
181   PyObject *py_callback;
182   char key[64];
183
184   if (!PyArg_ParseTuple (args, (char *) "Oi:guestfs_delete_event_callback",
185                          &py_g, &eh))
186     return NULL;
187   g = get_handle (py_g);
188
189   snprintf (key, sizeof key, "_python_event_%d", eh);
190   py_callback = guestfs_get_private (g, key);
191   if (py_callback) {
192     Py_XDECREF (py_callback);
193     guestfs_set_private (g, key, NULL);
194     guestfs_delete_event_callback (g, eh);
195   }
196
197   Py_INCREF (Py_None);
198   return Py_None;
199 }
200
201 static PyObject **
202 get_all_event_callbacks (guestfs_h *g, size_t *len_rtn)
203 {
204   PyObject **r;
205   size_t i;
206   const char *key;
207   PyObject *cb;
208
209   /* Count the length of the array that will be needed. */
210   *len_rtn = 0;
211   cb = guestfs_first_private (g, &key);
212   while (cb != NULL) {
213     if (strncmp (key, "_python_event_", strlen ("_python_event_")) == 0)
214       (*len_rtn)++;
215     cb = guestfs_next_private (g, &key);
216   }
217
218   /* Copy them into the return array. */
219   r = guestfs_safe_malloc (g, sizeof (PyObject *) * (*len_rtn));
220
221   i = 0;
222   cb = guestfs_first_private (g, &key);
223   while (cb != NULL) {
224     if (strncmp (key, "_python_event_", strlen ("_python_event_")) == 0) {
225       r[i] = cb;
226       i++;
227     }
228     cb = guestfs_next_private (g, &key);
229   }
230
231   return r;
232 }