Add vg-activate{,-all} commands, and resize recipe.
authorRichard Jones <rjones@redhat.com>
Mon, 18 May 2009 16:16:24 +0000 (17:16 +0100)
committerRichard Jones <rjones@redhat.com>
Mon, 18 May 2009 16:16:24 +0000 (17:16 +0100)
29 files changed:
TODO
daemon/actions.h
daemon/lvm.c
daemon/sfdisk.c
daemon/stubs.c
fish/cmds.c
fish/completion.c
guestfish-actions.pod
guestfs-actions.pod
java/com/redhat/et/libguestfs/GuestFS.java
java/com_redhat_et_libguestfs_GuestFS.c
ocaml/guestfs.ml
ocaml/guestfs.mli
ocaml/guestfs_c_actions.c
perl/Guestfs.xs
perl/lib/Sys/Guestfs.pm
python/guestfs-py.c
python/guestfs.py
recipes/resize.html [new file with mode: 0644]
recipes/resize.sh [new file with mode: 0755]
recipes/resize.title [new file with mode: 0644]
ruby/ext/guestfs/_guestfs.c
src/generator.ml
src/guestfs-actions.c
src/guestfs-actions.h
src/guestfs_protocol.c
src/guestfs_protocol.h
src/guestfs_protocol.x
tests.c

diff --git a/TODO b/TODO
index 323dc0b..71c9d59 100644 (file)
--- a/TODO
+++ b/TODO
@@ -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.
index 3e6589e..dcffd2a 100644 (file)
@@ -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);
index d1a6cd6..63a3e7e 100644 (file)
@@ -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);
+}
index 9d7a220..2f5206e 100644 (file)
@@ -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);
index e80ba9b..2fd2da9 100644 (file)
@@ -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);
   }
index 5680bfa..8d50021 100644 (file)
@@ -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;
index 03760ad..a072ce3 100644 (file)
@@ -159,6 +159,8 @@ static const char *const commands[] = {
   "unmount-all",
   "upload",
   "verbose",
+  "vg-activate",
+  "vg-activate-all",
   "vgcreate",
   "vgremove",
   "vgs",
index 213fa66..7e33cbb 100644 (file)
@@ -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 ...'
index abeed8f..9ed1cce 100644 (file)
@@ -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,
index 7eafce0..a6d6f6d 100644 (file)
@@ -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;
+
 }
index be7ea9f..3bf5c7e 100644 (file)
@@ -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 ;
+  }
+}
+
index d50b2d8..fa60a7b 100644 (file)
@@ -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"
index 358a6d3..5ce9122 100644 (file)
@@ -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 *)
+
index f2d13b0..f0aa7e2 100644 (file)
@@ -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);
+}
+
index ff7ca9e..374a40d 100644 (file)
@@ -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));
+
index 0249a41..0e4dde4 100644 (file)
@@ -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>
index 140594d..e967bd9 100644 (file)
@@ -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 }
 };
 
index 8ac4037..4a2804b 100644 (file)
@@ -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 (file)
index 0000000..1a0ca3b
--- /dev/null
@@ -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 (executable)
index 0000000..17a7e77
--- /dev/null
@@ -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 (file)
index 0000000..cc2f3a2
--- /dev/null
@@ -0,0 +1 @@
+Repartition and resize a block device
\ No newline at end of file
index b5c9b53..c57dcb3 100644 (file)
@@ -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);
 }
index 19dc20d..5717f9b 100755 (executable)
@@ -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
index 49e8961..41d873f 100644 (file)
@@ -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;
+}
+
index b07e3dd..3c760f2 100644 (file)
@@ -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);
index e6e865e..0a3fddc 100644 (file)
@@ -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;
index 6235577..25ed352 100644 (file)
@@ -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 ();
index 0df5cb0..38bb8ea 100644 (file)
@@ -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
 };
 
diff --git a/tests.c b/tests.c
index 31fa3bf..b344320 100644 (file)
--- a/tests.c
+++ b/tests.c
@@ -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)