From: Richard Jones Date: Wed, 15 Apr 2009 12:59:07 +0000 (+0100) Subject: Generated code for tune2fs-l command and RHashtable return type. X-Git-Tag: 0.9.2~3 X-Git-Url: http://git.annexia.org/?a=commitdiff_plain;h=ad5abc8d367c9c410051062cae066b1b141b4c76;p=libguestfs.git Generated code for tune2fs-l command and RHashtable return type. --- diff --git a/daemon/actions.h b/daemon/actions.h index c0f41ce..53f3b79 100644 --- a/daemon/actions.h +++ b/daemon/actions.h @@ -75,3 +75,4 @@ extern char **do_command_lines (char * const* const arguments); extern guestfs_int_stat *do_stat (const char *path); extern guestfs_int_stat *do_lstat (const char *path); extern guestfs_int_statvfs *do_statvfs (const char *path); +extern char **do_tune2fs_l (const char *device); diff --git a/daemon/stubs.c b/daemon/stubs.c index 9662de8..a6175cb 100644 --- a/daemon/stubs.c +++ b/daemon/stubs.c @@ -1304,6 +1304,34 @@ done: xdr_free ((xdrproc_t) xdr_guestfs_statvfs_args, (char *) &args); } +static void tune2fs_l_stub (XDR *xdr_in) +{ + char **r; + struct guestfs_tune2fs_l_args args; + const char *device; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_tune2fs_l_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "tune2fs_l"); + return; + } + device = args.device; + + r = do_tune2fs_l (device); + if (r == NULL) + /* do_tune2fs_l has already called reply_with_error */ + goto done; + + struct guestfs_tune2fs_l_ret ret; + ret.superblock.superblock_len = count_strings (r); + ret.superblock.superblock_val = r; + reply ((xdrproc_t) &xdr_guestfs_tune2fs_l_ret, (char *) &ret); + free_strings (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_tune2fs_l_args, (char *) &args); +} + void dispatch_incoming_message (XDR *xdr_in) { switch (proc_nr) { @@ -1469,6 +1497,9 @@ void dispatch_incoming_message (XDR *xdr_in) case GUESTFS_PROC_STATVFS: statvfs_stub (xdr_in); break; + case GUESTFS_PROC_TUNE2FS_L: + tune2fs_l_stub (xdr_in); + break; default: reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr); } diff --git a/fish/cmds.c b/fish/cmds.c index 60aee8c..c68924a 100644 --- a/fish/cmds.c +++ b/fish/cmds.c @@ -90,6 +90,7 @@ void list_commands (void) printf ("%-20s %s\n", "statvfs", "get file system statistics"); printf ("%-20s %s\n", "sync", "sync disks, writes are flushed through to the disk image"); printf ("%-20s %s\n", "touch", "update file timestamps or create a new file"); + printf ("%-20s %s\n", "tune2fs-l", "get ext2/ext3 superblock details"); printf ("%-20s %s\n", "umount", "unmount a filesystem"); printf ("%-20s %s\n", "umount-all", "unmount all filesystems"); printf ("%-20s %s\n", "vgcreate", "create an LVM volume group"); @@ -296,6 +297,9 @@ void display_command (const char *cmd) if (strcasecmp (cmd, "statvfs") == 0) pod2text ("statvfs - get file system statistics", " statvfs \n\nReturns file system statistics for any mounted file system.\nC should be a file or directory in the mounted file system\n(typically it is the mount point itself, but it doesn't need to be).\n\nThis is the same as the C system call."); else + if (strcasecmp (cmd, "tune2fs_l") == 0 || strcasecmp (cmd, "tune2fs-l") == 0) + pod2text ("tune2fs-l - get ext2/ext3 superblock details", " tune2fs-l \n\nThis returns the contents of the ext2 or ext3 filesystem superblock\non C.\n\nIt is the same as running C. See L\nmanpage for more details. The list of fields returned isn't\nclearly defined, and depends on both the version of C\nthat libguestfs was built against, and the filesystem itself."); + else display_builtin_command (cmd); } @@ -1435,6 +1439,23 @@ static int run_statvfs (const char *cmd, int argc, char *argv[]) return 0; } +static int run_tune2fs_l (const char *cmd, int argc, char *argv[]) +{ + char **r; + const char *device; + if (argc != 1) { + fprintf (stderr, "%s should have 1 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + device = argv[0]; + r = guestfs_tune2fs_l (g, device); + if (r == NULL) return -1; + print_table (r); + free_strings (r); + return 0; +} + int run_action (const char *cmd, int argc, char *argv[]) { if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0) @@ -1632,6 +1653,9 @@ int run_action (const char *cmd, int argc, char *argv[]) if (strcasecmp (cmd, "statvfs") == 0) return run_statvfs (cmd, argc, argv); else + if (strcasecmp (cmd, "tune2fs_l") == 0 || strcasecmp (cmd, "tune2fs-l") == 0) + return run_tune2fs_l (cmd, argc, argv); + else { fprintf (stderr, "%s: unknown command\n", cmd); return -1; diff --git a/fish/completion.c b/fish/completion.c index 7b4f818..cee2b39 100644 --- a/fish/completion.c +++ b/fish/completion.c @@ -98,6 +98,7 @@ static const char *commands[] = { "statvfs", "sync", "touch", + "tune2fs-l", "umount", "umount-all", "unmount", diff --git a/fish/fish.c b/fish/fish.c index b825626..e506f7e 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -645,6 +645,15 @@ print_strings (char * const * const argv) printf ("%s\n", argv[argc]); } +void +print_table (char * const * const argv) +{ + int i; + + for (i = 0; argv[i] != NULL; i += 2) + printf ("%s: %s\n", argv[i], argv[i+1]); +} + int is_true (const char *str) { diff --git a/fish/fish.h b/fish/fish.h index 86e5e35..6cd4d97 100644 --- a/fish/fish.h +++ b/fish/fish.h @@ -31,6 +31,7 @@ extern void list_builtin_commands (void); extern void display_builtin_command (const char *cmd); extern void free_strings (char **argv); extern void print_strings (char * const * const argv); +extern void print_table (char * const * const argv); extern int launch (guestfs_h *); extern int is_true (const char *str); extern char **parse_string_list (const char *str); diff --git a/guestfish-actions.pod b/guestfish-actions.pod index e240f49..28f9559 100644 --- a/guestfish-actions.pod +++ b/guestfish-actions.pod @@ -631,6 +631,18 @@ Touch acts like the L command. It can be used to update the timestamps on a file, or, if the file does not exist, to create a new zero-length file. +=head2 tune2fs-l + + tune2fs-l device + +This returns the contents of the ext2 or ext3 filesystem superblock +on C. + +It is the same as running C. See L +manpage for more details. The list of fields returned isn't +clearly defined, and depends on both the version of C +that libguestfs was built against, and the filesystem itself. + =head2 umount | unmount umount pathordevice diff --git a/guestfs-actions.pod b/guestfs-actions.pod index 03378e0..889363a 100644 --- a/guestfs-actions.pod +++ b/guestfs-actions.pod @@ -854,6 +854,25 @@ to create a new zero-length file. This function returns 0 on success or -1 on error. +=head2 guestfs_tune2fs_l + + char **guestfs_tune2fs_l (guestfs_h *handle, + const char *device); + +This returns the contents of the ext2 or ext3 filesystem superblock +on C. + +It is the same as running C. See L +manpage for more details. The list of fields returned isn't +clearly defined, and depends on both the version of C +that libguestfs was built against, and the filesystem itself. + +This function returns a NULL-terminated array of +strings, or NULL if there was an error. +The array of strings will always have length C<2n+1>, where +C keys and values alternate, followed by the trailing NULL entry. +I. + =head2 guestfs_umount int guestfs_umount (guestfs_h *handle, diff --git a/ocaml/guestfs.ml b/ocaml/guestfs.ml index f0344ac..e29daea 100644 --- a/ocaml/guestfs.ml +++ b/ocaml/guestfs.ml @@ -181,3 +181,4 @@ external command_lines : t -> string array -> string array = "ocaml_guestfs_comm external stat : t -> string -> stat = "ocaml_guestfs_stat" external lstat : t -> string -> stat = "ocaml_guestfs_lstat" external statvfs : t -> string -> statvfs = "ocaml_guestfs_statvfs" +external tune2fs_l : t -> string -> (string * string) list = "ocaml_guestfs_tune2fs_l" diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli index 3062968..e6f5231 100644 --- a/ocaml/guestfs.mli +++ b/ocaml/guestfs.mli @@ -322,3 +322,6 @@ val lstat : t -> string -> stat val statvfs : t -> string -> statvfs (** get file system statistics *) +val tune2fs_l : t -> string -> (string * string) list +(** get ext2/ext3 superblock details *) + diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c index 01fbcb0..b1c4652 100644 --- a/ocaml/guestfs_c_actions.c +++ b/ocaml/guestfs_c_actions.c @@ -35,6 +35,33 @@ #include "guestfs_c.h" +/* Copy a hashtable of string pairs into an assoc-list. We return + * the list in reverse order, but hashtables aren't supposed to be + * ordered anyway. + */ +static CAMLprim value +copy_table (char * const * argv) +{ + CAMLparam0 (); + CAMLlocal5 (rv, pairv, kv, vv, cons); + int i; + + rv = Val_int (0); + for (i = 0; argv[i] != NULL; i += 2) { + kv = caml_copy_string (argv[i]); + vv = caml_copy_string (argv[i+1]); + pairv = caml_alloc (2, 0); + Store_field (pairv, 0, kv); + Store_field (pairv, 1, vv); + cons = caml_alloc (2, 0); + Store_field (cons, 1, rv); + rv = cons; + Store_field (cons, 0, pairv); + } + + CAMLreturn (rv); +} + static CAMLprim value copy_lvm_pv (const struct guestfs_lvm_pv *pv) { @@ -1881,3 +1908,27 @@ ocaml_guestfs_statvfs (value gv, value pathv) CAMLreturn (rv); } +CAMLprim value +ocaml_guestfs_tune2fs_l (value gv, value devicev) +{ + CAMLparam2 (gv, devicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("tune2fs_l: used handle after closing it"); + + const char *device = String_val (devicev); + char **r; + + caml_enter_blocking_section (); + r = guestfs_tune2fs_l (g, device); + caml_leave_blocking_section (); + if (r == NULL) + ocaml_guestfs_raise_error (g, "tune2fs_l"); + + rv = copy_table (r); + free (r); + CAMLreturn (rv); +} + diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs index 37a15e0..93abd9e 100644 --- a/perl/Guestfs.xs +++ b/perl/Guestfs.xs @@ -1087,3 +1087,22 @@ PREINIT: PUSHs (sv_2mortal (my_newSVll (statbuf->namemax))); free (statbuf); +void +tune2fs_l (g, device) + guestfs_h *g; + char *device; +PREINIT: + char **superblock; + int i, n; + PPCODE: + superblock = guestfs_tune2fs_l (g, device); + if (superblock == NULL) + croak ("tune2fs_l: %s", guestfs_last_error (g)); + for (n = 0; superblock[n] != NULL; ++n) /**/; + EXTEND (SP, n); + for (i = 0; i < n; ++i) { + PUSHs (sv_2mortal (newSVpv (superblock[i], 0))); + free (superblock[i]); + } + free (superblock); + diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm index 09663bc..36bedd5 100644 --- a/perl/lib/Sys/Guestfs.pm +++ b/perl/lib/Sys/Guestfs.pm @@ -606,6 +606,16 @@ Touch acts like the L command. It can be used to update the timestamps on a file, or, if the file does not exist, to create a new zero-length file. +=item %superblock = $h->tune2fs_l ($device); + +This returns the contents of the ext2 or ext3 filesystem superblock +on C. + +It is the same as running C. See L +manpage for more details. The list of fields returned isn't +clearly defined, and depends on both the version of C +that libguestfs was built against, and the filesystem itself. + =item $h->umount ($pathordevice); This unmounts the given filesystem. The filesystem may be diff --git a/python/guestfs-py.c b/python/guestfs-py.c index 81c8798..8fbab74 100644 --- a/python/guestfs-py.c +++ b/python/guestfs-py.c @@ -92,6 +92,27 @@ put_string_list (char * const * const argv) return list; } +static PyObject * +put_table (char * const * const argv) +{ + PyObject *list, *item; + int argc, i; + + for (argc = 0; argv[argc] != NULL; ++argc) + ; + + list = PyList_New (argc >> 1); + for (i = 0; i < argc; i += 2) { + PyObject *item; + item = PyTuple_New (2); + PyTuple_SetItem (item, 0, PyString_FromString (argv[i])); + PyTuple_SetItem (item, 1, PyString_FromString (argv[i+1])); + PyList_SetItem (list, i >> 1, item); + } + + return list; +} + static void free_strings (char **argv) { @@ -2030,6 +2051,31 @@ py_guestfs_statvfs (PyObject *self, PyObject *args) return py_r; } +static PyObject * +py_guestfs_tune2fs_l (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + char **r; + const char *device; + + if (!PyArg_ParseTuple (args, (char *) "Os:guestfs_tune2fs_l", + &py_g, &device)) + return NULL; + g = get_handle (py_g); + + r = guestfs_tune2fs_l (g, device); + if (r == NULL) { + PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); + return NULL; + } + + py_r = put_table (r); + free (r); + return py_r; +} + static PyMethodDef methods[] = { { (char *) "create", py_guestfs_create, METH_VARARGS, NULL }, { (char *) "close", py_guestfs_close, METH_VARARGS, NULL }, @@ -2099,6 +2145,7 @@ static PyMethodDef methods[] = { { (char *) "stat", py_guestfs_stat, METH_VARARGS, NULL }, { (char *) "lstat", py_guestfs_lstat, METH_VARARGS, NULL }, { (char *) "statvfs", py_guestfs_statvfs, METH_VARARGS, NULL }, + { (char *) "tune2fs_l", py_guestfs_tune2fs_l, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; diff --git a/python/guestfs.py b/python/guestfs.py index 2e0be5c..95156fc 100644 --- a/python/guestfs.py +++ b/python/guestfs.py @@ -225,3 +225,6 @@ class GuestFS: def statvfs (self, path): return libguestfsmod.statvfs (self._o, path) + def tune2fs_l (self, device): + return libguestfsmod.tune2fs_l (self._o, device) + diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index 8f40102..0961df6 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -3924,3 +3924,81 @@ struct guestfs_statvfs *guestfs_statvfs (guestfs_h *g, return safe_memdup (g, &rv.ret.statbuf, sizeof (rv.ret.statbuf)); } +struct tune2fs_l_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; + struct guestfs_tune2fs_l_ret ret; +}; + +static void tune2fs_l_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct tune2fs_l_rv *rv = (struct tune2fs_l_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_tune2fs_l: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_tune2fs_l: failed to parse reply error"); + return; + } + goto done; + } + if (!xdr_guestfs_tune2fs_l_ret (xdr, &rv->ret)) { + error (g, "guestfs_tune2fs_l: failed to parse reply"); + return; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +char **guestfs_tune2fs_l (guestfs_h *g, + const char *device) +{ + struct guestfs_tune2fs_l_args args; + struct tune2fs_l_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_tune2fs_l called from the wrong state, %d != READY", + g->state); + return NULL; + } + + memset (&rv, 0, sizeof rv); + + args.device = (char *) device; + serial = dispatch (g, GUESTFS_PROC_TUNE2FS_L, + (xdrproc_t) xdr_guestfs_tune2fs_l_args, (char *) &args); + if (serial == -1) + return NULL; + + rv.cb_done = 0; + g->reply_cb_internal = tune2fs_l_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_tune2fs_l failed, see earlier error messages"); + return NULL; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_TUNE2FS_L, serial) == -1) + return NULL; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return NULL; + } + + /* caller will free this, but we need to add a NULL entry */ + rv.ret.superblock.superblock_val = safe_realloc (g, rv.ret.superblock.superblock_val, + sizeof (char *) * (rv.ret.superblock.superblock_len + 1)); + rv.ret.superblock.superblock_val[rv.ret.superblock.superblock_len] = NULL; + return rv.ret.superblock.superblock_val; +} + diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h index a838a04..5f523c3 100644 --- a/src/guestfs-actions.h +++ b/src/guestfs-actions.h @@ -85,3 +85,4 @@ extern char **guestfs_command_lines (guestfs_h *handle, char * const* const argu extern struct guestfs_stat *guestfs_stat (guestfs_h *handle, const char *path); extern struct guestfs_stat *guestfs_lstat (guestfs_h *handle, const char *path); extern struct guestfs_statvfs *guestfs_statvfs (guestfs_h *handle, const char *path); +extern char **guestfs_tune2fs_l (guestfs_h *handle, const char *device); diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c index 99377b4..33de1dc 100644 --- a/src/guestfs_protocol.c +++ b/src/guestfs_protocol.c @@ -1014,6 +1014,27 @@ xdr_guestfs_statvfs_ret (XDR *xdrs, guestfs_statvfs_ret *objp) } bool_t +xdr_guestfs_tune2fs_l_args (XDR *xdrs, guestfs_tune2fs_l_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_tune2fs_l_ret (XDR *xdrs, guestfs_tune2fs_l_ret *objp) +{ + register int32_t *buf; + + if (!xdr_array (xdrs, (char **)&objp->superblock.superblock_val, (u_int *) &objp->superblock.superblock_len, ~0, + sizeof (str), (xdrproc_t) xdr_str)) + return FALSE; + return TRUE; +} + +bool_t xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp) { register int32_t *buf; diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h index 0720723..270571e 100644 --- a/src/guestfs_protocol.h +++ b/src/guestfs_protocol.h @@ -527,6 +527,19 @@ struct guestfs_statvfs_ret { }; typedef struct guestfs_statvfs_ret guestfs_statvfs_ret; +struct guestfs_tune2fs_l_args { + char *device; +}; +typedef struct guestfs_tune2fs_l_args guestfs_tune2fs_l_args; + +struct guestfs_tune2fs_l_ret { + struct { + u_int superblock_len; + str *superblock_val; + } superblock; +}; +typedef struct guestfs_tune2fs_l_ret guestfs_tune2fs_l_ret; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -582,7 +595,8 @@ enum guestfs_procedure { GUESTFS_PROC_STAT = 52, GUESTFS_PROC_LSTAT = 53, GUESTFS_PROC_STATVFS = 54, - GUESTFS_PROC_dummy = 54 + 1, + GUESTFS_PROC_TUNE2FS_L = 55, + GUESTFS_PROC_dummy = 55 + 1, }; typedef enum guestfs_procedure guestfs_procedure; #define GUESTFS_MESSAGE_MAX 4194304 @@ -696,6 +710,8 @@ extern bool_t xdr_guestfs_lstat_args (XDR *, guestfs_lstat_args*); extern bool_t xdr_guestfs_lstat_ret (XDR *, guestfs_lstat_ret*); extern bool_t xdr_guestfs_statvfs_args (XDR *, guestfs_statvfs_args*); extern bool_t xdr_guestfs_statvfs_ret (XDR *, guestfs_statvfs_ret*); +extern bool_t xdr_guestfs_tune2fs_l_args (XDR *, guestfs_tune2fs_l_args*); +extern bool_t xdr_guestfs_tune2fs_l_ret (XDR *, guestfs_tune2fs_l_ret*); extern bool_t xdr_guestfs_procedure (XDR *, guestfs_procedure*); extern bool_t xdr_guestfs_message_direction (XDR *, guestfs_message_direction*); extern bool_t xdr_guestfs_message_status (XDR *, guestfs_message_status*); @@ -779,6 +795,8 @@ extern bool_t xdr_guestfs_lstat_args (); extern bool_t xdr_guestfs_lstat_ret (); extern bool_t xdr_guestfs_statvfs_args (); extern bool_t xdr_guestfs_statvfs_ret (); +extern bool_t xdr_guestfs_tune2fs_l_args (); +extern bool_t xdr_guestfs_tune2fs_l_ret (); extern bool_t xdr_guestfs_procedure (); extern bool_t xdr_guestfs_message_direction (); extern bool_t xdr_guestfs_message_status (); diff --git a/src/guestfs_protocol.x b/src/guestfs_protocol.x index e03aef6..1b6e717 100644 --- a/src/guestfs_protocol.x +++ b/src/guestfs_protocol.x @@ -406,6 +406,14 @@ struct guestfs_statvfs_ret { guestfs_int_statvfs statbuf; }; +struct guestfs_tune2fs_l_args { + string device<>; +}; + +struct guestfs_tune2fs_l_ret { + str superblock<>; +}; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -461,6 +469,7 @@ enum guestfs_procedure { GUESTFS_PROC_STAT = 52, GUESTFS_PROC_LSTAT = 53, GUESTFS_PROC_STATVFS = 54, + GUESTFS_PROC_TUNE2FS_L = 55, GUESTFS_PROC_dummy }; diff --git a/tests.c b/tests.c index 1c6676b..2791145 100644 --- a/tests.c +++ b/tests.c @@ -45,6 +45,14 @@ static void print_strings (char * const * const argv) printf ("\t%s\n", argv[argc]); } +static void print_table (char * const * const argv) +{ + int i; + + for (i = 0; argv[i] != NULL; i += 2) + printf ("%s: %s\n", argv[i], argv[i+1]); +} + static int test_mount_0 (void) { /* InitEmpty for mount (0) */