diff options
-rw-r--r-- | daemon/actions.h | 4 | ||||
-rw-r--r-- | daemon/stubs.c | 118 | ||||
-rw-r--r-- | fish/cmds.c | 94 | ||||
-rw-r--r-- | fish/completion.c | 4 | ||||
-rw-r--r-- | guestfish-actions.pod | 37 | ||||
-rw-r--r-- | guestfs-actions.pod | 53 | ||||
-rw-r--r-- | java/com/redhat/et/libguestfs/GuestFS.java | 81 | ||||
-rw-r--r-- | java/com_redhat_et_libguestfs_GuestFS.c | 82 | ||||
-rwxr-xr-x | make-recipes.sh | 9 | ||||
-rw-r--r-- | ocaml/guestfs.ml | 4 | ||||
-rw-r--r-- | ocaml/guestfs.mli | 12 | ||||
-rw-r--r-- | ocaml/guestfs_c_actions.c | 96 | ||||
-rw-r--r-- | perl/Guestfs.xs | 54 | ||||
-rw-r--r-- | perl/lib/Sys/Guestfs.pm | 29 | ||||
-rw-r--r-- | python/guestfs-py.c | 106 | ||||
-rw-r--r-- | python/guestfs.py | 33 | ||||
-rw-r--r-- | ruby/ext/guestfs/_guestfs.c | 104 | ||||
-rw-r--r-- | src/guestfs-actions.c | 358 | ||||
-rw-r--r-- | src/guestfs-actions.h | 4 | ||||
-rw-r--r-- | src/guestfs_protocol.c | 64 | ||||
-rw-r--r-- | src/guestfs_protocol.h | 50 | ||||
-rw-r--r-- | src/guestfs_protocol.x | 30 | ||||
-rw-r--r-- | tests.c | 335 |
23 files changed, 1758 insertions, 3 deletions
diff --git a/daemon/actions.h b/daemon/actions.h index 8e79f7b8..373e513f 100644 --- a/daemon/actions.h +++ b/daemon/actions.h @@ -100,3 +100,7 @@ extern char *do_debug (const char *subcmd, char * const* const extraargs); extern int do_lvremove (const char *device); extern int do_vgremove (const char *vgname); extern int do_pvremove (const char *device); +extern int do_set_e2label (const char *device, const char *label); +extern char *do_get_e2label (const char *device); +extern int do_set_e2uuid (const char *device, const char *uuid); +extern char *do_get_e2uuid (const char *device); diff --git a/daemon/stubs.c b/daemon/stubs.c index 02c76f1e..cafadbea 100644 --- a/daemon/stubs.c +++ b/daemon/stubs.c @@ -1944,6 +1944,112 @@ done: xdr_free ((xdrproc_t) xdr_guestfs_pvremove_args, (char *) &args); } +static void set_e2label_stub (XDR *xdr_in) +{ + int r; + struct guestfs_set_e2label_args args; + const char *device; + const char *label; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_set_e2label_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "set_e2label"); + return; + } + device = args.device; + label = args.label; + + r = do_set_e2label (device, label); + if (r == -1) + /* do_set_e2label has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_set_e2label_args, (char *) &args); +} + +static void get_e2label_stub (XDR *xdr_in) +{ + char *r; + struct guestfs_get_e2label_args args; + const char *device; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_get_e2label_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "get_e2label"); + return; + } + device = args.device; + + r = do_get_e2label (device); + if (r == NULL) + /* do_get_e2label has already called reply_with_error */ + goto done; + + struct guestfs_get_e2label_ret ret; + ret.label = r; + reply ((xdrproc_t) &xdr_guestfs_get_e2label_ret, (char *) &ret); + free (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_get_e2label_args, (char *) &args); +} + +static void set_e2uuid_stub (XDR *xdr_in) +{ + int r; + struct guestfs_set_e2uuid_args args; + const char *device; + const char *uuid; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_set_e2uuid_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "set_e2uuid"); + return; + } + device = args.device; + uuid = args.uuid; + + r = do_set_e2uuid (device, uuid); + if (r == -1) + /* do_set_e2uuid has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_set_e2uuid_args, (char *) &args); +} + +static void get_e2uuid_stub (XDR *xdr_in) +{ + char *r; + struct guestfs_get_e2uuid_args args; + const char *device; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_get_e2uuid_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "get_e2uuid"); + return; + } + device = args.device; + + r = do_get_e2uuid (device); + if (r == NULL) + /* do_get_e2uuid has already called reply_with_error */ + goto done; + + struct guestfs_get_e2uuid_ret ret; + ret.uuid = r; + reply ((xdrproc_t) &xdr_guestfs_get_e2uuid_ret, (char *) &ret); + free (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_get_e2uuid_args, (char *) &args); +} + void dispatch_incoming_message (XDR *xdr_in) { switch (proc_nr) { @@ -2184,6 +2290,18 @@ void dispatch_incoming_message (XDR *xdr_in) case GUESTFS_PROC_PVREMOVE: pvremove_stub (xdr_in); break; + case GUESTFS_PROC_SET_E2LABEL: + set_e2label_stub (xdr_in); + break; + case GUESTFS_PROC_GET_E2LABEL: + get_e2label_stub (xdr_in); + break; + case GUESTFS_PROC_SET_E2UUID: + set_e2uuid_stub (xdr_in); + break; + case GUESTFS_PROC_GET_E2UUID: + get_e2uuid_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 411c6f71..f0da3291 100644 --- a/fish/cmds.c +++ b/fish/cmds.c @@ -68,6 +68,8 @@ void list_commands (void) printf ("%-20s %s\n", "exists", "test if file or directory exists"); printf ("%-20s %s\n", "file", "determine file type"); printf ("%-20s %s\n", "get-autosync", "get autosync mode"); + printf ("%-20s %s\n", "get-e2label", "get the ext2/3/4 filesystem label"); + printf ("%-20s %s\n", "get-e2uuid", "get the ext2/3/4 filesystem UUID"); printf ("%-20s %s\n", "get-path", "get the search path"); printf ("%-20s %s\n", "get-qemu", "get the qemu binary"); printf ("%-20s %s\n", "get-state", "get the current state"); @@ -107,6 +109,8 @@ void list_commands (void) printf ("%-20s %s\n", "rm-rf", "remove a file or directory recursively"); printf ("%-20s %s\n", "rmdir", "remove a directory"); printf ("%-20s %s\n", "set-autosync", "set autosync mode"); + printf ("%-20s %s\n", "set-e2label", "set the ext2/3/4 filesystem label"); + printf ("%-20s %s\n", "set-e2uuid", "set the ext2/3/4 filesystem UUID"); printf ("%-20s %s\n", "set-path", "set the search path"); printf ("%-20s %s\n", "set-qemu", "set the qemu binary"); printf ("%-20s %s\n", "set-verbose", "set verbose mode"); @@ -424,6 +428,18 @@ void display_command (const char *cmd) if (strcasecmp (cmd, "pvremove") == 0) pod2text ("pvremove - remove an LVM physical volume", " pvremove <device>\n\nThis wipes a physical volume C<device> so that LVM will no longer\nrecognise it.\n\nThe implementation uses the C<pvremove> command which refuses to\nwipe physical volumes that contain any volume groups, so you have\nto remove those first."); else + if (strcasecmp (cmd, "set_e2label") == 0 || strcasecmp (cmd, "set-e2label") == 0) + pod2text ("set-e2label - set the ext2/3/4 filesystem label", " set-e2label <device> <label>\n\nThis sets the ext2/3/4 filesystem label of the filesystem on\nC<device> to C<label>. Filesystem labels are limited to\n16 characters.\n\nYou can use either C<tune2fs_l> or C<get_e2label>\nto return the existing label on a filesystem."); + else + if (strcasecmp (cmd, "get_e2label") == 0 || strcasecmp (cmd, "get-e2label") == 0) + pod2text ("get-e2label - get the ext2/3/4 filesystem label", " get-e2label <device>\n\nThis returns the ext2/3/4 filesystem label of the filesystem on\nC<device>."); + else + if (strcasecmp (cmd, "set_e2uuid") == 0 || strcasecmp (cmd, "set-e2uuid") == 0) + pod2text ("set-e2uuid - set the ext2/3/4 filesystem UUID", " set-e2uuid <device> <uuid>\n\nThis sets the ext2/3/4 filesystem UUID of the filesystem on\nC<device> to C<uuid>. The format of the UUID and alternatives\nsuch as C<clear>, C<random> and C<time> are described in the\nL<tune2fs(8)> manpage.\n\nYou can use either C<tune2fs_l> or C<get_e2uuid>\nto return the existing UUID of a filesystem."); + else + if (strcasecmp (cmd, "get_e2uuid") == 0 || strcasecmp (cmd, "get-e2uuid") == 0) + pod2text ("get-e2uuid - get the ext2/3/4 filesystem UUID", " get-e2uuid <device>\n\nThis returns the ext2/3/4 filesystem UUID of the filesystem on\nC<device>."); + else display_builtin_command (cmd); } @@ -2060,6 +2076,72 @@ static int run_pvremove (const char *cmd, int argc, char *argv[]) return r; } +static int run_set_e2label (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *device; + const char *label; + if (argc != 2) { + fprintf (stderr, "%s should have 2 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + device = argv[0]; + label = argv[1]; + r = guestfs_set_e2label (g, device, label); + return r; +} + +static int run_get_e2label (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_get_e2label (g, device); + if (r == NULL) return -1; + printf ("%s\n", r); + free (r); + return 0; +} + +static int run_set_e2uuid (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *device; + const char *uuid; + if (argc != 2) { + fprintf (stderr, "%s should have 2 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + device = argv[0]; + uuid = argv[1]; + r = guestfs_set_e2uuid (g, device, uuid); + return r; +} + +static int run_get_e2uuid (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_get_e2uuid (g, device); + 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) @@ -2353,6 +2435,18 @@ int run_action (const char *cmd, int argc, char *argv[]) if (strcasecmp (cmd, "pvremove") == 0) return run_pvremove (cmd, argc, argv); else + if (strcasecmp (cmd, "set_e2label") == 0 || strcasecmp (cmd, "set-e2label") == 0) + return run_set_e2label (cmd, argc, argv); + else + if (strcasecmp (cmd, "get_e2label") == 0 || strcasecmp (cmd, "get-e2label") == 0) + return run_get_e2label (cmd, argc, argv); + else + if (strcasecmp (cmd, "set_e2uuid") == 0 || strcasecmp (cmd, "set-e2uuid") == 0) + return run_set_e2uuid (cmd, argc, argv); + else + if (strcasecmp (cmd, "get_e2uuid") == 0 || strcasecmp (cmd, "get-e2uuid") == 0) + return run_get_e2uuid (cmd, argc, argv); + else { fprintf (stderr, "%s: unknown command\n", cmd); return -1; diff --git a/fish/completion.c b/fish/completion.c index 08d44735..d7dfc499 100644 --- a/fish/completion.c +++ b/fish/completion.c @@ -74,6 +74,8 @@ static const char *commands[] = { "exists", "file", "get-autosync", + "get-e2label", + "get-e2uuid", "get-path", "get-qemu", "get-state", @@ -116,6 +118,8 @@ static const char *commands[] = { "rmdir", "run", "set-autosync", + "set-e2label", + "set-e2uuid", "set-path", "set-qemu", "set-verbose", diff --git a/guestfish-actions.pod b/guestfish-actions.pod index 47fb59b7..62688eed 100644 --- a/guestfish-actions.pod +++ b/guestfish-actions.pod @@ -455,6 +455,20 @@ particular that the filename is not prepended to the output Get the autosync flag. +=head2 get-e2label + + get-e2label device + +This returns the ext2/3/4 filesystem label of the filesystem on +C<device>. + +=head2 get-e2uuid + + get-e2uuid device + +This returns the ext2/3/4 filesystem UUID of the filesystem on +C<device>. + =head2 get-path get-path @@ -812,6 +826,29 @@ If C<autosync> is true, this enables autosync. Libguestfs will make a best effort attempt to run C<sync> when the handle is closed (also if the program exits without closing handles). +=head2 set-e2label + + set-e2label device label + +This sets the ext2/3/4 filesystem label of the filesystem on +C<device> to C<label>. Filesystem labels are limited to +16 characters. + +You can use either C<tune2fs-l> or C<get-e2label> +to return the existing label on a filesystem. + +=head2 set-e2uuid + + set-e2uuid device uuid + +This sets the ext2/3/4 filesystem UUID of the filesystem on +C<device> to C<uuid>. The format of the UUID and alternatives +such as C<clear>, C<random> and C<time> are described in the +L<tune2fs(8)> manpage. + +You can use either C<tune2fs-l> or C<get-e2uuid> +to return the existing UUID of a filesystem. + =head2 set-path | path set-path path diff --git a/guestfs-actions.pod b/guestfs-actions.pod index 7c5223bb..260cb4f2 100644 --- a/guestfs-actions.pod +++ b/guestfs-actions.pod @@ -590,6 +590,28 @@ Get the autosync flag. This function returns a C truth value on success or -1 on error. +=head2 guestfs_get_e2label + + char *guestfs_get_e2label (guestfs_h *handle, + const char *device); + +This returns the ext2/3/4 filesystem label of the filesystem on +C<device>. + +This function returns a string, or NULL on error. +I<The caller must free the returned string after use>. + +=head2 guestfs_get_e2uuid + + char *guestfs_get_e2uuid (guestfs_h *handle, + const char *device); + +This returns the ext2/3/4 filesystem UUID of the filesystem on +C<device>. + +This function returns a string, or NULL on error. +I<The caller must free the returned string after use>. + =head2 guestfs_get_path const char *guestfs_get_path (guestfs_h *handle); @@ -1093,6 +1115,37 @@ For more information on states, see L<guestfs(3)>. This function returns 0 on success or -1 on error. +=head2 guestfs_set_e2label + + int guestfs_set_e2label (guestfs_h *handle, + const char *device, + const char *label); + +This sets the ext2/3/4 filesystem label of the filesystem on +C<device> to C<label>. Filesystem labels are limited to +16 characters. + +You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2label> +to return the existing label on a filesystem. + +This function returns 0 on success or -1 on error. + +=head2 guestfs_set_e2uuid + + int guestfs_set_e2uuid (guestfs_h *handle, + const char *device, + const char *uuid); + +This sets the ext2/3/4 filesystem UUID of the filesystem on +C<device> to C<uuid>. The format of the UUID and alternatives +such as C<clear>, C<random> and C<time> are described in the +L<tune2fs(8)> manpage. + +You can use either C<guestfs_tune2fs_l> or C<guestfs_get_e2uuid> +to return the existing UUID of a filesystem. + +This function returns 0 on success or -1 on error. + =head2 guestfs_set_path int guestfs_set_path (guestfs_h *handle, diff --git a/java/com/redhat/et/libguestfs/GuestFS.java b/java/com/redhat/et/libguestfs/GuestFS.java index 04a8124c..fdf6e4ec 100644 --- a/java/com/redhat/et/libguestfs/GuestFS.java +++ b/java/com/redhat/et/libguestfs/GuestFS.java @@ -2272,4 +2272,85 @@ public class GuestFS { private native void _pvremove (long g, String device) throws LibGuestFSException; + /** + * set the ext2/3/4 filesystem label + * + * This sets the ext2/3/4 filesystem label of the + * filesystem on "device" to "label". Filesystem labels are + * limited to 16 characters. + * + * You can use either "g.tune2fs_l" or "g.get_e2label" to + * return the existing label on a filesystem. + * + * @throws LibGuestFSException + */ + public void set_e2label (String device, String label) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("set_e2label: handle is closed"); + _set_e2label (g, device, label); + } + private native void _set_e2label (long g, String device, String label) + throws LibGuestFSException; + + /** + * get the ext2/3/4 filesystem label + * + * This returns the ext2/3/4 filesystem label of the + * filesystem on "device". + * + * @throws LibGuestFSException + */ + public String get_e2label (String device) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("get_e2label: handle is closed"); + return _get_e2label (g, device); + } + private native String _get_e2label (long g, String device) + throws LibGuestFSException; + + /** + * set the ext2/3/4 filesystem UUID + * + * This sets the ext2/3/4 filesystem UUID of the filesystem + * on "device" to "uuid". The format of the UUID and + * alternatives such as "clear", "random" and "time" are + * described in the tune2fs(8) manpage. + * + * You can use either "g.tune2fs_l" or "g.get_e2uuid" to + * return the existing UUID of a filesystem. + * + * @throws LibGuestFSException + */ + public void set_e2uuid (String device, String uuid) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("set_e2uuid: handle is closed"); + _set_e2uuid (g, device, uuid); + } + private native void _set_e2uuid (long g, String device, String uuid) + throws LibGuestFSException; + + /** + * get the ext2/3/4 filesystem UUID + * + * This returns the ext2/3/4 filesystem UUID of the + * filesystem on "device". + * + * @throws LibGuestFSException + */ + public String get_e2uuid (String device) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("get_e2uuid: handle is closed"); + return _get_e2uuid (g, device); + } + private native String _get_e2uuid (long g, String device) + throws LibGuestFSException; + } diff --git a/java/com_redhat_et_libguestfs_GuestFS.c b/java/com_redhat_et_libguestfs_GuestFS.c index 8f5e3537..45c19376 100644 --- a/java/com_redhat_et_libguestfs_GuestFS.c +++ b/java/com_redhat_et_libguestfs_GuestFS.c @@ -2317,3 +2317,85 @@ Java_com_redhat_et_libguestfs_GuestFS__1pvremove } } +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1set_1e2label + (JNIEnv *env, jobject obj, jlong jg, jstring jdevice, jstring jlabel) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + const char *device; + const char *label; + + device = (*env)->GetStringUTFChars (env, jdevice, NULL); + label = (*env)->GetStringUTFChars (env, jlabel, NULL); + r = guestfs_set_e2label (g, device, label); + (*env)->ReleaseStringUTFChars (env, jdevice, device); + (*env)->ReleaseStringUTFChars (env, jlabel, label); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + +JNIEXPORT jstring JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1get_1e2label + (JNIEnv *env, jobject obj, jlong jg, jstring jdevice) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + jstring jr; + char *r; + const char *device; + + device = (*env)->GetStringUTFChars (env, jdevice, NULL); + r = guestfs_get_e2label (g, device); + (*env)->ReleaseStringUTFChars (env, jdevice, device); + if (r == NULL) { + throw_exception (env, guestfs_last_error (g)); + return NULL; + } + jr = (*env)->NewStringUTF (env, r); + free (r); + return jr; +} + +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1set_1e2uuid + (JNIEnv *env, jobject obj, jlong jg, jstring jdevice, jstring juuid) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + const char *device; + const char *uuid; + + device = (*env)->GetStringUTFChars (env, jdevice, NULL); + uuid = (*env)->GetStringUTFChars (env, juuid, NULL); + r = guestfs_set_e2uuid (g, device, uuid); + (*env)->ReleaseStringUTFChars (env, jdevice, device); + (*env)->ReleaseStringUTFChars (env, juuid, uuid); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + +JNIEXPORT jstring JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1get_1e2uuid + (JNIEnv *env, jobject obj, jlong jg, jstring jdevice) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + jstring jr; + char *r; + const char *device; + + device = (*env)->GetStringUTFChars (env, jdevice, NULL); + r = guestfs_get_e2uuid (g, device); + (*env)->ReleaseStringUTFChars (env, jdevice, device); + if (r == NULL) { + throw_exception (env, guestfs_last_error (g)); + return NULL; + } + jr = (*env)->NewStringUTF (env, r); + free (r); + return jr; +} + diff --git a/make-recipes.sh b/make-recipes.sh index 2220beed..b3cd76a7 100755 --- a/make-recipes.sh +++ b/make-recipes.sh @@ -26,7 +26,14 @@ cat <<EOF <h1>guestfish recipes</h1> <p>You can also find these in the <a href="http://git.et.redhat.com/?p=libguestfs.git;a=tree;f=recipes;hb=HEAD"><code>recipes/</code> - subdirectory</a> of the source. + subdirectory</a> of the source.</p> + + <p> + <a href="http://et.redhat.com/~rjones/libguestfs/files/">Download + libguestfs and guestfish here</a> or + <a href="http://et.redhat.com/~rjones/libguestfs/">go to the + libguestfs home page</a>. + </p> <h2>Table of recipes</h2> <ul> diff --git a/ocaml/guestfs.ml b/ocaml/guestfs.ml index d020df8c..b8511a4f 100644 --- a/ocaml/guestfs.ml +++ b/ocaml/guestfs.ml @@ -215,3 +215,7 @@ external debug : t -> string -> string array -> string = "ocaml_guestfs_debug" external lvremove : t -> string -> unit = "ocaml_guestfs_lvremove" external vgremove : t -> string -> unit = "ocaml_guestfs_vgremove" external pvremove : t -> string -> unit = "ocaml_guestfs_pvremove" +external set_e2label : t -> string -> string -> unit = "ocaml_guestfs_set_e2label" +external get_e2label : t -> string -> string = "ocaml_guestfs_get_e2label" +external set_e2uuid : t -> string -> string -> unit = "ocaml_guestfs_set_e2uuid" +external get_e2uuid : t -> string -> string = "ocaml_guestfs_get_e2uuid" diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli index f38fa48a..291f3401 100644 --- a/ocaml/guestfs.mli +++ b/ocaml/guestfs.mli @@ -424,3 +424,15 @@ val vgremove : t -> string -> unit val pvremove : t -> string -> unit (** remove an LVM physical volume *) +val set_e2label : t -> string -> string -> unit +(** set the ext2/3/4 filesystem label *) + +val get_e2label : t -> string -> string +(** get the ext2/3/4 filesystem label *) + +val set_e2uuid : t -> string -> string -> unit +(** set the ext2/3/4 filesystem UUID *) + +val get_e2uuid : t -> string -> string +(** get the ext2/3/4 filesystem UUID *) + diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c index 73515cfc..b8c07878 100644 --- a/ocaml/guestfs_c_actions.c +++ b/ocaml/guestfs_c_actions.c @@ -2703,3 +2703,99 @@ ocaml_guestfs_pvremove (value gv, value devicev) CAMLreturn (rv); } +CAMLprim value +ocaml_guestfs_set_e2label (value gv, value devicev, value labelv) +{ + CAMLparam3 (gv, devicev, labelv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("set_e2label: used handle after closing it"); + + const char *device = String_val (devicev); + const char *label = String_val (labelv); + int r; + + caml_enter_blocking_section (); + r = guestfs_set_e2label (g, device, label); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "set_e2label"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_get_e2label (value gv, value devicev) +{ + CAMLparam2 (gv, devicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("get_e2label: used handle after closing it"); + + const char *device = String_val (devicev); + char *r; + + caml_enter_blocking_section (); + r = guestfs_get_e2label (g, device); + caml_leave_blocking_section (); + if (r == NULL) + ocaml_guestfs_raise_error (g, "get_e2label"); + + rv = caml_copy_string (r); + free (r); + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_set_e2uuid (value gv, value devicev, value uuidv) +{ + CAMLparam3 (gv, devicev, uuidv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("set_e2uuid: used handle after closing it"); + + const char *device = String_val (devicev); + const char *uuid = String_val (uuidv); + int r; + + caml_enter_blocking_section (); + r = guestfs_set_e2uuid (g, device, uuid); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "set_e2uuid"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_get_e2uuid (value gv, value devicev) +{ + CAMLparam2 (gv, devicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("get_e2uuid: used handle after closing it"); + + const char *device = String_val (devicev); + char *r; + + caml_enter_blocking_section (); + r = guestfs_get_e2uuid (g, device); + caml_leave_blocking_section (); + if (r == NULL) + ocaml_guestfs_raise_error (g, "get_e2uuid"); + + rv = caml_copy_string (r); + free (r); + CAMLreturn (rv); +} + diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs index 53c589d9..12c6cbbc 100644 --- a/perl/Guestfs.xs +++ b/perl/Guestfs.xs @@ -1518,3 +1518,57 @@ PREINIT: if (r == -1) croak ("pvremove: %s", guestfs_last_error (g)); +void +set_e2label (g, device, label) + guestfs_h *g; + char *device; + char *label; +PREINIT: + int r; + PPCODE: + r = guestfs_set_e2label (g, device, label); + if (r == -1) + croak ("set_e2label: %s", guestfs_last_error (g)); + +SV * +get_e2label (g, device) + guestfs_h *g; + char *device; +PREINIT: + char *label; + CODE: + label = guestfs_get_e2label (g, device); + if (label == NULL) + croak ("get_e2label: %s", guestfs_last_error (g)); + RETVAL = newSVpv (label, 0); + free (label); + OUTPUT: + RETVAL + +void +set_e2uuid (g, device, uuid) + guestfs_h *g; + char *device; + char *uuid; +PREINIT: + int r; + PPCODE: + r = guestfs_set_e2uuid (g, device, uuid); + if (r == -1) + croak ("set_e2uuid: %s", guestfs_last_error (g)); + +SV * +get_e2uuid (g, device) + guestfs_h *g; + char *device; +PREINIT: + char *uuid; + CODE: + uuid = guestfs_get_e2uuid (g, device); + if (uuid == NULL) + croak ("get_e2uuid: %s", guestfs_last_error (g)); + RETVAL = newSVpv (uuid, 0); + free (uuid); + OUTPUT: + RETVAL + diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm index bd2d9616..90384da8 100644 --- a/perl/lib/Sys/Guestfs.pm +++ b/perl/lib/Sys/Guestfs.pm @@ -472,6 +472,16 @@ particular that the filename is not prepended to the output Get the autosync flag. +=item $label = $h->get_e2label ($device); + +This returns the ext2/3/4 filesystem label of the filesystem on +C<device>. + +=item $uuid = $h->get_e2uuid ($device); + +This returns the ext2/3/4 filesystem UUID of the filesystem on +C<device>. + =item $path = $h->get_path (); Return the current search path. @@ -758,6 +768,25 @@ actions using the low-level API. For more information on states, see L<guestfs(3)>. +=item $h->set_e2label ($device, $label); + +This sets the ext2/3/4 filesystem label of the filesystem on +C<device> to C<label>. Filesystem labels are limited to +16 characters. + +You can use either C<$h-E<gt>tune2fs_l> or C<$h-E<gt>get_e2label> +to return the existing label on a filesystem. + +=item $h->set_e2uuid ($device, $uuid); + +This sets the ext2/3/4 filesystem UUID of the filesystem on +C<device> to C<uuid>. The format of the UUID and alternatives +such as C<clear>, C<random> and C<time> are described in the +L<tune2fs(8)> manpage. + +You can use either C<$h-E<gt>tune2fs_l> or C<$h-E<gt>get_e2uuid> +to return the existing UUID of a filesystem. + =item $h->set_path ($path); Set the path that libguestfs searches for kernel and initrd.img. diff --git a/python/guestfs-py.c b/python/guestfs-py.c index 38f78c03..3f3cb4de 100644 --- a/python/guestfs-py.c +++ b/python/guestfs-py.c @@ -2900,6 +2900,108 @@ py_guestfs_pvremove (PyObject *self, PyObject *args) return py_r; } +static PyObject * +py_guestfs_set_e2label (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + const char *device; + const char *label; + + if (!PyArg_ParseTuple (args, (char *) "Oss:guestfs_set_e2label", + &py_g, &device, &label)) + return NULL; + g = get_handle (py_g); + + r = guestfs_set_e2label (g, device, label); + if (r == -1) { + PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); + return NULL; + } + + Py_INCREF (Py_None); + py_r = Py_None; + return py_r; +} + +static PyObject * +py_guestfs_get_e2label (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_get_e2label", + &py_g, &device)) + return NULL; + g = get_handle (py_g); + + r = guestfs_get_e2label (g, device); + 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_set_e2uuid (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + const char *device; + const char *uuid; + + if (!PyArg_ParseTuple (args, (char *) "Oss:guestfs_set_e2uuid", + &py_g, &device, &uuid)) + return NULL; + g = get_handle (py_g); + + r = guestfs_set_e2uuid (g, device, uuid); + if (r == -1) { + PyErr_SetString (PyExc_RuntimeError, guestfs_last_error (g)); + return NULL; + } + + Py_INCREF (Py_None); + py_r = Py_None; + return py_r; +} + +static PyObject * +py_guestfs_get_e2uuid (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_get_e2uuid", + &py_g, &device)) + return NULL; + g = get_handle (py_g); + + r = guestfs_get_e2uuid (g, device); + 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 }, @@ -3003,6 +3105,10 @@ static PyMethodDef methods[] = { { (char *) "lvremove", py_guestfs_lvremove, METH_VARARGS, NULL }, { (char *) "vgremove", py_guestfs_vgremove, METH_VARARGS, NULL }, { (char *) "pvremove", py_guestfs_pvremove, METH_VARARGS, NULL }, + { (char *) "set_e2label", py_guestfs_set_e2label, METH_VARARGS, NULL }, + { (char *) "get_e2label", py_guestfs_get_e2label, METH_VARARGS, NULL }, + { (char *) "set_e2uuid", py_guestfs_set_e2uuid, METH_VARARGS, NULL }, + { (char *) "get_e2uuid", py_guestfs_get_e2uuid, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; diff --git a/python/guestfs.py b/python/guestfs.py index 1ebaa74a..ab0154f2 100644 --- a/python/guestfs.py +++ b/python/guestfs.py @@ -1113,3 +1113,36 @@ class GuestFS: """ return libguestfsmod.pvremove (self._o, device) + def set_e2label (self, device, label): + u"""This sets the ext2/3/4 filesystem label of the + filesystem on "device" to "label". Filesystem labels are + limited to 16 characters. + + You can use either "g.tune2fs_l" or "g.get_e2label" to + return the existing label on a filesystem. + """ + return libguestfsmod.set_e2label (self._o, device, label) + + def get_e2label (self, device): + u"""This returns the ext2/3/4 filesystem label of the + filesystem on "device". + """ + return libguestfsmod.get_e2label (self._o, device) + + def set_e2uuid (self, device, uuid): + u"""This sets the ext2/3/4 filesystem UUID of the filesystem + on "device" to "uuid". The format of the UUID and + alternatives such as "clear", "random" and "time" are + described in the tune2fs(8) manpage. + + You can use either "g.tune2fs_l" or "g.get_e2uuid" to + return the existing UUID of a filesystem. + """ + return libguestfsmod.set_e2uuid (self._o, device, uuid) + + def get_e2uuid (self, device): + u"""This returns the ext2/3/4 filesystem UUID of the + filesystem on "device". + """ + return libguestfsmod.get_e2uuid (self._o, device) + diff --git a/ruby/ext/guestfs/_guestfs.c b/ruby/ext/guestfs/_guestfs.c index 0429ae60..af80e3f5 100644 --- a/ruby/ext/guestfs/_guestfs.c +++ b/ruby/ext/guestfs/_guestfs.c @@ -2419,6 +2419,102 @@ static VALUE ruby_guestfs_pvremove (VALUE gv, VALUE devicev) return Qnil; } +static VALUE ruby_guestfs_set_e2label (VALUE gv, VALUE devicev, VALUE labelv) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "set_e2label"); + + const char *device = StringValueCStr (devicev); + if (!device) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "device", "set_e2label"); + const char *label = StringValueCStr (labelv); + if (!label) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "label", "set_e2label"); + + int r; + + r = guestfs_set_e2label (g, device, label); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + +static VALUE ruby_guestfs_get_e2label (VALUE gv, VALUE devicev) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "get_e2label"); + + const char *device = StringValueCStr (devicev); + if (!device) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "device", "get_e2label"); + + char *r; + + r = guestfs_get_e2label (g, device); + 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_set_e2uuid (VALUE gv, VALUE devicev, VALUE uuidv) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "set_e2uuid"); + + const char *device = StringValueCStr (devicev); + if (!device) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "device", "set_e2uuid"); + const char *uuid = StringValueCStr (uuidv); + if (!uuid) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "uuid", "set_e2uuid"); + + int r; + + r = guestfs_set_e2uuid (g, device, uuid); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + +static VALUE ruby_guestfs_get_e2uuid (VALUE gv, VALUE devicev) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "get_e2uuid"); + + const char *device = StringValueCStr (devicev); + if (!device) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "device", "get_e2uuid"); + + char *r; + + r = guestfs_get_e2uuid (g, device); + 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 () { @@ -2629,4 +2725,12 @@ void Init__guestfs () ruby_guestfs_vgremove, 1); rb_define_method (c_guestfs, "pvremove", ruby_guestfs_pvremove, 1); + rb_define_method (c_guestfs, "set_e2label", + ruby_guestfs_set_e2label, 2); + rb_define_method (c_guestfs, "get_e2label", + ruby_guestfs_get_e2label, 1); + rb_define_method (c_guestfs, "set_e2uuid", + ruby_guestfs_set_e2uuid, 2); + rb_define_method (c_guestfs, "get_e2uuid", + ruby_guestfs_get_e2uuid, 1); } diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index 37dabc07..f39aa75e 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -7191,3 +7191,361 @@ int guestfs_pvremove (guestfs_h *g, return 0; } +struct set_e2label_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; +}; + +static void set_e2label_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct set_e2label_ctx *ctx = (struct set_e2label_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_set_e2label"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_set_e2label"); + 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_set_e2label"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_set_e2label (guestfs_h *g, + const char *device, + const char *label) +{ + struct guestfs_set_e2label_args args; + struct set_e2label_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_set_e2label") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.device = (char *) device; + args.label = (char *) label; + serial = guestfs__send_sync (g, GUESTFS_PROC_SET_E2LABEL, + (xdrproc_t) xdr_guestfs_set_e2label_args, (char *) &args); + if (serial == -1) { + guestfs_set_ready (g); + return -1; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, set_e2label_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_set_e2label"); + guestfs_set_ready (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SET_E2LABEL, serial) == -1) { + guestfs_set_ready (g); + return -1; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + guestfs_set_ready (g); + return -1; + } + + guestfs_set_ready (g); + return 0; +} + +struct get_e2label_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_get_e2label_ret ret; +}; + +static void get_e2label_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct get_e2label_ctx *ctx = (struct get_e2label_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_get_e2label"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_get_e2label"); + 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_get_e2label"); + return; + } + goto done; + } + if (!xdr_guestfs_get_e2label_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_get_e2label"); + return; + } + done: + ctx->cb_sequence = 1; +} + +char *guestfs_get_e2label (guestfs_h *g, + const char *device) +{ + struct guestfs_get_e2label_args args; + struct get_e2label_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_get_e2label") == -1) return NULL; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.device = (char *) device; + serial = guestfs__send_sync (g, GUESTFS_PROC_GET_E2LABEL, + (xdrproc_t) xdr_guestfs_get_e2label_args, (char *) &args); + if (serial == -1) { + guestfs_set_ready (g); + return NULL; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, get_e2label_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_get_e2label"); + guestfs_set_ready (g); + return NULL; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_GET_E2LABEL, serial) == -1) { + guestfs_set_ready (g); + return NULL; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + guestfs_set_ready (g); + return NULL; + } + + guestfs_set_ready (g); + return ctx.ret.label; /* caller will free */ +} + +struct set_e2uuid_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; +}; + +static void set_e2uuid_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct set_e2uuid_ctx *ctx = (struct set_e2uuid_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_set_e2uuid"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_set_e2uuid"); + 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_set_e2uuid"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_set_e2uuid (guestfs_h *g, + const char *device, + const char *uuid) +{ + struct guestfs_set_e2uuid_args args; + struct set_e2uuid_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_set_e2uuid") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.device = (char *) device; + args.uuid = (char *) uuid; + serial = guestfs__send_sync (g, GUESTFS_PROC_SET_E2UUID, + (xdrproc_t) xdr_guestfs_set_e2uuid_args, (char *) &args); + if (serial == -1) { + guestfs_set_ready (g); + return -1; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, set_e2uuid_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_set_e2uuid"); + guestfs_set_ready (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SET_E2UUID, serial) == -1) { + guestfs_set_ready (g); + return -1; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + guestfs_set_ready (g); + return -1; + } + + guestfs_set_ready (g); + return 0; +} + +struct get_e2uuid_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_get_e2uuid_ret ret; +}; + +static void get_e2uuid_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct get_e2uuid_ctx *ctx = (struct get_e2uuid_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_get_e2uuid"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_get_e2uuid"); + 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_get_e2uuid"); + return; + } + goto done; + } + if (!xdr_guestfs_get_e2uuid_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_get_e2uuid"); + return; + } + done: + ctx->cb_sequence = 1; +} + +char *guestfs_get_e2uuid (guestfs_h *g, + const char *device) +{ + struct guestfs_get_e2uuid_args args; + struct get_e2uuid_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_get_e2uuid") == -1) return NULL; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.device = (char *) device; + serial = guestfs__send_sync (g, GUESTFS_PROC_GET_E2UUID, + (xdrproc_t) xdr_guestfs_get_e2uuid_args, (char *) &args); + if (serial == -1) { + guestfs_set_ready (g); + return NULL; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, get_e2uuid_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_get_e2uuid"); + guestfs_set_ready (g); + return NULL; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_GET_E2UUID, serial) == -1) { + guestfs_set_ready (g); + return NULL; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + guestfs_set_ready (g); + return NULL; + } + + guestfs_set_ready (g); + return ctx.ret.uuid; /* caller will free */ +} + diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h index a11a6b27..c8570b01 100644 --- a/src/guestfs-actions.h +++ b/src/guestfs-actions.h @@ -119,3 +119,7 @@ extern char *guestfs_debug (guestfs_h *handle, const char *subcmd, char * const* extern int guestfs_lvremove (guestfs_h *handle, const char *device); extern int guestfs_vgremove (guestfs_h *handle, const char *vgname); extern int guestfs_pvremove (guestfs_h *handle, const char *device); +extern int guestfs_set_e2label (guestfs_h *handle, const char *device, const char *label); +extern char *guestfs_get_e2label (guestfs_h *handle, const char *device); +extern int guestfs_set_e2uuid (guestfs_h *handle, const char *device, const char *uuid); +extern char *guestfs_get_e2uuid (guestfs_h *handle, const char *device); diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c index 2a34a925..c26d5398 100644 --- a/src/guestfs_protocol.c +++ b/src/guestfs_protocol.c @@ -1364,6 +1364,70 @@ xdr_guestfs_pvremove_args (XDR *xdrs, guestfs_pvremove_args *objp) } bool_t +xdr_guestfs_set_e2label_args (XDR *xdrs, guestfs_set_e2label_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + if (!xdr_string (xdrs, &objp->label, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_get_e2label_args (XDR *xdrs, guestfs_get_e2label_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_get_e2label_ret (XDR *xdrs, guestfs_get_e2label_ret *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->label, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_set_e2uuid_args (XDR *xdrs, guestfs_set_e2uuid_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + if (!xdr_string (xdrs, &objp->uuid, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_get_e2uuid_args (XDR *xdrs, guestfs_get_e2uuid_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_get_e2uuid_ret (XDR *xdrs, guestfs_get_e2uuid_ret *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->uuid, ~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 826dc42e..90b0ede9 100644 --- a/src/guestfs_protocol.h +++ b/src/guestfs_protocol.h @@ -707,6 +707,38 @@ struct guestfs_pvremove_args { }; typedef struct guestfs_pvremove_args guestfs_pvremove_args; +struct guestfs_set_e2label_args { + char *device; + char *label; +}; +typedef struct guestfs_set_e2label_args guestfs_set_e2label_args; + +struct guestfs_get_e2label_args { + char *device; +}; +typedef struct guestfs_get_e2label_args guestfs_get_e2label_args; + +struct guestfs_get_e2label_ret { + char *label; +}; +typedef struct guestfs_get_e2label_ret guestfs_get_e2label_ret; + +struct guestfs_set_e2uuid_args { + char *device; + char *uuid; +}; +typedef struct guestfs_set_e2uuid_args guestfs_set_e2uuid_args; + +struct guestfs_get_e2uuid_args { + char *device; +}; +typedef struct guestfs_get_e2uuid_args guestfs_get_e2uuid_args; + +struct guestfs_get_e2uuid_ret { + char *uuid; +}; +typedef struct guestfs_get_e2uuid_ret guestfs_get_e2uuid_ret; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -787,7 +819,11 @@ enum guestfs_procedure { GUESTFS_PROC_LVREMOVE = 77, GUESTFS_PROC_VGREMOVE = 78, GUESTFS_PROC_PVREMOVE = 79, - GUESTFS_PROC_NR_PROCS = 79 + 1, + GUESTFS_PROC_SET_E2LABEL = 80, + GUESTFS_PROC_GET_E2LABEL = 81, + GUESTFS_PROC_SET_E2UUID = 82, + GUESTFS_PROC_GET_E2UUID = 83, + GUESTFS_PROC_NR_PROCS = 83 + 1, }; typedef enum guestfs_procedure guestfs_procedure; #define GUESTFS_MESSAGE_MAX 4194304 @@ -946,6 +982,12 @@ extern bool_t xdr_guestfs_debug_ret (XDR *, guestfs_debug_ret*); extern bool_t xdr_guestfs_lvremove_args (XDR *, guestfs_lvremove_args*); extern bool_t xdr_guestfs_vgremove_args (XDR *, guestfs_vgremove_args*); extern bool_t xdr_guestfs_pvremove_args (XDR *, guestfs_pvremove_args*); +extern bool_t xdr_guestfs_set_e2label_args (XDR *, guestfs_set_e2label_args*); +extern bool_t xdr_guestfs_get_e2label_args (XDR *, guestfs_get_e2label_args*); +extern bool_t xdr_guestfs_get_e2label_ret (XDR *, guestfs_get_e2label_ret*); +extern bool_t xdr_guestfs_set_e2uuid_args (XDR *, guestfs_set_e2uuid_args*); +extern bool_t xdr_guestfs_get_e2uuid_args (XDR *, guestfs_get_e2uuid_args*); +extern bool_t xdr_guestfs_get_e2uuid_ret (XDR *, guestfs_get_e2uuid_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*); @@ -1063,6 +1105,12 @@ extern bool_t xdr_guestfs_debug_ret (); extern bool_t xdr_guestfs_lvremove_args (); extern bool_t xdr_guestfs_vgremove_args (); extern bool_t xdr_guestfs_pvremove_args (); +extern bool_t xdr_guestfs_set_e2label_args (); +extern bool_t xdr_guestfs_get_e2label_args (); +extern bool_t xdr_guestfs_get_e2label_ret (); +extern bool_t xdr_guestfs_set_e2uuid_args (); +extern bool_t xdr_guestfs_get_e2uuid_args (); +extern bool_t xdr_guestfs_get_e2uuid_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 348f3f9c..0cfb8ee2 100644 --- a/src/guestfs_protocol.x +++ b/src/guestfs_protocol.x @@ -547,6 +547,32 @@ struct guestfs_pvremove_args { string device<>; }; +struct guestfs_set_e2label_args { + string device<>; + string label<>; +}; + +struct guestfs_get_e2label_args { + string device<>; +}; + +struct guestfs_get_e2label_ret { + string label<>; +}; + +struct guestfs_set_e2uuid_args { + string device<>; + string uuid<>; +}; + +struct guestfs_get_e2uuid_args { + string device<>; +}; + +struct guestfs_get_e2uuid_ret { + string uuid<>; +}; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -627,6 +653,10 @@ enum guestfs_procedure { GUESTFS_PROC_LVREMOVE = 77, GUESTFS_PROC_VGREMOVE = 78, GUESTFS_PROC_PVREMOVE = 79, + GUESTFS_PROC_SET_E2LABEL = 80, + GUESTFS_PROC_GET_E2LABEL = 81, + GUESTFS_PROC_SET_E2UUID = 82, + GUESTFS_PROC_GET_E2UUID = 83, GUESTFS_PROC_NR_PROCS }; @@ -108,6 +108,309 @@ static void no_test_warnings (void) fprintf (stderr, "warning: \"guestfs_mount_options\" has no tests\n"); fprintf (stderr, "warning: \"guestfs_mount_vfs\" has no tests\n"); fprintf (stderr, "warning: \"guestfs_debug\" has no tests\n"); + fprintf (stderr, "warning: \"guestfs_get_e2label\" has no tests\n"); + fprintf (stderr, "warning: \"guestfs_get_e2uuid\" has no tests\n"); +} + +static int test_set_e2uuid_0 (void) +{ + /* InitBasicFS for set_e2uuid (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutput for set_e2uuid (0) */ + { + int r; + suppress_error = 0; + r = guestfs_set_e2uuid (g, "/dev/sda1", "a3a61220-882b-4f61-89f4-cf24dcc7297d"); + if (r == -1) + return -1; + } + { + char *r; + suppress_error = 0; + r = guestfs_get_e2uuid (g, "/dev/sda1"); + if (r == NULL) + return -1; + if (strcmp (r, "a3a61220-882b-4f61-89f4-cf24dcc7297d") != 0) { + fprintf (stderr, "test_set_e2uuid_0: expected \"a3a61220-882b-4f61-89f4-cf24dcc7297d\" but got \"%s\"\n", r); + return -1; + } + free (r); + } + return 0; +} + +static int test_set_e2uuid_1 (void) +{ + /* InitBasicFS for set_e2uuid (1): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutput for set_e2uuid (1) */ + { + int r; + suppress_error = 0; + r = guestfs_set_e2uuid (g, "/dev/sda1", "clear"); + if (r == -1) + return -1; + } + { + char *r; + suppress_error = 0; + r = guestfs_get_e2uuid (g, "/dev/sda1"); + if (r == NULL) + return -1; + if (strcmp (r, "") != 0) { + fprintf (stderr, "test_set_e2uuid_1: expected \"\" but got \"%s\"\n", r); + return -1; + } + free (r); + } + return 0; +} + +static int test_set_e2uuid_2 (void) +{ + /* InitBasicFS for set_e2uuid (2): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestRun for set_e2uuid (2) */ + { + int r; + suppress_error = 0; + r = guestfs_set_e2uuid (g, "/dev/sda1", "random"); + if (r == -1) + return -1; + } + return 0; +} + +static int test_set_e2uuid_3 (void) +{ + /* InitBasicFS for set_e2uuid (3): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestRun for set_e2uuid (3) */ + { + int r; + suppress_error = 0; + r = guestfs_set_e2uuid (g, "/dev/sda1", "time"); + if (r == -1) + return -1; + } + return 0; +} + +static int test_set_e2label_0 (void) +{ + /* InitBasicFS for set_e2label (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutput for set_e2label (0) */ + { + int r; + suppress_error = 0; + r = guestfs_set_e2label (g, "/dev/sda1", "testlabel"); + if (r == -1) + return -1; + } + { + char *r; + suppress_error = 0; + r = guestfs_get_e2label (g, "/dev/sda1"); + if (r == NULL) + return -1; + if (strcmp (r, "testlabel") != 0) { + fprintf (stderr, "test_set_e2label_0: expected \"testlabel\" but got \"%s\"\n", r); + return -1; + } + free (r); + } + return 0; } static int test_pvremove_0 (void) @@ -6090,9 +6393,39 @@ int main (int argc, char *argv[]) exit (1); } - nr_tests = 85; + nr_tests = 90; test_num++; + printf ("%3d/%3d test_set_e2uuid_0\n", test_num, nr_tests); + if (test_set_e2uuid_0 () == -1) { + printf ("test_set_e2uuid_0 FAILED\n"); + failed++; + } + test_num++; + printf ("%3d/%3d test_set_e2uuid_1\n", test_num, nr_tests); + if (test_set_e2uuid_1 () == -1) { + printf ("test_set_e2uuid_1 FAILED\n"); + failed++; + } + test_num++; + printf ("%3d/%3d test_set_e2uuid_2\n", test_num, nr_tests); + if (test_set_e2uuid_2 () == -1) { + printf ("test_set_e2uuid_2 FAILED\n"); + failed++; + } + test_num++; + printf ("%3d/%3d test_set_e2uuid_3\n", test_num, nr_tests); + if (test_set_e2uuid_3 () == -1) { + printf ("test_set_e2uuid_3 FAILED\n"); + failed++; + } + test_num++; + printf ("%3d/%3d test_set_e2label_0\n", test_num, nr_tests); + if (test_set_e2label_0 () == -1) { + printf ("test_set_e2label_0 FAILED\n"); + failed++; + } + test_num++; printf ("%3d/%3d test_pvremove_0\n", test_num, nr_tests); if (test_pvremove_0 () == -1) { printf ("test_pvremove_0 FAILED\n"); |