From b2ed0f4c55c2bd3d07341ba2207f0cb238eb4e18 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 29 Jun 2009 12:26:11 +0100 Subject: [PATCH] Generated code for df / df-h. --- capitests/tests.c | 2 + daemon/actions.h | 2 + daemon/stubs.c | 38 +++++++ fish/cmds.c | 44 ++++++++ fish/completion.c | 2 + guestfish-actions.pod | 21 ++++ guestfs-actions.pod | 27 +++++ java/com/redhat/et/libguestfs/GuestFS.java | 44 ++++++++ java/com_redhat_et_libguestfs_GuestFS.c | 36 ++++++ ocaml/guestfs.ml | 2 + ocaml/guestfs.mli | 6 + ocaml/guestfs_c_actions.c | 46 ++++++++ perl/Guestfs.xs | 28 +++++ perl/lib/Sys/Guestfs.pm | 17 +++ python/guestfs-py.c | 50 ++++++++ python/guestfs.py | 20 ++++ ruby/ext/guestfs/_guestfs.c | 42 +++++++ src/MAX_PROC_NR | 2 +- src/guestfs-actions.c | 176 +++++++++++++++++++++++++++++ src/guestfs-actions.h | 2 + src/guestfs_protocol.c | 20 ++++ src/guestfs_protocol.h | 18 ++- src/guestfs_protocol.x | 10 ++ 23 files changed, 653 insertions(+), 2 deletions(-) diff --git a/capitests/tests.c b/capitests/tests.c index 7a30498..08f64ee 100644 --- a/capitests/tests.c +++ b/capitests/tests.c @@ -151,6 +151,8 @@ static void no_test_warnings (void) fprintf (stderr, "warning: \"guestfs_sh\" has no tests\n"); fprintf (stderr, "warning: \"guestfs_sh_lines\" has no tests\n"); fprintf (stderr, "warning: \"guestfs_scrub_freespace\" has no tests\n"); + fprintf (stderr, "warning: \"guestfs_df\" has no tests\n"); + fprintf (stderr, "warning: \"guestfs_df_h\" has no tests\n"); } static int test_tail_n_0_skip (void) diff --git a/daemon/actions.h b/daemon/actions.h index 8beeed6..8f38163 100644 --- a/daemon/actions.h +++ b/daemon/actions.h @@ -145,3 +145,5 @@ extern char **do_head (char *path); extern char **do_head_n (int nrlines, char *path); extern char **do_tail (char *path); extern char **do_tail_n (int nrlines, char *path); +extern char *do_df (void); +extern char *do_df_h (void); diff --git a/daemon/stubs.c b/daemon/stubs.c index 170726c..0c311a9 100644 --- a/daemon/stubs.c +++ b/daemon/stubs.c @@ -3147,6 +3147,38 @@ done: xdr_free ((xdrproc_t) xdr_guestfs_tail_n_args, (char *) &args); } +static void df_stub (XDR *xdr_in) +{ + char *r; + + r = do_df (); + if (r == NULL) + /* do_df has already called reply_with_error */ + goto done; + + struct guestfs_df_ret ret; + ret.output = r; + reply ((xdrproc_t) &xdr_guestfs_df_ret, (char *) &ret); + free (r); +done: ; +} + +static void df_h_stub (XDR *xdr_in) +{ + char *r; + + r = do_df_h (); + if (r == NULL) + /* do_df_h has already called reply_with_error */ + goto done; + + struct guestfs_df_h_ret ret; + ret.output = r; + reply ((xdrproc_t) &xdr_guestfs_df_h_ret, (char *) &ret); + free (r); +done: ; +} + void dispatch_incoming_message (XDR *xdr_in) { switch (proc_nr) { @@ -3522,6 +3554,12 @@ void dispatch_incoming_message (XDR *xdr_in) case GUESTFS_PROC_TAIL_N: tail_n_stub (xdr_in); break; + case GUESTFS_PROC_DF: + df_stub (xdr_in); + break; + case GUESTFS_PROC_DF_H: + df_h_stub (xdr_in); + break; default: reply_with_error ("dispatch_incoming_message: unknown procedure number %d, set LIBGUESTFS_PATH to point to the matching libguestfs appliance directory", proc_nr); } diff --git a/fish/cmds.c b/fish/cmds.c index 9bd53ec..6067eed 100644 --- a/fish/cmds.c +++ b/fish/cmds.c @@ -67,6 +67,8 @@ void list_commands (void) printf ("%-20s %s\n", "cp", "copy a file"); printf ("%-20s %s\n", "cp-a", "copy a file or directory recursively"); printf ("%-20s %s\n", "debug", "debugging and internals"); + printf ("%-20s %s\n", "df", "report file system disk space usage"); + printf ("%-20s %s\n", "df-h", "report file system disk space usage (human readable)"); printf ("%-20s %s\n", "dmesg", "return kernel messages"); printf ("%-20s %s\n", "download", "download a file to the local machine"); printf ("%-20s %s\n", "drop-caches", "drop kernel page cache, dentries and inodes"); @@ -616,6 +618,12 @@ void display_command (const char *cmd) if (strcasecmp (cmd, "tail_n") == 0 || strcasecmp (cmd, "tail-n") == 0) pod2text ("tail-n - return last N lines of a file", " tail-n \n\nIf the parameter C is a positive number, this returns the last\nC lines of the file C.\n\nIf the parameter C is a negative number, this returns lines\nfrom the file C, starting with the C<-nrlines>th line.\n\nIf the parameter C is zero, this returns an empty list.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB. To transfer large files you should use\nFTP."); else + if (strcasecmp (cmd, "df") == 0) + pod2text ("df - report file system disk space usage", " df\n\nThis command runs the C command to report disk space used.\n\nThis command is mostly useful for interactive sessions. It\nis I intended that you try to parse the output string.\nUse C from programs."); + else + if (strcasecmp (cmd, "df_h") == 0 || strcasecmp (cmd, "df-h") == 0) + pod2text ("df-h - report file system disk space usage (human readable)", " df-h\n\nThis command runs the C command to report disk space used\nin human-readable format.\n\nThis command is mostly useful for interactive sessions. It\nis I intended that you try to parse the output string.\nUse C from programs."); + else display_builtin_command (cmd); } @@ -3024,6 +3032,36 @@ static int run_tail_n (const char *cmd, int argc, char *argv[]) return 0; } +static int run_df (const char *cmd, int argc, char *argv[]) +{ + char *r; + if (argc != 0) { + fprintf (stderr, "%s should have 0 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + r = guestfs_df (g); + if (r == NULL) return -1; + printf ("%s\n", r); + free (r); + return 0; +} + +static int run_df_h (const char *cmd, int argc, char *argv[]) +{ + char *r; + if (argc != 0) { + fprintf (stderr, "%s should have 0 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + r = guestfs_df_h (g); + if (r == NULL) return -1; + printf ("%s\n", r); + free (r); + return 0; +} + int run_action (const char *cmd, int argc, char *argv[]) { if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0) @@ -3461,6 +3499,12 @@ int run_action (const char *cmd, int argc, char *argv[]) if (strcasecmp (cmd, "tail_n") == 0 || strcasecmp (cmd, "tail-n") == 0) return run_tail_n (cmd, argc, argv); else + if (strcasecmp (cmd, "df") == 0) + return run_df (cmd, argc, argv); + else + if (strcasecmp (cmd, "df_h") == 0 || strcasecmp (cmd, "df-h") == 0) + return run_df_h (cmd, argc, argv); + else { fprintf (stderr, "%s: unknown command\n", cmd); return -1; diff --git a/fish/completion.c b/fish/completion.c index a2febb7..6b58bd2 100644 --- a/fish/completion.c +++ b/fish/completion.c @@ -191,6 +191,8 @@ static const char *const commands[] = { "head-n", "tail", "tail-n", + "df", + "df-h", NULL }; diff --git a/guestfish-actions.pod b/guestfish-actions.pod index d45c001..e22aad1 100644 --- a/guestfish-actions.pod +++ b/guestfish-actions.pod @@ -479,6 +479,27 @@ There is no comprehensive help for this command. You have to look at the file C in the libguestfs source to find out what you can do. +=head2 df + + df + +This command runs the C command to report disk space used. + +This command is mostly useful for interactive sessions. It +is I intended that you try to parse the output string. +Use C from programs. + +=head2 df-h + + df-h + +This command runs the C command to report disk space used +in human-readable format. + +This command is mostly useful for interactive sessions. It +is I intended that you try to parse the output string. +Use C from programs. + =head2 dmesg dmesg diff --git a/guestfs-actions.pod b/guestfs-actions.pod index 68357d6..a48bbe6 100644 --- a/guestfs-actions.pod +++ b/guestfs-actions.pod @@ -614,6 +614,33 @@ to find out what you can do. This function returns a string, or NULL on error. I. +=head2 guestfs_df + + char *guestfs_df (guestfs_h *handle); + +This command runs the C command to report disk space used. + +This command is mostly useful for interactive sessions. It +is I intended that you try to parse the output string. +Use C from programs. + +This function returns a string, or NULL on error. +I. + +=head2 guestfs_df_h + + char *guestfs_df_h (guestfs_h *handle); + +This command runs the C command to report disk space used +in human-readable format. + +This command is mostly useful for interactive sessions. It +is I intended that you try to parse the output string. +Use C from programs. + +This function returns a string, or NULL on error. +I. + =head2 guestfs_dmesg char *guestfs_dmesg (guestfs_h *handle); diff --git a/java/com/redhat/et/libguestfs/GuestFS.java b/java/com/redhat/et/libguestfs/GuestFS.java index 3091332..1d65581 100644 --- a/java/com/redhat/et/libguestfs/GuestFS.java +++ b/java/com/redhat/et/libguestfs/GuestFS.java @@ -3725,4 +3725,48 @@ public HashMap test0rhashtableerr () private native String[] _tail_n (long g, int nrlines, String path) throws LibGuestFSException; + /** + * report file system disk space usage + *

+ * This command runs the "df" command to report disk space + * used. + *

+ * This command is mostly useful for interactive sessions. + * It is *not* intended that you try to parse the output + * string. Use "statvfs" from programs. + *

+ * @throws LibGuestFSException + */ + public String df () + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("df: handle is closed"); + return _df (g); + } + private native String _df (long g) + throws LibGuestFSException; + + /** + * report file system disk space usage (human readable) + *

+ * This command runs the "df -h" command to report disk + * space used in human-readable format. + *

+ * This command is mostly useful for interactive sessions. + * It is *not* intended that you try to parse the output + * string. Use "statvfs" from programs. + *

+ * @throws LibGuestFSException + */ + public String df_h () + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("df_h: handle is closed"); + return _df_h (g); + } + private native String _df_h (long g) + throws LibGuestFSException; + } diff --git a/java/com_redhat_et_libguestfs_GuestFS.c b/java/com_redhat_et_libguestfs_GuestFS.c index 501e8d1..206f2dc 100644 --- a/java/com_redhat_et_libguestfs_GuestFS.c +++ b/java/com_redhat_et_libguestfs_GuestFS.c @@ -4335,3 +4335,39 @@ Java_com_redhat_et_libguestfs_GuestFS__1tail_1n return jr; } +JNIEXPORT jstring JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1df + (JNIEnv *env, jobject obj, jlong jg) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + jstring jr; + char *r; + + r = guestfs_df (g); + if (r == NULL) { + throw_exception (env, guestfs_last_error (g)); + return NULL; + } + jr = (*env)->NewStringUTF (env, r); + free (r); + return jr; +} + +JNIEXPORT jstring JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1df_1h + (JNIEnv *env, jobject obj, jlong jg) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + jstring jr; + char *r; + + r = guestfs_df_h (g); + if (r == NULL) { + throw_exception (env, guestfs_last_error (g)); + return NULL; + } + jr = (*env)->NewStringUTF (env, r); + free (r); + return jr; +} + diff --git a/ocaml/guestfs.ml b/ocaml/guestfs.ml index c631024..52bd54c 100644 --- a/ocaml/guestfs.ml +++ b/ocaml/guestfs.ml @@ -291,3 +291,5 @@ external head : t -> string -> string array = "ocaml_guestfs_head" external head_n : t -> int -> string -> string array = "ocaml_guestfs_head_n" external tail : t -> string -> string array = "ocaml_guestfs_tail" external tail_n : t -> int -> string -> string array = "ocaml_guestfs_tail_n" +external df : t -> string = "ocaml_guestfs_df" +external df_h : t -> string = "ocaml_guestfs_df_h" diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli index 97180b0..390b6b9 100644 --- a/ocaml/guestfs.mli +++ b/ocaml/guestfs.mli @@ -652,3 +652,9 @@ val tail : t -> string -> string array val tail_n : t -> int -> string -> string array (** return last N lines of a file *) +val df : t -> string +(** report file system disk space usage *) + +val df_h : t -> string +(** report file system disk space usage (human readable) *) + diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c index d8b0567..04be818 100644 --- a/ocaml/guestfs_c_actions.c +++ b/ocaml/guestfs_c_actions.c @@ -4542,3 +4542,49 @@ ocaml_guestfs_tail_n (value gv, value nrlinesv, value pathv) CAMLreturn (rv); } +CAMLprim value +ocaml_guestfs_df (value gv) +{ + CAMLparam1 (gv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("df: used handle after closing it"); + + char *r; + + caml_enter_blocking_section (); + r = guestfs_df (g); + caml_leave_blocking_section (); + if (r == NULL) + ocaml_guestfs_raise_error (g, "df"); + + rv = caml_copy_string (r); + free (r); + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_df_h (value gv) +{ + CAMLparam1 (gv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("df_h: used handle after closing it"); + + char *r; + + caml_enter_blocking_section (); + r = guestfs_df_h (g); + caml_leave_blocking_section (); + if (r == NULL) + ocaml_guestfs_raise_error (g, "df_h"); + + rv = caml_copy_string (r); + free (r); + CAMLreturn (rv); +} + diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs index bcd7304..6980bda 100644 --- a/perl/Guestfs.xs +++ b/perl/Guestfs.xs @@ -2770,3 +2770,31 @@ PREINIT: } free (lines); +SV * +df (g) + guestfs_h *g; +PREINIT: + char *output; + CODE: + output = guestfs_df (g); + if (output == NULL) + croak ("df: %s", guestfs_last_error (g)); + RETVAL = newSVpv (output, 0); + free (output); + OUTPUT: + RETVAL + +SV * +df_h (g) + guestfs_h *g; +PREINIT: + char *output; + CODE: + output = guestfs_df_h (g); + if (output == NULL) + croak ("df_h: %s", guestfs_last_error (g)); + RETVAL = newSVpv (output, 0); + free (output); + OUTPUT: + RETVAL + diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm index 3d15738..69ffe8b 100644 --- a/perl/lib/Sys/Guestfs.pm +++ b/perl/lib/Sys/Guestfs.pm @@ -500,6 +500,23 @@ There is no comprehensive help for this command. You have to look at the file C in the libguestfs source to find out what you can do. +=item $output = $h->df (); + +This command runs the C command to report disk space used. + +This command is mostly useful for interactive sessions. It +is I intended that you try to parse the output string. +Use C from programs. + +=item $output = $h->df_h (); + +This command runs the C command to report disk space used +in human-readable format. + +This command is mostly useful for interactive sessions. It +is I intended that you try to parse the output string. +Use C from programs. + =item $kmsgs = $h->dmesg (); This returns the kernel messages (C output) from diff --git a/python/guestfs-py.c b/python/guestfs-py.c index 7d28af4..59a891f 100644 --- a/python/guestfs-py.c +++ b/python/guestfs-py.c @@ -4805,6 +4805,54 @@ py_guestfs_tail_n (PyObject *self, PyObject *args) return py_r; } +static PyObject * +py_guestfs_df (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + char *r; + + if (!PyArg_ParseTuple (args, (char *) "O:guestfs_df", + &py_g)) + return NULL; + g = get_handle (py_g); + + r = guestfs_df (g); + if (r == NULL) { + PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); + return NULL; + } + + py_r = PyString_FromString (r); + free (r); + return py_r; +} + +static PyObject * +py_guestfs_df_h (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + char *r; + + if (!PyArg_ParseTuple (args, (char *) "O:guestfs_df_h", + &py_g)) + return NULL; + g = get_handle (py_g); + + r = guestfs_df_h (g); + if (r == NULL) { + PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); + return NULL; + } + + py_r = PyString_FromString (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 }, @@ -4984,6 +5032,8 @@ static PyMethodDef methods[] = { { (char *) "head_n", py_guestfs_head_n, METH_VARARGS, NULL }, { (char *) "tail", py_guestfs_tail, METH_VARARGS, NULL }, { (char *) "tail_n", py_guestfs_tail_n, METH_VARARGS, NULL }, + { (char *) "df", py_guestfs_df, METH_VARARGS, NULL }, + { (char *) "df_h", py_guestfs_df_h, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; diff --git a/python/guestfs.py b/python/guestfs.py index 30728be..d838aae 100644 --- a/python/guestfs.py +++ b/python/guestfs.py @@ -1807,3 +1807,23 @@ class GuestFS: """ return libguestfsmod.tail_n (self._o, nrlines, path) + def df (self): + u"""This command runs the "df" command to report disk space + used. + + This command is mostly useful for interactive sessions. + It is *not* intended that you try to parse the output + string. Use "statvfs" from programs. + """ + return libguestfsmod.df (self._o) + + def df_h (self): + u"""This command runs the "df -h" command to report disk + space used in human-readable format. + + This command is mostly useful for interactive sessions. + It is *not* intended that you try to parse the output + string. Use "statvfs" from programs. + """ + return libguestfsmod.df_h (self._o) + diff --git a/ruby/ext/guestfs/_guestfs.c b/ruby/ext/guestfs/_guestfs.c index a48ecab..336a3a4 100644 --- a/ruby/ext/guestfs/_guestfs.c +++ b/ruby/ext/guestfs/_guestfs.c @@ -4521,6 +4521,44 @@ static VALUE ruby_guestfs_tail_n (VALUE gv, VALUE nrlinesv, VALUE pathv) return rv; } +static VALUE ruby_guestfs_df (VALUE gv) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "df"); + + + char *r; + + r = guestfs_df (g); + if (r == NULL) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + VALUE rv = rb_str_new2 (r); + free (r); + return rv; +} + +static VALUE ruby_guestfs_df_h (VALUE gv) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "df_h"); + + + char *r; + + r = guestfs_df_h (g); + if (r == NULL) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + VALUE rv = rb_str_new2 (r); + free (r); + return rv; +} + /* Initialize the module. */ void Init__guestfs () { @@ -4883,4 +4921,8 @@ void Init__guestfs () ruby_guestfs_tail, 1); rb_define_method (c_guestfs, "tail_n", ruby_guestfs_tail_n, 2); + rb_define_method (c_guestfs, "df", + ruby_guestfs_df, 0); + rb_define_method (c_guestfs, "df_h", + ruby_guestfs_df_h, 0); } diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index fc902f4..0a3e7b0 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -124 +126 diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index 4a38b45..745a52b 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -11381,3 +11381,179 @@ char **guestfs_tail_n (guestfs_h *g, return ctx.ret.lines.lines_val; } +struct df_ctx { + /* This flag is set by the callbacks, so we know we've done + * the callbacks as expected, and in the right sequence. + * 0 = not called, 1 = reply_cb called. + */ + int cb_sequence; + struct guestfs_message_header hdr; + struct guestfs_message_error err; + struct guestfs_df_ret ret; +}; + +static void df_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct df_ctx *ctx = (struct df_ctx *) data; + + /* This should definitely not happen. */ + if (ctx->cb_sequence != 0) { + ctx->cb_sequence = 9999; + error (g, "%s: internal error: reply callback called twice", "guestfs_df"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_df"); + return; + } + if (ctx->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &ctx->err)) { + error (g, "%s: failed to parse reply error", "guestfs_df"); + return; + } + goto done; + } + if (!xdr_guestfs_df_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_df"); + return; + } + done: + ctx->cb_sequence = 1; +} + +char *guestfs_df (guestfs_h *g) +{ + struct df_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_df") == -1) return NULL; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + serial = guestfs__send_sync (g, GUESTFS_PROC_DF, NULL, NULL); + if (serial == -1) { + guestfs_end_busy (g); + return NULL; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, df_reply_cb, &ctx); + (void) ml->main_loop_run (ml, g); + guestfs_set_reply_callback (g, NULL, NULL); + if (ctx.cb_sequence != 1) { + error (g, "%s reply failed, see earlier error messages", "guestfs_df"); + guestfs_end_busy (g); + return NULL; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DF, serial) == -1) { + guestfs_end_busy (g); + return NULL; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return NULL; + } + + guestfs_end_busy (g); + return ctx.ret.output; /* caller will free */ +} + +struct df_h_ctx { + /* This flag is set by the callbacks, so we know we've done + * the callbacks as expected, and in the right sequence. + * 0 = not called, 1 = reply_cb called. + */ + int cb_sequence; + struct guestfs_message_header hdr; + struct guestfs_message_error err; + struct guestfs_df_h_ret ret; +}; + +static void df_h_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct df_h_ctx *ctx = (struct df_h_ctx *) data; + + /* This should definitely not happen. */ + if (ctx->cb_sequence != 0) { + ctx->cb_sequence = 9999; + error (g, "%s: internal error: reply callback called twice", "guestfs_df_h"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_df_h"); + return; + } + if (ctx->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &ctx->err)) { + error (g, "%s: failed to parse reply error", "guestfs_df_h"); + return; + } + goto done; + } + if (!xdr_guestfs_df_h_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_df_h"); + return; + } + done: + ctx->cb_sequence = 1; +} + +char *guestfs_df_h (guestfs_h *g) +{ + struct df_h_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_df_h") == -1) return NULL; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + serial = guestfs__send_sync (g, GUESTFS_PROC_DF_H, NULL, NULL); + if (serial == -1) { + guestfs_end_busy (g); + return NULL; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, df_h_reply_cb, &ctx); + (void) ml->main_loop_run (ml, g); + guestfs_set_reply_callback (g, NULL, NULL); + if (ctx.cb_sequence != 1) { + error (g, "%s reply failed, see earlier error messages", "guestfs_df_h"); + guestfs_end_busy (g); + return NULL; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_DF_H, serial) == -1) { + guestfs_end_busy (g); + return NULL; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return NULL; + } + + guestfs_end_busy (g); + return ctx.ret.output; /* caller will free */ +} + diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h index 42951cb..cbf5ff7 100644 --- a/src/guestfs-actions.h +++ b/src/guestfs-actions.h @@ -195,3 +195,5 @@ extern char **guestfs_head (guestfs_h *handle, const char *path); extern char **guestfs_head_n (guestfs_h *handle, int nrlines, const char *path); extern char **guestfs_tail (guestfs_h *handle, const char *path); extern char **guestfs_tail_n (guestfs_h *handle, int nrlines, const char *path); +extern char *guestfs_df (guestfs_h *handle); +extern char *guestfs_df_h (guestfs_h *handle); diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c index 3f08084..2830bf2 100644 --- a/src/guestfs_protocol.c +++ b/src/guestfs_protocol.c @@ -2131,6 +2131,26 @@ xdr_guestfs_tail_n_ret (XDR *xdrs, guestfs_tail_n_ret *objp) } bool_t +xdr_guestfs_df_ret (XDR *xdrs, guestfs_df_ret *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->output, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_df_h_ret (XDR *xdrs, guestfs_df_h_ret *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->output, ~0)) + 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 7fe3a32..16db25a 100644 --- a/src/guestfs_protocol.h +++ b/src/guestfs_protocol.h @@ -1091,6 +1091,16 @@ struct guestfs_tail_n_ret { }; typedef struct guestfs_tail_n_ret guestfs_tail_n_ret; +struct guestfs_df_ret { + char *output; +}; +typedef struct guestfs_df_ret guestfs_df_ret; + +struct guestfs_df_h_ret { + char *output; +}; +typedef struct guestfs_df_h_ret guestfs_df_h_ret; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -1216,7 +1226,9 @@ enum guestfs_procedure { GUESTFS_PROC_HEAD_N = 122, GUESTFS_PROC_TAIL = 123, GUESTFS_PROC_TAIL_N = 124, - GUESTFS_PROC_NR_PROCS = 124 + 1, + GUESTFS_PROC_DF = 125, + GUESTFS_PROC_DF_H = 126, + GUESTFS_PROC_NR_PROCS = 126 + 1, }; typedef enum guestfs_procedure guestfs_procedure; #define GUESTFS_MESSAGE_MAX 4194304 @@ -1442,6 +1454,8 @@ extern bool_t xdr_guestfs_tail_args (XDR *, guestfs_tail_args*); extern bool_t xdr_guestfs_tail_ret (XDR *, guestfs_tail_ret*); extern bool_t xdr_guestfs_tail_n_args (XDR *, guestfs_tail_n_args*); extern bool_t xdr_guestfs_tail_n_ret (XDR *, guestfs_tail_n_ret*); +extern bool_t xdr_guestfs_df_ret (XDR *, guestfs_df_ret*); +extern bool_t xdr_guestfs_df_h_ret (XDR *, guestfs_df_h_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*); @@ -1626,6 +1640,8 @@ extern bool_t xdr_guestfs_tail_args (); extern bool_t xdr_guestfs_tail_ret (); extern bool_t xdr_guestfs_tail_n_args (); extern bool_t xdr_guestfs_tail_n_ret (); +extern bool_t xdr_guestfs_df_ret (); +extern bool_t xdr_guestfs_df_h_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 fd8953f..702df5b 100644 --- a/src/guestfs_protocol.x +++ b/src/guestfs_protocol.x @@ -834,6 +834,14 @@ struct guestfs_tail_n_ret { str lines<>; }; +struct guestfs_df_ret { + string output<>; +}; + +struct guestfs_df_h_ret { + string output<>; +}; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -959,6 +967,8 @@ enum guestfs_procedure { GUESTFS_PROC_HEAD_N = 122, GUESTFS_PROC_TAIL = 123, GUESTFS_PROC_TAIL_N = 124, + GUESTFS_PROC_DF = 125, + GUESTFS_PROC_DF_H = 126, GUESTFS_PROC_NR_PROCS }; -- 1.8.3.1