diff options
author | Richard Jones <rjones@redhat.com> | 2009-05-18 17:16:24 +0100 |
---|---|---|
committer | Richard Jones <rjones@redhat.com> | 2009-05-18 17:16:24 +0100 |
commit | 85ed8cef99c19b4143844991d14e0b848fecc5da (patch) | |
tree | 61e34886d4ec4b59a37c8e4ab6779e7ef7834f34 | |
parent | adf0974245af914c46b48766d0efdd5ee8608dda (diff) | |
download | libguestfs-85ed8cef99c19b4143844991d14e0b848fecc5da.tar.gz libguestfs-85ed8cef99c19b4143844991d14e0b848fecc5da.tar.xz libguestfs-85ed8cef99c19b4143844991d14e0b848fecc5da.zip |
Add vg-activate{,-all} commands, and resize recipe.
-rw-r--r-- | TODO | 22 | ||||
-rw-r--r-- | daemon/actions.h | 2 | ||||
-rw-r--r-- | daemon/lvm.c | 39 | ||||
-rw-r--r-- | daemon/sfdisk.c | 5 | ||||
-rw-r--r-- | daemon/stubs.c | 63 | ||||
-rw-r--r-- | fish/cmds.c | 44 | ||||
-rw-r--r-- | fish/completion.c | 2 | ||||
-rw-r--r-- | guestfish-actions.pod | 27 | ||||
-rw-r--r-- | guestfs-actions.pod | 34 | ||||
-rw-r--r-- | java/com/redhat/et/libguestfs/GuestFS.java | 50 | ||||
-rw-r--r-- | java/com_redhat_et_libguestfs_GuestFS.c | 47 | ||||
-rw-r--r-- | ocaml/guestfs.ml | 2 | ||||
-rw-r--r-- | ocaml/guestfs.mli | 6 | ||||
-rw-r--r-- | ocaml/guestfs_c_actions.c | 48 | ||||
-rw-r--r-- | perl/Guestfs.xs | 24 | ||||
-rw-r--r-- | perl/lib/Sys/Guestfs.pm | 23 | ||||
-rw-r--r-- | python/guestfs-py.c | 57 | ||||
-rw-r--r-- | python/guestfs.py | 26 | ||||
-rw-r--r-- | recipes/resize.html | 19 | ||||
-rwxr-xr-x | recipes/resize.sh | 35 | ||||
-rw-r--r-- | recipes/resize.title | 1 | ||||
-rw-r--r-- | ruby/ext/guestfs/_guestfs.c | 51 | ||||
-rwxr-xr-x | src/generator.ml | 27 | ||||
-rw-r--r-- | src/guestfs-actions.c | 177 | ||||
-rw-r--r-- | src/guestfs-actions.h | 2 | ||||
-rw-r--r-- | src/guestfs_protocol.c | 23 | ||||
-rw-r--r-- | src/guestfs_protocol.h | 22 | ||||
-rw-r--r-- | src/guestfs_protocol.x | 11 | ||||
-rw-r--r-- | tests.c | 2 |
29 files changed, 867 insertions, 24 deletions
@@ -27,25 +27,3 @@ Implement febootstrap command. ---------------------------------------------------------------------- Complete the Haskell bindings (see discussion on haskell-cafe). - ----------------------------------------------------------------------- - -Practically, resizing the partitions when a block device is resized -isn't possible. So for example it's not possible to resize a Fedora -block device. If you try to use sfdisk-N to change the boundaries of -the existing partition to fill up the new space, you get an error that -the partition is in use. - -The reason, I now think, is because LVM is using the partition as a -PV, and this locks it as far as the kernel is concerned. - -Removing the PV [which is what we do in the test suite] isn't -desirable if the PV contains data you care about. Rebooting the qemu -subprocess after the partition table change works, but isn't very -cool. I believe what we need to do is to temporarily reconfigure LVM -(using /etc/lvm/lvm.conf) to ignore the PV, vgscan (which will then -ignore the PV), make the changes to the partition table, then set the -LVM configuration back and do a final vgscan. - -Need to test the above, and find a nice way to present it through -the API. diff --git a/daemon/actions.h b/daemon/actions.h index 3e6589e2..dcffd2a2 100644 --- a/daemon/actions.h +++ b/daemon/actions.h @@ -123,3 +123,5 @@ extern int do_sfdisk_N (const char *device, int n, int cyls, int heads, int sect extern char *do_sfdisk_l (const char *device); extern char *do_sfdisk_kernel_geometry (const char *device); extern char *do_sfdisk_disk_geometry (const char *device); +extern int do_vg_activate_all (int activate); +extern int do_vg_activate (int activate, char * const* const volgroups); diff --git a/daemon/lvm.c b/daemon/lvm.c index d1a6cd60..63a3e7e5 100644 --- a/daemon/lvm.c +++ b/daemon/lvm.c @@ -376,3 +376,42 @@ do_pvresize (const char *device) free (err); return 0; } + +int +do_vg_activate (int activate, char * const* const volgroups) +{ + char *err; + int r, i, argc; + const char **argv; + + argc = count_strings (volgroups) + 4; + argv = malloc (sizeof (char *) * (argc+1)); + if (argv == NULL) { + reply_with_perror ("malloc"); + return -1; + } + + argv[0] = "/sbin/lvm"; + argv[1] = "vgchange"; + argv[2] = "-a"; + argv[3] = activate ? "y" : "n"; + for (i = 4; i <= argc; ++i) + argv[i] = volgroups[i-4]; + + r = commandv (NULL, &err, argv); + if (r == -1) { + reply_with_error ("vgchange: %s", err); + free (err); + return -1; + } + + free (err); + return 0; +} + +int +do_vg_activate_all (int activate) +{ + char *empty[] = { NULL }; + return do_vg_activate (activate, empty); +} diff --git a/daemon/sfdisk.c b/daemon/sfdisk.c index 9d7a220f..2f5206ed 100644 --- a/daemon/sfdisk.c +++ b/daemon/sfdisk.c @@ -39,7 +39,7 @@ sfdisk (const char *device, int n, int cyls, int heads, int sectors, IS_DEVICE (device, -1); - strcpy (buf, "/sbin/sfdisk --no-reread"); + strcpy (buf, "/sbin/sfdisk"); if (n > 0) sprintf (buf + strlen (buf), " -N %d", n); if (cyls) @@ -51,6 +51,9 @@ sfdisk (const char *device, int n, int cyls, int heads, int sectors, /* Safe because of IS_DEVICE above: */ sprintf (buf + strlen (buf), " %s", device); + if (verbose) + printf ("%s\n", buf); + fp = popen (buf, "w"); if (fp == NULL) { reply_with_perror (buf); diff --git a/daemon/stubs.c b/daemon/stubs.c index e80ba9be..2fd2da93 100644 --- a/daemon/stubs.c +++ b/daemon/stubs.c @@ -2560,6 +2560,63 @@ done: xdr_free ((xdrproc_t) xdr_guestfs_sfdisk_disk_geometry_args, (char *) &args); } +static void vg_activate_all_stub (XDR *xdr_in) +{ + int r; + struct guestfs_vg_activate_all_args args; + int activate; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_vg_activate_all_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "vg_activate_all"); + return; + } + activate = args.activate; + + r = do_vg_activate_all (activate); + if (r == -1) + /* do_vg_activate_all has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_vg_activate_all_args, (char *) &args); +} + +static void vg_activate_stub (XDR *xdr_in) +{ + int r; + struct guestfs_vg_activate_args args; + int activate; + char **volgroups; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_vg_activate_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "vg_activate"); + return; + } + activate = args.activate; + volgroups = realloc (args.volgroups.volgroups_val, + sizeof (char *) * (args.volgroups.volgroups_len+1)); + if (volgroups == NULL) { + reply_with_perror ("realloc"); + goto done; + } + volgroups[args.volgroups.volgroups_len] = NULL; + args.volgroups.volgroups_val = volgroups; + + r = do_vg_activate (activate, volgroups); + if (r == -1) + /* do_vg_activate has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_vg_activate_args, (char *) &args); +} + void dispatch_incoming_message (XDR *xdr_in) { switch (proc_nr) { @@ -2869,6 +2926,12 @@ void dispatch_incoming_message (XDR *xdr_in) case GUESTFS_PROC_SFDISK_DISK_GEOMETRY: sfdisk_disk_geometry_stub (xdr_in); break; + case GUESTFS_PROC_VG_ACTIVATE_ALL: + vg_activate_all_stub (xdr_in); + break; + case GUESTFS_PROC_VG_ACTIVATE: + vg_activate_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 5680bfa3..8d50021e 100644 --- a/fish/cmds.c +++ b/fish/cmds.c @@ -146,6 +146,8 @@ void list_commands (void) printf ("%-20s %s\n", "umount", "unmount a filesystem"); printf ("%-20s %s\n", "umount-all", "unmount all filesystems"); printf ("%-20s %s\n", "upload", "upload a file from the local machine"); + printf ("%-20s %s\n", "vg-activate", "activate or deactivate some volume groups"); + printf ("%-20s %s\n", "vg-activate-all", "activate or deactivate all volume groups"); printf ("%-20s %s\n", "vgcreate", "create an LVM volume group"); printf ("%-20s %s\n", "vgremove", "remove an LVM volume group"); printf ("%-20s %s\n", "vgs", "list the LVM volume groups (VGs)"); @@ -524,6 +526,12 @@ void display_command (const char *cmd) if (strcasecmp (cmd, "sfdisk_disk_geometry") == 0 || strcasecmp (cmd, "sfdisk-disk-geometry") == 0) pod2text ("sfdisk-disk-geometry - display the disk geometry from the partition table", " sfdisk-disk-geometry <device>\n\nThis displays the disk geometry of C<device> read from the\npartition table. Especially in the case where the underlying\nblock device has been resized, this can be different from the\nkernel's idea of the geometry (see C<sfdisk_kernel_geometry>).\n\nThe result is in human-readable format, and not designed to\nbe parsed."); else + if (strcasecmp (cmd, "vg_activate_all") == 0 || strcasecmp (cmd, "vg-activate-all") == 0) + pod2text ("vg-activate-all - activate or deactivate all volume groups", " vg-activate-all <activate>\n\nThis command activates or (if C<activate> is false) deactivates\nall logical volumes in all volume groups.\nIf activated, then they are made known to the\nkernel, ie. they appear as C</dev/mapper> devices. If deactivated,\nthen those devices disappear.\n\nThis command is the same as running C<vgchange -a y|n>"); + else + if (strcasecmp (cmd, "vg_activate") == 0 || strcasecmp (cmd, "vg-activate") == 0) + pod2text ("vg-activate - activate or deactivate some volume groups", " vg-activate <activate> <volgroups>\n\nThis command activates or (if C<activate> is false) deactivates\nall logical volumes in the listed volume groups C<volgroups>.\nIf activated, then they are made known to the\nkernel, ie. they appear as C</dev/mapper> devices. If deactivated,\nthen those devices disappear.\n\nThis command is the same as running C<vgchange -a y|n volgroups...>\n\nNote that if C<volgroups> is an empty list then B<all> volume groups\nare activated or deactivated."); + else display_builtin_command (cmd); } @@ -2565,6 +2573,36 @@ static int run_sfdisk_disk_geometry (const char *cmd, int argc, char *argv[]) return 0; } +static int run_vg_activate_all (const char *cmd, int argc, char *argv[]) +{ + int r; + int activate; + 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; + } + activate = is_true (argv[0]) ? 1 : 0; + r = guestfs_vg_activate_all (g, activate); + return r; +} + +static int run_vg_activate (const char *cmd, int argc, char *argv[]) +{ + int r; + int activate; + char **volgroups; + 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; + } + activate = is_true (argv[0]) ? 1 : 0; + volgroups = parse_string_list (argv[1]); + r = guestfs_vg_activate (g, activate, volgroups); + return r; +} + int run_action (const char *cmd, int argc, char *argv[]) { if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0) @@ -2933,6 +2971,12 @@ int run_action (const char *cmd, int argc, char *argv[]) if (strcasecmp (cmd, "sfdisk_disk_geometry") == 0 || strcasecmp (cmd, "sfdisk-disk-geometry") == 0) return run_sfdisk_disk_geometry (cmd, argc, argv); else + if (strcasecmp (cmd, "vg_activate_all") == 0 || strcasecmp (cmd, "vg-activate-all") == 0) + return run_vg_activate_all (cmd, argc, argv); + else + if (strcasecmp (cmd, "vg_activate") == 0 || strcasecmp (cmd, "vg-activate") == 0) + return run_vg_activate (cmd, argc, argv); + else { fprintf (stderr, "%s: unknown command\n", cmd); return -1; diff --git a/fish/completion.c b/fish/completion.c index 03760ad6..a072ce36 100644 --- a/fish/completion.c +++ b/fish/completion.c @@ -159,6 +159,8 @@ static const char *const commands[] = { "unmount-all", "upload", "verbose", + "vg-activate", + "vg-activate-all", "vgcreate", "vgremove", "vgs", diff --git a/guestfish-actions.pod b/guestfish-actions.pod index 213fa66e..7e33cbbe 100644 --- a/guestfish-actions.pod +++ b/guestfish-actions.pod @@ -1268,6 +1268,33 @@ See also C<download>. Use C<-> instead of a filename to read/write from stdin/stdout. +=head2 vg-activate + + vg-activate true|false 'volgroups ...' + +This command activates or (if C<activate> is false) deactivates +all logical volumes in the listed volume groups C<volgroups>. +If activated, then they are made known to the +kernel, ie. they appear as C</dev/mapper> devices. If deactivated, +then those devices disappear. + +This command is the same as running C<vgchange -a y|n volgroups...> + +Note that if C<volgroups> is an empty list then B<all> volume groups +are activated or deactivated. + +=head2 vg-activate-all + + vg-activate-all true|false + +This command activates or (if C<activate> is false) deactivates +all logical volumes in all volume groups. +If activated, then they are made known to the +kernel, ie. they appear as C</dev/mapper> devices. If deactivated, +then those devices disappear. + +This command is the same as running C<vgchange -a y|n> + =head2 vgcreate vgcreate volgroup 'physvols ...' diff --git a/guestfs-actions.pod b/guestfs-actions.pod index abeed8ff..9ed1cce4 100644 --- a/guestfs-actions.pod +++ b/guestfs-actions.pod @@ -1719,6 +1719,40 @@ See also C<guestfs_download>. This function returns 0 on success or -1 on error. +=head2 guestfs_vg_activate + + int guestfs_vg_activate (guestfs_h *handle, + int activate, + char * const* const volgroups); + +This command activates or (if C<activate> is false) deactivates +all logical volumes in the listed volume groups C<volgroups>. +If activated, then they are made known to the +kernel, ie. they appear as C</dev/mapper> devices. If deactivated, +then those devices disappear. + +This command is the same as running C<vgchange -a y|n volgroups...> + +Note that if C<volgroups> is an empty list then B<all> volume groups +are activated or deactivated. + +This function returns 0 on success or -1 on error. + +=head2 guestfs_vg_activate_all + + int guestfs_vg_activate_all (guestfs_h *handle, + int activate); + +This command activates or (if C<activate> is false) deactivates +all logical volumes in all volume groups. +If activated, then they are made known to the +kernel, ie. they appear as C</dev/mapper> devices. If deactivated, +then those devices disappear. + +This command is the same as running C<vgchange -a y|n> + +This function returns 0 on success or -1 on error. + =head2 guestfs_vgcreate int guestfs_vgcreate (guestfs_h *handle, diff --git a/java/com/redhat/et/libguestfs/GuestFS.java b/java/com/redhat/et/libguestfs/GuestFS.java index 7eafce0f..a6d6f6db 100644 --- a/java/com/redhat/et/libguestfs/GuestFS.java +++ b/java/com/redhat/et/libguestfs/GuestFS.java @@ -2864,4 +2864,54 @@ public class GuestFS { private native String _sfdisk_disk_geometry (long g, String device) throws LibGuestFSException; + /** + * activate or deactivate all volume groups + * + * This command activates or (if "activate" is false) + * deactivates all logical volumes in all volume groups. If + * activated, then they are made known to the kernel, ie. + * they appear as "/dev/mapper" devices. If deactivated, + * then those devices disappear. + * + * This command is the same as running "vgchange -a y|n" + * + * @throws LibGuestFSException + */ + public void vg_activate_all (boolean activate) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("vg_activate_all: handle is closed"); + _vg_activate_all (g, activate); + } + private native void _vg_activate_all (long g, boolean activate) + throws LibGuestFSException; + + /** + * activate or deactivate some volume groups + * + * This command activates or (if "activate" is false) + * deactivates all logical volumes in the listed volume + * groups "volgroups". If activated, then they are made + * known to the kernel, ie. they appear as "/dev/mapper" + * devices. If deactivated, then those devices disappear. + * + * This command is the same as running "vgchange -a y|n + * volgroups..." + * + * Note that if "volgroups" is an empty list then all + * volume groups are activated or deactivated. + * + * @throws LibGuestFSException + */ + public void vg_activate (boolean activate, String[] volgroups) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("vg_activate: handle is closed"); + _vg_activate (g, activate, volgroups); + } + private native void _vg_activate (long g, boolean activate, String[] volgroups) + throws LibGuestFSException; + } diff --git a/java/com_redhat_et_libguestfs_GuestFS.c b/java/com_redhat_et_libguestfs_GuestFS.c index be7ea9f2..3bf5c7e5 100644 --- a/java/com_redhat_et_libguestfs_GuestFS.c +++ b/java/com_redhat_et_libguestfs_GuestFS.c @@ -2847,3 +2847,50 @@ Java_com_redhat_et_libguestfs_GuestFS__1sfdisk_1disk_1geometry return jr; } +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1vg_1activate_1all + (JNIEnv *env, jobject obj, jlong jg, jboolean jactivate) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + int activate; + + activate = jactivate; + r = guestfs_vg_activate_all (g, activate); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1vg_1activate + (JNIEnv *env, jobject obj, jlong jg, jboolean jactivate, jobjectArray jvolgroups) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + int activate; + int volgroups_len; + const char **volgroups; + int i; + + activate = jactivate; + volgroups_len = (*env)->GetArrayLength (env, jvolgroups); + volgroups = guestfs_safe_malloc (g, sizeof (char *) * (volgroups_len+1)); + for (i = 0; i < volgroups_len; ++i) { + jobject o = (*env)->GetObjectArrayElement (env, jvolgroups, i); + volgroups[i] = (*env)->GetStringUTFChars (env, o, NULL); + } + volgroups[volgroups_len] = NULL; + r = guestfs_vg_activate (g, activate, volgroups); + for (i = 0; i < volgroups_len; ++i) { + jobject o = (*env)->GetObjectArrayElement (env, jvolgroups, i); + (*env)->ReleaseStringUTFChars (env, o, volgroups[i]); + } + free (volgroups); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + diff --git a/ocaml/guestfs.ml b/ocaml/guestfs.ml index d50b2d8c..fa60a7bb 100644 --- a/ocaml/guestfs.ml +++ b/ocaml/guestfs.ml @@ -241,3 +241,5 @@ external sfdisk_N : t -> string -> int -> int -> int -> int -> string -> unit = external sfdisk_l : t -> string -> string = "ocaml_guestfs_sfdisk_l" external sfdisk_kernel_geometry : t -> string -> string = "ocaml_guestfs_sfdisk_kernel_geometry" external sfdisk_disk_geometry : t -> string -> string = "ocaml_guestfs_sfdisk_disk_geometry" +external vg_activate_all : t -> bool -> unit = "ocaml_guestfs_vg_activate_all" +external vg_activate : t -> bool -> string array -> unit = "ocaml_guestfs_vg_activate" diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli index 358a6d30..5ce91220 100644 --- a/ocaml/guestfs.mli +++ b/ocaml/guestfs.mli @@ -502,3 +502,9 @@ val sfdisk_kernel_geometry : t -> string -> string val sfdisk_disk_geometry : t -> string -> string (** display the disk geometry from the partition table *) +val vg_activate_all : t -> bool -> unit +(** activate or deactivate all volume groups *) + +val vg_activate : t -> bool -> string array -> unit +(** activate or deactivate some volume groups *) + diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c index f2d13b03..f0aa7e23 100644 --- a/ocaml/guestfs_c_actions.c +++ b/ocaml/guestfs_c_actions.c @@ -3331,3 +3331,51 @@ ocaml_guestfs_sfdisk_disk_geometry (value gv, value devicev) CAMLreturn (rv); } +CAMLprim value +ocaml_guestfs_vg_activate_all (value gv, value activatev) +{ + CAMLparam2 (gv, activatev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("vg_activate_all: used handle after closing it"); + + int activate = Bool_val (activatev); + int r; + + caml_enter_blocking_section (); + r = guestfs_vg_activate_all (g, activate); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "vg_activate_all"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_vg_activate (value gv, value activatev, value volgroupsv) +{ + CAMLparam3 (gv, activatev, volgroupsv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("vg_activate: used handle after closing it"); + + int activate = Bool_val (activatev); + char **volgroups = ocaml_guestfs_strings_val (g, volgroupsv); + int r; + + caml_enter_blocking_section (); + r = guestfs_vg_activate (g, activate, volgroups); + caml_leave_blocking_section (); + ocaml_guestfs_free_strings (volgroups); + if (r == -1) + ocaml_guestfs_raise_error (g, "vg_activate"); + + rv = Val_unit; + CAMLreturn (rv); +} + diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs index ff7ca9e1..374a40d1 100644 --- a/perl/Guestfs.xs +++ b/perl/Guestfs.xs @@ -1870,3 +1870,27 @@ PREINIT: OUTPUT: RETVAL +void +vg_activate_all (g, activate) + guestfs_h *g; + int activate; +PREINIT: + int r; + PPCODE: + r = guestfs_vg_activate_all (g, activate); + if (r == -1) + croak ("vg_activate_all: %s", guestfs_last_error (g)); + +void +vg_activate (g, activate, volgroups) + guestfs_h *g; + int activate; + char **volgroups; +PREINIT: + int r; + PPCODE: + r = guestfs_vg_activate (g, activate, volgroups); + free (volgroups); + if (r == -1) + croak ("vg_activate: %s", guestfs_last_error (g)); + diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm index 0249a412..0e4dde4d 100644 --- a/perl/lib/Sys/Guestfs.pm +++ b/perl/lib/Sys/Guestfs.pm @@ -1141,6 +1141,29 @@ C<filename> can also be a named pipe. See also C<$h-E<gt>download>. +=item $h->vg_activate ($activate, \@volgroups); + +This command activates or (if C<activate> is false) deactivates +all logical volumes in the listed volume groups C<volgroups>. +If activated, then they are made known to the +kernel, ie. they appear as C</dev/mapper> devices. If deactivated, +then those devices disappear. + +This command is the same as running C<vgchange -a y|n volgroups...> + +Note that if C<volgroups> is an empty list then B<all> volume groups +are activated or deactivated. + +=item $h->vg_activate_all ($activate); + +This command activates or (if C<activate> is false) deactivates +all logical volumes in all volume groups. +If activated, then they are made known to the +kernel, ie. they appear as C</dev/mapper> devices. If deactivated, +then those devices disappear. + +This command is the same as running C<vgchange -a y|n> + =item $h->vgcreate ($volgroup, \@physvols); This creates an LVM volume group called C<volgroup> diff --git a/python/guestfs-py.c b/python/guestfs-py.c index 140594d2..e967bd94 100644 --- a/python/guestfs-py.c +++ b/python/guestfs-py.c @@ -3557,6 +3557,61 @@ py_guestfs_sfdisk_disk_geometry (PyObject *self, PyObject *args) return py_r; } +static PyObject * +py_guestfs_vg_activate_all (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + int activate; + + if (!PyArg_ParseTuple (args, (char *) "Oi:guestfs_vg_activate_all", + &py_g, &activate)) + return NULL; + g = get_handle (py_g); + + r = guestfs_vg_activate_all (g, activate); + 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_vg_activate (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + int activate; + PyObject *py_volgroups; + const char **volgroups; + + if (!PyArg_ParseTuple (args, (char *) "OiO:guestfs_vg_activate", + &py_g, &activate, &py_volgroups)) + return NULL; + g = get_handle (py_g); + volgroups = get_string_list (py_volgroups); + if (!volgroups) return NULL; + + r = guestfs_vg_activate (g, activate, volgroups); + free (volgroups); + 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 PyMethodDef methods[] = { { (char *) "create", py_guestfs_create, METH_VARARGS, NULL }, { (char *) "close", py_guestfs_close, METH_VARARGS, NULL }, @@ -3686,6 +3741,8 @@ static PyMethodDef methods[] = { { (char *) "sfdisk_l", py_guestfs_sfdisk_l, METH_VARARGS, NULL }, { (char *) "sfdisk_kernel_geometry", py_guestfs_sfdisk_kernel_geometry, METH_VARARGS, NULL }, { (char *) "sfdisk_disk_geometry", py_guestfs_sfdisk_disk_geometry, METH_VARARGS, NULL }, + { (char *) "vg_activate_all", py_guestfs_vg_activate_all, METH_VARARGS, NULL }, + { (char *) "vg_activate", py_guestfs_vg_activate, METH_VARARGS, NULL }, { NULL, NULL, 0, NULL } }; diff --git a/python/guestfs.py b/python/guestfs.py index 8ac4037c..4a2804b4 100644 --- a/python/guestfs.py +++ b/python/guestfs.py @@ -1397,3 +1397,29 @@ class GuestFS: """ return libguestfsmod.sfdisk_disk_geometry (self._o, device) + def vg_activate_all (self, activate): + u"""This command activates or (if "activate" is false) + deactivates all logical volumes in all volume groups. If + activated, then they are made known to the kernel, ie. + they appear as "/dev/mapper" devices. If deactivated, + then those devices disappear. + + This command is the same as running "vgchange -a y|n" + """ + return libguestfsmod.vg_activate_all (self._o, activate) + + def vg_activate (self, activate, volgroups): + u"""This command activates or (if "activate" is false) + deactivates all logical volumes in the listed volume + groups "volgroups". If activated, then they are made + known to the kernel, ie. they appear as "/dev/mapper" + devices. If deactivated, then those devices disappear. + + This command is the same as running "vgchange -a y|n + volgroups..." + + Note that if "volgroups" is an empty list then all + volume groups are activated or deactivated. + """ + return libguestfsmod.vg_activate (self._o, activate, volgroups) + diff --git a/recipes/resize.html b/recipes/resize.html new file mode 100644 index 00000000..1a0ca3bb --- /dev/null +++ b/recipes/resize.html @@ -0,0 +1,19 @@ +<p> +This example shows how a block device containing a partition +and a physical volume can be resized. +</p> + +<p> +If you try this out, you +may find that attempts to repartition the disk fail because the +disk is locked by the LVM devices which exist on it. You have +to deactivate (temporarily) the volume groups, perform the +fdisk, and then activate them again. +</p> + +<p> +This example script is self-contained. It first creates a +block device (a temporary file) containing some LVs, then it extends +the temporary file, and shows how to deactivate volgroups, repartition, +and activate them again. +</p> diff --git a/recipes/resize.sh b/recipes/resize.sh new file mode 100755 index 00000000..17a7e770 --- /dev/null +++ b/recipes/resize.sh @@ -0,0 +1,35 @@ +#!/bin/sh - + +guestfish <<EOF +alloc test.img 130M +run +# You can uncomment the following to see the +# geometry (CHS), which is needed to repartition. +#sfdisk-disk-geometry /dev/sda +sfdisk /dev/sda 0 0 0 , +pvcreate /dev/sda1 +vgcreate VG /dev/sda1 +lvcreate LV1 VG 32M +lvcreate LV2 VG 32M +lvcreate LV3 VG 32M +sync +EOF + +truncate --size=260M test.img + +guestfish -a test.img <<EOF +run +# Turn off the VGs before we can repartition. +vg-activate-all false +sfdisk-N /dev/sda 1 32 255 63 0,31 +vg-activate-all true + +pvresize /dev/sda1 + +# The following command would fail if the +# partition or PV hadn't been resized: +lvcreate LV4 VG 64M + +echo New LV list: +lvs +EOF
\ No newline at end of file diff --git a/recipes/resize.title b/recipes/resize.title new file mode 100644 index 00000000..cc2f3a23 --- /dev/null +++ b/recipes/resize.title @@ -0,0 +1 @@ +Repartition and resize a block device
\ No newline at end of file diff --git a/ruby/ext/guestfs/_guestfs.c b/ruby/ext/guestfs/_guestfs.c index b5c9b53a..c57dcb3a 100644 --- a/ruby/ext/guestfs/_guestfs.c +++ b/ruby/ext/guestfs/_guestfs.c @@ -3025,6 +3025,53 @@ static VALUE ruby_guestfs_sfdisk_disk_geometry (VALUE gv, VALUE devicev) return rv; } +static VALUE ruby_guestfs_vg_activate_all (VALUE gv, VALUE activatev) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "vg_activate_all"); + + int activate = NUM2INT (activatev); + + int r; + + r = guestfs_vg_activate_all (g, activate); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + +static VALUE ruby_guestfs_vg_activate (VALUE gv, VALUE activatev, VALUE volgroupsv) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "vg_activate"); + + int activate = NUM2INT (activatev); + char **volgroups; { + int i, len; + len = RARRAY_LEN (volgroupsv); + volgroups = guestfs_safe_malloc (g, sizeof (char *) * (len+1)); + for (i = 0; i < len; ++i) { + VALUE v = rb_ary_entry (volgroupsv, i); + volgroups[i] = StringValueCStr (v); + } + volgroups[len] = NULL; + } + + int r; + + r = guestfs_vg_activate (g, activate, volgroups); + free (volgroups); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + /* Initialize the module. */ void Init__guestfs () { @@ -3287,4 +3334,8 @@ void Init__guestfs () ruby_guestfs_sfdisk_kernel_geometry, 1); rb_define_method (c_guestfs, "sfdisk_disk_geometry", ruby_guestfs_sfdisk_disk_geometry, 1); + rb_define_method (c_guestfs, "vg_activate_all", + ruby_guestfs_vg_activate_all, 1); + rb_define_method (c_guestfs, "vg_activate", + ruby_guestfs_vg_activate, 2); } diff --git a/src/generator.ml b/src/generator.ml index 19dc20d5..5717f9b6 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -2069,6 +2069,33 @@ kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>). The result is in human-readable format, and not designed to be parsed."); + ("vg_activate_all", (RErr, [Bool "activate"]), 103, [], + [], + "activate or deactivate all volume groups", + "\ +This command activates or (if C<activate> is false) deactivates +all logical volumes in all volume groups. +If activated, then they are made known to the +kernel, ie. they appear as C</dev/mapper> devices. If deactivated, +then those devices disappear. + +This command is the same as running C<vgchange -a y|n>"); + + ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [], + [], + "activate or deactivate some volume groups", + "\ +This command activates or (if C<activate> is false) deactivates +all logical volumes in the listed volume groups C<volgroups>. +If activated, then they are made known to the +kernel, ie. they appear as C</dev/mapper> devices. If deactivated, +then those devices disappear. + +This command is the same as running C<vgchange -a y|n volgroups...> + +Note that if C<volgroups> is an empty list then B<all> volume groups +are activated or deactivated."); + ] let all_functions = non_daemon_functions @ daemon_functions diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index 49e8961d..41d873f9 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -9356,3 +9356,180 @@ char *guestfs_sfdisk_disk_geometry (guestfs_h *g, return ctx.ret.partitions; /* caller will free */ } +struct vg_activate_all_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 vg_activate_all_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct vg_activate_all_ctx *ctx = (struct vg_activate_all_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_vg_activate_all"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_vg_activate_all"); + 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_vg_activate_all"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_vg_activate_all (guestfs_h *g, + int activate) +{ + struct guestfs_vg_activate_all_args args; + struct vg_activate_all_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_vg_activate_all") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.activate = activate; + serial = guestfs__send_sync (g, GUESTFS_PROC_VG_ACTIVATE_ALL, + (xdrproc_t) xdr_guestfs_vg_activate_all_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (g); + return -1; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, vg_activate_all_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_vg_activate_all"); + guestfs_end_busy (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VG_ACTIVATE_ALL, serial) == -1) { + guestfs_end_busy (g); + return -1; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return -1; + } + + guestfs_end_busy (g); + return 0; +} + +struct vg_activate_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 vg_activate_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct vg_activate_ctx *ctx = (struct vg_activate_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_vg_activate"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_vg_activate"); + 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_vg_activate"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_vg_activate (guestfs_h *g, + int activate, + char * const* const volgroups) +{ + struct guestfs_vg_activate_args args; + struct vg_activate_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_vg_activate") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.activate = activate; + args.volgroups.volgroups_val = (char **) volgroups; + for (args.volgroups.volgroups_len = 0; volgroups[args.volgroups.volgroups_len]; args.volgroups.volgroups_len++) ; + serial = guestfs__send_sync (g, GUESTFS_PROC_VG_ACTIVATE, + (xdrproc_t) xdr_guestfs_vg_activate_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (g); + return -1; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, vg_activate_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_vg_activate"); + guestfs_end_busy (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_VG_ACTIVATE, serial) == -1) { + guestfs_end_busy (g); + return -1; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return -1; + } + + guestfs_end_busy (g); + return 0; +} + diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h index b07e3dd5..3c760f23 100644 --- a/src/guestfs-actions.h +++ b/src/guestfs-actions.h @@ -145,3 +145,5 @@ extern int guestfs_sfdisk_N (guestfs_h *handle, const char *device, int n, int c extern char *guestfs_sfdisk_l (guestfs_h *handle, const char *device); extern char *guestfs_sfdisk_kernel_geometry (guestfs_h *handle, const char *device); extern char *guestfs_sfdisk_disk_geometry (guestfs_h *handle, const char *device); +extern int guestfs_vg_activate_all (guestfs_h *handle, int activate); +extern int guestfs_vg_activate (guestfs_h *handle, int activate, char * const* const volgroups); diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c index e6e865e6..0a3fddc0 100644 --- a/src/guestfs_protocol.c +++ b/src/guestfs_protocol.c @@ -1763,6 +1763,29 @@ xdr_guestfs_sfdisk_disk_geometry_ret (XDR *xdrs, guestfs_sfdisk_disk_geometry_re } bool_t +xdr_guestfs_vg_activate_all_args (XDR *xdrs, guestfs_vg_activate_all_args *objp) +{ + register int32_t *buf; + + if (!xdr_bool (xdrs, &objp->activate)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_vg_activate_args (XDR *xdrs, guestfs_vg_activate_args *objp) +{ + register int32_t *buf; + + if (!xdr_bool (xdrs, &objp->activate)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->volgroups.volgroups_val, (u_int *) &objp->volgroups.volgroups_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 62355774..25ed3529 100644 --- a/src/guestfs_protocol.h +++ b/src/guestfs_protocol.h @@ -887,6 +887,20 @@ struct guestfs_sfdisk_disk_geometry_ret { }; typedef struct guestfs_sfdisk_disk_geometry_ret guestfs_sfdisk_disk_geometry_ret; +struct guestfs_vg_activate_all_args { + bool_t activate; +}; +typedef struct guestfs_vg_activate_all_args guestfs_vg_activate_all_args; + +struct guestfs_vg_activate_args { + bool_t activate; + struct { + u_int volgroups_len; + str *volgroups_val; + } volgroups; +}; +typedef struct guestfs_vg_activate_args guestfs_vg_activate_args; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -990,7 +1004,9 @@ enum guestfs_procedure { GUESTFS_PROC_SFDISK_L = 100, GUESTFS_PROC_SFDISK_KERNEL_GEOMETRY = 101, GUESTFS_PROC_SFDISK_DISK_GEOMETRY = 102, - GUESTFS_PROC_NR_PROCS = 102 + 1, + GUESTFS_PROC_VG_ACTIVATE_ALL = 103, + GUESTFS_PROC_VG_ACTIVATE = 104, + GUESTFS_PROC_NR_PROCS = 104 + 1, }; typedef enum guestfs_procedure guestfs_procedure; #define GUESTFS_MESSAGE_MAX 4194304 @@ -1181,6 +1197,8 @@ extern bool_t xdr_guestfs_sfdisk_kernel_geometry_args (XDR *, guestfs_sfdisk_ke extern bool_t xdr_guestfs_sfdisk_kernel_geometry_ret (XDR *, guestfs_sfdisk_kernel_geometry_ret*); extern bool_t xdr_guestfs_sfdisk_disk_geometry_args (XDR *, guestfs_sfdisk_disk_geometry_args*); extern bool_t xdr_guestfs_sfdisk_disk_geometry_ret (XDR *, guestfs_sfdisk_disk_geometry_ret*); +extern bool_t xdr_guestfs_vg_activate_all_args (XDR *, guestfs_vg_activate_all_args*); +extern bool_t xdr_guestfs_vg_activate_args (XDR *, guestfs_vg_activate_args*); 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*); @@ -1330,6 +1348,8 @@ extern bool_t xdr_guestfs_sfdisk_kernel_geometry_args (); extern bool_t xdr_guestfs_sfdisk_kernel_geometry_ret (); extern bool_t xdr_guestfs_sfdisk_disk_geometry_args (); extern bool_t xdr_guestfs_sfdisk_disk_geometry_ret (); +extern bool_t xdr_guestfs_vg_activate_all_args (); +extern bool_t xdr_guestfs_vg_activate_args (); 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 0df5cb07..38bb8ea9 100644 --- a/src/guestfs_protocol.x +++ b/src/guestfs_protocol.x @@ -689,6 +689,15 @@ struct guestfs_sfdisk_disk_geometry_ret { string partitions<>; }; +struct guestfs_vg_activate_all_args { + bool activate; +}; + +struct guestfs_vg_activate_args { + bool activate; + str volgroups<>; +}; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -792,6 +801,8 @@ enum guestfs_procedure { GUESTFS_PROC_SFDISK_L = 100, GUESTFS_PROC_SFDISK_KERNEL_GEOMETRY = 101, GUESTFS_PROC_SFDISK_DISK_GEOMETRY = 102, + GUESTFS_PROC_VG_ACTIVATE_ALL = 103, + GUESTFS_PROC_VG_ACTIVATE = 104, GUESTFS_PROC_NR_PROCS }; @@ -121,6 +121,8 @@ static void no_test_warnings (void) fprintf (stderr, "warning: \"guestfs_sfdisk_l\" has no tests\n"); fprintf (stderr, "warning: \"guestfs_sfdisk_kernel_geometry\" has no tests\n"); fprintf (stderr, "warning: \"guestfs_sfdisk_disk_geometry\" has no tests\n"); + fprintf (stderr, "warning: \"guestfs_vg_activate_all\" has no tests\n"); + fprintf (stderr, "warning: \"guestfs_vg_activate\" has no tests\n"); } static int test_zerofree_0 (void) |