todo: Add note about using blktrace.
[libguestfs.git] / generator / generator_python.ml
1 (* libguestfs
2  * Copyright (C) 2009-2010 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program 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
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  *)
18
19 (* Please read generator/README first. *)
20
21 open Printf
22
23 open Generator_types
24 open Generator_utils
25 open Generator_pr
26 open Generator_docstrings
27 open Generator_optgroups
28 open Generator_actions
29 open Generator_structs
30 open Generator_c
31
32 (* Generate Python C module. *)
33 let rec generate_python_c () =
34   generate_header CStyle LGPLv2plus;
35
36   pr "\
37 #define PY_SSIZE_T_CLEAN 1
38 #include <Python.h>
39
40 #if PY_VERSION_HEX < 0x02050000
41 typedef int Py_ssize_t;
42 #define PY_SSIZE_T_MAX INT_MAX
43 #define PY_SSIZE_T_MIN INT_MIN
44 #endif
45
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <assert.h>
49
50 #include \"guestfs.h\"
51
52 #ifndef HAVE_PYCAPSULE_NEW
53 typedef struct {
54   PyObject_HEAD
55   guestfs_h *g;
56 } Pyguestfs_Object;
57 #endif
58
59 static guestfs_h *
60 get_handle (PyObject *obj)
61 {
62   assert (obj);
63   assert (obj != Py_None);
64 #ifndef HAVE_PYCAPSULE_NEW
65   return ((Pyguestfs_Object *) obj)->g;
66 #else
67   return (guestfs_h*) PyCapsule_GetPointer(obj, \"guestfs_h\");
68 #endif
69 }
70
71 static PyObject *
72 put_handle (guestfs_h *g)
73 {
74   assert (g);
75 #ifndef HAVE_PYCAPSULE_NEW
76   return
77     PyCObject_FromVoidPtrAndDesc ((void *) g, (char *) \"guestfs_h\", NULL);
78 #else
79   return PyCapsule_New ((void *) g, \"guestfs_h\", NULL);
80 #endif
81 }
82
83 /* This list should be freed (but not the strings) after use. */
84 static char **
85 get_string_list (PyObject *obj)
86 {
87   size_t i, len;
88   char **r;
89
90   assert (obj);
91
92   if (!PyList_Check (obj)) {
93     PyErr_SetString (PyExc_RuntimeError, \"expecting a list parameter\");
94     return NULL;
95   }
96
97   Py_ssize_t slen = PyList_Size (obj);
98   if (slen == -1) {
99     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: PyList_Size failure\");
100     return NULL;
101   }
102   len = (size_t) slen;
103   r = malloc (sizeof (char *) * (len+1));
104   if (r == NULL) {
105     PyErr_SetString (PyExc_RuntimeError, \"get_string_list: out of memory\");
106     return NULL;
107   }
108
109   for (i = 0; i < len; ++i)
110     r[i] = PyString_AsString (PyList_GetItem (obj, i));
111   r[len] = NULL;
112
113   return r;
114 }
115
116 static PyObject *
117 put_string_list (char * const * const argv)
118 {
119   PyObject *list;
120   int argc, i;
121
122   for (argc = 0; argv[argc] != NULL; ++argc)
123     ;
124
125   list = PyList_New (argc);
126   for (i = 0; i < argc; ++i)
127     PyList_SetItem (list, i, PyString_FromString (argv[i]));
128
129   return list;
130 }
131
132 static PyObject *
133 put_table (char * const * const argv)
134 {
135   PyObject *list, *item;
136   int argc, i;
137
138   for (argc = 0; argv[argc] != NULL; ++argc)
139     ;
140
141   list = PyList_New (argc >> 1);
142   for (i = 0; i < argc; i += 2) {
143     item = PyTuple_New (2);
144     PyTuple_SetItem (item, 0, PyString_FromString (argv[i]));
145     PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1]));
146     PyList_SetItem (list, i >> 1, item);
147   }
148
149   return list;
150 }
151
152 static void
153 free_strings (char **argv)
154 {
155   int argc;
156
157   for (argc = 0; argv[argc] != NULL; ++argc)
158     free (argv[argc]);
159   free (argv);
160 }
161
162 static PyObject *
163 py_guestfs_create (PyObject *self, PyObject *args)
164 {
165   guestfs_h *g;
166
167   g = guestfs_create ();
168   if (g == NULL) {
169     PyErr_SetString (PyExc_RuntimeError,
170                      \"guestfs.create: failed to allocate handle\");
171     return NULL;
172   }
173   guestfs_set_error_handler (g, NULL, NULL);
174   /* This can return NULL, but in that case put_handle will have
175    * set the Python error string.
176    */
177   return put_handle (g);
178 }
179
180 static PyObject *
181 py_guestfs_close (PyObject *self, PyObject *args)
182 {
183   PyObject *py_g;
184   guestfs_h *g;
185
186   if (!PyArg_ParseTuple (args, (char *) \"O:guestfs_close\", &py_g))
187     return NULL;
188   g = get_handle (py_g);
189
190   guestfs_close (g);
191
192   Py_INCREF (Py_None);
193   return Py_None;
194 }
195
196 ";
197
198   let emit_put_list_function typ =
199     pr "static PyObject *\n";
200     pr "put_%s_list (struct guestfs_%s_list *%ss)\n" typ typ typ;
201     pr "{\n";
202     pr "  PyObject *list;\n";
203     pr "  size_t i;\n";
204     pr "\n";
205     pr "  list = PyList_New (%ss->len);\n" typ;
206     pr "  for (i = 0; i < %ss->len; ++i)\n" typ;
207     pr "    PyList_SetItem (list, i, put_%s (&%ss->val[i]));\n" typ typ;
208     pr "  return list;\n";
209     pr "};\n";
210     pr "\n"
211   in
212
213   (* Structures, turned into Python dictionaries. *)
214   List.iter (
215     fun (typ, cols) ->
216       pr "static PyObject *\n";
217       pr "put_%s (struct guestfs_%s *%s)\n" typ typ typ;
218       pr "{\n";
219       pr "  PyObject *dict;\n";
220       pr "\n";
221       pr "  dict = PyDict_New ();\n";
222       List.iter (
223         function
224         | name, FString ->
225             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
226             pr "                        PyString_FromString (%s->%s));\n"
227               typ name
228         | name, FBuffer ->
229             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
230             pr "                        PyString_FromStringAndSize (%s->%s, %s->%s_len));\n"
231               typ name typ name
232         | name, FUUID ->
233             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
234             pr "                        PyString_FromStringAndSize (%s->%s, 32));\n"
235               typ name
236         | name, (FBytes|FUInt64) ->
237             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
238             pr "                        PyLong_FromUnsignedLongLong (%s->%s));\n"
239               typ name
240         | name, FInt64 ->
241             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
242             pr "                        PyLong_FromLongLong (%s->%s));\n"
243               typ name
244         | name, FUInt32 ->
245             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
246             pr "                        PyLong_FromUnsignedLong (%s->%s));\n"
247               typ name
248         | name, FInt32 ->
249             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
250             pr "                        PyLong_FromLong (%s->%s));\n"
251               typ name
252         | name, FOptPercent ->
253             pr "  if (%s->%s >= 0)\n" typ name;
254             pr "    PyDict_SetItemString (dict, \"%s\",\n" name;
255             pr "                          PyFloat_FromDouble ((double) %s->%s));\n"
256               typ name;
257             pr "  else {\n";
258             pr "    Py_INCREF (Py_None);\n";
259             pr "    PyDict_SetItemString (dict, \"%s\", Py_None);\n" name;
260             pr "  }\n"
261         | name, FChar ->
262             pr "  PyDict_SetItemString (dict, \"%s\",\n" name;
263             pr "                        PyString_FromStringAndSize (&dirent->%s, 1));\n" name
264       ) cols;
265       pr "  return dict;\n";
266       pr "};\n";
267       pr "\n";
268
269   ) structs;
270
271   (* Emit a put_TYPE_list function definition only if that function is used. *)
272   List.iter (
273     function
274     | typ, (RStructListOnly | RStructAndList) ->
275         (* generate the function for typ *)
276         emit_put_list_function typ
277     | typ, _ -> () (* empty *)
278   ) (rstructs_used_by all_functions);
279
280   (* Python wrapper functions. *)
281   List.iter (
282     fun (name, style, _, _, _, _, _) ->
283       pr "static PyObject *\n";
284       pr "py_guestfs_%s (PyObject *self, PyObject *args)\n" name;
285       pr "{\n";
286
287       pr "  PyObject *py_g;\n";
288       pr "  guestfs_h *g;\n";
289       pr "  PyObject *py_r;\n";
290
291       let error_code =
292         match fst style with
293         | RErr | RInt _ | RBool _ -> pr "  int r;\n"; "-1"
294         | RInt64 _ -> pr "  int64_t r;\n"; "-1"
295         | RConstString _ | RConstOptString _ ->
296             pr "  const char *r;\n"; "NULL"
297         | RString _ -> pr "  char *r;\n"; "NULL"
298         | RStringList _ | RHashtable _ -> pr "  char **r;\n"; "NULL"
299         | RStruct (_, typ) -> pr "  struct guestfs_%s *r;\n" typ; "NULL"
300         | RStructList (_, typ) ->
301             pr "  struct guestfs_%s_list *r;\n" typ; "NULL"
302         | RBufferOut _ ->
303             pr "  char *r;\n";
304             pr "  size_t size;\n";
305             "NULL" in
306
307       List.iter (
308         function
309         | Pathname n | Device n | Dev_or_Path n | String n | Key n
310         | FileIn n | FileOut n ->
311             pr "  const char *%s;\n" n
312         | OptString n -> pr "  const char *%s;\n" n
313         | BufferIn n ->
314             pr "  const char *%s;\n" n;
315             pr "  Py_ssize_t %s_size;\n" n
316         | StringList n | DeviceList n ->
317             pr "  PyObject *py_%s;\n" n;
318             pr "  char **%s;\n" n
319         | Bool n -> pr "  int %s;\n" n
320         | Int n -> pr "  int %s;\n" n
321         | Int64 n -> pr "  long long %s;\n" n
322       ) (snd style);
323
324       pr "\n";
325
326       (* Convert the parameters. *)
327       pr "  if (!PyArg_ParseTuple (args, (char *) \"O";
328       List.iter (
329         function
330         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
331         | FileIn _ | FileOut _ -> pr "s"
332         | OptString _ -> pr "z"
333         | StringList _ | DeviceList _ -> pr "O"
334         | Bool _ -> pr "i" (* XXX Python has booleans? *)
335         | Int _ -> pr "i"
336         | Int64 _ -> pr "L" (* XXX Whoever thought it was a good idea to
337                              * emulate C's int/long/long long in Python?
338                              *)
339         | BufferIn _ -> pr "s#"
340       ) (snd style);
341       pr ":guestfs_%s\",\n" name;
342       pr "                         &py_g";
343       List.iter (
344         function
345         | Pathname n | Device n | Dev_or_Path n | String n | Key n
346         | FileIn n | FileOut n -> pr ", &%s" n
347         | OptString n -> pr ", &%s" n
348         | StringList n | DeviceList n -> pr ", &py_%s" n
349         | Bool n -> pr ", &%s" n
350         | Int n -> pr ", &%s" n
351         | Int64 n -> pr ", &%s" n
352         | BufferIn n -> pr ", &%s, &%s_size" n n
353       ) (snd style);
354
355       pr "))\n";
356       pr "    return NULL;\n";
357
358       pr "  g = get_handle (py_g);\n";
359       List.iter (
360         function
361         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
362         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
363         | BufferIn _ -> ()
364         | StringList n | DeviceList n ->
365             pr "  %s = get_string_list (py_%s);\n" n n;
366             pr "  if (!%s) return NULL;\n" n
367       ) (snd style);
368
369       pr "\n";
370
371       pr "  r = guestfs_%s " name;
372       generate_c_call_args ~handle:"g" style;
373       pr ";\n";
374
375       List.iter (
376         function
377         | Pathname _ | Device _ | Dev_or_Path _ | String _ | Key _
378         | FileIn _ | FileOut _ | OptString _ | Bool _ | Int _ | Int64 _
379         | BufferIn _ -> ()
380         | StringList n | DeviceList n ->
381             pr "  free (%s);\n" n
382       ) (snd style);
383
384       pr "  if (r == %s) {\n" error_code;
385       pr "    PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g));\n";
386       pr "    return NULL;\n";
387       pr "  }\n";
388       pr "\n";
389
390       (match fst style with
391        | RErr ->
392            pr "  Py_INCREF (Py_None);\n";
393            pr "  py_r = Py_None;\n"
394        | RInt _
395        | RBool _ -> pr "  py_r = PyInt_FromLong ((long) r);\n"
396        | RInt64 _ -> pr "  py_r = PyLong_FromLongLong (r);\n"
397        | RConstString _ -> pr "  py_r = PyString_FromString (r);\n"
398        | RConstOptString _ ->
399            pr "  if (r)\n";
400            pr "    py_r = PyString_FromString (r);\n";
401            pr "  else {\n";
402            pr "    Py_INCREF (Py_None);\n";
403            pr "    py_r = Py_None;\n";
404            pr "  }\n"
405        | RString _ ->
406            pr "  py_r = PyString_FromString (r);\n";
407            pr "  free (r);\n"
408        | RStringList _ ->
409            pr "  py_r = put_string_list (r);\n";
410            pr "  free_strings (r);\n"
411        | RStruct (_, typ) ->
412            pr "  py_r = put_%s (r);\n" typ;
413            pr "  guestfs_free_%s (r);\n" typ
414        | RStructList (_, typ) ->
415            pr "  py_r = put_%s_list (r);\n" typ;
416            pr "  guestfs_free_%s_list (r);\n" typ
417        | RHashtable n ->
418            pr "  py_r = put_table (r);\n";
419            pr "  free_strings (r);\n"
420        | RBufferOut _ ->
421            pr "  py_r = PyString_FromStringAndSize (r, size);\n";
422            pr "  free (r);\n"
423       );
424
425       pr "  return py_r;\n";
426       pr "}\n";
427       pr "\n"
428   ) all_functions;
429
430   (* Table of functions. *)
431   pr "static PyMethodDef methods[] = {\n";
432   pr "  { (char *) \"create\", py_guestfs_create, METH_VARARGS, NULL },\n";
433   pr "  { (char *) \"close\", py_guestfs_close, METH_VARARGS, NULL },\n";
434   List.iter (
435     fun (name, _, _, _, _, _, _) ->
436       pr "  { (char *) \"%s\", py_guestfs_%s, METH_VARARGS, NULL },\n"
437         name name
438   ) all_functions;
439   pr "  { NULL, NULL, 0, NULL }\n";
440   pr "};\n";
441   pr "\n";
442
443   (* Init function. *)
444   pr "\
445 void
446 initlibguestfsmod (void)
447 {
448   static int initialized = 0;
449
450   if (initialized) return;
451   Py_InitModule ((char *) \"libguestfsmod\", methods);
452   initialized = 1;
453 }
454 "
455
456 (* Generate Python module. *)
457 and generate_python_py () =
458   generate_header HashStyle LGPLv2plus;
459
460   pr "\
461 u\"\"\"Python bindings for libguestfs
462
463 import guestfs
464 g = guestfs.GuestFS ()
465 g.add_drive (\"guest.img\")
466 g.launch ()
467 parts = g.list_partitions ()
468
469 The guestfs module provides a Python binding to the libguestfs API
470 for examining and modifying virtual machine disk images.
471
472 Amongst the things this is good for: making batch configuration
473 changes to guests, getting disk used/free statistics (see also:
474 virt-df), migrating between virtualization systems (see also:
475 virt-p2v), performing partial backups, performing partial guest
476 clones, cloning guests and changing registry/UUID/hostname info, and
477 much else besides.
478
479 Libguestfs uses Linux kernel and qemu code, and can access any type of
480 guest filesystem that Linux and qemu can, including but not limited
481 to: ext2/3/4, btrfs, FAT and NTFS, LVM, many different disk partition
482 schemes, qcow, qcow2, vmdk.
483
484 Libguestfs provides ways to enumerate guest storage (eg. partitions,
485 LVs, what filesystem is in each LV, etc.).  It can also run commands
486 in the context of the guest.  Also you can access filesystems over
487 FUSE.
488
489 Errors which happen while using the API are turned into Python
490 RuntimeError exceptions.
491
492 To create a guestfs handle you usually have to perform the following
493 sequence of calls:
494
495 # Create the handle, call add_drive at least once, and possibly
496 # several times if the guest has multiple block devices:
497 g = guestfs.GuestFS ()
498 g.add_drive (\"guest.img\")
499
500 # Launch the qemu subprocess and wait for it to become ready:
501 g.launch ()
502
503 # Now you can issue commands, for example:
504 logvols = g.lvs ()
505
506 \"\"\"
507
508 import libguestfsmod
509
510 class GuestFS:
511     \"\"\"Instances of this class are libguestfs API handles.\"\"\"
512
513     def __init__ (self):
514         \"\"\"Create a new libguestfs handle.\"\"\"
515         self._o = libguestfsmod.create ()
516
517     def __del__ (self):
518         libguestfsmod.close (self._o)
519
520 ";
521
522   List.iter (
523     fun (name, style, _, flags, _, _, longdesc) ->
524       pr "    def %s " name;
525       generate_py_call_args ~handle:"self" (snd style);
526       pr ":\n";
527
528       if not (List.mem NotInDocs flags) then (
529         let doc = replace_str longdesc "C<guestfs_" "C<g." in
530         let doc =
531           match fst style with
532           | RErr | RInt _ | RInt64 _ | RBool _
533           | RConstOptString _ | RConstString _
534           | RString _ | RBufferOut _ -> doc
535           | RStringList _ ->
536               doc ^ "\n\nThis function returns a list of strings."
537           | RStruct (_, typ) ->
538               doc ^ sprintf "\n\nThis function returns a dictionary, with keys matching the various fields in the guestfs_%s structure." typ
539           | RStructList (_, typ) ->
540               doc ^ sprintf "\n\nThis function returns a list of %ss.  Each %s is represented as a dictionary." typ typ
541           | RHashtable _ ->
542               doc ^ "\n\nThis function returns a dictionary." in
543         let doc =
544           if List.mem ProtocolLimitWarning flags then
545             doc ^ "\n\n" ^ protocol_limit_warning
546           else doc in
547         let doc =
548           if List.mem DangerWillRobinson flags then
549             doc ^ "\n\n" ^ danger_will_robinson
550           else doc in
551         let doc =
552           match deprecation_notice flags with
553           | None -> doc
554           | Some txt -> doc ^ "\n\n" ^ txt in
555         let doc = pod2text ~width:60 name doc in
556         let doc = List.map (fun line -> replace_str line "\\" "\\\\") doc in
557         let doc = String.concat "\n        " doc in
558         pr "        u\"\"\"%s\"\"\"\n" doc;
559       );
560       pr "        return libguestfsmod.%s " name;
561       generate_py_call_args ~handle:"self._o" (snd style);
562       pr "\n";
563       pr "\n";
564   ) all_functions
565
566 (* Generate Python call arguments, eg "(handle, foo, bar)" *)
567 and generate_py_call_args ~handle args =
568   pr "(%s" handle;
569   List.iter (fun arg -> pr ", %s" (name_of_argt arg)) args;
570   pr ")"