From 5cd39c83e23eb300d1bdfa806902a31b409ff420 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Fri, 15 May 2009 14:01:28 +0100 Subject: [PATCH] Add: pvresize, sfdisk-N, sfdisk-l, sfdisk-kernel-geomtry, sfdisk-disk-geometry commands. Pass --no-reread flag to sfdisk. --- daemon/Makefile.am | 1 + daemon/actions.h | 5 + daemon/devsparts.c | 43 --- daemon/lvm.c | 18 ++ daemon/sfdisk.c | 130 ++++++++ daemon/stubs.c | 154 ++++++++++ fish/cmds.c | 126 +++++++- fish/completion.c | 5 + guestfish-actions.pod | 51 ++++ guestfs-actions.pod | 74 +++++ haskell/Guestfs.hs | 15 +- java/com/redhat/et/libguestfs/GuestFS.java | 109 +++++++ java/com_redhat_et_libguestfs_GuestFS.c | 108 +++++++ ocaml/guestfs.ml | 5 + ocaml/guestfs.mli | 15 + ocaml/guestfs_c_actions.c | 130 ++++++++ perl/Guestfs.xs | 72 +++++ perl/lib/Sys/Guestfs.pm | 41 +++ python/guestfs-py.c | 135 +++++++++ python/guestfs.py | 49 +++ ruby/ext/guestfs/_guestfs.c | 129 ++++++++ src/generator.ml | 58 +++- src/guestfs-actions.c | 460 +++++++++++++++++++++++++++++ src/guestfs-actions.h | 5 + src/guestfs_protocol.c | 139 +++++++++ src/guestfs_protocol.h | 68 ++++- src/guestfs_protocol.x | 42 +++ tests.c | 5 + 28 files changed, 2143 insertions(+), 49 deletions(-) create mode 100644 daemon/sfdisk.c diff --git a/daemon/Makefile.am b/daemon/Makefile.am index d6ae6c3..ac1f8c5 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -43,6 +43,7 @@ guestfsd_SOURCES = \ mount.c \ pingdaemon.c \ proto.c \ + sfdisk.c \ stat.c \ strings.c \ stubs.c \ diff --git a/daemon/actions.h b/daemon/actions.h index 37ec125..3e6589e 100644 --- a/daemon/actions.h +++ b/daemon/actions.h @@ -118,3 +118,8 @@ extern char **do_strings (const char *path); extern char **do_strings_e (const char *encoding, const char *path); extern char *do_hexdump (const char *path); extern int do_zerofree (const char *device); +extern int do_pvresize (const char *device); +extern int do_sfdisk_N (const char *device, int n, int cyls, int heads, int sectors, const char *line); +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); diff --git a/daemon/devsparts.c b/daemon/devsparts.c index 0a4d5e4..21854b5 100644 --- a/daemon/devsparts.c +++ b/daemon/devsparts.c @@ -152,46 +152,3 @@ do_mkfs (const char *fstype, const char *device) free (err); return 0; } - -int -do_sfdisk (const char *device, int cyls, int heads, int sectors, - char * const* const lines) -{ - FILE *fp; - char buf[256]; - int i; - - IS_DEVICE (device, -1); - - /* Safe because of IS_DEVICE above. */ - strcpy (buf, "/sbin/sfdisk"); - if (cyls) - sprintf (buf + strlen (buf), " -C %d", cyls); - if (heads) - sprintf (buf + strlen (buf), " -H %d", heads); - if (sectors) - sprintf (buf + strlen (buf), " -S %d", sectors); - sprintf (buf + strlen (buf), " %s", device); - - fp = popen (buf, "w"); - if (fp == NULL) { - reply_with_perror (buf); - return -1; - } - - for (i = 0; lines[i] != NULL; ++i) { - if (fprintf (fp, "%s\n", lines[i]) < 0) { - reply_with_perror (buf); - fclose (fp); - return -1; - } - } - - if (fclose (fp) == EOF) { - reply_with_perror (buf); - fclose (fp); - return -1; - } - - return 0; -} diff --git a/daemon/lvm.c b/daemon/lvm.c index 326b583..d1a6cd6 100644 --- a/daemon/lvm.c +++ b/daemon/lvm.c @@ -358,3 +358,21 @@ do_pvremove (const char *device) free (err); return 0; } + +int +do_pvresize (const char *device) +{ + char *err; + int r; + + r = command (NULL, &err, + "/sbin/lvm", "pvresize", device, NULL); + if (r == -1) { + reply_with_error ("pvresize: %s: %s", device, err); + free (err); + return -1; + } + + free (err); + return 0; +} diff --git a/daemon/sfdisk.c b/daemon/sfdisk.c new file mode 100644 index 0000000..9d7a220 --- /dev/null +++ b/daemon/sfdisk.c @@ -0,0 +1,130 @@ +/* libguestfs - the guestfsd daemon + * Copyright (C) 2009 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "daemon.h" +#include "actions.h" + +static int +sfdisk (const char *device, int n, int cyls, int heads, int sectors, + char * const* const lines) +{ + FILE *fp; + char buf[256]; + int i; + + IS_DEVICE (device, -1); + + strcpy (buf, "/sbin/sfdisk --no-reread"); + if (n > 0) + sprintf (buf + strlen (buf), " -N %d", n); + if (cyls) + sprintf (buf + strlen (buf), " -C %d", cyls); + if (heads) + sprintf (buf + strlen (buf), " -H %d", heads); + if (sectors) + sprintf (buf + strlen (buf), " -S %d", sectors); + /* Safe because of IS_DEVICE above: */ + sprintf (buf + strlen (buf), " %s", device); + + fp = popen (buf, "w"); + if (fp == NULL) { + reply_with_perror (buf); + return -1; + } + + for (i = 0; lines[i] != NULL; ++i) { + if (fprintf (fp, "%s\n", lines[i]) < 0) { + reply_with_perror (buf); + fclose (fp); + return -1; + } + } + + if (fclose (fp) == EOF) { + reply_with_perror (buf); + fclose (fp); + return -1; + } + + return 0; +} + +int +do_sfdisk (const char *device, int cyls, int heads, int sectors, + char * const* const lines) +{ + return sfdisk (device, 0, cyls, heads, sectors, lines); +} + +int +do_sfdisk_N (const char *device, int n, int cyls, int heads, int sectors, + const char *line) +{ + const char *lines[2] = { line, NULL }; + + return sfdisk (device, n, cyls, heads, sectors, lines); +} + +static char * +sfdisk_flag (const char *device, const char *flag) +{ + char *out, *err; + int r; + + IS_DEVICE (device, NULL); + + r = command (&out, &err, "/sbin/sfdisk", flag, device, NULL); + if (r == -1) { + reply_with_error ("sfdisk: %s: %s", device, err); + free (out); + free (err); + return NULL; + } + + free (err); + + return out; /* caller frees */ +} + +char * +do_sfdisk_l (const char *device) +{ + return sfdisk_flag (device, "-l"); +} + +char * +do_sfdisk_kernel_geometry (const char *device) +{ + return sfdisk_flag (device, "-g"); +} + +char * +do_sfdisk_disk_geometry (const char *device) +{ + return sfdisk_flag (device, "-G"); +} diff --git a/daemon/stubs.c b/daemon/stubs.c index 212634f..e80ba9b 100644 --- a/daemon/stubs.c +++ b/daemon/stubs.c @@ -2421,6 +2421,145 @@ done: xdr_free ((xdrproc_t) xdr_guestfs_zerofree_args, (char *) &args); } +static void pvresize_stub (XDR *xdr_in) +{ + int r; + struct guestfs_pvresize_args args; + const char *device; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_pvresize_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "pvresize"); + return; + } + device = args.device; + + r = do_pvresize (device); + if (r == -1) + /* do_pvresize has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_pvresize_args, (char *) &args); +} + +static void sfdisk_N_stub (XDR *xdr_in) +{ + int r; + struct guestfs_sfdisk_N_args args; + const char *device; + int n; + int cyls; + int heads; + int sectors; + const char *line; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_sfdisk_N_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "sfdisk_N"); + return; + } + device = args.device; + n = args.n; + cyls = args.cyls; + heads = args.heads; + sectors = args.sectors; + line = args.line; + + r = do_sfdisk_N (device, n, cyls, heads, sectors, line); + if (r == -1) + /* do_sfdisk_N has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_sfdisk_N_args, (char *) &args); +} + +static void sfdisk_l_stub (XDR *xdr_in) +{ + char *r; + struct guestfs_sfdisk_l_args args; + const char *device; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_sfdisk_l_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "sfdisk_l"); + return; + } + device = args.device; + + r = do_sfdisk_l (device); + if (r == NULL) + /* do_sfdisk_l has already called reply_with_error */ + goto done; + + struct guestfs_sfdisk_l_ret ret; + ret.partitions = r; + reply ((xdrproc_t) &xdr_guestfs_sfdisk_l_ret, (char *) &ret); + free (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_sfdisk_l_args, (char *) &args); +} + +static void sfdisk_kernel_geometry_stub (XDR *xdr_in) +{ + char *r; + struct guestfs_sfdisk_kernel_geometry_args args; + const char *device; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_sfdisk_kernel_geometry_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "sfdisk_kernel_geometry"); + return; + } + device = args.device; + + r = do_sfdisk_kernel_geometry (device); + if (r == NULL) + /* do_sfdisk_kernel_geometry has already called reply_with_error */ + goto done; + + struct guestfs_sfdisk_kernel_geometry_ret ret; + ret.partitions = r; + reply ((xdrproc_t) &xdr_guestfs_sfdisk_kernel_geometry_ret, (char *) &ret); + free (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_sfdisk_kernel_geometry_args, (char *) &args); +} + +static void sfdisk_disk_geometry_stub (XDR *xdr_in) +{ + char *r; + struct guestfs_sfdisk_disk_geometry_args args; + const char *device; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_sfdisk_disk_geometry_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "sfdisk_disk_geometry"); + return; + } + device = args.device; + + r = do_sfdisk_disk_geometry (device); + if (r == NULL) + /* do_sfdisk_disk_geometry has already called reply_with_error */ + goto done; + + struct guestfs_sfdisk_disk_geometry_ret ret; + ret.partitions = r; + reply ((xdrproc_t) &xdr_guestfs_sfdisk_disk_geometry_ret, (char *) &ret); + free (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_sfdisk_disk_geometry_args, (char *) &args); +} + void dispatch_incoming_message (XDR *xdr_in) { switch (proc_nr) { @@ -2715,6 +2854,21 @@ void dispatch_incoming_message (XDR *xdr_in) case GUESTFS_PROC_ZEROFREE: zerofree_stub (xdr_in); break; + case GUESTFS_PROC_PVRESIZE: + pvresize_stub (xdr_in); + break; + case GUESTFS_PROC_SFDISK_N: + sfdisk_N_stub (xdr_in); + break; + case GUESTFS_PROC_SFDISK_L: + sfdisk_l_stub (xdr_in); + break; + case GUESTFS_PROC_SFDISK_KERNEL_GEOMETRY: + sfdisk_kernel_geometry_stub (xdr_in); + break; + case GUESTFS_PROC_SFDISK_DISK_GEOMETRY: + sfdisk_disk_geometry_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 1f3d9ce..5680bfa 100644 --- a/fish/cmds.c +++ b/fish/cmds.c @@ -113,6 +113,7 @@ void list_commands (void) printf ("%-20s %s\n", "ping-daemon", "ping the guest daemon"); printf ("%-20s %s\n", "pvcreate", "create an LVM physical volume"); printf ("%-20s %s\n", "pvremove", "remove an LVM physical volume"); + printf ("%-20s %s\n", "pvresize", "resize an LVM physical volume"); printf ("%-20s %s\n", "pvs", "list the LVM physical volumes (PVs)"); printf ("%-20s %s\n", "pvs-full", "list the LVM physical volumes (PVs)"); printf ("%-20s %s\n", "read-lines", "read file as lines"); @@ -127,6 +128,10 @@ void list_commands (void) printf ("%-20s %s\n", "set-qemu", "set the qemu binary"); printf ("%-20s %s\n", "set-verbose", "set verbose mode"); printf ("%-20s %s\n", "sfdisk", "create partitions on a block device"); + printf ("%-20s %s\n", "sfdisk-N", "modify a single partition on a block device"); + printf ("%-20s %s\n", "sfdisk-disk-geometry", "display the disk geometry from the partition table"); + printf ("%-20s %s\n", "sfdisk-kernel-geometry", "display the kernel geometry"); + printf ("%-20s %s\n", "sfdisk-l", "display the partition table"); printf ("%-20s %s\n", "stat", "get file information"); printf ("%-20s %s\n", "statvfs", "get file system statistics"); printf ("%-20s %s\n", "strings", "print the printable strings in a file"); @@ -340,7 +345,7 @@ void display_command (const char *cmd) pod2text ("mkfs - make a filesystem", " mkfs \n\nThis creates a filesystem on C (usually a partition\nor LVM logical volume). The filesystem type is C, for\nexample C."); else if (strcasecmp (cmd, "sfdisk") == 0) - pod2text ("sfdisk - create partitions on a block device", " sfdisk \n\nThis is a direct interface to the L program for creating\npartitions on block devices.\n\nC should be a block device, for example C.\n\nC, C and C are the number of cylinders, heads\nand sectors on the device, which are passed directly to sfdisk as\nthe I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any\nof these, then the corresponding parameter is omitted. Usually for\n'large' disks, you can just pass C<0> for these, but for small\n(floppy-sized) disks, sfdisk (or rather, the kernel) cannot work\nout the right geometry and you will need to tell it.\n\nC is a list of lines that we feed to C. For more\ninformation refer to the L manpage.\n\nTo create a single partition occupying the whole disk, you would\npass C as a single element list, when the single element being\nthe string C<,> (comma).\n\nB."); + pod2text ("sfdisk - create partitions on a block device", " sfdisk \n\nThis is a direct interface to the L program for creating\npartitions on block devices.\n\nC should be a block device, for example C.\n\nC, C and C are the number of cylinders, heads\nand sectors on the device, which are passed directly to sfdisk as\nthe I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any\nof these, then the corresponding parameter is omitted. Usually for\n'large' disks, you can just pass C<0> for these, but for small\n(floppy-sized) disks, sfdisk (or rather, the kernel) cannot work\nout the right geometry and you will need to tell it.\n\nC is a list of lines that we feed to C. For more\ninformation refer to the L manpage.\n\nTo create a single partition occupying the whole disk, you would\npass C as a single element list, when the single element being\nthe string C<,> (comma).\n\nSee also: C, C\n\nB."); else if (strcasecmp (cmd, "write_file") == 0 || strcasecmp (cmd, "write-file") == 0) pod2text ("write-file - create a file", " write-file \n\nThis call creates a file called C. The contents of the\nfile is the string C (which can contain any 8 bit data),\nwith length C.\n\nAs a special case, if C is C<0>\nthen the length is calculated using C (so in this case\nthe content cannot contain embedded ASCII NULs).\n\nI Owing to a bug, writing content containing ASCII NUL\ncharacters does I work, even if the length is specified.\nWe hope to resolve this bug in a future version. In the meantime\nuse C.\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB. To transfer large files you should use\nFTP."); @@ -504,6 +509,21 @@ void display_command (const char *cmd) if (strcasecmp (cmd, "zerofree") == 0) pod2text ("zerofree - zero unused inodes and disk blocks on ext2/3 filesystem", " zerofree \n\nThis runs the I program on C. This program\nclaims to zero unused inodes and disk blocks on an ext2/3\nfilesystem, thus making it possible to compress the filesystem\nmore effectively.\n\nYou should B run this program if the filesystem is\nmounted.\n\nIt is possible that using this program can damage the filesystem\nor data on the filesystem."); else + if (strcasecmp (cmd, "pvresize") == 0) + pod2text ("pvresize - resize an LVM physical volume", " pvresize \n\nThis resizes (expands or shrinks) an existing LVM physical\nvolume to match the new size of the underlying device."); + else + if (strcasecmp (cmd, "sfdisk_N") == 0 || strcasecmp (cmd, "sfdisk-N") == 0) + pod2text ("sfdisk-N - modify a single partition on a block device", " sfdisk-N \n\nThis runs L option to modify just the single\npartition C (note: C counts from 1).\n\nFor other parameters, see C. You should usually\npass C<0> for the cyls/heads/sectors parameters.\n\nB."); + else + if (strcasecmp (cmd, "sfdisk_l") == 0 || strcasecmp (cmd, "sfdisk-l") == 0) + pod2text ("sfdisk-l - display the partition table", " sfdisk-l \n\nThis displays the partition table on C, in the\nhuman-readable output of the L command. It is\nnot intended to be parsed."); + else + if (strcasecmp (cmd, "sfdisk_kernel_geometry") == 0 || strcasecmp (cmd, "sfdisk-kernel-geometry") == 0) + pod2text ("sfdisk-kernel-geometry - display the kernel geometry", " sfdisk-kernel-geometry \n\nThis displays the kernel's idea of the geometry of C.\n\nThe result is in human-readable format, and not designed to\nbe parsed."); + else + 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 \n\nThis displays the disk geometry of C 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).\n\nThe result is in human-readable format, and not designed to\nbe parsed."); + else display_builtin_command (cmd); } @@ -2456,6 +2476,95 @@ static int run_zerofree (const char *cmd, int argc, char *argv[]) return r; } +static int run_pvresize (const char *cmd, int argc, char *argv[]) +{ + int 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_pvresize (g, device); + return r; +} + +static int run_sfdisk_N (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *device; + int n; + int cyls; + int heads; + int sectors; + const char *line; + if (argc != 6) { + fprintf (stderr, "%s should have 6 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + device = argv[0]; + n = atoi (argv[1]); + cyls = atoi (argv[2]); + heads = atoi (argv[3]); + sectors = atoi (argv[4]); + line = argv[5]; + r = guestfs_sfdisk_N (g, device, n, cyls, heads, sectors, line); + return r; +} + +static int run_sfdisk_l (const char *cmd, int argc, char *argv[]) +{ + char *r; + const char *device; + if (argc != 1) { + fprintf (stderr, "%s should have 1 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + device = argv[0]; + r = guestfs_sfdisk_l (g, device); + if (r == NULL) return -1; + printf ("%s\n", r); + free (r); + return 0; +} + +static int run_sfdisk_kernel_geometry (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_sfdisk_kernel_geometry (g, device); + if (r == NULL) return -1; + printf ("%s\n", r); + free (r); + return 0; +} + +static int run_sfdisk_disk_geometry (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_sfdisk_disk_geometry (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) @@ -2809,6 +2918,21 @@ int run_action (const char *cmd, int argc, char *argv[]) if (strcasecmp (cmd, "zerofree") == 0) return run_zerofree (cmd, argc, argv); else + if (strcasecmp (cmd, "pvresize") == 0) + return run_pvresize (cmd, argc, argv); + else + if (strcasecmp (cmd, "sfdisk_N") == 0 || strcasecmp (cmd, "sfdisk-N") == 0) + return run_sfdisk_N (cmd, argc, argv); + else + if (strcasecmp (cmd, "sfdisk_l") == 0 || strcasecmp (cmd, "sfdisk-l") == 0) + return run_sfdisk_l (cmd, argc, argv); + else + if (strcasecmp (cmd, "sfdisk_kernel_geometry") == 0 || strcasecmp (cmd, "sfdisk-kernel-geometry") == 0) + return run_sfdisk_kernel_geometry (cmd, argc, argv); + else + if (strcasecmp (cmd, "sfdisk_disk_geometry") == 0 || strcasecmp (cmd, "sfdisk-disk-geometry") == 0) + return run_sfdisk_disk_geometry (cmd, argc, argv); + else { fprintf (stderr, "%s: unknown command\n", cmd); return -1; diff --git a/fish/completion.c b/fish/completion.c index 5c7f5e0..03760ad 100644 --- a/fish/completion.c +++ b/fish/completion.c @@ -121,6 +121,7 @@ static const char *const commands[] = { "ping-daemon", "pvcreate", "pvremove", + "pvresize", "pvs", "pvs-full", "qemu", @@ -137,6 +138,10 @@ static const char *const commands[] = { "set-qemu", "set-verbose", "sfdisk", + "sfdisk-N", + "sfdisk-disk-geometry", + "sfdisk-kernel-geometry", + "sfdisk-l", "stat", "statvfs", "strings", diff --git a/guestfish-actions.pod b/guestfish-actions.pod index 7b5a4be..213fa66 100644 --- a/guestfish-actions.pod +++ b/guestfish-actions.pod @@ -905,6 +905,13 @@ The implementation uses the C command which refuses to wipe physical volumes that contain any volume groups, so you have to remove those first. +=head2 pvresize + + pvresize device + +This resizes (expands or shrinks) an existing LVM physical +volume to match the new size of the underlying device. + =head2 pvs pvs @@ -1064,9 +1071,53 @@ To create a single partition occupying the whole disk, you would pass C as a single element list, when the single element being the string C<,> (comma). +See also: C, C + +B. + +=head2 sfdisk-N + + sfdisk-N device n cyls heads sectors line + +This runs L option to modify just the single +partition C (note: C counts from 1). + +For other parameters, see C. You should usually +pass C<0> for the cyls/heads/sectors parameters. + B. +=head2 sfdisk-disk-geometry + + sfdisk-disk-geometry device + +This displays the disk geometry of C read from the +partition table. Especially in the case where the underlying +block device has been resized, this can be different from the +kernel's idea of the geometry (see C). + +The result is in human-readable format, and not designed to +be parsed. + +=head2 sfdisk-kernel-geometry + + sfdisk-kernel-geometry device + +This displays the kernel's idea of the geometry of C. + +The result is in human-readable format, and not designed to +be parsed. + +=head2 sfdisk-l + + sfdisk-l device + +This displays the partition table on C, in the +human-readable output of the L command. It is +not intended to be parsed. + =head2 stat stat path diff --git a/guestfs-actions.pod b/guestfs-actions.pod index 109c73e..abeed8f 100644 --- a/guestfs-actions.pod +++ b/guestfs-actions.pod @@ -1208,6 +1208,16 @@ to remove those first. This function returns 0 on success or -1 on error. +=head2 guestfs_pvresize + + int guestfs_pvresize (guestfs_h *handle, + const char *device); + +This resizes (expands or shrinks) an existing LVM physical +volume to match the new size of the underlying device. + +This function returns 0 on success or -1 on error. + =head2 guestfs_pvs char **guestfs_pvs (guestfs_h *handle); @@ -1440,11 +1450,75 @@ To create a single partition occupying the whole disk, you would pass C as a single element list, when the single element being the string C<,> (comma). +See also: C, C + +This function returns 0 on success or -1 on error. + +B. + +=head2 guestfs_sfdisk_N + + int guestfs_sfdisk_N (guestfs_h *handle, + const char *device, + int n, + int cyls, + int heads, + int sectors, + const char *line); + +This runs L option to modify just the single +partition C (note: C counts from 1). + +For other parameters, see C. You should usually +pass C<0> for the cyls/heads/sectors parameters. + This function returns 0 on success or -1 on error. B. +=head2 guestfs_sfdisk_disk_geometry + + char *guestfs_sfdisk_disk_geometry (guestfs_h *handle, + const char *device); + +This displays the disk geometry of C read from the +partition table. Especially in the case where the underlying +block device has been resized, this can be different from the +kernel's idea of the geometry (see C). + +The result is in human-readable format, and not designed to +be parsed. + +This function returns a string, or NULL on error. +I. + +=head2 guestfs_sfdisk_kernel_geometry + + char *guestfs_sfdisk_kernel_geometry (guestfs_h *handle, + const char *device); + +This displays the kernel's idea of the geometry of C. + +The result is in human-readable format, and not designed to +be parsed. + +This function returns a string, or NULL on error. +I. + +=head2 guestfs_sfdisk_l + + char *guestfs_sfdisk_l (guestfs_h *handle, + const char *device); + +This displays the partition table on C, in the +human-readable output of the L command. It is +not intended to be parsed. + +This function returns a string, or NULL on error. +I. + =head2 guestfs_stat struct guestfs_stat *guestfs_stat (guestfs_h *handle, diff --git a/haskell/Guestfs.hs b/haskell/Guestfs.hs index c061a7a..170f040 100644 --- a/haskell/Guestfs.hs +++ b/haskell/Guestfs.hs @@ -79,7 +79,8 @@ module Guestfs ( cp_a, mv, ping_daemon, - zerofree + zerofree, + pvresize ) where import Foreign import Foreign.C @@ -801,3 +802,15 @@ zerofree h device = do fail err else return () +foreign import ccall unsafe "guestfs_pvresize" c_pvresize + :: GuestfsP -> CString -> IO (CInt) + +pvresize :: GuestfsH -> String -> IO () +pvresize h device = do + r <- withCString device $ \device -> withForeignPtr h (\p -> c_pvresize p device) + if (r == -1) + then do + err <- last_error h + fail err + else return () + diff --git a/java/com/redhat/et/libguestfs/GuestFS.java b/java/com/redhat/et/libguestfs/GuestFS.java index 76ada90..7eafce0 100644 --- a/java/com/redhat/et/libguestfs/GuestFS.java +++ b/java/com/redhat/et/libguestfs/GuestFS.java @@ -1518,6 +1518,8 @@ public class GuestFS { * you would pass "lines" as a single element list, when * the single element being the string "," (comma). * + * See also: "g.sfdisk_l", "g.sfdisk_N" + * * This command is dangerous. Without careful use you can * easily destroy all your data. * @@ -2755,4 +2757,111 @@ public class GuestFS { private native void _zerofree (long g, String device) throws LibGuestFSException; + /** + * resize an LVM physical volume + * + * This resizes (expands or shrinks) an existing LVM + * physical volume to match the new size of the underlying + * device. + * + * @throws LibGuestFSException + */ + public void pvresize (String device) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("pvresize: handle is closed"); + _pvresize (g, device); + } + private native void _pvresize (long g, String device) + throws LibGuestFSException; + + /** + * modify a single partition on a block device + * + * This runs sfdisk(8) option to modify just the single + * partition "n" (note: "n" counts from 1). + * + * For other parameters, see "g.sfdisk". You should usually + * pass 0 for the cyls/heads/sectors parameters. + * + * This command is dangerous. Without careful use you can + * easily destroy all your data. + * + * @throws LibGuestFSException + */ + public void sfdisk_N (String device, int n, int cyls, int heads, int sectors, String line) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("sfdisk_N: handle is closed"); + _sfdisk_N (g, device, n, cyls, heads, sectors, line); + } + private native void _sfdisk_N (long g, String device, int n, int cyls, int heads, int sectors, String line) + throws LibGuestFSException; + + /** + * display the partition table + * + * This displays the partition table on "device", in the + * human-readable output of the sfdisk(8) command. It is + * not intended to be parsed. + * + * @throws LibGuestFSException + */ + public String sfdisk_l (String device) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("sfdisk_l: handle is closed"); + return _sfdisk_l (g, device); + } + private native String _sfdisk_l (long g, String device) + throws LibGuestFSException; + + /** + * display the kernel geometry + * + * This displays the kernel's idea of the geometry of + * "device". + * + * The result is in human-readable format, and not designed + * to be parsed. + * + * @throws LibGuestFSException + */ + public String sfdisk_kernel_geometry (String device) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("sfdisk_kernel_geometry: handle is closed"); + return _sfdisk_kernel_geometry (g, device); + } + private native String _sfdisk_kernel_geometry (long g, String device) + throws LibGuestFSException; + + /** + * display the disk geometry from the partition table + * + * This displays the disk geometry of "device" read from + * the partition table. Especially in the case where the + * underlying block device has been resized, this can be + * different from the kernel's idea of the geometry (see + * "g.sfdisk_kernel_geometry"). + * + * The result is in human-readable format, and not designed + * to be parsed. + * + * @throws LibGuestFSException + */ + public String sfdisk_disk_geometry (String device) + throws LibGuestFSException + { + if (g == 0) + throw new LibGuestFSException ("sfdisk_disk_geometry: handle is closed"); + return _sfdisk_disk_geometry (g, device); + } + private native String _sfdisk_disk_geometry (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 a823d84..be7ea9f 100644 --- a/java/com_redhat_et_libguestfs_GuestFS.c +++ b/java/com_redhat_et_libguestfs_GuestFS.c @@ -2739,3 +2739,111 @@ Java_com_redhat_et_libguestfs_GuestFS__1zerofree } } +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1pvresize + (JNIEnv *env, jobject obj, jlong jg, jstring jdevice) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + const char *device; + + device = (*env)->GetStringUTFChars (env, jdevice, NULL); + r = guestfs_pvresize (g, device); + (*env)->ReleaseStringUTFChars (env, jdevice, device); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + +JNIEXPORT void JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1sfdisk_1N + (JNIEnv *env, jobject obj, jlong jg, jstring jdevice, jint jn, jint jcyls, jint jheads, jint jsectors, jstring jline) +{ + guestfs_h *g = (guestfs_h *) (long) jg; + int r; + const char *device; + int n; + int cyls; + int heads; + int sectors; + const char *line; + + device = (*env)->GetStringUTFChars (env, jdevice, NULL); + n = jn; + cyls = jcyls; + heads = jheads; + sectors = jsectors; + line = (*env)->GetStringUTFChars (env, jline, NULL); + r = guestfs_sfdisk_N (g, device, n, cyls, heads, sectors, line); + (*env)->ReleaseStringUTFChars (env, jdevice, device); + (*env)->ReleaseStringUTFChars (env, jline, line); + if (r == -1) { + throw_exception (env, guestfs_last_error (g)); + return ; + } +} + +JNIEXPORT jstring JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1sfdisk_1l + (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_sfdisk_l (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 jstring JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1sfdisk_1kernel_1geometry + (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_sfdisk_kernel_geometry (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 jstring JNICALL +Java_com_redhat_et_libguestfs_GuestFS__1sfdisk_1disk_1geometry + (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_sfdisk_disk_geometry (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/ocaml/guestfs.ml b/ocaml/guestfs.ml index 3886022..d50b2d8 100644 --- a/ocaml/guestfs.ml +++ b/ocaml/guestfs.ml @@ -236,3 +236,8 @@ external strings : t -> string -> string array = "ocaml_guestfs_strings" external strings_e : t -> string -> string -> string array = "ocaml_guestfs_strings_e" external hexdump : t -> string -> string = "ocaml_guestfs_hexdump" external zerofree : t -> string -> unit = "ocaml_guestfs_zerofree" +external pvresize : t -> string -> unit = "ocaml_guestfs_pvresize" +external sfdisk_N : t -> string -> int -> int -> int -> int -> string -> unit = "ocaml_guestfs_sfdisk_N_byte" "ocaml_guestfs_sfdisk_N" +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" diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli index 3776abe..358a6d3 100644 --- a/ocaml/guestfs.mli +++ b/ocaml/guestfs.mli @@ -487,3 +487,18 @@ val hexdump : t -> string -> string val zerofree : t -> string -> unit (** zero unused inodes and disk blocks on ext2/3 filesystem *) +val pvresize : t -> string -> unit +(** resize an LVM physical volume *) + +val sfdisk_N : t -> string -> int -> int -> int -> int -> string -> unit +(** modify a single partition on a block device *) + +val sfdisk_l : t -> string -> string +(** display the partition table *) + +val sfdisk_kernel_geometry : t -> string -> string +(** display the kernel geometry *) + +val sfdisk_disk_geometry : t -> string -> string +(** display the disk geometry from the partition table *) + diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c index 79a5c16..f2d13b0 100644 --- a/ocaml/guestfs_c_actions.c +++ b/ocaml/guestfs_c_actions.c @@ -3201,3 +3201,133 @@ ocaml_guestfs_zerofree (value gv, value devicev) CAMLreturn (rv); } +CAMLprim value +ocaml_guestfs_pvresize (value gv, value devicev) +{ + CAMLparam2 (gv, devicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("pvresize: used handle after closing it"); + + const char *device = String_val (devicev); + int r; + + caml_enter_blocking_section (); + r = guestfs_pvresize (g, device); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "pvresize"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_sfdisk_N (value gv, value devicev, value nv, value cylsv, value headsv, value sectorsv, value linev) +{ + CAMLparam5 (gv, devicev, nv, cylsv, headsv); + CAMLxparam2 (sectorsv, linev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("sfdisk_N: used handle after closing it"); + + const char *device = String_val (devicev); + int n = Int_val (nv); + int cyls = Int_val (cylsv); + int heads = Int_val (headsv); + int sectors = Int_val (sectorsv); + const char *line = String_val (linev); + int r; + + caml_enter_blocking_section (); + r = guestfs_sfdisk_N (g, device, n, cyls, heads, sectors, line); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "sfdisk_N"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_sfdisk_N_byte (value *argv, int argn) +{ + return ocaml_guestfs_sfdisk_N (argv[0], argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); +} + +CAMLprim value +ocaml_guestfs_sfdisk_l (value gv, value devicev) +{ + CAMLparam2 (gv, devicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("sfdisk_l: used handle after closing it"); + + const char *device = String_val (devicev); + char *r; + + caml_enter_blocking_section (); + r = guestfs_sfdisk_l (g, device); + caml_leave_blocking_section (); + if (r == NULL) + ocaml_guestfs_raise_error (g, "sfdisk_l"); + + rv = caml_copy_string (r); + free (r); + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_sfdisk_kernel_geometry (value gv, value devicev) +{ + CAMLparam2 (gv, devicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("sfdisk_kernel_geometry: used handle after closing it"); + + const char *device = String_val (devicev); + char *r; + + caml_enter_blocking_section (); + r = guestfs_sfdisk_kernel_geometry (g, device); + caml_leave_blocking_section (); + if (r == NULL) + ocaml_guestfs_raise_error (g, "sfdisk_kernel_geometry"); + + rv = caml_copy_string (r); + free (r); + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_sfdisk_disk_geometry (value gv, value devicev) +{ + CAMLparam2 (gv, devicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("sfdisk_disk_geometry: used handle after closing it"); + + const char *device = String_val (devicev); + char *r; + + caml_enter_blocking_section (); + r = guestfs_sfdisk_disk_geometry (g, device); + caml_leave_blocking_section (); + if (r == NULL) + ocaml_guestfs_raise_error (g, "sfdisk_disk_geometry"); + + rv = caml_copy_string (r); + free (r); + CAMLreturn (rv); +} + diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs index e87131b..ff7ca9e 100644 --- a/perl/Guestfs.xs +++ b/perl/Guestfs.xs @@ -1798,3 +1798,75 @@ PREINIT: if (r == -1) croak ("zerofree: %s", guestfs_last_error (g)); +void +pvresize (g, device) + guestfs_h *g; + char *device; +PREINIT: + int r; + PPCODE: + r = guestfs_pvresize (g, device); + if (r == -1) + croak ("pvresize: %s", guestfs_last_error (g)); + +void +sfdisk_N (g, device, n, cyls, heads, sectors, line) + guestfs_h *g; + char *device; + int n; + int cyls; + int heads; + int sectors; + char *line; +PREINIT: + int r; + PPCODE: + r = guestfs_sfdisk_N (g, device, n, cyls, heads, sectors, line); + if (r == -1) + croak ("sfdisk_N: %s", guestfs_last_error (g)); + +SV * +sfdisk_l (g, device) + guestfs_h *g; + char *device; +PREINIT: + char *partitions; + CODE: + partitions = guestfs_sfdisk_l (g, device); + if (partitions == NULL) + croak ("sfdisk_l: %s", guestfs_last_error (g)); + RETVAL = newSVpv (partitions, 0); + free (partitions); + OUTPUT: + RETVAL + +SV * +sfdisk_kernel_geometry (g, device) + guestfs_h *g; + char *device; +PREINIT: + char *partitions; + CODE: + partitions = guestfs_sfdisk_kernel_geometry (g, device); + if (partitions == NULL) + croak ("sfdisk_kernel_geometry: %s", guestfs_last_error (g)); + RETVAL = newSVpv (partitions, 0); + free (partitions); + OUTPUT: + RETVAL + +SV * +sfdisk_disk_geometry (g, device) + guestfs_h *g; + char *device; +PREINIT: + char *partitions; + CODE: + partitions = guestfs_sfdisk_disk_geometry (g, device); + if (partitions == NULL) + croak ("sfdisk_disk_geometry: %s", guestfs_last_error (g)); + RETVAL = newSVpv (partitions, 0); + free (partitions); + OUTPUT: + RETVAL + diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm index b11594f..0249a41 100644 --- a/perl/lib/Sys/Guestfs.pm +++ b/perl/lib/Sys/Guestfs.pm @@ -840,6 +840,11 @@ The implementation uses the C command which refuses to wipe physical volumes that contain any volume groups, so you have to remove those first. +=item $h->pvresize ($device); + +This resizes (expands or shrinks) an existing LVM physical +volume to match the new size of the underlying device. + =item @physvols = $h->pvs (); List all the physical volumes detected. This is the equivalent @@ -985,9 +990,45 @@ To create a single partition occupying the whole disk, you would pass C as a single element list, when the single element being the string C<,> (comma). +See also: C<$h-Esfdisk_l>, C<$h-Esfdisk_N> + +B. + +=item $h->sfdisk_N ($device, $n, $cyls, $heads, $sectors, $line); + +This runs L option to modify just the single +partition C (note: C counts from 1). + +For other parameters, see C<$h-Esfdisk>. You should usually +pass C<0> for the cyls/heads/sectors parameters. + B. +=item $partitions = $h->sfdisk_disk_geometry ($device); + +This displays the disk geometry of C read from the +partition table. Especially in the case where the underlying +block device has been resized, this can be different from the +kernel's idea of the geometry (see C<$h-Esfdisk_kernel_geometry>). + +The result is in human-readable format, and not designed to +be parsed. + +=item $partitions = $h->sfdisk_kernel_geometry ($device); + +This displays the kernel's idea of the geometry of C. + +The result is in human-readable format, and not designed to +be parsed. + +=item $partitions = $h->sfdisk_l ($device); + +This displays the partition table on C, in the +human-readable output of the L command. It is +not intended to be parsed. + =item %statbuf = $h->stat ($path); Returns file information for the given C. diff --git a/python/guestfs-py.c b/python/guestfs-py.c index 8301c70..140594d 100644 --- a/python/guestfs-py.c +++ b/python/guestfs-py.c @@ -3427,6 +3427,136 @@ py_guestfs_zerofree (PyObject *self, PyObject *args) return py_r; } +static PyObject * +py_guestfs_pvresize (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + const char *device; + + if (!PyArg_ParseTuple (args, (char *) "Os:guestfs_pvresize", + &py_g, &device)) + return NULL; + g = get_handle (py_g); + + r = guestfs_pvresize (g, device); + 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_sfdisk_N (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + int r; + const char *device; + int n; + int cyls; + int heads; + int sectors; + const char *line; + + if (!PyArg_ParseTuple (args, (char *) "Osiiiis:guestfs_sfdisk_N", + &py_g, &device, &n, &cyls, &heads, §ors, &line)) + return NULL; + g = get_handle (py_g); + + r = guestfs_sfdisk_N (g, device, n, cyls, heads, sectors, line); + 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_sfdisk_l (PyObject *self, PyObject *args) +{ + PyObject *py_g; + guestfs_h *g; + PyObject *py_r; + char *r; + const char *device; + + if (!PyArg_ParseTuple (args, (char *) "Os:guestfs_sfdisk_l", + &py_g, &device)) + return NULL; + g = get_handle (py_g); + + r = guestfs_sfdisk_l (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_sfdisk_kernel_geometry (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_sfdisk_kernel_geometry", + &py_g, &device)) + return NULL; + g = get_handle (py_g); + + r = guestfs_sfdisk_kernel_geometry (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_sfdisk_disk_geometry (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_sfdisk_disk_geometry", + &py_g, &device)) + return NULL; + g = get_handle (py_g); + + r = guestfs_sfdisk_disk_geometry (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 }, @@ -3551,6 +3681,11 @@ static PyMethodDef methods[] = { { (char *) "strings_e", py_guestfs_strings_e, METH_VARARGS, NULL }, { (char *) "hexdump", py_guestfs_hexdump, METH_VARARGS, NULL }, { (char *) "zerofree", py_guestfs_zerofree, METH_VARARGS, NULL }, + { (char *) "pvresize", py_guestfs_pvresize, METH_VARARGS, NULL }, + { (char *) "sfdisk_N", py_guestfs_sfdisk_N, METH_VARARGS, NULL }, + { (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 }, { NULL, NULL, 0, NULL } }; diff --git a/python/guestfs.py b/python/guestfs.py index 044e1fa..8ac4037 100644 --- a/python/guestfs.py +++ b/python/guestfs.py @@ -750,6 +750,8 @@ class GuestFS: you would pass "lines" as a single element list, when the single element being the string "," (comma). + See also: "g.sfdisk_l", "g.sfdisk_N" + This command is dangerous. Without careful use you can easily destroy all your data. """ @@ -1348,3 +1350,50 @@ class GuestFS: """ return libguestfsmod.zerofree (self._o, device) + def pvresize (self, device): + u"""This resizes (expands or shrinks) an existing LVM + physical volume to match the new size of the underlying + device. + """ + return libguestfsmod.pvresize (self._o, device) + + def sfdisk_N (self, device, n, cyls, heads, sectors, line): + u"""This runs sfdisk(8) option to modify just the single + partition "n" (note: "n" counts from 1). + + For other parameters, see "g.sfdisk". You should usually + pass 0 for the cyls/heads/sectors parameters. + + This command is dangerous. Without careful use you can + easily destroy all your data. + """ + return libguestfsmod.sfdisk_N (self._o, device, n, cyls, heads, sectors, line) + + def sfdisk_l (self, device): + u"""This displays the partition table on "device", in the + human-readable output of the sfdisk(8) command. It is + not intended to be parsed. + """ + return libguestfsmod.sfdisk_l (self._o, device) + + def sfdisk_kernel_geometry (self, device): + u"""This displays the kernel's idea of the geometry of + "device". + + The result is in human-readable format, and not designed + to be parsed. + """ + return libguestfsmod.sfdisk_kernel_geometry (self._o, device) + + def sfdisk_disk_geometry (self, device): + u"""This displays the disk geometry of "device" read from + the partition table. Especially in the case where the + underlying block device has been resized, this can be + different from the kernel's idea of the geometry (see + "g.sfdisk_kernel_geometry"). + + The result is in human-readable format, and not designed + to be parsed. + """ + return libguestfsmod.sfdisk_disk_geometry (self._o, device) + diff --git a/ruby/ext/guestfs/_guestfs.c b/ruby/ext/guestfs/_guestfs.c index 4fb6ce7..b5c9b53 100644 --- a/ruby/ext/guestfs/_guestfs.c +++ b/ruby/ext/guestfs/_guestfs.c @@ -2906,6 +2906,125 @@ static VALUE ruby_guestfs_zerofree (VALUE gv, VALUE devicev) return Qnil; } +static VALUE ruby_guestfs_pvresize (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", "pvresize"); + + const char *device = StringValueCStr (devicev); + if (!device) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "device", "pvresize"); + + int r; + + r = guestfs_pvresize (g, device); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + +static VALUE ruby_guestfs_sfdisk_N (VALUE gv, VALUE devicev, VALUE nv, VALUE cylsv, VALUE headsv, VALUE sectorsv, VALUE linev) +{ + guestfs_h *g; + Data_Get_Struct (gv, guestfs_h, g); + if (!g) + rb_raise (rb_eArgError, "%s: used handle after closing it", "sfdisk_N"); + + const char *device = StringValueCStr (devicev); + if (!device) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "device", "sfdisk_N"); + int n = NUM2INT (nv); + int cyls = NUM2INT (cylsv); + int heads = NUM2INT (headsv); + int sectors = NUM2INT (sectorsv); + const char *line = StringValueCStr (linev); + if (!line) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "line", "sfdisk_N"); + + int r; + + r = guestfs_sfdisk_N (g, device, n, cyls, heads, sectors, line); + if (r == -1) + rb_raise (e_Error, "%s", guestfs_last_error (g)); + + return Qnil; +} + +static VALUE ruby_guestfs_sfdisk_l (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", "sfdisk_l"); + + const char *device = StringValueCStr (devicev); + if (!device) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "device", "sfdisk_l"); + + char *r; + + r = guestfs_sfdisk_l (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_sfdisk_kernel_geometry (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", "sfdisk_kernel_geometry"); + + const char *device = StringValueCStr (devicev); + if (!device) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "device", "sfdisk_kernel_geometry"); + + char *r; + + r = guestfs_sfdisk_kernel_geometry (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_sfdisk_disk_geometry (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", "sfdisk_disk_geometry"); + + const char *device = StringValueCStr (devicev); + if (!device) + rb_raise (rb_eTypeError, "expected string for parameter %s of %s", + "device", "sfdisk_disk_geometry"); + + char *r; + + r = guestfs_sfdisk_disk_geometry (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 () { @@ -3158,4 +3277,14 @@ void Init__guestfs () ruby_guestfs_hexdump, 1); rb_define_method (c_guestfs, "zerofree", ruby_guestfs_zerofree, 1); + rb_define_method (c_guestfs, "pvresize", + ruby_guestfs_pvresize, 1); + rb_define_method (c_guestfs, "sfdisk_N", + ruby_guestfs_sfdisk_N, 6); + rb_define_method (c_guestfs, "sfdisk_l", + ruby_guestfs_sfdisk_l, 1); + rb_define_method (c_guestfs, "sfdisk_kernel_geometry", + ruby_guestfs_sfdisk_kernel_geometry, 1); + rb_define_method (c_guestfs, "sfdisk_disk_geometry", + ruby_guestfs_sfdisk_disk_geometry, 1); } diff --git a/src/generator.ml b/src/generator.ml index 652564d..19dc20d 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -1076,7 +1076,9 @@ information refer to the L manpage. To create a single partition occupying the whole disk, you would pass C as a single element list, when the single element being -the string C<,> (comma)."); +the string C<,> (comma). + +See also: C, C"); ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning], [InitBasicFS, Always, TestOutput ( @@ -2019,6 +2021,54 @@ mounted. It is possible that using this program can damage the filesystem or data on the filesystem."); + ("pvresize", (RErr, [String "device"]), 98, [], + [], + "resize an LVM physical volume", + "\ +This resizes (expands or shrinks) an existing LVM physical +volume to match the new size of the underlying device."); + + ("sfdisk_N", (RErr, [String "device"; Int "n"; + Int "cyls"; Int "heads"; Int "sectors"; + String "line"]), 99, [DangerWillRobinson], + [], + "modify a single partition on a block device", + "\ +This runs L option to modify just the single +partition C (note: C counts from 1). + +For other parameters, see C. You should usually +pass C<0> for the cyls/heads/sectors parameters."); + + ("sfdisk_l", (RString "partitions", [String "device"]), 100, [], + [], + "display the partition table", + "\ +This displays the partition table on C, in the +human-readable output of the L command. It is +not intended to be parsed."); + + ("sfdisk_kernel_geometry", (RString "partitions", [String "device"]), 101, [], + [], + "display the kernel geometry", + "\ +This displays the kernel's idea of the geometry of C. + +The result is in human-readable format, and not designed to +be parsed."); + + ("sfdisk_disk_geometry", (RString "partitions", [String "device"]), 102, [], + [], + "display the disk geometry from the partition table", + "\ +This displays the disk geometry of C read from the +partition table. Especially in the case where the underlying +block device has been resized, this can be different from the +kernel's idea of the geometry (see C). + +The result is in human-readable format, and not designed to +be parsed."); + ] let all_functions = non_daemon_functions @ daemon_functions @@ -2267,8 +2317,10 @@ let check_functions () = fun (name, _, _, _, _, _, _) -> if String.length name >= 7 && String.sub name 0 7 = "guestfs" then failwithf "function name %s does not need 'guestfs' prefix" name; - if contains_uppercase name then - failwithf "function name %s should not contain uppercase chars" name; + if name = "" then + failwithf "function name is empty"; + if name.[0] < 'a' || name.[0] > 'z' then + failwithf "function name %s must start with lowercase a-z" name; if String.contains name '-' then failwithf "function name %s should not contain '-', use '_' instead." name diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index d27ef01..49e8961 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -8896,3 +8896,463 @@ int guestfs_zerofree (guestfs_h *g, return 0; } +struct pvresize_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 pvresize_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct pvresize_ctx *ctx = (struct pvresize_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_pvresize"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_pvresize"); + 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_pvresize"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_pvresize (guestfs_h *g, + const char *device) +{ + struct guestfs_pvresize_args args; + struct pvresize_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_pvresize") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.device = (char *) device; + serial = guestfs__send_sync (g, GUESTFS_PROC_PVRESIZE, + (xdrproc_t) xdr_guestfs_pvresize_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, pvresize_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_pvresize"); + guestfs_end_busy (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_PVRESIZE, 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 sfdisk_N_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 sfdisk_N_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct sfdisk_N_ctx *ctx = (struct sfdisk_N_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_sfdisk_N"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_sfdisk_N"); + 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_sfdisk_N"); + return; + } + goto done; + } + done: + ctx->cb_sequence = 1; +} + +int guestfs_sfdisk_N (guestfs_h *g, + const char *device, + int n, + int cyls, + int heads, + int sectors, + const char *line) +{ + struct guestfs_sfdisk_N_args args; + struct sfdisk_N_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_sfdisk_N") == -1) return -1; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.device = (char *) device; + args.n = n; + args.cyls = cyls; + args.heads = heads; + args.sectors = sectors; + args.line = (char *) line; + serial = guestfs__send_sync (g, GUESTFS_PROC_SFDISK_N, + (xdrproc_t) xdr_guestfs_sfdisk_N_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, sfdisk_N_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_sfdisk_N"); + guestfs_end_busy (g); + return -1; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SFDISK_N, 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 sfdisk_l_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_sfdisk_l_ret ret; +}; + +static void sfdisk_l_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct sfdisk_l_ctx *ctx = (struct sfdisk_l_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_sfdisk_l"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_sfdisk_l"); + 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_sfdisk_l"); + return; + } + goto done; + } + if (!xdr_guestfs_sfdisk_l_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_sfdisk_l"); + return; + } + done: + ctx->cb_sequence = 1; +} + +char *guestfs_sfdisk_l (guestfs_h *g, + const char *device) +{ + struct guestfs_sfdisk_l_args args; + struct sfdisk_l_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_sfdisk_l") == -1) return NULL; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.device = (char *) device; + serial = guestfs__send_sync (g, GUESTFS_PROC_SFDISK_L, + (xdrproc_t) xdr_guestfs_sfdisk_l_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (g); + return NULL; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, sfdisk_l_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_sfdisk_l"); + guestfs_end_busy (g); + return NULL; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SFDISK_L, serial) == -1) { + guestfs_end_busy (g); + return NULL; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return NULL; + } + + guestfs_end_busy (g); + return ctx.ret.partitions; /* caller will free */ +} + +struct sfdisk_kernel_geometry_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_sfdisk_kernel_geometry_ret ret; +}; + +static void sfdisk_kernel_geometry_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct sfdisk_kernel_geometry_ctx *ctx = (struct sfdisk_kernel_geometry_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_sfdisk_kernel_geometry"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_sfdisk_kernel_geometry"); + 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_sfdisk_kernel_geometry"); + return; + } + goto done; + } + if (!xdr_guestfs_sfdisk_kernel_geometry_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_sfdisk_kernel_geometry"); + return; + } + done: + ctx->cb_sequence = 1; +} + +char *guestfs_sfdisk_kernel_geometry (guestfs_h *g, + const char *device) +{ + struct guestfs_sfdisk_kernel_geometry_args args; + struct sfdisk_kernel_geometry_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_sfdisk_kernel_geometry") == -1) return NULL; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.device = (char *) device; + serial = guestfs__send_sync (g, GUESTFS_PROC_SFDISK_KERNEL_GEOMETRY, + (xdrproc_t) xdr_guestfs_sfdisk_kernel_geometry_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (g); + return NULL; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, sfdisk_kernel_geometry_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_sfdisk_kernel_geometry"); + guestfs_end_busy (g); + return NULL; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SFDISK_KERNEL_GEOMETRY, serial) == -1) { + guestfs_end_busy (g); + return NULL; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return NULL; + } + + guestfs_end_busy (g); + return ctx.ret.partitions; /* caller will free */ +} + +struct sfdisk_disk_geometry_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_sfdisk_disk_geometry_ret ret; +}; + +static void sfdisk_disk_geometry_reply_cb (guestfs_h *g, void *data, XDR *xdr) +{ + guestfs_main_loop *ml = guestfs_get_main_loop (g); + struct sfdisk_disk_geometry_ctx *ctx = (struct sfdisk_disk_geometry_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_sfdisk_disk_geometry"); + return; + } + + ml->main_loop_quit (ml, g); + + if (!xdr_guestfs_message_header (xdr, &ctx->hdr)) { + error (g, "%s: failed to parse reply header", "guestfs_sfdisk_disk_geometry"); + 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_sfdisk_disk_geometry"); + return; + } + goto done; + } + if (!xdr_guestfs_sfdisk_disk_geometry_ret (xdr, &ctx->ret)) { + error (g, "%s: failed to parse reply", "guestfs_sfdisk_disk_geometry"); + return; + } + done: + ctx->cb_sequence = 1; +} + +char *guestfs_sfdisk_disk_geometry (guestfs_h *g, + const char *device) +{ + struct guestfs_sfdisk_disk_geometry_args args; + struct sfdisk_disk_geometry_ctx ctx; + guestfs_main_loop *ml = guestfs_get_main_loop (g); + int serial; + + if (check_state (g, "guestfs_sfdisk_disk_geometry") == -1) return NULL; + guestfs_set_busy (g); + + memset (&ctx, 0, sizeof ctx); + + args.device = (char *) device; + serial = guestfs__send_sync (g, GUESTFS_PROC_SFDISK_DISK_GEOMETRY, + (xdrproc_t) xdr_guestfs_sfdisk_disk_geometry_args, (char *) &args); + if (serial == -1) { + guestfs_end_busy (g); + return NULL; + } + + guestfs__switch_to_receiving (g); + ctx.cb_sequence = 0; + guestfs_set_reply_callback (g, sfdisk_disk_geometry_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_sfdisk_disk_geometry"); + guestfs_end_busy (g); + return NULL; + } + + if (check_reply_header (g, &ctx.hdr, GUESTFS_PROC_SFDISK_DISK_GEOMETRY, serial) == -1) { + guestfs_end_busy (g); + return NULL; + } + + if (ctx.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", ctx.err.error_message); + free (ctx.err.error_message); + guestfs_end_busy (g); + return NULL; + } + + guestfs_end_busy (g); + return ctx.ret.partitions; /* caller will free */ +} + diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h index 9a4e923..b07e3dd 100644 --- a/src/guestfs-actions.h +++ b/src/guestfs-actions.h @@ -140,3 +140,8 @@ extern char **guestfs_strings (guestfs_h *handle, const char *path); extern char **guestfs_strings_e (guestfs_h *handle, const char *encoding, const char *path); extern char *guestfs_hexdump (guestfs_h *handle, const char *path); extern int guestfs_zerofree (guestfs_h *handle, const char *device); +extern int guestfs_pvresize (guestfs_h *handle, const char *device); +extern int guestfs_sfdisk_N (guestfs_h *handle, const char *device, int n, int cyls, int heads, int sectors, const char *line); +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); diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c index c505b25..e6e865e 100644 --- a/src/guestfs_protocol.c +++ b/src/guestfs_protocol.c @@ -1624,6 +1624,145 @@ xdr_guestfs_zerofree_args (XDR *xdrs, guestfs_zerofree_args *objp) } bool_t +xdr_guestfs_pvresize_args (XDR *xdrs, guestfs_pvresize_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_sfdisk_N_args (XDR *xdrs, guestfs_sfdisk_N_args *objp) +{ + register int32_t *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int (xdrs, &objp->n)) + return FALSE; + if (!xdr_int (xdrs, &objp->cyls)) + return FALSE; + if (!xdr_int (xdrs, &objp->heads)) + return FALSE; + if (!xdr_int (xdrs, &objp->sectors)) + return FALSE; + + } else { + IXDR_PUT_LONG(buf, objp->n); + IXDR_PUT_LONG(buf, objp->cyls); + IXDR_PUT_LONG(buf, objp->heads); + IXDR_PUT_LONG(buf, objp->sectors); + } + if (!xdr_string (xdrs, &objp->line, ~0)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + buf = XDR_INLINE (xdrs, 4 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int (xdrs, &objp->n)) + return FALSE; + if (!xdr_int (xdrs, &objp->cyls)) + return FALSE; + if (!xdr_int (xdrs, &objp->heads)) + return FALSE; + if (!xdr_int (xdrs, &objp->sectors)) + return FALSE; + + } else { + objp->n = IXDR_GET_LONG(buf); + objp->cyls = IXDR_GET_LONG(buf); + objp->heads = IXDR_GET_LONG(buf); + objp->sectors = IXDR_GET_LONG(buf); + } + if (!xdr_string (xdrs, &objp->line, ~0)) + return FALSE; + return TRUE; + } + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + if (!xdr_int (xdrs, &objp->n)) + return FALSE; + if (!xdr_int (xdrs, &objp->cyls)) + return FALSE; + if (!xdr_int (xdrs, &objp->heads)) + return FALSE; + if (!xdr_int (xdrs, &objp->sectors)) + return FALSE; + if (!xdr_string (xdrs, &objp->line, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_sfdisk_l_args (XDR *xdrs, guestfs_sfdisk_l_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_sfdisk_l_ret (XDR *xdrs, guestfs_sfdisk_l_ret *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->partitions, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_sfdisk_kernel_geometry_args (XDR *xdrs, guestfs_sfdisk_kernel_geometry_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_sfdisk_kernel_geometry_ret (XDR *xdrs, guestfs_sfdisk_kernel_geometry_ret *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->partitions, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_sfdisk_disk_geometry_args (XDR *xdrs, guestfs_sfdisk_disk_geometry_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_sfdisk_disk_geometry_ret (XDR *xdrs, guestfs_sfdisk_disk_geometry_ret *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->partitions, ~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 a855307..6235577 100644 --- a/src/guestfs_protocol.h +++ b/src/guestfs_protocol.h @@ -842,6 +842,51 @@ struct guestfs_zerofree_args { }; typedef struct guestfs_zerofree_args guestfs_zerofree_args; +struct guestfs_pvresize_args { + char *device; +}; +typedef struct guestfs_pvresize_args guestfs_pvresize_args; + +struct guestfs_sfdisk_N_args { + char *device; + int n; + int cyls; + int heads; + int sectors; + char *line; +}; +typedef struct guestfs_sfdisk_N_args guestfs_sfdisk_N_args; + +struct guestfs_sfdisk_l_args { + char *device; +}; +typedef struct guestfs_sfdisk_l_args guestfs_sfdisk_l_args; + +struct guestfs_sfdisk_l_ret { + char *partitions; +}; +typedef struct guestfs_sfdisk_l_ret guestfs_sfdisk_l_ret; + +struct guestfs_sfdisk_kernel_geometry_args { + char *device; +}; +typedef struct guestfs_sfdisk_kernel_geometry_args guestfs_sfdisk_kernel_geometry_args; + +struct guestfs_sfdisk_kernel_geometry_ret { + char *partitions; +}; +typedef struct guestfs_sfdisk_kernel_geometry_ret guestfs_sfdisk_kernel_geometry_ret; + +struct guestfs_sfdisk_disk_geometry_args { + char *device; +}; +typedef struct guestfs_sfdisk_disk_geometry_args guestfs_sfdisk_disk_geometry_args; + +struct guestfs_sfdisk_disk_geometry_ret { + char *partitions; +}; +typedef struct guestfs_sfdisk_disk_geometry_ret guestfs_sfdisk_disk_geometry_ret; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -940,7 +985,12 @@ enum guestfs_procedure { GUESTFS_PROC_STRINGS_E = 95, GUESTFS_PROC_HEXDUMP = 96, GUESTFS_PROC_ZEROFREE = 97, - GUESTFS_PROC_NR_PROCS = 97 + 1, + GUESTFS_PROC_PVRESIZE = 98, + GUESTFS_PROC_SFDISK_N = 99, + GUESTFS_PROC_SFDISK_L = 100, + GUESTFS_PROC_SFDISK_KERNEL_GEOMETRY = 101, + GUESTFS_PROC_SFDISK_DISK_GEOMETRY = 102, + GUESTFS_PROC_NR_PROCS = 102 + 1, }; typedef enum guestfs_procedure guestfs_procedure; #define GUESTFS_MESSAGE_MAX 4194304 @@ -1123,6 +1173,14 @@ extern bool_t xdr_guestfs_strings_e_ret (XDR *, guestfs_strings_e_ret*); extern bool_t xdr_guestfs_hexdump_args (XDR *, guestfs_hexdump_args*); extern bool_t xdr_guestfs_hexdump_ret (XDR *, guestfs_hexdump_ret*); extern bool_t xdr_guestfs_zerofree_args (XDR *, guestfs_zerofree_args*); +extern bool_t xdr_guestfs_pvresize_args (XDR *, guestfs_pvresize_args*); +extern bool_t xdr_guestfs_sfdisk_N_args (XDR *, guestfs_sfdisk_N_args*); +extern bool_t xdr_guestfs_sfdisk_l_args (XDR *, guestfs_sfdisk_l_args*); +extern bool_t xdr_guestfs_sfdisk_l_ret (XDR *, guestfs_sfdisk_l_ret*); +extern bool_t xdr_guestfs_sfdisk_kernel_geometry_args (XDR *, guestfs_sfdisk_kernel_geometry_args*); +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_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*); @@ -1264,6 +1322,14 @@ extern bool_t xdr_guestfs_strings_e_ret (); extern bool_t xdr_guestfs_hexdump_args (); extern bool_t xdr_guestfs_hexdump_ret (); extern bool_t xdr_guestfs_zerofree_args (); +extern bool_t xdr_guestfs_pvresize_args (); +extern bool_t xdr_guestfs_sfdisk_N_args (); +extern bool_t xdr_guestfs_sfdisk_l_args (); +extern bool_t xdr_guestfs_sfdisk_l_ret (); +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_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 f09e5b5..0df5cb0 100644 --- a/src/guestfs_protocol.x +++ b/src/guestfs_protocol.x @@ -652,6 +652,43 @@ struct guestfs_zerofree_args { string device<>; }; +struct guestfs_pvresize_args { + string device<>; +}; + +struct guestfs_sfdisk_N_args { + string device<>; + int n; + int cyls; + int heads; + int sectors; + string line<>; +}; + +struct guestfs_sfdisk_l_args { + string device<>; +}; + +struct guestfs_sfdisk_l_ret { + string partitions<>; +}; + +struct guestfs_sfdisk_kernel_geometry_args { + string device<>; +}; + +struct guestfs_sfdisk_kernel_geometry_ret { + string partitions<>; +}; + +struct guestfs_sfdisk_disk_geometry_args { + string device<>; +}; + +struct guestfs_sfdisk_disk_geometry_ret { + string partitions<>; +}; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -750,6 +787,11 @@ enum guestfs_procedure { GUESTFS_PROC_STRINGS_E = 95, GUESTFS_PROC_HEXDUMP = 96, GUESTFS_PROC_ZEROFREE = 97, + GUESTFS_PROC_PVRESIZE = 98, + GUESTFS_PROC_SFDISK_N = 99, + GUESTFS_PROC_SFDISK_L = 100, + GUESTFS_PROC_SFDISK_KERNEL_GEOMETRY = 101, + GUESTFS_PROC_SFDISK_DISK_GEOMETRY = 102, GUESTFS_PROC_NR_PROCS }; diff --git a/tests.c b/tests.c index 11a1568..31fa3bf 100644 --- a/tests.c +++ b/tests.c @@ -116,6 +116,11 @@ static void no_test_warnings (void) 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"); + fprintf (stderr, "warning: \"guestfs_pvresize\" has no tests\n"); + fprintf (stderr, "warning: \"guestfs_sfdisk_N\" has no tests\n"); + 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"); } static int test_zerofree_0 (void) -- 1.8.3.1