diff options
author | Richard Jones <rjones@redhat.com> | 2009-04-10 18:25:07 +0100 |
---|---|---|
committer | Richard Jones <rjones@redhat.com> | 2009-04-11 17:04:35 +0100 |
commit | b4d2a01828e5de85e5eee3631f7fe3925a0312ca (patch) | |
tree | 6f77ecceccd53a84afce4cecf0fe199ba7707752 | |
parent | 99f68f259f92eee884c6c7396f61b9c16e2bf354 (diff) | |
download | libguestfs-b4d2a01828e5de85e5eee3631f7fe3925a0312ca.tar.gz libguestfs-b4d2a01828e5de85e5eee3631f7fe3925a0312ca.tar.xz libguestfs-b4d2a01828e5de85e5eee3631f7fe3925a0312ca.zip |
Added test suite.
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | daemon/actions.h | 13 | ||||
-rw-r--r-- | daemon/daemon.h | 31 | ||||
-rw-r--r-- | daemon/devsparts.c | 62 | ||||
-rw-r--r-- | daemon/dir.c | 27 | ||||
-rw-r--r-- | daemon/file.c | 74 | ||||
-rw-r--r-- | daemon/guestfsd.c | 88 | ||||
-rw-r--r-- | daemon/lvm.c | 131 | ||||
-rw-r--r-- | daemon/mount.c | 115 | ||||
-rw-r--r-- | daemon/proto.c | 8 | ||||
-rw-r--r-- | daemon/stubs.c | 548 | ||||
-rw-r--r-- | daemon/sync.c | 1 | ||||
-rw-r--r-- | fish/cmds.c | 296 | ||||
-rw-r--r-- | fish/fish.c | 35 | ||||
-rw-r--r-- | fish/fish.h | 3 | ||||
-rw-r--r-- | guestfish-actions.pod | 141 | ||||
-rw-r--r-- | guestfs-actions.pod | 185 | ||||
-rw-r--r-- | libguestfs.spec.in | 4 | ||||
-rwxr-xr-x | make-initramfs.sh.in | 4 | ||||
-rw-r--r-- | ocaml/guestfs.ml | 13 | ||||
-rw-r--r-- | ocaml/guestfs.mli | 39 | ||||
-rw-r--r-- | ocaml/guestfs_c.c | 26 | ||||
-rw-r--r-- | ocaml/guestfs_c.h | 2 | ||||
-rw-r--r-- | ocaml/guestfs_c_actions.c | 318 | ||||
-rw-r--r-- | perl/Guestfs.xs | 318 | ||||
-rw-r--r-- | perl/lib/Sys/Guestfs.pm | 169 | ||||
-rwxr-xr-x | src/generator.ml | 1046 | ||||
-rw-r--r-- | src/guestfs-actions.c | 931 | ||||
-rw-r--r-- | src/guestfs-actions.h | 13 | ||||
-rw-r--r-- | src/guestfs_protocol.c | 208 | ||||
-rw-r--r-- | src/guestfs_protocol.h | 132 | ||||
-rw-r--r-- | src/guestfs_protocol.x | 79 | ||||
-rw-r--r-- | tests.c | 3933 |
33 files changed, 8670 insertions, 325 deletions
diff --git a/Makefile.am b/Makefile.am index 47954a50..2345018f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -72,6 +72,8 @@ tests_LDADD = $(top_builddir)/src/libguestfs.la TESTS = $(check_PROGRAMS) +$(TESTS): $(INITRAMFS) $(VMLINUZ) + # Manual pages. # guestfs-actions.pod and guestfs-structs are autogenerated. There is # no include mechanism for POD, so we have to do it by hand. diff --git a/daemon/actions.h b/daemon/actions.h index 1b35cad1..2a9d3d1d 100644 --- a/daemon/actions.h +++ b/daemon/actions.h @@ -56,3 +56,16 @@ extern int do_mkdir (const char *path); extern int do_mkdir_p (const char *path); extern int do_chmod (int mode, const char *path); extern int do_chown (int owner, int group, const char *path); +extern int do_exists (const char *path); +extern int do_is_file (const char *path); +extern int do_is_dir (const char *path); +extern int do_pvcreate (const char *device); +extern int do_vgcreate (const char *volgroup, char * const* const physvols); +extern int do_lvcreate (const char *logvol, const char *volgroup, int mbytes); +extern int do_mkfs (const char *fstype, const char *device); +extern int do_sfdisk (const char *device, int cyls, int heads, int sectors, char * const* const lines); +extern int do_write_file (const char *path, const char *content, int size); +extern int do_umount (const char *pathordevice); +extern char **do_mounts (void); +extern int do_umount_all (void); +extern int do_lvm_remove_all (void); diff --git a/daemon/daemon.h b/daemon/daemon.h index b2396a19..27d86c9b 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -21,6 +21,9 @@ #include <stdarg.h> #include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> #include <rpc/types.h> #include <rpc/xdr.h> @@ -28,16 +31,18 @@ #include "../src/guestfs_protocol.h" /* in guestfsd.c */ -extern void xwrite (int sock, const void *buf, size_t len); -extern void xread (int sock, void *buf, size_t len); +extern int xwrite (int sock, const void *buf, size_t len); +extern int xread (int sock, void *buf, size_t len); extern int add_string (char ***argv, int *size, int *alloc, const char *str); -extern int count_strings (char **argv); +extern int count_strings (char * const* const argv); extern void sort_strings (char **argv, int len); extern void free_strings (char **argv); extern void free_stringslen (char **argv, int len); extern int command (char **stdoutput, char **stderror, const char *name, ...); +extern int commandv (char **stdoutput, char **stderror, + char * const* const argv); /* in proto.c */ extern int proc_nr; @@ -75,6 +80,19 @@ extern void reply (xdrproc_t xdrp, char *ret); } \ } while (0) +#define IS_DEVICE(path,errcode) \ + do { \ + struct stat statbuf; \ + if (strncmp ((path), "/dev/", 5) != 0) { \ + reply_with_error ("%s: %s: expecting a device name", __func__, (path)); \ + return (errcode); \ + } \ + if (stat ((path), &statbuf) == -1) { \ + reply_with_perror ("%s: %s", __func__, (path)); \ + return (errcode); \ + } \ + } while (0) + /* NB: * (1) You must match CHROOT_IN and CHROOT_OUT even along error paths. * (2) You must not change directory! cwd must always be "/", otherwise @@ -86,4 +104,11 @@ extern void reply (xdrproc_t xdrp, char *ret); #define CHROOT_OUT \ do { int old_errno = errno; chroot ("."); errno = old_errno; } while (0) +#define XXX_NOT_IMPL(errcode) \ + do { \ + reply_with_error ("%s: function not implemented", __func__); \ + return (errcode); \ + } \ + while (0) + #endif /* GUESTFSD_DAEMON_H */ diff --git a/daemon/devsparts.c b/daemon/devsparts.c index b0d79569..324b8870 100644 --- a/daemon/devsparts.c +++ b/daemon/devsparts.c @@ -131,3 +131,65 @@ do_list_partitions (void) sort_strings (r, size-1); return r; } + +int +do_mkfs (const char *fstype, const char *device) +{ + char *err; + int r; + + IS_DEVICE (device, -1); + + r = command (NULL, &err, "/sbin/mkfs", "-t", fstype, device, NULL); + if (r == -1) { + reply_with_error ("mkfs: %s", err); + free (err); + return -1; + } + + 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/dir.c b/daemon/dir.c index 7892682f..f7064660 100644 --- a/daemon/dir.c +++ b/daemon/dir.c @@ -76,7 +76,7 @@ do_rm_rf (const char *path) snprintf (buf, len, "/sysroot%s", path); - r = command (NULL, &err, "rm", "-rf", buf); + r = command (NULL, &err, "rm", "-rf", buf, NULL); free (buf); /* rm -rf is never supposed to fail. I/O errors perhaps? */ @@ -165,3 +165,28 @@ do_mkdir_p (const char *path) return 0; } + +int +do_is_dir (const char *path) +{ + int r; + struct stat buf; + + NEED_ROOT (-1); + ABS_PATH (path, -1); + + CHROOT_IN; + r = lstat (path, &buf); + CHROOT_OUT; + + if (r == -1) { + if (errno != ENOENT && errno != ENOTDIR) { + reply_with_perror ("stat: %s", path); + return -1; + } + else + return 0; /* Not a directory. */ + } + + return S_ISDIR (buf.st_mode); +} diff --git a/daemon/file.c b/daemon/file.c index 43c875cc..0b8b463c 100644 --- a/daemon/file.c +++ b/daemon/file.c @@ -240,3 +240,77 @@ do_chown (int owner, int group, const char *path) return 0; } + +int +do_exists (const char *path) +{ + int r; + + NEED_ROOT (-1); + ABS_PATH (path, -1); + + CHROOT_IN; + r = access (path, F_OK); + CHROOT_OUT; + + return r == 0; +} + +int +do_is_file (const char *path) +{ + int r; + struct stat buf; + + NEED_ROOT (-1); + ABS_PATH (path, -1); + + CHROOT_IN; + r = lstat (path, &buf); + CHROOT_OUT; + + if (r == -1) { + if (errno != ENOENT && errno != ENOTDIR) { + reply_with_perror ("stat: %s", path); + return -1; + } + else + return 0; /* Not a file. */ + } + + return S_ISREG (buf.st_mode); +} + +int +do_write_file (const char *path, const char *content, int size) +{ + int fd; + + NEED_ROOT (-1); + ABS_PATH (path, -1); + + if (size == 0) + size = strlen (content); + + CHROOT_IN; + fd = open (path, O_WRONLY | O_CREAT | O_NOCTTY | O_NONBLOCK, 0666); + CHROOT_OUT; + + if (fd == -1) { + reply_with_perror ("open: %s", path); + return -1; + } + + if (xwrite (fd, content, size) == -1) { + reply_with_perror ("write"); + close (fd); + return -1; + } + + if (close (fd) == -1) { + reply_with_perror ("close: %s", path); + return -1; + } + + return 0; +} diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c index a243c0be..c701f194 100644 --- a/daemon/guestfsd.c +++ b/daemon/guestfsd.c @@ -170,7 +170,7 @@ main (int argc, char *argv[]) exit (1); } - xwrite (sock, buf, xdr_getpos (&xdr)); + (void) xwrite (sock, buf, xdr_getpos (&xdr)); xdr_destroy (&xdr); @@ -188,7 +188,7 @@ main (int argc, char *argv[]) exit (0); } -void +int xwrite (int sock, const void *buf, size_t len) { int r; @@ -197,14 +197,16 @@ xwrite (int sock, const void *buf, size_t len) r = write (sock, buf, len); if (r == -1) { perror ("write"); - exit (1); + return -1; } buf += r; len -= r; } + + return 0; } -void +int xread (int sock, void *buf, size_t len) { int r; @@ -213,15 +215,17 @@ xread (int sock, void *buf, size_t len) r = read (sock, buf, len); if (r == -1) { perror ("read"); - exit (1); + return -1; } if (r == 0) { - fprintf (stderr, "read: unexpected end of file on comms socket\n"); - exit (1); + fprintf (stderr, "read: unexpected end of file on fd %d\n", sock); + return -1; } buf += r; len -= r; } + + return 0; } static void @@ -263,7 +267,7 @@ add_string (char ***argv, int *size, int *alloc, const char *str) } int -count_strings (char **argv) +count_strings (char * const* const argv) { int argc; @@ -314,15 +318,52 @@ free_stringslen (char **argv, int len) int command (char **stdoutput, char **stderror, const char *name, ...) { + va_list args; + char **argv; + char *s; + int i, r; + + /* Collect the command line arguments into an array. */ + va_start (args, name); + + i = 2; + argv = malloc (sizeof (char *) * i); + argv[0] = (char *) name; + argv[1] = NULL; + + while ((s = va_arg (args, char *)) != NULL) { + argv = realloc (argv, sizeof (char *) * (++i)); + argv[i-2] = s; + argv[i-1] = NULL; + } + + va_end (args); + + r = commandv (stdoutput, stderror, argv); + + /* NB: Mustn't free the strings which are on the stack. */ + free (argv); + + return r; +} + +int +commandv (char **stdoutput, char **stderror, char * const* const argv) +{ int so_size = 0, se_size = 0; int so_fd[2], se_fd[2]; - int pid, r, quit; + int pid, r, quit, i; fd_set rset, rset2; char buf[256]; if (stdoutput) *stdoutput = NULL; if (stderror) *stderror = NULL; + printf ("%s", argv[0]); + for (i = 1; argv[i] != NULL; ++i) + printf (" %s", argv[i]); + printf ("\n"); + if (pipe (so_fd) == -1 || pipe (se_fd) == -1) { perror ("pipe"); return -1; @@ -335,25 +376,6 @@ command (char **stdoutput, char **stderror, const char *name, ...) } if (pid == 0) { /* Child process. */ - va_list args; - char **argv; - char *s; - int i; - - /* Collect the command line arguments into an array. */ - va_start (args, name); - - i = 2; - argv = malloc (sizeof (char *) * i); - argv[0] = (char *) name; - argv[1] = NULL; - - while ((s = va_arg (args, char *)) != NULL) { - argv = realloc (argv, sizeof (char *) * (++i)); - argv[i-2] = s; - argv[i-1] = NULL; - } - close (0); close (so_fd[0]); close (se_fd[0]); @@ -362,8 +384,8 @@ command (char **stdoutput, char **stderror, const char *name, ...) close (so_fd[1]); close (se_fd[1]); - execvp (name, argv); - perror (name); + execvp (argv[0], argv); + perror (argv[0]); _exit (1); } @@ -376,7 +398,7 @@ command (char **stdoutput, char **stderror, const char *name, ...) FD_SET (se_fd[0], &rset); quit = 0; - while (!quit) { + while (quit < 2) { rset2 = rset; r = select (MAX (so_fd[0], se_fd[0]) + 1, &rset2, NULL, NULL, NULL); if (r == -1) { @@ -392,7 +414,7 @@ command (char **stdoutput, char **stderror, const char *name, ...) waitpid (pid, NULL, 0); return -1; } - if (r == 0) quit = 1; + if (r == 0) { FD_CLR (so_fd[0], &rset); quit++; } if (r > 0 && stdoutput) { so_size += r; @@ -413,7 +435,7 @@ command (char **stdoutput, char **stderror, const char *name, ...) waitpid (pid, NULL, 0); return -1; } - if (r == 0) quit = 1; + if (r == 0) { FD_CLR (se_fd[0], &rset); quit++; } if (r > 0 && stderror) { se_size += r; diff --git a/daemon/lvm.c b/daemon/lvm.c index 7f31c84e..55b41f02 100644 --- a/daemon/lvm.c +++ b/daemon/lvm.c @@ -169,3 +169,134 @@ do_lvs_full (void) { return parse_command_line_lvs (); } + +int +do_pvcreate (const char *device) +{ + char *err; + int r; + + r = command (NULL, &err, + "/sbin/lvm", "pvcreate", device, NULL); + if (r == -1) { + reply_with_error ("%s", err); + free (err); + return -1; + } + + free (err); + return 0; +} + +int +do_vgcreate (const char *volgroup, char * const* const physvols) +{ + char *err; + int r, argc, i; + const char **argv; + + argc = count_strings (physvols) + 3; + argv = malloc (sizeof (char *) * (argc + 1)); + argv[0] = "/sbin/lvm"; + argv[1] = "vgcreate"; + argv[2] = volgroup; + for (i = 3; i <= argc; ++i) + argv[i] = physvols[i-3]; + + r = commandv (NULL, &err, argv); + if (r == -1) { + reply_with_error ("%s", err); + free (err); + return -1; + } + + free (err); + return 0; +} + +int +do_lvcreate (const char *logvol, const char *volgroup, int mbytes) +{ + char *err; + int r; + char size[64]; + + snprintf (size, sizeof size, "%d", mbytes); + + r = command (NULL, &err, + "/sbin/lvm", "lvcreate", + "-L", size, "-n", logvol, volgroup, NULL); + if (r == -1) { + reply_with_error ("%s", err); + free (err); + return -1; + } + + free (err); + return 0; +} + +/* Super-dangerous command used for testing. It removes all + * LVs, VGs and PVs permanently. + */ +int +do_lvm_remove_all (void) +{ + char **xs; + int i, r; + char *err; + + /* Remove LVs. */ + xs = do_lvs (); + if (xs == NULL) + return -1; + + for (i = 0; xs[i] != NULL; ++i) { + r = command (NULL, &err, "/sbin/lvm", "lvremove", "-f", xs[i], NULL); + if (r == -1) { + reply_with_error ("lvremove: %s: %s", xs[i], err); + free (err); + free_strings (xs); + return -1; + } + free (err); + } + free_strings (xs); + + /* Remove VGs. */ + xs = do_vgs (); + if (xs == NULL) + return -1; + + for (i = 0; xs[i] != NULL; ++i) { + r = command (NULL, &err, "/sbin/lvm", "vgremove", "-f", xs[i], NULL); + if (r == -1) { + reply_with_error ("vgremove: %s: %s", xs[i], err); + free (err); + free_strings (xs); + return -1; + } + free (err); + } + free_strings (xs); + + /* Remove PVs. */ + xs = do_pvs (); + if (xs == NULL) + return -1; + + for (i = 0; xs[i] != NULL; ++i) { + r = command (NULL, &err, "/sbin/lvm", "pvremove", "-f", xs[i], NULL); + if (r == -1) { + reply_with_error ("pvremove: %s: %s", xs[i], err); + free (err); + free_strings (xs); + return -1; + } + free (err); + } + free_strings (xs); + + /* There, that was easy, sorry about your data. */ + return 0; +} diff --git a/daemon/mount.c b/daemon/mount.c index 440ec0de..fd9c8e43 100644 --- a/daemon/mount.c +++ b/daemon/mount.c @@ -74,3 +74,118 @@ do_mount (const char *device, const char *mountpoint) return 0; } + +/* Again, use the external /bin/umount program, so that /etc/mtab + * is kept updated. + */ +int +do_umount (const char *pathordevice) +{ + int len, freeit = 0, r; + char *buf; + char *err; + + if (strncmp (pathordevice, "/dev/", 5) == 0) + buf = (char *) pathordevice; + else { + len = strlen (pathordevice) + 9; + freeit = 1; + buf = malloc (len); + if (buf == NULL) { + reply_with_perror ("malloc"); + return -1; + } + snprintf (buf, len, "/sysroot%s", pathordevice); + } + + r = command (NULL, &err, "umount", buf, NULL); + if (freeit) free (buf); + if (r == -1) { + reply_with_error ("umount: %s: %s", pathordevice, err); + free (err); + return -1; + } + + free (err); + + /* update root_mounted? */ + + return 0; +} + +char ** +do_mounts (void) +{ + char *out, *err; + int r; + char **ret = NULL; + int size = 0, alloc = 0; + char *p, *pend, *p2; + + r = command (&out, &err, "mount", NULL); + if (r == -1) { + reply_with_error ("mount: %s", err); + free (out); + free (err); + return NULL; + } + + free (err); + + p = out; + while (p) { + pend = strchr (p, '\n'); + if (pend) { + *pend = '\0'; + pend++; + } + + /* Lines have the format: + * /dev/foo on /mountpoint type ... + */ + p2 = strstr (p, " on /sysroot"); + if (p2 != NULL) { + *p2 = '\0'; + if (add_string (&ret, &size, &alloc, p) == -1) { + free (out); + return NULL; + } + } + + p = pend; + } + + free (out); + + if (add_string (&ret, &size, &alloc, NULL) == -1) + return NULL; + + return ret; +} + +/* Only unmount stuff under /sysroot */ +int +do_umount_all (void) +{ + char **mounts; + int i, r; + char *err; + + mounts = do_mounts (); + if (mounts == NULL) /* do_mounts has already replied */ + return -1; + + for (i = 0; mounts[i] != NULL; ++i) { + r = command (NULL, &err, "umount", mounts[i], NULL); + if (r == -1) { + reply_with_error ("umount: %s: %s", mounts[i], err); + free (err); + free_strings (mounts); + return -1; + } + free (err); + } + + free_strings (mounts); + return 0; +} diff --git a/daemon/proto.c b/daemon/proto.c index 93d33c2c..42bc6eaa 100644 --- a/daemon/proto.c +++ b/daemon/proto.c @@ -206,8 +206,8 @@ send_error (const char *msg) xdr_uint32_t (&xdr, &len); xdr_destroy (&xdr); - xwrite (sock, lenbuf, 4); - xwrite (sock, buf, len); + (void) xwrite (sock, lenbuf, 4); + (void) xwrite (sock, buf, len); } void @@ -247,6 +247,6 @@ reply (xdrproc_t xdrp, char *ret) xdr_uint32_t (&xdr, &len); xdr_destroy (&xdr); - xwrite (sock, lenbuf, 4); - xwrite (sock, buf, len); + (void) xwrite (sock, lenbuf, 4); + (void) xwrite (sock, buf, len); } diff --git a/daemon/stubs.c b/daemon/stubs.c index 1227fa88..4540ca56 100644 --- a/daemon/stubs.c +++ b/daemon/stubs.c @@ -51,10 +51,12 @@ static void mount_stub (XDR *xdr_in) r = do_mount (device, mountpoint); if (r == -1) - /* do_mount has already called reply_with_error, so just return */ - return; + /* do_mount has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_mount_args, (char *) &args); } static void sync_stub (XDR *xdr_in) @@ -63,10 +65,11 @@ static void sync_stub (XDR *xdr_in) r = do_sync (); if (r == -1) - /* do_sync has already called reply_with_error, so just return */ - return; + /* do_sync has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: ; } static void touch_stub (XDR *xdr_in) @@ -85,10 +88,12 @@ static void touch_stub (XDR *xdr_in) r = do_touch (path); if (r == -1) - /* do_touch has already called reply_with_error, so just return */ - return; + /* do_touch has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_touch_args, (char *) &args); } static void cat_stub (XDR *xdr_in) @@ -107,13 +112,15 @@ static void cat_stub (XDR *xdr_in) r = do_cat (path); if (r == NULL) - /* do_cat has already called reply_with_error, so just return */ - return; + /* do_cat has already called reply_with_error */ + goto done; struct guestfs_cat_ret ret; ret.content = r; reply ((xdrproc_t) &xdr_guestfs_cat_ret, (char *) &ret); free (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_cat_args, (char *) &args); } static void ll_stub (XDR *xdr_in) @@ -132,13 +139,15 @@ static void ll_stub (XDR *xdr_in) r = do_ll (directory); if (r == NULL) - /* do_ll has already called reply_with_error, so just return */ - return; + /* do_ll has already called reply_with_error */ + goto done; struct guestfs_ll_ret ret; ret.listing = r; reply ((xdrproc_t) &xdr_guestfs_ll_ret, (char *) &ret); free (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_ll_args, (char *) &args); } static void ls_stub (XDR *xdr_in) @@ -157,14 +166,16 @@ static void ls_stub (XDR *xdr_in) r = do_ls (directory); if (r == NULL) - /* do_ls has already called reply_with_error, so just return */ - return; + /* do_ls has already called reply_with_error */ + goto done; struct guestfs_ls_ret ret; ret.listing.listing_len = count_strings (r); ret.listing.listing_val = r; reply ((xdrproc_t) &xdr_guestfs_ls_ret, (char *) &ret); free_strings (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_ls_args, (char *) &args); } static void list_devices_stub (XDR *xdr_in) @@ -173,14 +184,15 @@ static void list_devices_stub (XDR *xdr_in) r = do_list_devices (); if (r == NULL) - /* do_list_devices has already called reply_with_error, so just return */ - return; + /* do_list_devices has already called reply_with_error */ + goto done; struct guestfs_list_devices_ret ret; ret.devices.devices_len = count_strings (r); ret.devices.devices_val = r; reply ((xdrproc_t) &xdr_guestfs_list_devices_ret, (char *) &ret); free_strings (r); +done: ; } static void list_partitions_stub (XDR *xdr_in) @@ -189,14 +201,15 @@ static void list_partitions_stub (XDR *xdr_in) r = do_list_partitions (); if (r == NULL) - /* do_list_partitions has already called reply_with_error, so just return */ - return; + /* do_list_partitions has already called reply_with_error */ + goto done; struct guestfs_list_partitions_ret ret; ret.partitions.partitions_len = count_strings (r); ret.partitions.partitions_val = r; reply ((xdrproc_t) &xdr_guestfs_list_partitions_ret, (char *) &ret); free_strings (r); +done: ; } static void pvs_stub (XDR *xdr_in) @@ -205,14 +218,15 @@ static void pvs_stub (XDR *xdr_in) r = do_pvs (); if (r == NULL) - /* do_pvs has already called reply_with_error, so just return */ - return; + /* do_pvs has already called reply_with_error */ + goto done; struct guestfs_pvs_ret ret; ret.physvols.physvols_len = count_strings (r); ret.physvols.physvols_val = r; reply ((xdrproc_t) &xdr_guestfs_pvs_ret, (char *) &ret); free_strings (r); +done: ; } static void vgs_stub (XDR *xdr_in) @@ -221,14 +235,15 @@ static void vgs_stub (XDR *xdr_in) r = do_vgs (); if (r == NULL) - /* do_vgs has already called reply_with_error, so just return */ - return; + /* do_vgs has already called reply_with_error */ + goto done; struct guestfs_vgs_ret ret; ret.volgroups.volgroups_len = count_strings (r); ret.volgroups.volgroups_val = r; reply ((xdrproc_t) &xdr_guestfs_vgs_ret, (char *) &ret); free_strings (r); +done: ; } static void lvs_stub (XDR *xdr_in) @@ -237,14 +252,15 @@ static void lvs_stub (XDR *xdr_in) r = do_lvs (); if (r == NULL) - /* do_lvs has already called reply_with_error, so just return */ - return; + /* do_lvs has already called reply_with_error */ + goto done; struct guestfs_lvs_ret ret; ret.logvols.logvols_len = count_strings (r); ret.logvols.logvols_val = r; reply ((xdrproc_t) &xdr_guestfs_lvs_ret, (char *) &ret); free_strings (r); +done: ; } static void pvs_full_stub (XDR *xdr_in) @@ -253,13 +269,14 @@ static void pvs_full_stub (XDR *xdr_in) r = do_pvs_full (); if (r == NULL) - /* do_pvs_full has already called reply_with_error, so just return */ - return; + /* do_pvs_full has already called reply_with_error */ + goto done; struct guestfs_pvs_full_ret ret; ret.physvols = *r; reply ((xdrproc_t) xdr_guestfs_pvs_full_ret, (char *) &ret); xdr_free ((xdrproc_t) xdr_guestfs_pvs_full_ret, (char *) &ret); +done: ; } static void vgs_full_stub (XDR *xdr_in) @@ -268,13 +285,14 @@ static void vgs_full_stub (XDR *xdr_in) r = do_vgs_full (); if (r == NULL) - /* do_vgs_full has already called reply_with_error, so just return */ - return; + /* do_vgs_full has already called reply_with_error */ + goto done; struct guestfs_vgs_full_ret ret; ret.volgroups = *r; reply ((xdrproc_t) xdr_guestfs_vgs_full_ret, (char *) &ret); xdr_free ((xdrproc_t) xdr_guestfs_vgs_full_ret, (char *) &ret); +done: ; } static void lvs_full_stub (XDR *xdr_in) @@ -283,13 +301,14 @@ static void lvs_full_stub (XDR *xdr_in) r = do_lvs_full (); if (r == NULL) - /* do_lvs_full has already called reply_with_error, so just return */ - return; + /* do_lvs_full has already called reply_with_error */ + goto done; struct guestfs_lvs_full_ret ret; ret.logvols = *r; reply ((xdrproc_t) xdr_guestfs_lvs_full_ret, (char *) &ret); xdr_free ((xdrproc_t) xdr_guestfs_lvs_full_ret, (char *) &ret); +done: ; } static void read_lines_stub (XDR *xdr_in) @@ -308,14 +327,16 @@ static void read_lines_stub (XDR *xdr_in) r = do_read_lines (path); if (r == NULL) - /* do_read_lines has already called reply_with_error, so just return */ - return; + /* do_read_lines has already called reply_with_error */ + goto done; struct guestfs_read_lines_ret ret; ret.lines.lines_len = count_strings (r); ret.lines.lines_val = r; reply ((xdrproc_t) &xdr_guestfs_read_lines_ret, (char *) &ret); free_strings (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_read_lines_args, (char *) &args); } static void aug_init_stub (XDR *xdr_in) @@ -336,10 +357,12 @@ static void aug_init_stub (XDR *xdr_in) r = do_aug_init (root, flags); if (r == -1) - /* do_aug_init has already called reply_with_error, so just return */ - return; + /* do_aug_init has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_aug_init_args, (char *) &args); } static void aug_close_stub (XDR *xdr_in) @@ -348,10 +371,11 @@ static void aug_close_stub (XDR *xdr_in) r = do_aug_close (); if (r == -1) - /* do_aug_close has already called reply_with_error, so just return */ - return; + /* do_aug_close has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: ; } static void aug_defvar_stub (XDR *xdr_in) @@ -372,12 +396,14 @@ static void aug_defvar_stub (XDR *xdr_in) r = do_aug_defvar (name, expr); if (r == -1) - /* do_aug_defvar has already called reply_with_error, so just return */ - return; + /* do_aug_defvar has already called reply_with_error */ + goto done; struct guestfs_aug_defvar_ret ret; ret.nrnodes = r; reply ((xdrproc_t) &xdr_guestfs_aug_defvar_ret, (char *) &ret); +done: + xdr_free ((xdrproc_t) xdr_guestfs_aug_defvar_args, (char *) &args); } static void aug_defnode_stub (XDR *xdr_in) @@ -400,11 +426,13 @@ static void aug_defnode_stub (XDR *xdr_in) r = do_aug_defnode (name, expr, val); if (r == NULL) - /* do_aug_defnode has already called reply_with_error, so just return */ - return; + /* do_aug_defnode has already called reply_with_error */ + goto done; reply ((xdrproc_t) xdr_guestfs_aug_defnode_ret, (char *) r); xdr_free ((xdrproc_t) xdr_guestfs_aug_defnode_ret, (char *) r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_aug_defnode_args, (char *) &args); } static void aug_get_stub (XDR *xdr_in) @@ -423,13 +451,15 @@ static void aug_get_stub (XDR *xdr_in) r = do_aug_get (path); if (r == NULL) - /* do_aug_get has already called reply_with_error, so just return */ - return; + /* do_aug_get has already called reply_with_error */ + goto done; struct guestfs_aug_get_ret ret; ret.val = r; reply ((xdrproc_t) &xdr_guestfs_aug_get_ret, (char *) &ret); free (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_aug_get_args, (char *) &args); } static void aug_set_stub (XDR *xdr_in) @@ -450,10 +480,12 @@ static void aug_set_stub (XDR *xdr_in) r = do_aug_set (path, val); if (r == -1) - /* do_aug_set has already called reply_with_error, so just return */ - return; + /* do_aug_set has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_aug_set_args, (char *) &args); } static void aug_insert_stub (XDR *xdr_in) @@ -476,10 +508,12 @@ static void aug_insert_stub (XDR *xdr_in) r = do_aug_insert (path, label, before); if (r == -1) - /* do_aug_insert has already called reply_with_error, so just return */ - return; + /* do_aug_insert has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_aug_insert_args, (char *) &args); } static void aug_rm_stub (XDR *xdr_in) @@ -498,12 +532,14 @@ static void aug_rm_stub (XDR *xdr_in) r = do_aug_rm (path); if (r == -1) - /* do_aug_rm has already called reply_with_error, so just return */ - return; + /* do_aug_rm has already called reply_with_error */ + goto done; struct guestfs_aug_rm_ret ret; ret.nrnodes = r; reply ((xdrproc_t) &xdr_guestfs_aug_rm_ret, (char *) &ret); +done: + xdr_free ((xdrproc_t) xdr_guestfs_aug_rm_args, (char *) &args); } static void aug_mv_stub (XDR *xdr_in) @@ -524,10 +560,12 @@ static void aug_mv_stub (XDR *xdr_in) r = do_aug_mv (src, dest); if (r == -1) - /* do_aug_mv has already called reply_with_error, so just return */ - return; + /* do_aug_mv has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_aug_mv_args, (char *) &args); } static void aug_match_stub (XDR *xdr_in) @@ -546,14 +584,16 @@ static void aug_match_stub (XDR *xdr_in) r = do_aug_match (path); if (r == NULL) - /* do_aug_match has already called reply_with_error, so just return */ - return; + /* do_aug_match has already called reply_with_error */ + goto done; struct guestfs_aug_match_ret ret; ret.matches.matches_len = count_strings (r); ret.matches.matches_val = r; reply ((xdrproc_t) &xdr_guestfs_aug_match_ret, (char *) &ret); free_strings (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_aug_match_args, (char *) &args); } static void aug_save_stub (XDR *xdr_in) @@ -562,10 +602,11 @@ static void aug_save_stub (XDR *xdr_in) r = do_aug_save (); if (r == -1) - /* do_aug_save has already called reply_with_error, so just return */ - return; + /* do_aug_save has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: ; } static void aug_load_stub (XDR *xdr_in) @@ -574,10 +615,11 @@ static void aug_load_stub (XDR *xdr_in) r = do_aug_load (); if (r == -1) - /* do_aug_load has already called reply_with_error, so just return */ - return; + /* do_aug_load has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: ; } static void aug_ls_stub (XDR *xdr_in) @@ -596,14 +638,16 @@ static void aug_ls_stub (XDR *xdr_in) r = do_aug_ls (path); if (r == NULL) - /* do_aug_ls has already called reply_with_error, so just return */ - return; + /* do_aug_ls has already called reply_with_error */ + goto done; struct guestfs_aug_ls_ret ret; ret.matches.matches_len = count_strings (r); ret.matches.matches_val = r; reply ((xdrproc_t) &xdr_guestfs_aug_ls_ret, (char *) &ret); free_strings (r); +done: + xdr_free ((xdrproc_t) xdr_guestfs_aug_ls_args, (char *) &args); } static void rm_stub (XDR *xdr_in) @@ -622,10 +666,12 @@ static void rm_stub (XDR *xdr_in) r = do_rm (path); if (r == -1) - /* do_rm has already called reply_with_error, so just return */ - return; + /* do_rm has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_rm_args, (char *) &args); } static void rmdir_stub (XDR *xdr_in) @@ -644,10 +690,12 @@ static void rmdir_stub (XDR *xdr_in) r = do_rmdir (path); if (r == -1) - /* do_rmdir has already called reply_with_error, so just return */ - return; + /* do_rmdir has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_rmdir_args, (char *) &args); } static void rm_rf_stub (XDR *xdr_in) @@ -666,10 +714,12 @@ static void rm_rf_stub (XDR *xdr_in) r = do_rm_rf (path); if (r == -1) - /* do_rm_rf has already called reply_with_error, so just return */ - return; + /* do_rm_rf has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_rm_rf_args, (char *) &args); } static void mkdir_stub (XDR *xdr_in) @@ -688,10 +738,12 @@ static void mkdir_stub (XDR *xdr_in) r = do_mkdir (path); if (r == -1) - /* do_mkdir has already called reply_with_error, so just return */ - return; + /* do_mkdir has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_mkdir_args, (char *) &args); } static void mkdir_p_stub (XDR *xdr_in) @@ -710,10 +762,12 @@ static void mkdir_p_stub (XDR *xdr_in) r = do_mkdir_p (path); if (r == -1) - /* do_mkdir_p has already called reply_with_error, so just return */ - return; + /* do_mkdir_p has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_mkdir_p_args, (char *) &args); } static void chmod_stub (XDR *xdr_in) @@ -734,10 +788,12 @@ static void chmod_stub (XDR *xdr_in) r = do_chmod (mode, path); if (r == -1) - /* do_chmod has already called reply_with_error, so just return */ - return; + /* do_chmod has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_chmod_args, (char *) &args); } static void chown_stub (XDR *xdr_in) @@ -760,10 +816,325 @@ static void chown_stub (XDR *xdr_in) r = do_chown (owner, group, path); if (r == -1) - /* do_chown has already called reply_with_error, so just return */ + /* do_chown has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_chown_args, (char *) &args); +} + +static void exists_stub (XDR *xdr_in) +{ + int r; + struct guestfs_exists_args args; + const char *path; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_exists_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "exists"); return; + } + path = args.path; + + r = do_exists (path); + if (r == -1) + /* do_exists has already called reply_with_error */ + goto done; + + struct guestfs_exists_ret ret; + ret.existsflag = r; + reply ((xdrproc_t) &xdr_guestfs_exists_ret, (char *) &ret); +done: + xdr_free ((xdrproc_t) xdr_guestfs_exists_args, (char *) &args); +} + +static void is_file_stub (XDR *xdr_in) +{ + int r; + struct guestfs_is_file_args args; + const char *path; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_is_file_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "is_file"); + return; + } + path = args.path; + + r = do_is_file (path); + if (r == -1) + /* do_is_file has already called reply_with_error */ + goto done; + + struct guestfs_is_file_ret ret; + ret.fileflag = r; + reply ((xdrproc_t) &xdr_guestfs_is_file_ret, (char *) &ret); +done: + xdr_free ((xdrproc_t) xdr_guestfs_is_file_args, (char *) &args); +} + +static void is_dir_stub (XDR *xdr_in) +{ + int r; + struct guestfs_is_dir_args args; + const char *path; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_is_dir_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "is_dir"); + return; + } + path = args.path; + + r = do_is_dir (path); + if (r == -1) + /* do_is_dir has already called reply_with_error */ + goto done; + + struct guestfs_is_dir_ret ret; + ret.dirflag = r; + reply ((xdrproc_t) &xdr_guestfs_is_dir_ret, (char *) &ret); +done: + xdr_free ((xdrproc_t) xdr_guestfs_is_dir_args, (char *) &args); +} + +static void pvcreate_stub (XDR *xdr_in) +{ + int r; + struct guestfs_pvcreate_args args; + const char *device; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_pvcreate_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "pvcreate"); + return; + } + device = args.device; + + r = do_pvcreate (device); + if (r == -1) + /* do_pvcreate has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_pvcreate_args, (char *) &args); +} + +static void vgcreate_stub (XDR *xdr_in) +{ + int r; + struct guestfs_vgcreate_args args; + const char *volgroup; + char **physvols; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_vgcreate_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "vgcreate"); + return; + } + volgroup = args.volgroup; + args.physvols.physvols_val = realloc (args.physvols.physvols_val, sizeof (char *) * (args.physvols.physvols_len+1)); + args.physvols.physvols_val[args.physvols.physvols_len] = NULL; + physvols = args.physvols.physvols_val; + + r = do_vgcreate (volgroup, physvols); + if (r == -1) + /* do_vgcreate has already called reply_with_error */ + goto done; reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_vgcreate_args, (char *) &args); +} + +static void lvcreate_stub (XDR *xdr_in) +{ + int r; + struct guestfs_lvcreate_args args; + const char *logvol; + const char *volgroup; + int mbytes; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_lvcreate_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "lvcreate"); + return; + } + logvol = args.logvol; + volgroup = args.volgroup; + mbytes = args.mbytes; + + r = do_lvcreate (logvol, volgroup, mbytes); + if (r == -1) + /* do_lvcreate has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_lvcreate_args, (char *) &args); +} + +static void mkfs_stub (XDR *xdr_in) +{ + int r; + struct guestfs_mkfs_args args; + const char *fstype; + const char *device; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_mkfs_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "mkfs"); + return; + } + fstype = args.fstype; + device = args.device; + + r = do_mkfs (fstype, device); + if (r == -1) + /* do_mkfs has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_mkfs_args, (char *) &args); +} + +static void sfdisk_stub (XDR *xdr_in) +{ + int r; + struct guestfs_sfdisk_args args; + const char *device; + int cyls; + int heads; + int sectors; + char **lines; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_sfdisk_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "sfdisk"); + return; + } + device = args.device; + cyls = args.cyls; + heads = args.heads; + sectors = args.sectors; + args.lines.lines_val = realloc (args.lines.lines_val, sizeof (char *) * (args.lines.lines_len+1)); + args.lines.lines_val[args.lines.lines_len] = NULL; + lines = args.lines.lines_val; + + r = do_sfdisk (device, cyls, heads, sectors, lines); + if (r == -1) + /* do_sfdisk has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_sfdisk_args, (char *) &args); +} + +static void write_file_stub (XDR *xdr_in) +{ + int r; + struct guestfs_write_file_args args; + const char *path; + const char *content; + int size; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_write_file_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "write_file"); + return; + } + path = args.path; + content = args.content; + size = args.size; + + r = do_write_file (path, content, size); + if (r == -1) + /* do_write_file has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_write_file_args, (char *) &args); +} + +static void umount_stub (XDR *xdr_in) +{ + int r; + struct guestfs_umount_args args; + const char *pathordevice; + + memset (&args, 0, sizeof args); + + if (!xdr_guestfs_umount_args (xdr_in, &args)) { + reply_with_error ("%s: daemon failed to decode procedure arguments", "umount"); + return; + } + pathordevice = args.pathordevice; + + r = do_umount (pathordevice); + if (r == -1) + /* do_umount has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: + xdr_free ((xdrproc_t) xdr_guestfs_umount_args, (char *) &args); +} + +static void mounts_stub (XDR *xdr_in) +{ + char **r; + + r = do_mounts (); + if (r == NULL) + /* do_mounts has already called reply_with_error */ + goto done; + + struct guestfs_mounts_ret ret; + ret.devices.devices_len = count_strings (r); + ret.devices.devices_val = r; + reply ((xdrproc_t) &xdr_guestfs_mounts_ret, (char *) &ret); + free_strings (r); +done: ; +} + +static void umount_all_stub (XDR *xdr_in) +{ + int r; + + r = do_umount_all (); + if (r == -1) + /* do_umount_all has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: ; +} + +static void lvm_remove_all_stub (XDR *xdr_in) +{ + int r; + + r = do_lvm_remove_all (); + if (r == -1) + /* do_lvm_remove_all has already called reply_with_error */ + goto done; + + reply (NULL, NULL); +done: ; } void dispatch_incoming_message (XDR *xdr_in) @@ -874,6 +1245,45 @@ void dispatch_incoming_message (XDR *xdr_in) case GUESTFS_PROC_CHOWN: chown_stub (xdr_in); break; + case GUESTFS_PROC_EXISTS: + exists_stub (xdr_in); + break; + case GUESTFS_PROC_IS_FILE: + is_file_stub (xdr_in); + break; + case GUESTFS_PROC_IS_DIR: + is_dir_stub (xdr_in); + break; + case GUESTFS_PROC_PVCREATE: + pvcreate_stub (xdr_in); + break; + case GUESTFS_PROC_VGCREATE: + vgcreate_stub (xdr_in); + break; + case GUESTFS_PROC_LVCREATE: + lvcreate_stub (xdr_in); + break; + case GUESTFS_PROC_MKFS: + mkfs_stub (xdr_in); + break; + case GUESTFS_PROC_SFDISK: + sfdisk_stub (xdr_in); + break; + case GUESTFS_PROC_WRITE_FILE: + write_file_stub (xdr_in); + break; + case GUESTFS_PROC_UMOUNT: + umount_stub (xdr_in); + break; + case GUESTFS_PROC_MOUNTS: + mounts_stub (xdr_in); + break; + case GUESTFS_PROC_UMOUNT_ALL: + umount_all_stub (xdr_in); + break; + case GUESTFS_PROC_LVM_REMOVE_ALL: + lvm_remove_all_stub (xdr_in); + break; default: reply_with_error ("dispatch_incoming_message: unknown procedure number %d", proc_nr); } diff --git a/daemon/sync.c b/daemon/sync.c index 9ade8403..70962dff 100644 --- a/daemon/sync.c +++ b/daemon/sync.c @@ -27,6 +27,5 @@ int do_sync () { sync (); - fprintf (stderr, "guestfsd: disk synched\n"); return 0; } diff --git a/fish/cmds.c b/fish/cmds.c index cef38ccc..1ab9ea0b 100644 --- a/fish/cmds.c +++ b/fish/cmds.c @@ -50,20 +50,28 @@ void list_commands (void) printf ("%-20s %s\n", "chmod", "change file mode"); printf ("%-20s %s\n", "chown", "change file owner and group"); printf ("%-20s %s\n", "config", "add qemu parameters"); + printf ("%-20s %s\n", "exists", "test if file or directory exists"); printf ("%-20s %s\n", "get-autosync", "get autosync mode"); printf ("%-20s %s\n", "get-path", "get the search path"); printf ("%-20s %s\n", "get-verbose", "get verbose mode"); + printf ("%-20s %s\n", "is-dir", "test if file exists"); + printf ("%-20s %s\n", "is-file", "test if file exists"); printf ("%-20s %s\n", "kill-subprocess", "kill the qemu subprocess"); printf ("%-20s %s\n", "launch", "launch the qemu subprocess"); printf ("%-20s %s\n", "list-devices", "list the block devices"); printf ("%-20s %s\n", "list-partitions", "list the partitions"); printf ("%-20s %s\n", "ll", "list the files in a directory (long format)"); printf ("%-20s %s\n", "ls", "list the files in a directory"); + printf ("%-20s %s\n", "lvcreate", "create an LVM volume group"); + printf ("%-20s %s\n", "lvm-remove-all", "remove all LVM LVs, VGs and PVs"); printf ("%-20s %s\n", "lvs", "list the LVM logical volumes (LVs)"); printf ("%-20s %s\n", "lvs-full", "list the LVM logical volumes (LVs)"); printf ("%-20s %s\n", "mkdir", "create a directory"); printf ("%-20s %s\n", "mkdir-p", "create a directory and parents"); + printf ("%-20s %s\n", "mkfs", "make a filesystem"); printf ("%-20s %s\n", "mount", "mount a guest disk at a position in the filesystem"); + printf ("%-20s %s\n", "mounts", "show mounted filesystems"); + printf ("%-20s %s\n", "pvcreate", "create 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"); @@ -73,10 +81,15 @@ void list_commands (void) printf ("%-20s %s\n", "set-autosync", "set autosync mode"); printf ("%-20s %s\n", "set-path", "set the search path"); printf ("%-20s %s\n", "set-verbose", "set verbose mode"); + printf ("%-20s %s\n", "sfdisk", "create partitions on a block device"); printf ("%-20s %s\n", "sync", "sync disks, writes are flushed through to the disk image"); printf ("%-20s %s\n", "touch", "update file timestamps or create a new file"); + printf ("%-20s %s\n", "umount", "unmount a filesystem"); + printf ("%-20s %s\n", "umount-all", "unmount all filesystems"); + printf ("%-20s %s\n", "vgcreate", "create an LVM volume group"); printf ("%-20s %s\n", "vgs", "list the LVM volume groups (VGs)"); printf ("%-20s %s\n", "vgs-full", "list the LVM volume groups (VGs)"); + printf ("%-20s %s\n", "write-file", "Create a file"); printf (" Use -h <cmd> / help <cmd> to show detailed help for a command.\n"); } @@ -220,6 +233,45 @@ void display_command (const char *cmd) if (strcasecmp (cmd, "chown") == 0) pod2text ("chown - change file owner and group", " chown <owner> <group> <path>\n\nChange the file owner to C<owner> and group to C<group>.\n\nOnly numeric uid and gid are supported. If you want to use\nnames, you will need to locate and parse the password file\nyourself (Augeas support makes this relatively easy)."); else + if (strcasecmp (cmd, "exists") == 0) + pod2text ("exists - test if file or directory exists", " exists <path>\n\nThis returns C<true> if and only if there is a file, directory\n(or anything) with the given C<path> name.\n\nSee also C<is_file>, C<is_dir>, C<stat>."); + else + if (strcasecmp (cmd, "is_file") == 0 || strcasecmp (cmd, "is-file") == 0) + pod2text ("is-file - test if file exists", " is-file <path>\n\nThis returns C<true> if and only if there is a file\nwith the given C<path> name. Note that it returns false for\nother objects like directories.\n\nSee also C<stat>."); + else + if (strcasecmp (cmd, "is_dir") == 0 || strcasecmp (cmd, "is-dir") == 0) + pod2text ("is-dir - test if file exists", " is-dir <path>\n\nThis returns C<true> if and only if there is a directory\nwith the given C<path> name. Note that it returns false for\nother objects like files.\n\nSee also C<stat>."); + else + if (strcasecmp (cmd, "pvcreate") == 0) + pod2text ("pvcreate - create an LVM physical volume", " pvcreate <device>\n\nThis creates an LVM physical volume on the named C<device>,\nwhere C<device> should usually be a partition name such\nas C</dev/sda1>."); + else + if (strcasecmp (cmd, "vgcreate") == 0) + pod2text ("vgcreate - create an LVM volume group", " vgcreate <volgroup> <physvols>\n\nThis creates an LVM volume group called C<volgroup>\nfrom the non-empty list of physical volumes C<physvols>."); + else + if (strcasecmp (cmd, "lvcreate") == 0) + pod2text ("lvcreate - create an LVM volume group", " lvcreate <logvol> <volgroup> <mbytes>\n\nThis creates an LVM volume group called C<logvol>\non the volume group C<volgroup>, with C<size> megabytes."); + else + if (strcasecmp (cmd, "mkfs") == 0) + pod2text ("mkfs - make a filesystem", " mkfs <fstype> <device>\n\nThis creates a filesystem on C<device> (usually a partition\nof LVM logical volume). The filesystem type is C<fstype>, for\nexample C<ext3>."); + else + if (strcasecmp (cmd, "sfdisk") == 0) + pod2text ("sfdisk - create partitions on a block device", " sfdisk <device> <cyls> <heads> <sectors> <lines>\n\nThis is a direct interface to the L<sfdisk(8)> program for creating\npartitions on block devices.\n\nC<device> should be a block device, for example C</dev/sda>.\n\nC<cyls>, C<heads> and C<sectors> 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<lines> is a list of lines that we feed to C<sfdisk>. For more\ninformation refer to the L<sfdisk(8)> manpage.\n\nTo create a single partition occupying the whole disk, you would\npass C<lines> as a single element list, when the single element being\nthe string C<,> (comma).\n\nB<This command is dangerous. Without careful use you\ncan easily destroy all your data>."); + else + if (strcasecmp (cmd, "write_file") == 0 || strcasecmp (cmd, "write-file") == 0) + pod2text ("write-file - Create a file", " write-file <path> <content> <size>\n\nThis call creates a file called C<path>. The contents of the\nfile is the string C<content> (which can contain any 8 bit data),\nwith length C<size>.\n\nAs a special case, if C<size> is C<0>\nthen the length is calculated using C<strlen> (so in this case\nthe content cannot contain embedded ASCII NULs).\n\nBecause of the message protocol, there is a transfer limit \nof somewhere between 2MB and 4MB. To transfer large files you should use\nFTP."); + else + if (strcasecmp (cmd, "umount") == 0 || strcasecmp (cmd, "unmount") == 0) + pod2text ("umount - unmount a filesystem", " umount <pathordevice>\n\nThis unmounts the given filesystem. The filesystem may be\nspecified either by its mountpoint (path) or the device which\ncontains the filesystem.\n\nYou can use 'unmount' as an alias for this command."); + else + if (strcasecmp (cmd, "mounts") == 0) + pod2text ("mounts - show mounted filesystems", " mounts\n\nThis returns the list of currently mounted filesystems. It returns\nthe list of devices (eg. C</dev/sda1>, C</dev/VG/LV>).\n\nSome internal mounts are not shown."); + else + if (strcasecmp (cmd, "umount_all") == 0 || strcasecmp (cmd, "umount-all") == 0 || strcasecmp (cmd, "unmount-all") == 0) + pod2text ("umount-all - unmount all filesystems", " umount-all\n\nThis unmounts all mounted filesystems.\n\nSome internal mounts are not unmounted by this call.\n\nYou can use 'unmount-all' as an alias for this command."); + else + if (strcasecmp (cmd, "lvm_remove_all") == 0 || strcasecmp (cmd, "lvm-remove-all") == 0) + pod2text ("lvm-remove-all - remove all LVM LVs, VGs and PVs", " lvm-remove-all\n\nThis command removes all LVM logical volumes, volume groups\nand physical volumes.\n\nB<This command is dangerous. Without careful use you\ncan easily destroy all your data>."); + else display_builtin_command (cmd); } @@ -1020,6 +1072,211 @@ static int run_chown (const char *cmd, int argc, char *argv[]) return r; } +static int run_exists (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *path; + 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; + } + path = argv[0]; + r = guestfs_exists (g, path); + if (r == -1) return -1; + if (r) printf ("true\n"); else printf ("false\n"); + return 0; +} + +static int run_is_file (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *path; + 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; + } + path = argv[0]; + r = guestfs_is_file (g, path); + if (r == -1) return -1; + if (r) printf ("true\n"); else printf ("false\n"); + return 0; +} + +static int run_is_dir (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *path; + 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; + } + path = argv[0]; + r = guestfs_is_dir (g, path); + if (r == -1) return -1; + if (r) printf ("true\n"); else printf ("false\n"); + return 0; +} + +static int run_pvcreate (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_pvcreate (g, device); + return r; +} + +static int run_vgcreate (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *volgroup; + char **physvols; + 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; + } + volgroup = argv[0]; + physvols = parse_string_list (argv[1]); + r = guestfs_vgcreate (g, volgroup, physvols); + return r; +} + +static int run_lvcreate (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *logvol; + const char *volgroup; + int mbytes; + if (argc != 3) { + fprintf (stderr, "%s should have 3 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + logvol = argv[0]; + volgroup = argv[1]; + mbytes = atoi (argv[2]); + r = guestfs_lvcreate (g, logvol, volgroup, mbytes); + return r; +} + +static int run_mkfs (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *fstype; + const char *device; + 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; + } + fstype = argv[0]; + device = argv[1]; + r = guestfs_mkfs (g, fstype, device); + return r; +} + +static int run_sfdisk (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *device; + int cyls; + int heads; + int sectors; + char **lines; + if (argc != 5) { + fprintf (stderr, "%s should have 5 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + device = argv[0]; + cyls = atoi (argv[1]); + heads = atoi (argv[2]); + sectors = atoi (argv[3]); + lines = parse_string_list (argv[4]); + r = guestfs_sfdisk (g, device, cyls, heads, sectors, lines); + return r; +} + +static int run_write_file (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *path; + const char *content; + int size; + if (argc != 3) { + fprintf (stderr, "%s should have 3 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + path = argv[0]; + content = argv[1]; + size = atoi (argv[2]); + r = guestfs_write_file (g, path, content, size); + return r; +} + +static int run_umount (const char *cmd, int argc, char *argv[]) +{ + int r; + const char *pathordevice; + 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; + } + pathordevice = argv[0]; + r = guestfs_umount (g, pathordevice); + return r; +} + +static int run_mounts (const char *cmd, int argc, char *argv[]) +{ + char **r; + if (argc != 0) { + fprintf (stderr, "%s should have 0 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + r = guestfs_mounts (g); + if (r == NULL) return -1; + print_strings (r); + free_strings (r); + return 0; +} + +static int run_umount_all (const char *cmd, int argc, char *argv[]) +{ + int r; + if (argc != 0) { + fprintf (stderr, "%s should have 0 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + r = guestfs_umount_all (g); + return r; +} + +static int run_lvm_remove_all (const char *cmd, int argc, char *argv[]) +{ + int r; + if (argc != 0) { + fprintf (stderr, "%s should have 0 parameter(s)\n", cmd); + fprintf (stderr, "type 'help %s' for help on %s\n", cmd, cmd); + return -1; + } + r = guestfs_lvm_remove_all (g); + return r; +} + int run_action (const char *cmd, int argc, char *argv[]) { if (strcasecmp (cmd, "launch") == 0 || strcasecmp (cmd, "run") == 0) @@ -1160,6 +1417,45 @@ int run_action (const char *cmd, int argc, char *argv[]) if (strcasecmp (cmd, "chown") == 0) return run_chown (cmd, argc, argv); else + if (strcasecmp (cmd, "exists") == 0) + return run_exists (cmd, argc, argv); + else + if (strcasecmp (cmd, "is_file") == 0 || strcasecmp (cmd, "is-file") == 0) + return run_is_file (cmd, argc, argv); + else + if (strcasecmp (cmd, "is_dir") == 0 || strcasecmp (cmd, "is-dir") == 0) + return run_is_dir (cmd, argc, argv); + else + if (strcasecmp (cmd, "pvcreate") == 0) + return run_pvcreate (cmd, argc, argv); + else + if (strcasecmp (cmd, "vgcreate") == 0) + return run_vgcreate (cmd, argc, argv); + else + if (strcasecmp (cmd, "lvcreate") == 0) + return run_lvcreate (cmd, argc, argv); + else + if (strcasecmp (cmd, "mkfs") == 0) + return run_mkfs (cmd, argc, argv); + else + if (strcasecmp (cmd, "sfdisk") == 0) + return run_sfdisk (cmd, argc, argv); + else + if (strcasecmp (cmd, "write_file") == 0 || strcasecmp (cmd, "write-file") == 0) + return run_write_file (cmd, argc, argv); + else + if (strcasecmp (cmd, "umount") == 0 || strcasecmp (cmd, "unmount") == 0) + return run_umount (cmd, argc, argv); + else + if (strcasecmp (cmd, "mounts") == 0) + return run_mounts (cmd, argc, argv); + else + if (strcasecmp (cmd, "umount_all") == 0 || strcasecmp (cmd, "umount-all") == 0 || strcasecmp (cmd, "unmount-all") == 0) + return run_umount_all (cmd, argc, argv); + else + if (strcasecmp (cmd, "lvm_remove_all") == 0 || strcasecmp (cmd, "lvm-remove-all") == 0) + return run_lvm_remove_all (cmd, argc, argv); + else { fprintf (stderr, "%s: unknown command\n", cmd); return -1; diff --git a/fish/fish.c b/fish/fish.c index e845e4de..18b8d451 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -18,6 +18,8 @@ #include <config.h> +#define _GNU_SOURCE // for strchrnul + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -495,7 +497,7 @@ free_strings (char **argv) } void -print_strings (char **argv) +print_strings (char * const * const argv) { int argc; @@ -513,3 +515,34 @@ is_true (const char *str) strcasecmp (str, "n") != 0 && strcasecmp (str, "no") != 0; } + +/* This is quite inadequate for real use. For example, there is no way + * to specify an empty list. We need to use a real parser to allow + * quoting, empty lists, etc. + */ +char ** +parse_string_list (const char *str) +{ + char **argv; + const char *p, *pend; + int argc, i; + + argc = 1; + for (i = 0; str[i]; ++i) + if (str[i] == ':') argc++; + + argv = malloc (sizeof (char *) * (argc+1)); + if (argv == NULL) { perror ("malloc"); exit (1); } + + p = str; + i = 0; + while (*p) { + pend = strchrnul (p, ':'); + argv[i] = strndup (p, pend-p); + i++; + p = *pend == ':' ? pend+1 : p; + } + argv[i] = NULL; + + return argv; +} diff --git a/fish/fish.h b/fish/fish.h index 6d0892fa..3997d6d4 100644 --- a/fish/fish.h +++ b/fish/fish.h @@ -30,9 +30,10 @@ extern void pod2text (const char *heading, const char *body); extern void list_builtin_commands (void); extern void display_builtin_command (const char *cmd); extern void free_strings (char **argv); -extern void print_strings (char **argv); +extern void print_strings (char * const * const argv); extern int launch (guestfs_h *); extern int is_true (const char *str); +extern char **parse_string_list (const char *str); /* in cmds.c (auto-generated) */ extern void list_commands (void); diff --git a/guestfish-actions.pod b/guestfish-actions.pod index d47e9bf9..50ecfec6 100644 --- a/guestfish-actions.pod +++ b/guestfish-actions.pod @@ -193,6 +193,10 @@ Note that this function cannot correctly handle binary files as end of string). For those you need to use the C<read_file> function which has a more complex interface. +Because of the message protocol, there is a transfer limit +of somewhere between 2MB and 4MB. To transfer large files you should use +FTP. + =head2 chmod chmod mode path @@ -223,6 +227,15 @@ The first character of C<param> string must be a C<-> (dash). C<value> can be NULL. +=head2 exists + + exists path + +This returns C<true> if and only if there is a file, directory +(or anything) with the given C<path> name. + +See also C<is_file>, C<is_dir>, C<stat>. + =head2 get-autosync get-autosync @@ -244,6 +257,26 @@ return the default path. This returns the verbose messages flag. +=head2 is-dir + + is-dir path + +This returns C<true> if and only if there is a directory +with the given C<path> name. Note that it returns false for +other objects like files. + +See also C<stat>. + +=head2 is-file + + is-file path + +This returns C<true> if and only if there is a file +with the given C<path> name. Note that it returns false for +other objects like directories. + +See also C<stat>. + =head2 kill-subprocess kill-subprocess @@ -300,6 +333,23 @@ hidden files are shown. This command is mostly useful for interactive sessions. Programs should probably use C<readdir> instead. +=head2 lvcreate + + lvcreate logvol volgroup mbytes + +This creates an LVM volume group called C<logvol> +on the volume group C<volgroup>, with C<size> megabytes. + +=head2 lvm-remove-all + + lvm-remove-all + +This command removes all LVM logical volumes, volume groups +and physical volumes. + +B<This command is dangerous. Without careful use you +can easily destroy all your data>. + =head2 lvs lvs @@ -332,6 +382,14 @@ Create a directory named C<path>. Create a directory named C<path>, creating any parent directories as necessary. This is like the C<mkdir -p> shell command. +=head2 mkfs + + mkfs fstype device + +This creates a filesystem on C<device> (usually a partition +of LVM logical volume). The filesystem type is C<fstype>, for +example C<ext3>. + =head2 mount mount device mountpoint @@ -353,6 +411,23 @@ on the underlying device. The filesystem options C<sync> and C<noatime> are set with this call, in order to improve reliability. +=head2 mounts + + mounts + +This returns the list of currently mounted filesystems. It returns +the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>). + +Some internal mounts are not shown. + +=head2 pvcreate + + pvcreate device + +This creates an LVM physical volume on the named C<device>, +where C<device> should usually be a partition name such +as C</dev/sda1>. + =head2 pvs pvs @@ -437,6 +512,33 @@ If C<verbose> is true, this turns on verbose messages (to C<stderr>). Verbose messages are disabled unless the environment variable C<LIBGUESTFS_DEBUG> is defined and set to C<1>. +=head2 sfdisk + + sfdisk device cyls heads sectors lines,... + +This is a direct interface to the L<sfdisk(8)> program for creating +partitions on block devices. + +C<device> should be a block device, for example C</dev/sda>. + +C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads +and sectors on the device, which are passed directly to sfdisk as +the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any +of these, then the corresponding parameter is omitted. Usually for +'large' disks, you can just pass C<0> for these, but for small +(floppy-sized) disks, sfdisk (or rather, the kernel) cannot work +out the right geometry and you will need to tell it. + +C<lines> is a list of lines that we feed to C<sfdisk>. For more +information refer to the L<sfdisk(8)> manpage. + +To create a single partition occupying the whole disk, you would +pass C<lines> as a single element list, when the single element being +the string C<,> (comma). + +B<This command is dangerous. Without careful use you +can easily destroy all your data>. + =head2 sync sync @@ -455,6 +557,29 @@ Touch acts like the L<touch(1)> command. It can be used to update the timestamps on a file, or, if the file does not exist, to create a new zero-length file. +=head2 umount | unmount + + umount pathordevice + +This unmounts the given filesystem. The filesystem may be +specified either by its mountpoint (path) or the device which +contains the filesystem. + +=head2 umount-all | unmount-all + + umount-all + +This unmounts all mounted filesystems. + +Some internal mounts are not unmounted by this call. + +=head2 vgcreate + + vgcreate volgroup physvols,... + +This creates an LVM volume group called C<volgroup> +from the non-empty list of physical volumes C<physvols>. + =head2 vgs vgs @@ -474,3 +599,19 @@ See also C<vgs_full>. List all the volumes groups detected. This is the equivalent of the L<vgs(8)> command. The "full" version includes all fields. +=head2 write-file + + write-file path content size + +This call creates a file called C<path>. The contents of the +file is the string C<content> (which can contain any 8 bit data), +with length C<size>. + +As a special case, if C<size> is C<0> +then the length is calculated using C<strlen> (so in this case +the content cannot contain embedded ASCII NULs). + +Because of the message protocol, there is a transfer limit +of somewhere between 2MB and 4MB. To transfer large files you should use +FTP. + diff --git a/guestfs-actions.pod b/guestfs-actions.pod index 069ea8f7..310db2e4 100644 --- a/guestfs-actions.pod +++ b/guestfs-actions.pod @@ -300,6 +300,18 @@ C<value> can be NULL. This function returns 0 on success or -1 on error. +=head2 guestfs_exists + + int guestfs_exists (guestfs_h *handle, + const char *path); + +This returns C<true> if and only if there is a file, directory +(or anything) with the given C<path> name. + +See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>. + +This function returns a C truth value on success or -1 on error. + =head2 guestfs_get_autosync int guestfs_get_autosync (guestfs_h *handle); @@ -328,6 +340,32 @@ This returns the verbose messages flag. This function returns a C truth value on success or -1 on error. +=head2 guestfs_is_dir + + int guestfs_is_dir (guestfs_h *handle, + const char *path); + +This returns C<true> if and only if there is a directory +with the given C<path> name. Note that it returns false for +other objects like files. + +See also C<guestfs_stat>. + +This function returns a C truth value on success or -1 on error. + +=head2 guestfs_is_file + + int guestfs_is_file (guestfs_h *handle, + const char *path); + +This returns C<true> if and only if there is a file +with the given C<path> name. Note that it returns false for +other objects like directories. + +See also C<guestfs_stat>. + +This function returns a C truth value on success or -1 on error. + =head2 guestfs_kill_subprocess int guestfs_kill_subprocess (guestfs_h *handle); @@ -405,6 +443,30 @@ This function returns a NULL-terminated array of strings (like L<environ(3)>), or NULL if there was an error. I<The caller must free the strings and the array after use>. +=head2 guestfs_lvcreate + + int guestfs_lvcreate (guestfs_h *handle, + const char *logvol, + const char *volgroup, + int mbytes); + +This creates an LVM volume group called C<logvol> +on the volume group C<volgroup>, with C<size> megabytes. + +This function returns 0 on success or -1 on error. + +=head2 guestfs_lvm_remove_all + + int guestfs_lvm_remove_all (guestfs_h *handle); + +This command removes all LVM logical volumes, volume groups +and physical volumes. + +This function returns 0 on success or -1 on error. + +B<This command is dangerous. Without careful use you +can easily destroy all your data>. + =head2 guestfs_lvs char **guestfs_lvs (guestfs_h *handle); @@ -450,6 +512,18 @@ as necessary. This is like the C<mkdir -p> shell command. This function returns 0 on success or -1 on error. +=head2 guestfs_mkfs + + int guestfs_mkfs (guestfs_h *handle, + const char *fstype, + const char *device); + +This creates a filesystem on C<device> (usually a partition +of LVM logical volume). The filesystem type is C<fstype>, for +example C<ext3>. + +This function returns 0 on success or -1 on error. + =head2 guestfs_mount int guestfs_mount (guestfs_h *handle, @@ -475,6 +549,30 @@ call, in order to improve reliability. This function returns 0 on success or -1 on error. +=head2 guestfs_mounts + + char **guestfs_mounts (guestfs_h *handle); + +This returns the list of currently mounted filesystems. It returns +the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>). + +Some internal mounts are not shown. + +This function returns a NULL-terminated array of strings +(like L<environ(3)>), or NULL if there was an error. +I<The caller must free the strings and the array after use>. + +=head2 guestfs_pvcreate + + int guestfs_pvcreate (guestfs_h *handle, + const char *device); + +This creates an LVM physical volume on the named C<device>, +where C<device> should usually be a partition name such +as C</dev/sda1>. + +This function returns 0 on success or -1 on error. + =head2 guestfs_pvs char **guestfs_pvs (guestfs_h *handle); @@ -589,6 +687,40 @@ C<LIBGUESTFS_DEBUG> is defined and set to C<1>. This function returns 0 on success or -1 on error. +=head2 guestfs_sfdisk + + int guestfs_sfdisk (guestfs_h *handle, + const char *device, + int cyls, + int heads, + int sectors, + char * const* const lines); + +This is a direct interface to the L<sfdisk(8)> program for creating +partitions on block devices. + +C<device> should be a block device, for example C</dev/sda>. + +C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads +and sectors on the device, which are passed directly to sfdisk as +the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any +of these, then the corresponding parameter is omitted. Usually for +'large' disks, you can just pass C<0> for these, but for small +(floppy-sized) disks, sfdisk (or rather, the kernel) cannot work +out the right geometry and you will need to tell it. + +C<lines> is a list of lines that we feed to C<sfdisk>. For more +information refer to the L<sfdisk(8)> manpage. + +To create a single partition occupying the whole disk, you would +pass C<lines> as a single element list, when the single element being +the string C<,> (comma). + +This function returns 0 on success or -1 on error. + +B<This command is dangerous. Without careful use you +can easily destroy all your data>. + =head2 guestfs_sync int guestfs_sync (guestfs_h *handle); @@ -612,6 +744,38 @@ to create a new zero-length file. This function returns 0 on success or -1 on error. +=head2 guestfs_umount + + int guestfs_umount (guestfs_h *handle, + const char *pathordevice); + +This unmounts the given filesystem. The filesystem may be +specified either by its mountpoint (path) or the device which +contains the filesystem. + +This function returns 0 on success or -1 on error. + +=head2 guestfs_umount_all + + int guestfs_umount_all (guestfs_h *handle); + +This unmounts all mounted filesystems. + +Some internal mounts are not unmounted by this call. + +This function returns 0 on success or -1 on error. + +=head2 guestfs_vgcreate + + int guestfs_vgcreate (guestfs_h *handle, + const char *volgroup, + char * const* const physvols); + +This creates an LVM volume group called C<volgroup> +from the non-empty list of physical volumes C<physvols>. + +This function returns 0 on success or -1 on error. + =head2 guestfs_vgs char **guestfs_vgs (guestfs_h *handle); @@ -650,3 +814,24 @@ to complete. This function returns 0 on success or -1 on error. +=head2 guestfs_write_file + + int guestfs_write_file (guestfs_h *handle, + const char *path, + const char *content, + int size); + +This call creates a file called C<path>. The contents of the +file is the string C<content> (which can contain any 8 bit data), +with length C<size>. + +As a special case, if C<size> is C<0> +then the length is calculated using C<strlen> (so in this case +the content cannot contain embedded ASCII NULs). + +This function returns 0 on success or -1 on error. + +Because of the message protocol, there is a transfer limit +of somewhere between 2MB and 4MB. To transfer large files you should use +FTP. + diff --git a/libguestfs.spec.in b/libguestfs.spec.in index 29c95ffa..e4dcaef1 100644 --- a/libguestfs.spec.in +++ b/libguestfs.spec.in @@ -138,6 +138,10 @@ Requires: perl(:MODULE_COMPAT_%(eval "`%{__perl} -V:version`"; echo $version) make INSTALLDIRS=vendor +%check +make check + + %install rm -rf $RPM_BUILD_ROOT diff --git a/make-initramfs.sh.in b/make-initramfs.sh.in index 4579e901..3dbac635 100755 --- a/make-initramfs.sh.in +++ b/make-initramfs.sh.in @@ -65,11 +65,13 @@ find initramfs -name '*plymouth*' -print0 | xargs -0 rm -rf find initramfs -name '*python*' -print0 | xargs -0 rm -rf # Modules take up nearly half of the image. It's a rough guess that -# we don't need any drivers (which take up most of the space). +# we don't need many drivers (which take up most of the space). find initramfs/lib/modules/*/kernel \ -name '*.ko' \ -a ! -name 'mii.ko' \ -a ! -name '8139cp.ko' \ + -a ! -name 'ext2.ko' \ + -a ! -name 'ext4.ko' \ -a -delete # Pull the kernel out into the current directory. We don't want it in diff --git a/ocaml/guestfs.ml b/ocaml/guestfs.ml index 32a6b82a..58f99dc2 100644 --- a/ocaml/guestfs.ml +++ b/ocaml/guestfs.ml @@ -132,3 +132,16 @@ external mkdir : t -> string -> unit = "ocaml_guestfs_mkdir" external mkdir_p : t -> string -> unit = "ocaml_guestfs_mkdir_p" external chmod : t -> int -> string -> unit = "ocaml_guestfs_chmod" external chown : t -> int -> int -> string -> unit = "ocaml_guestfs_chown" +external exists : t -> string -> bool = "ocaml_guestfs_exists" +external is_file : t -> string -> bool = "ocaml_guestfs_is_file" +external is_dir : t -> string -> bool = "ocaml_guestfs_is_dir" +external pvcreate : t -> string -> unit = "ocaml_guestfs_pvcreate" +external vgcreate : t -> string -> string array -> unit = "ocaml_guestfs_vgcreate" +external lvcreate : t -> string -> string -> int -> unit = "ocaml_guestfs_lvcreate" +external mkfs : t -> string -> string -> unit = "ocaml_guestfs_mkfs" +external sfdisk : t -> string -> int -> int -> int -> string array -> unit = "ocaml_guestfs_sfdisk_byte" "ocaml_guestfs_sfdisk" +external write_file : t -> string -> string -> int -> unit = "ocaml_guestfs_write_file" +external umount : t -> string -> unit = "ocaml_guestfs_umount" +external mounts : t -> string array = "ocaml_guestfs_mounts" +external umount_all : t -> unit = "ocaml_guestfs_umount_all" +external lvm_remove_all : t -> unit = "ocaml_guestfs_lvm_remove_all" diff --git a/ocaml/guestfs.mli b/ocaml/guestfs.mli index ecf86f11..1ce1cab2 100644 --- a/ocaml/guestfs.mli +++ b/ocaml/guestfs.mli @@ -235,3 +235,42 @@ val chmod : t -> int -> string -> unit val chown : t -> int -> int -> string -> unit (** change file owner and group *) +val exists : t -> string -> bool +(** test if file or directory exists *) + +val is_file : t -> string -> bool +(** test if file exists *) + +val is_dir : t -> string -> bool +(** test if file exists *) + +val pvcreate : t -> string -> unit +(** create an LVM physical volume *) + +val vgcreate : t -> string -> string array -> unit +(** create an LVM volume group *) + +val lvcreate : t -> string -> string -> int -> unit +(** create an LVM volume group *) + +val mkfs : t -> string -> string -> unit +(** make a filesystem *) + +val sfdisk : t -> string -> int -> int -> int -> string array -> unit +(** create partitions on a block device *) + +val write_file : t -> string -> string -> int -> unit +(** Create a file *) + +val umount : t -> string -> unit +(** unmount a filesystem *) + +val mounts : t -> string array +(** show mounted filesystems *) + +val umount_all : t -> unit +(** unmount all filesystems *) + +val lvm_remove_all : t -> unit +(** remove all LVM LVs, VGs and PVs *) + diff --git a/ocaml/guestfs_c.c b/ocaml/guestfs_c.c index 600440c9..291c4308 100644 --- a/ocaml/guestfs_c.c +++ b/ocaml/guestfs_c.c @@ -119,3 +119,29 @@ ocaml_guestfs_close (value gv) CAMLreturn (Val_unit); } + +/* Copy string array value. */ +char ** +ocaml_guestfs_strings_val (value sv) +{ + CAMLparam1 (sv); + char **r; + int i; + + r = malloc (sizeof (char *) * (Wosize_val (sv) + 1)); + for (i = 0; i < Wosize_val (sv); ++i) + r[i] = String_val (Field (sv, i)); + r[i] = NULL; + + CAMLreturnT (char **, r); +} + +/* Free array of strings. */ +void +ocaml_guestfs_free_strings (char **argv) +{ + /* Don't free the actual strings - they are String_vals on + * the OCaml heap. + */ + free (argv); +} diff --git a/ocaml/guestfs_c.h b/ocaml/guestfs_c.h index 3da41d05..4fb81881 100644 --- a/ocaml/guestfs_c.h +++ b/ocaml/guestfs_c.h @@ -22,5 +22,7 @@ #define Guestfs_val(v) (*((guestfs_h **)Data_custom_val(v))) extern void ocaml_guestfs_raise_error (guestfs_h *g, const char *func) Noreturn; +extern char **ocaml_guestfs_strings_val (value sv); +extern void ocaml_guestfs_free_strings (char **r); #endif /* GUESTFS_OCAML_C_H */ diff --git a/ocaml/guestfs_c_actions.c b/ocaml/guestfs_c_actions.c index 6675cf8c..6b1a9f62 100644 --- a/ocaml/guestfs_c_actions.c +++ b/ocaml/guestfs_c_actions.c @@ -1347,3 +1347,321 @@ ocaml_guestfs_chown (value gv, value ownerv, value groupv, value pathv) CAMLreturn (rv); } +CAMLprim value +ocaml_guestfs_exists (value gv, value pathv) +{ + CAMLparam2 (gv, pathv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("exists: used handle after closing it"); + + const char *path = String_val (pathv); + int r; + + caml_enter_blocking_section (); + r = guestfs_exists (g, path); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "exists"); + + rv = Val_bool (r); + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_is_file (value gv, value pathv) +{ + CAMLparam2 (gv, pathv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("is_file: used handle after closing it"); + + const char *path = String_val (pathv); + int r; + + caml_enter_blocking_section (); + r = guestfs_is_file (g, path); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "is_file"); + + rv = Val_bool (r); + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_is_dir (value gv, value pathv) +{ + CAMLparam2 (gv, pathv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("is_dir: used handle after closing it"); + + const char *path = String_val (pathv); + int r; + + caml_enter_blocking_section (); + r = guestfs_is_dir (g, path); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "is_dir"); + + rv = Val_bool (r); + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_pvcreate (value gv, value devicev) +{ + CAMLparam2 (gv, devicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("pvcreate: used handle after closing it"); + + const char *device = String_val (devicev); + int r; + + caml_enter_blocking_section (); + r = guestfs_pvcreate (g, device); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "pvcreate"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_vgcreate (value gv, value volgroupv, value physvolsv) +{ + CAMLparam3 (gv, volgroupv, physvolsv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("vgcreate: used handle after closing it"); + + const char *volgroup = String_val (volgroupv); + char **physvols = ocaml_guestfs_strings_val (physvolsv); + int r; + + caml_enter_blocking_section (); + r = guestfs_vgcreate (g, volgroup, physvols); + caml_leave_blocking_section (); + ocaml_guestfs_free_strings (physvols); + if (r == -1) + ocaml_guestfs_raise_error (g, "vgcreate"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_lvcreate (value gv, value logvolv, value volgroupv, value mbytesv) +{ + CAMLparam4 (gv, logvolv, volgroupv, mbytesv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("lvcreate: used handle after closing it"); + + const char *logvol = String_val (logvolv); + const char *volgroup = String_val (volgroupv); + int mbytes = Int_val (mbytesv); + int r; + + caml_enter_blocking_section (); + r = guestfs_lvcreate (g, logvol, volgroup, mbytes); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "lvcreate"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_mkfs (value gv, value fstypev, value devicev) +{ + CAMLparam3 (gv, fstypev, devicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("mkfs: used handle after closing it"); + + const char *fstype = String_val (fstypev); + const char *device = String_val (devicev); + int r; + + caml_enter_blocking_section (); + r = guestfs_mkfs (g, fstype, device); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "mkfs"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_sfdisk (value gv, value devicev, value cylsv, value headsv, value sectorsv, value linesv) +{ + CAMLparam5 (gv, devicev, cylsv, headsv, sectorsv); + CAMLxparam1 (linesv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("sfdisk: used handle after closing it"); + + const char *device = String_val (devicev); + int cyls = Int_val (cylsv); + int heads = Int_val (headsv); + int sectors = Int_val (sectorsv); + char **lines = ocaml_guestfs_strings_val (linesv); + int r; + + caml_enter_blocking_section (); + r = guestfs_sfdisk (g, device, cyls, heads, sectors, lines); + caml_leave_blocking_section (); + ocaml_guestfs_free_strings (lines); + if (r == -1) + ocaml_guestfs_raise_error (g, "sfdisk"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_sfdisk_byte (value *argv, int argn) +{ + return ocaml_guestfs_sfdisk (argv[0], argv[0], argv[1], argv[2], argv[3], argv[4]); +} + +CAMLprim value +ocaml_guestfs_write_file (value gv, value pathv, value contentv, value sizev) +{ + CAMLparam4 (gv, pathv, contentv, sizev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("write_file: used handle after closing it"); + + const char *path = String_val (pathv); + const char *content = String_val (contentv); + int size = Int_val (sizev); + int r; + + caml_enter_blocking_section (); + r = guestfs_write_file (g, path, content, size); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "write_file"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_umount (value gv, value pathordevicev) +{ + CAMLparam2 (gv, pathordevicev); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("umount: used handle after closing it"); + + const char *pathordevice = String_val (pathordevicev); + int r; + + caml_enter_blocking_section (); + r = guestfs_umount (g, pathordevice); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "umount"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_mounts (value gv) +{ + CAMLparam1 (gv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("mounts: used handle after closing it"); + + int i; + char **r; + + caml_enter_blocking_section (); + r = guestfs_mounts (g); + caml_leave_blocking_section (); + if (r == NULL) + ocaml_guestfs_raise_error (g, "mounts"); + + rv = caml_copy_string_array ((const char **) r); + for (i = 0; r[i] != NULL; ++i) free (r[i]); + free (r); + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_umount_all (value gv) +{ + CAMLparam1 (gv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("umount_all: used handle after closing it"); + + int r; + + caml_enter_blocking_section (); + r = guestfs_umount_all (g); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "umount_all"); + + rv = Val_unit; + CAMLreturn (rv); +} + +CAMLprim value +ocaml_guestfs_lvm_remove_all (value gv) +{ + CAMLparam1 (gv); + CAMLlocal1 (rv); + + guestfs_h *g = Guestfs_val (gv); + if (g == NULL) + caml_failwith ("lvm_remove_all: used handle after closing it"); + + int r; + + caml_enter_blocking_section (); + r = guestfs_lvm_remove_all (g); + caml_leave_blocking_section (); + if (r == -1) + ocaml_guestfs_raise_error (g, "lvm_remove_all"); + + rv = Val_unit; + CAMLreturn (rv); +} + diff --git a/perl/Guestfs.xs b/perl/Guestfs.xs index d5f1da6b..0f72c282 100644 --- a/perl/Guestfs.xs +++ b/perl/Guestfs.xs @@ -73,6 +73,35 @@ error_handler (guestfs_h *g, last_error = strdup (msg); } +/* http://www.perlmonks.org/?node_id=680842 */ +static char ** +XS_unpack_charPtrPtr (SV *arg) { + char **ret; + AV *av; + I32 i; + + if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) { + croak ("array reference expected"); + } + + av = (AV *)SvRV (arg); + ret = (char **)malloc (av_len (av) + 1 + 1); + + for (i = 0; i <= av_len (av); i++) { + SV **elem = av_fetch (av, i, 0); + + if (!elem || !*elem) { + croak ("missing element in list"); + } + + ret[i] = SvPV_nolen (*elem); + } + + ret[i + 1] = NULL; + + return ret; +} + MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs guestfs_h * @@ -95,38 +124,43 @@ void launch (g) guestfs_h *g; PPCODE: - if (guestfs_launch (g) == -1) + if (guestfs_launch (g) == -1) { croak ("launch: %s", last_error); + } void wait_ready (g) guestfs_h *g; PPCODE: - if (guestfs_wait_ready (g) == -1) + if (guestfs_wait_ready (g) == -1) { croak ("wait_ready: %s", last_error); + } void kill_subprocess (g) guestfs_h *g; PPCODE: - if (guestfs_kill_subprocess (g) == -1) + if (guestfs_kill_subprocess (g) == -1) { croak ("kill_subprocess: %s", last_error); + } void add_drive (g, filename) guestfs_h *g; char *filename; PPCODE: - if (guestfs_add_drive (g, filename) == -1) + if (guestfs_add_drive (g, filename) == -1) { croak ("add_drive: %s", last_error); + } void add_cdrom (g, filename) guestfs_h *g; char *filename; PPCODE: - if (guestfs_add_cdrom (g, filename) == -1) + if (guestfs_add_cdrom (g, filename) == -1) { croak ("add_cdrom: %s", last_error); + } void config (g, qemuparam, qemuvalue) @@ -134,16 +168,18 @@ config (g, qemuparam, qemuvalue) char *qemuparam; char *qemuvalue; PPCODE: - if (guestfs_config (g, qemuparam, qemuvalue) == -1) + if (guestfs_config (g, qemuparam, qemuvalue) == -1) { croak ("config: %s", last_error); + } void set_path (g, path) guestfs_h *g; char *path; PPCODE: - if (guestfs_set_path (g, path) == -1) + if (guestfs_set_path (g, path) == -1) { croak ("set_path: %s", last_error); + } SV * get_path (g) @@ -152,8 +188,9 @@ PREINIT: const char *path; CODE: path = guestfs_get_path (g); - if (path == NULL) + if (path == NULL) { croak ("get_path: %s", last_error); + } RETVAL = newSVpv (path, 0); OUTPUT: RETVAL @@ -163,8 +200,9 @@ set_autosync (g, autosync) guestfs_h *g; int autosync; PPCODE: - if (guestfs_set_autosync (g, autosync) == -1) + if (guestfs_set_autosync (g, autosync) == -1) { croak ("set_autosync: %s", last_error); + } SV * get_autosync (g) @@ -173,8 +211,9 @@ PREINIT: int autosync; CODE: autosync = guestfs_get_autosync (g); - if (autosync == -1) + if (autosync == -1) { croak ("get_autosync: %s", last_error); + } RETVAL = newSViv (autosync); OUTPUT: RETVAL @@ -184,8 +223,9 @@ set_verbose (g, verbose) guestfs_h *g; int verbose; PPCODE: - if (guestfs_set_verbose (g, verbose) == -1) + if (guestfs_set_verbose (g, verbose) == -1) { croak ("set_verbose: %s", last_error); + } SV * get_verbose (g) @@ -194,8 +234,9 @@ PREINIT: int verbose; CODE: verbose = guestfs_get_verbose (g); - if (verbose == -1) + if (verbose == -1) { croak ("get_verbose: %s", last_error); + } RETVAL = newSViv (verbose); OUTPUT: RETVAL @@ -206,23 +247,26 @@ mount (g, device, mountpoint) char *device; char *mountpoint; PPCODE: - if (guestfs_mount (g, device, mountpoint) == -1) + if (guestfs_mount (g, device, mountpoint) == -1) { croak ("mount: %s", last_error); + } void sync (g) guestfs_h *g; PPCODE: - if (guestfs_sync (g) == -1) + if (guestfs_sync (g) == -1) { croak ("sync: %s", last_error); + } void touch (g, path) guestfs_h *g; char *path; PPCODE: - if (guestfs_touch (g, path) == -1) + if (guestfs_touch (g, path) == -1) { croak ("touch: %s", last_error); + } SV * cat (g, path) @@ -232,8 +276,9 @@ PREINIT: char *content; CODE: content = guestfs_cat (g, path); - if (content == NULL) + if (content == NULL) { croak ("cat: %s", last_error); + } RETVAL = newSVpv (content, 0); free (content); OUTPUT: @@ -247,8 +292,9 @@ PREINIT: char *listing; CODE: listing = guestfs_ll (g, directory); - if (listing == NULL) + if (listing == NULL) { croak ("ll: %s", last_error); + } RETVAL = newSVpv (listing, 0); free (listing); OUTPUT: @@ -263,8 +309,9 @@ PREINIT: int i, n; PPCODE: listing = guestfs_ls (g, directory); - if (listing == NULL) + if (listing == NULL) { croak ("ls: %s", last_error); + } for (n = 0; listing[n] != NULL; ++n) /**/; EXTEND (SP, n); for (i = 0; i < n; ++i) { @@ -281,8 +328,9 @@ PREINIT: int i, n; PPCODE: devices = guestfs_list_devices (g); - if (devices == NULL) + if (devices == NULL) { croak ("list_devices: %s", last_error); + } for (n = 0; devices[n] != NULL; ++n) /**/; EXTEND (SP, n); for (i = 0; i < n; ++i) { @@ -299,8 +347,9 @@ PREINIT: int i, n; PPCODE: partitions = guestfs_list_partitions (g); - if (partitions == NULL) + if (partitions == NULL) { croak ("list_partitions: %s", last_error); + } for (n = 0; partitions[n] != NULL; ++n) /**/; EXTEND (SP, n); for (i = 0; i < n; ++i) { @@ -317,8 +366,9 @@ PREINIT: int i, n; PPCODE: physvols = guestfs_pvs (g); - if (physvols == NULL) + if (physvols == NULL) { croak ("pvs: %s", last_error); + } for (n = 0; physvols[n] != NULL; ++n) /**/; EXTEND (SP, n); for (i = 0; i < n; ++i) { @@ -335,8 +385,9 @@ PREINIT: int i, n; PPCODE: volgroups = guestfs_vgs (g); - if (volgroups == NULL) + if (volgroups == NULL) { croak ("vgs: %s", last_error); + } for (n = 0; volgroups[n] != NULL; ++n) /**/; EXTEND (SP, n); for (i = 0; i < n; ++i) { @@ -353,8 +404,9 @@ PREINIT: int i, n; PPCODE: logvols = guestfs_lvs (g); - if (logvols == NULL) + if (logvols == NULL) { croak ("lvs: %s", last_error); + } for (n = 0; logvols[n] != NULL; ++n) /**/; EXTEND (SP, n); for (i = 0; i < n; ++i) { @@ -475,8 +527,9 @@ PREINIT: int i, n; PPCODE: lines = guestfs_read_lines (g, path); - if (lines == NULL) + if (lines == NULL) { croak ("read_lines: %s", last_error); + } for (n = 0; lines[n] != NULL; ++n) /**/; EXTEND (SP, n); for (i = 0; i < n; ++i) { @@ -491,15 +544,17 @@ aug_init (g, root, flags) char *root; int flags; PPCODE: - if (guestfs_aug_init (g, root, flags) == -1) + if (guestfs_aug_init (g, root, flags) == -1) { croak ("aug_init: %s", last_error); + } void aug_close (g) guestfs_h *g; PPCODE: - if (guestfs_aug_close (g) == -1) + if (guestfs_aug_close (g) == -1) { croak ("aug_close: %s", last_error); + } SV * aug_defvar (g, name, expr) @@ -510,8 +565,9 @@ PREINIT: int nrnodes; CODE: nrnodes = guestfs_aug_defvar (g, name, expr); - if (nrnodes == -1) + if (nrnodes == -1) { croak ("aug_defvar: %s", last_error); + } RETVAL = newSViv (nrnodes); OUTPUT: RETVAL @@ -526,8 +582,9 @@ PREINIT: struct guestfs_int_bool *r; PPCODE: r = guestfs_aug_defnode (g, name, expr, val); - if (r == NULL) + if (r == NULL) { croak ("aug_defnode: %s", last_error); + } EXTEND (SP, 2); PUSHs (sv_2mortal (newSViv (r->i))); PUSHs (sv_2mortal (newSViv (r->b))); @@ -541,8 +598,9 @@ PREINIT: char *val; CODE: val = guestfs_aug_get (g, path); - if (val == NULL) + if (val == NULL) { croak ("aug_get: %s", last_error); + } RETVAL = newSVpv (val, 0); free (val); OUTPUT: @@ -554,8 +612,9 @@ aug_set (g, path, val) char *path; char *val; PPCODE: - if (guestfs_aug_set (g, path, val) == -1) + if (guestfs_aug_set (g, path, val) == -1) { croak ("aug_set: %s", last_error); + } void aug_insert (g, path, label, before) @@ -564,8 +623,9 @@ aug_insert (g, path, label, before) char *label; int before; PPCODE: - if (guestfs_aug_insert (g, path, label, before) == -1) + if (guestfs_aug_insert (g, path, label, before) == -1) { croak ("aug_insert: %s", last_error); + } SV * aug_rm (g, path) @@ -575,8 +635,9 @@ PREINIT: int nrnodes; CODE: nrnodes = guestfs_aug_rm (g, path); - if (nrnodes == -1) + if (nrnodes == -1) { croak ("aug_rm: %s", last_error); + } RETVAL = newSViv (nrnodes); OUTPUT: RETVAL @@ -587,8 +648,9 @@ aug_mv (g, src, dest) char *src; char *dest; PPCODE: - if (guestfs_aug_mv (g, src, dest) == -1) + if (guestfs_aug_mv (g, src, dest) == -1) { croak ("aug_mv: %s", last_error); + } void aug_match (g, path) @@ -599,8 +661,9 @@ PREINIT: int i, n; PPCODE: matches = guestfs_aug_match (g, path); - if (matches == NULL) + if (matches == NULL) { croak ("aug_match: %s", last_error); + } for (n = 0; matches[n] != NULL; ++n) /**/; EXTEND (SP, n); for (i = 0; i < n; ++i) { @@ -613,15 +676,17 @@ void aug_save (g) guestfs_h *g; PPCODE: - if (guestfs_aug_save (g) == -1) + if (guestfs_aug_save (g) == -1) { croak ("aug_save: %s", last_error); + } void aug_load (g) guestfs_h *g; PPCODE: - if (guestfs_aug_load (g) == -1) + if (guestfs_aug_load (g) == -1) { croak ("aug_load: %s", last_error); + } void aug_ls (g, path) @@ -632,8 +697,9 @@ PREINIT: int i, n; PPCODE: matches = guestfs_aug_ls (g, path); - if (matches == NULL) + if (matches == NULL) { croak ("aug_ls: %s", last_error); + } for (n = 0; matches[n] != NULL; ++n) /**/; EXTEND (SP, n); for (i = 0; i < n; ++i) { @@ -647,40 +713,45 @@ rm (g, path) guestfs_h *g; char *path; PPCODE: - if (guestfs_rm (g, path) == -1) + if (guestfs_rm (g, path) == -1) { croak ("rm: %s", last_error); + } void rmdir (g, path) guestfs_h *g; char *path; PPCODE: - if (guestfs_rmdir (g, path) == -1) + if (guestfs_rmdir (g, path) == -1) { croak ("rmdir: %s", last_error); + } void rm_rf (g, path) guestfs_h *g; char *path; PPCODE: - if (guestfs_rm_rf (g, path) == -1) + if (guestfs_rm_rf (g, path) == -1) { croak ("rm_rf: %s", last_error); + } void mkdir (g, path) guestfs_h *g; char *path; PPCODE: - if (guestfs_mkdir (g, path) == -1) + if (guestfs_mkdir (g, path) == -1) { croak ("mkdir: %s", last_error); + } void mkdir_p (g, path) guestfs_h *g; char *path; PPCODE: - if (guestfs_mkdir_p (g, path) == -1) + if (guestfs_mkdir_p (g, path) == -1) { croak ("mkdir_p: %s", last_error); + } void chmod (g, mode, path) @@ -688,8 +759,9 @@ chmod (g, mode, path) int mode; char *path; PPCODE: - if (guestfs_chmod (g, mode, path) == -1) + if (guestfs_chmod (g, mode, path) == -1) { croak ("chmod: %s", last_error); + } void chown (g, owner, group, path) @@ -698,6 +770,164 @@ chown (g, owner, group, path) int group; char *path; PPCODE: - if (guestfs_chown (g, owner, group, path) == -1) + if (guestfs_chown (g, owner, group, path) == -1) { croak ("chown: %s", last_error); + } + +SV * +exists (g, path) + guestfs_h *g; + char *path; +PREINIT: + int existsflag; + CODE: + existsflag = guestfs_exists (g, path); + if (existsflag == -1) { + croak ("exists: %s", last_error); + } + RETVAL = newSViv (existsflag); + OUTPUT: + RETVAL + +SV * +is_file (g, path) + guestfs_h *g; + char *path; +PREINIT: + int fileflag; + CODE: + fileflag = guestfs_is_file (g, path); + if (fileflag == -1) { + croak ("is_file: %s", last_error); + } + RETVAL = newSViv (fileflag); + OUTPUT: + RETVAL + +SV * +is_dir (g, path) + guestfs_h *g; + char *path; +PREINIT: + int dirflag; + CODE: + dirflag = guestfs_is_dir (g, path); + if (dirflag == -1) { + croak ("is_dir: %s", last_error); + } + RETVAL = newSViv (dirflag); + OUTPUT: + RETVAL + +void +pvcreate (g, device) + guestfs_h *g; + char *device; + PPCODE: + if (guestfs_pvcreate (g, device) == -1) { + croak ("pvcreate: %s", last_error); + } + +void +vgcreate (g, volgroup, physvols) + guestfs_h *g; + char *volgroup; + char **physvols; + PPCODE: + if (guestfs_vgcreate (g, volgroup, physvols) == -1) { + free (physvols); + croak ("vgcreate: %s", last_error); + } + free (physvols); + +void +lvcreate (g, logvol, volgroup, mbytes) + guestfs_h *g; + char *logvol; + char *volgroup; + int mbytes; + PPCODE: + if (guestfs_lvcreate (g, logvol, volgroup, mbytes) == -1) { + croak ("lvcreate: %s", last_error); + } + +void +mkfs (g, fstype, device) + guestfs_h *g; + char *fstype; + char *device; + PPCODE: + if (guestfs_mkfs (g, fstype, device) == -1) { + croak ("mkfs: %s", last_error); + } + +void +sfdisk (g, device, cyls, heads, sectors, lines) + guestfs_h *g; + char *device; + int cyls; + int heads; + int sectors; + char **lines; + PPCODE: + if (guestfs_sfdisk (g, device, cyls, heads, sectors, lines) == -1) { + free (lines); + croak ("sfdisk: %s", last_error); + } + free (lines); + +void +write_file (g, path, content, size) + guestfs_h *g; + char *path; + char *content; + int size; + PPCODE: + if (guestfs_write_file (g, path, content, size) == -1) { + croak ("write_file: %s", last_error); + } + +void +umount (g, pathordevice) + guestfs_h *g; + char *pathordevice; + PPCODE: + if (guestfs_umount (g, pathordevice) == -1) { + croak ("umount: %s", last_error); + } + +void +mounts (g) + guestfs_h *g; +PREINIT: + char **devices; + int i, n; + PPCODE: + devices = guestfs_mounts (g); + if (devices == NULL) { + croak ("mounts: %s", last_error); + } + for (n = 0; devices[n] != NULL; ++n) /**/; + EXTEND (SP, n); + for (i = 0; i < n; ++i) { + PUSHs (sv_2mortal (newSVpv (devices[i], 0))); + free (devices[i]); + } + free (devices); + +void +umount_all (g) + guestfs_h *g; + PPCODE: + if (guestfs_umount_all (g) == -1) { + croak ("umount_all: %s", last_error); + } + +void +lvm_remove_all (g) + guestfs_h *g; + PPCODE: + if (guestfs_lvm_remove_all (g) == -1) { + croak ("lvm_remove_all: %s", last_error); + } diff --git a/perl/lib/Sys/Guestfs.pm b/perl/lib/Sys/Guestfs.pm index 50f5d750..c708a29c 100644 --- a/perl/lib/Sys/Guestfs.pm +++ b/perl/lib/Sys/Guestfs.pm @@ -91,13 +91,13 @@ sub new { return $self; } -=item $h->add_cdrom (filename); +=item $h->add_cdrom ($filename); This function adds a virtual CD-ROM disk image to the guest. This is equivalent to the qemu parameter C<-cdrom filename>. -=item $h->add_drive (filename); +=item $h->add_drive ($filename); This function adds a virtual machine disk image C<filename> to the guest. The first time you call this function, the disk appears as IDE @@ -119,7 +119,7 @@ used by it. After calling this, you have to call C<$h-E<gt>aug_init> again before you can use any other Augeas functions. -=item ($nrnodes, $created) = $h->aug_defnode (name, expr, val); +=item ($nrnodes, $created) = $h->aug_defnode ($name, $expr, $val); Defines a variable C<name> whose value is the result of evaluating C<expr>. @@ -132,7 +132,7 @@ On success this returns a pair containing the number of nodes in the nodeset, and a boolean flag if a node was created. -=item $nrnodes = $h->aug_defvar (name, expr); +=item $nrnodes = $h->aug_defvar ($name, $expr); Defines an Augeas variable C<name> whose value is the result of evaluating C<expr>. If C<expr> is NULL, then C<name> is @@ -141,12 +141,12 @@ undefined. On success this returns the number of nodes in C<expr>, or C<0> if C<expr> evaluates to something which is not a nodeset. -=item $val = $h->aug_get (path); +=item $val = $h->aug_get ($path); Look up the value associated with C<path>. If C<path> matches exactly one node, the C<value> is returned. -=item $h->aug_init (root, flags); +=item $h->aug_init ($root, $flags); Create a new Augeas handle for editing configuration files. If there was any previous Augeas handle associated with this @@ -195,7 +195,7 @@ To close the handle, you can call C<$h-E<gt>aug_close>. To find out more about Augeas, see L<http://augeas.net/>. -=item $h->aug_insert (path, label, before); +=item $h->aug_insert ($path, $label, $before); Create a new sibling C<label> for C<path>, inserting it into the tree before or after C<path> (depending on the boolean @@ -212,23 +212,23 @@ Load files into the tree. See C<aug_load> in the Augeas documentation for the full gory details. -=item @matches = $h->aug_ls (path); +=item @matches = $h->aug_ls ($path); This is just a shortcut for listing C<$h-E<gt>aug_match> C<path/*> and sorting the resulting nodes into alphabetical order. -=item @matches = $h->aug_match (path); +=item @matches = $h->aug_match ($path); Returns a list of paths which match the path expression C<path>. The returned paths are sufficiently qualified so that they match exactly one node in the current tree. -=item $h->aug_mv (src, dest); +=item $h->aug_mv ($src, $dest); Move the node C<src> to C<dest>. C<src> must match exactly one node. C<dest> is overwritten if it exists. -=item $nrnodes = $h->aug_rm (path); +=item $nrnodes = $h->aug_rm ($path); Remove C<path> and all of its children. @@ -241,11 +241,11 @@ This writes all pending changes to disk. The flags which were passed to C<$h-E<gt>aug_init> affect exactly how files are saved. -=item $h->aug_set (path, val); +=item $h->aug_set ($path, $val); Set the value associated with C<path> to C<value>. -=item $content = $h->cat (path); +=item $content = $h->cat ($path); Return the contents of the file named C<path>. @@ -258,12 +258,12 @@ Because of the message protocol, there is a transfer limit of somewhere between 2MB and 4MB. To transfer large files you should use FTP. -=item $h->chmod (mode, path); +=item $h->chmod ($mode, $path); Change the mode (permissions) of C<path> to C<mode>. Only numeric modes are supported. -=item $h->chown (owner, group, path); +=item $h->chown ($owner, $group, $path); Change the file owner to C<owner> and group to C<group>. @@ -271,7 +271,7 @@ Only numeric uid and gid are supported. If you want to use names, you will need to locate and parse the password file yourself (Augeas support makes this relatively easy). -=item $h->config (qemuparam, qemuvalue); +=item $h->config ($qemuparam, $qemuvalue); This can be used to add arbitrary qemu command line parameters of the form C<-param value>. Actually it's not quite arbitrary - we @@ -282,6 +282,13 @@ The first character of C<param> string must be a C<-> (dash). C<value> can be NULL. +=item $existsflag = $h->exists ($path); + +This returns C<true> if and only if there is a file, directory +(or anything) with the given C<path> name. + +See also C<$h-E<gt>is_file>, C<$h-E<gt>is_dir>, C<$h-E<gt>stat>. + =item $autosync = $h->get_autosync (); Get the autosync flag. @@ -297,6 +304,22 @@ return the default path. This returns the verbose messages flag. +=item $dirflag = $h->is_dir ($path); + +This returns C<true> if and only if there is a directory +with the given C<path> name. Note that it returns false for +other objects like files. + +See also C<$h-E<gt>stat>. + +=item $fileflag = $h->is_file ($path); + +This returns C<true> if and only if there is a file +with the given C<path> name. Note that it returns false for +other objects like directories. + +See also C<$h-E<gt>stat>. + =item $h->kill_subprocess (); This kills the qemu subprocess. You should never need to call this. @@ -324,7 +347,7 @@ The full partition device names are returned, eg. C</dev/sda1> This does not return logical volumes. For that you will need to call C<$h-E<gt>lvs>. -=item $listing = $h->ll (directory); +=item $listing = $h->ll ($directory); List the files in C<directory> (relative to the root directory, there is no cwd) in the format of 'ls -la'. @@ -332,7 +355,7 @@ there is no cwd) in the format of 'ls -la'. This command is mostly useful for interactive sessions. It is I<not> intended that you try to parse the output string. -=item @listing = $h->ls (directory); +=item @listing = $h->ls ($directory); List the files in C<directory> (relative to the root directory, there is no cwd). The '.' and '..' entries are not returned, but @@ -341,6 +364,19 @@ hidden files are shown. This command is mostly useful for interactive sessions. Programs should probably use C<$h-E<gt>readdir> instead. +=item $h->lvcreate ($logvol, $volgroup, $mbytes); + +This creates an LVM volume group called C<logvol> +on the volume group C<volgroup>, with C<size> megabytes. + +=item $h->lvm_remove_all (); + +This command removes all LVM logical volumes, volume groups +and physical volumes. + +B<This command is dangerous. Without careful use you +can easily destroy all your data>. + =item @logvols = $h->lvs (); List all the logical volumes detected. This is the equivalent @@ -356,16 +392,22 @@ See also C<$h-E<gt>lvs_full>. List all the logical volumes detected. This is the equivalent of the L<lvs(8)> command. The "full" version includes all fields. -=item $h->mkdir (path); +=item $h->mkdir ($path); Create a directory named C<path>. -=item $h->mkdir_p (path); +=item $h->mkdir_p ($path); Create a directory named C<path>, creating any parent directories as necessary. This is like the C<mkdir -p> shell command. -=item $h->mount (device, mountpoint); +=item $h->mkfs ($fstype, $device); + +This creates a filesystem on C<device> (usually a partition +of LVM logical volume). The filesystem type is C<fstype>, for +example C<ext3>. + +=item $h->mount ($device, $mountpoint); Mount a guest disk at a position in the filesystem. Block devices are named C</dev/sda>, C</dev/sdb> and so on, as they were added to @@ -384,6 +426,19 @@ on the underlying device. The filesystem options C<sync> and C<noatime> are set with this call, in order to improve reliability. +=item @devices = $h->mounts (); + +This returns the list of currently mounted filesystems. It returns +the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>). + +Some internal mounts are not shown. + +=item $h->pvcreate ($device); + +This creates an LVM physical volume on the named C<device>, +where C<device> should usually be a partition name such +as C</dev/sda1>. + =item @physvols = $h->pvs (); List all the physical volumes detected. This is the equivalent @@ -399,7 +454,7 @@ See also C<$h-E<gt>pvs_full>. List all the physical volumes detected. This is the equivalent of the L<pvs(8)> command. The "full" version includes all fields. -=item @lines = $h->read_lines (path); +=item @lines = $h->read_lines ($path); Return the contents of the file named C<path>. @@ -411,27 +466,27 @@ Note that this function cannot correctly handle binary files as end of line). For those you need to use the C<$h-E<gt>read_file> function which has a more complex interface. -=item $h->rm (path); +=item $h->rm ($path); Remove the single file C<path>. -=item $h->rm_rf (path); +=item $h->rm_rf ($path); Remove the file or directory C<path>, recursively removing the contents if its a directory. This is like the C<rm -rf> shell command. -=item $h->rmdir (path); +=item $h->rmdir ($path); Remove the single directory C<path>. -=item $h->set_autosync (autosync); +=item $h->set_autosync ($autosync); If C<autosync> is true, this enables autosync. Libguestfs will make a best effort attempt to run C<$h-E<gt>sync> when the handle is closed (also if the program exits without closing handles). -=item $h->set_path (path); +=item $h->set_path ($path); Set the path that libguestfs searches for kernel and initrd.img. @@ -443,13 +498,38 @@ must make sure it remains valid for the lifetime of the handle. Setting C<path> to C<NULL> restores the default path. -=item $h->set_verbose (verbose); +=item $h->set_verbose ($verbose); If C<verbose> is true, this turns on verbose messages (to C<stderr>). Verbose messages are disabled unless the environment variable C<LIBGUESTFS_DEBUG> is defined and set to C<1>. +=item $h->sfdisk ($device, $cyls, $heads, $sectors, \@lines); + +This is a direct interface to the L<sfdisk(8)> program for creating +partitions on block devices. + +C<device> should be a block device, for example C</dev/sda>. + +C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads +and sectors on the device, which are passed directly to sfdisk as +the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any +of these, then the corresponding parameter is omitted. Usually for +'large' disks, you can just pass C<0> for these, but for small +(floppy-sized) disks, sfdisk (or rather, the kernel) cannot work +out the right geometry and you will need to tell it. + +C<lines> is a list of lines that we feed to C<sfdisk>. For more +information refer to the L<sfdisk(8)> manpage. + +To create a single partition occupying the whole disk, you would +pass C<lines> as a single element list, when the single element being +the string C<,> (comma). + +B<This command is dangerous. Without careful use you +can easily destroy all your data>. + =item $h->sync (); This syncs the disk, so that any writes are flushed through to the @@ -458,12 +538,29 @@ underlying disk image. You should always call this if you have modified a disk image, before closing the handle. -=item $h->touch (path); +=item $h->touch ($path); Touch acts like the L<touch(1)> command. It can be used to update the timestamps on a file, or, if the file does not exist, to create a new zero-length file. +=item $h->umount ($pathordevice); + +This unmounts the given filesystem. The filesystem may be +specified either by its mountpoint (path) or the device which +contains the filesystem. + +=item $h->umount_all (); + +This unmounts all mounted filesystems. + +Some internal mounts are not unmounted by this call. + +=item $h->vgcreate ($volgroup, \@physvols); + +This creates an LVM volume group called C<volgroup> +from the non-empty list of physical volumes C<physvols>. + =item @volgroups = $h->vgs (); List all the volumes groups detected. This is the equivalent @@ -487,6 +584,20 @@ using L<qemu(1)>. You should call this after C<$h-E<gt>launch> to wait for the launch to complete. +=item $h->write_file ($path, $content, $size); + +This call creates a file called C<path>. The contents of the +file is the string C<content> (which can contain any 8 bit data), +with length C<size>. + +As a special case, if C<size> is C<0> +then the length is calculated using C<strlen> (so in this case +the content cannot contain embedded ASCII NULs). + +Because of the message protocol, there is a transfer limit +of somewhere between 2MB and 4MB. To transfer large files you should use +FTP. + =cut 1; diff --git a/src/generator.ml b/src/generator.ml index 06a638e6..6792e07a 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -77,59 +77,74 @@ and args = argt list (* Function parameters, guestfs handle is implicit. *) and argt = | String of string (* const char *name, cannot be NULL *) | OptString of string (* const char *name, may be NULL *) + | StringList of string(* list of strings (each string cannot be NULL) *) | Bool of string (* boolean *) | Int of string (* int (smallish ints, signed, <= 31 bits) *) type flags = | ProtocolLimitWarning (* display warning about protocol size limits *) + | DangerWillRobinson (* flags particularly dangerous commands *) | FishAlias of string (* provide an alias for this cmd in guestfish *) | FishAction of string (* call this function in guestfish *) | NotInFish (* do not export via guestfish *) +let protocol_limit_warning = + "Because of the message protocol, there is a transfer limit +of somewhere between 2MB and 4MB. To transfer large files you should use +FTP." + +let danger_will_robinson = + "B<This command is dangerous. Without careful use you +can easily destroy all your data>." + (* You can supply zero or as many tests as you want per API call. * - * Note that the test environment has 3 block devices, of size 10M, 20M - * and 30M (respectively /dev/sda, /dev/sdb, /dev/sdc). To run the - * tests in a reasonable amount of time, the virtual machine and - * block devices are reused between tests. So don't try testing - * kill_subprocess :-x + * Note that the test environment has 3 block devices, of size 500MB, + * 50MB and 10MB (respectively /dev/sda, /dev/sdb, /dev/sdc). + * Note for partitioning purposes, the 500MB device has 63 cylinders. + * + * To be able to run the tests in a reasonable amount of time, + * the virtual machine and block devices are reused between tests. + * So don't try testing kill_subprocess :-x + * + * Between each test we umount-all and lvm-remove-all. * * Don't assume anything about the previous contents of the block * devices. Use 'Init*' to create some initial scenarios. *) -type tests = test list +type tests = (test_init * test) list and test = (* Run the command sequence and just expect nothing to fail. *) - | TestRun of test_init * seq + | TestRun of seq (* Run the command sequence and expect the output of the final * command to be the string. *) - | TestOutput of test_init * seq * string + | TestOutput of seq * string (* Run the command sequence and expect the output of the final * command to be the list of strings. *) - | TestOutputList of test_init * seq * string list + | TestOutputList of seq * string list (* Run the command sequence and expect the output of the final * command to be the integer. *) - | TestOutputInt of test_init * seq * int + | TestOutputInt of seq * int (* Run the command sequence and expect the output of the final * command to be a true value (!= 0 or != NULL). *) - | TestOutputTrue of test_init * seq + | TestOutputTrue of seq (* Run the command sequence and expect the output of the final * command to be a false value (== 0 or == NULL, but not an error). *) - | TestOutputFalse of test_init * seq + | TestOutputFalse of seq (* Run the command sequence and expect the output of the final * command to be a list of the given length (but don't care about * content). *) - | TestOutputLength of test_init * seq * int + | TestOutputLength of seq * int (* Run the command sequence and expect the final command (only) * to fail. *) - | TestLastFail of test_init * seq + | TestLastFail of seq (* Some initial scenarios for testing. *) and test_init = @@ -143,7 +158,7 @@ and test_init = | InitEmpty (* /dev/sda: * /dev/sda1 (is a PV): - * /dev/VG/LV: + * /dev/VG/LV (size 8MB): * formatted as ext2, empty [except for lost+found], mounted on / * /dev/sdb and /dev/sdc may have random content. *) @@ -281,9 +296,8 @@ This returns the verbose messages flag.") let daemon_functions = [ ("mount", (RErr, [String "device"; String "mountpoint"]), 1, [], - [TestOutput ( - InitNone, - [["sfdisk"]; + [InitNone, TestOutput ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; ["mkfs"; "ext2"; "/dev/sda1"]; ["mount"; "/dev/sda1"; "/"]; ["write_file"; "/new"; "new file contents"; "0"]; @@ -308,7 +322,7 @@ The filesystem options C<sync> and C<noatime> are set with this call, in order to improve reliability."); ("sync", (RErr, []), 2, [], - [ TestRun (InitNone, [["sync"]])], + [ InitNone, TestRun [["sync"]]], "sync disks, writes are flushed through to the disk image", "\ This syncs the disk, so that any writes are flushed through to the @@ -318,8 +332,7 @@ You should always call this if you have modified a disk image, before closing the handle."); ("touch", (RErr, [String "path"]), 3, [], - [TestOutputTrue ( - InitEmpty, + [InitEmpty, TestOutputTrue ( [["touch"; "/new"]; ["exists"; "/new"]])], "update file timestamps or create a new file", @@ -329,8 +342,7 @@ update the timestamps on a file, or, if the file does not exist, to create a new zero-length file."); ("cat", (RString "content", [String "path"]), 4, [ProtocolLimitWarning], - [TestOutput ( - InitEmpty, + [InitEmpty, TestOutput ( [["write_file"; "/new"; "new file contents"; "0"]; ["cat"; "/new"]], "new file contents")], "list the contents of a file", @@ -355,8 +367,7 @@ This command is mostly useful for interactive sessions. It is I<not> intended that you try to parse the output string."); ("ls", (RStringList "listing", [String "directory"]), 6, [], - [TestOutputList ( - InitEmpty, + [InitEmpty, TestOutputList ( [["touch"; "/new"]; ["touch"; "/newer"]; ["touch"; "/newest"]; @@ -371,8 +382,7 @@ This command is mostly useful for interactive sessions. Programs should probably use C<guestfs_readdir> instead."); ("list_devices", (RStringList "devices", []), 7, [], - [TestOutputList ( - InitNone, + [InitNone, TestOutputList ( [["list_devices"]], ["/dev/sda"; "/dev/sdb"; "/dev/sdc"])], "list the block devices", "\ @@ -381,12 +391,10 @@ List all the block devices. The full block device names are returned, eg. C</dev/sda>"); ("list_partitions", (RStringList "partitions", []), 8, [], - [TestOutputList ( - InitEmpty, + [InitEmpty, TestOutputList ( [["list_partitions"]], ["/dev/sda1"]); - TestOutputList ( - InitEmpty, - [["sfdisk"]; + InitNone, TestOutputList ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; ["list_partitions"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])], "list the partitions", "\ @@ -398,12 +406,10 @@ This does not return logical volumes. For that you will need to call C<guestfs_lvs>."); ("pvs", (RStringList "physvols", []), 9, [], - [TestOutputList ( - InitEmptyLVM, + [InitEmptyLVM, TestOutputList ( [["pvs"]], ["/dev/sda1"]); - TestOutputList ( - InitNone, - [["sfdisk"]; + InitNone, TestOutputList ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; ["pvcreate"; "/dev/sda1"]; ["pvcreate"; "/dev/sda2"]; ["pvcreate"; "/dev/sda3"]; @@ -419,12 +425,10 @@ PVs (eg. C</dev/sda2>). See also C<guestfs_pvs_full>."); ("vgs", (RStringList "volgroups", []), 10, [], - [TestOutputList ( - InitEmptyLVM, + [InitEmptyLVM, TestOutputList ( [["vgs"]], ["VG"]); - TestOutputList ( - InitNone, - [["sfdisk"]; + InitNone, TestOutputList ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; ["pvcreate"; "/dev/sda1"]; ["pvcreate"; "/dev/sda2"]; ["pvcreate"; "/dev/sda3"]; @@ -442,21 +446,19 @@ detected (eg. C<VolGroup00>). See also C<guestfs_vgs_full>."); ("lvs", (RStringList "logvols", []), 11, [], - [TestOutputList ( - InitEmptyLVM, + [InitEmptyLVM, TestOutputList ( [["lvs"]], ["/dev/VG/LV"]); - TestOutputList ( - InitNone, - [["sfdisk"]; + InitNone, TestOutputList ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; ["pvcreate"; "/dev/sda1"]; ["pvcreate"; "/dev/sda2"]; ["pvcreate"; "/dev/sda3"]; ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"]; ["vgcreate"; "VG2"; "/dev/sda3"]; - ["lvcreate"; "LV1"; "VG1"; "5000"]; - ["lvcreate"; "LV2"; "VG1"; "5000"]; - ["lvcreate"; "LV3"; "VG2"; "5000"]; - ["lvs"]], ["LV1"; "LV2"; "LV3"])], + ["lvcreate"; "LV1"; "VG1"; "50"]; + ["lvcreate"; "LV2"; "VG1"; "50"]; + ["lvcreate"; "LV3"; "VG2"; "50"]; + ["lvs"]], ["/dev/VG1/LV1"; "/dev/VG1/LV2"; "/dev/VG2/LV3"])], "list the LVM logical volumes (LVs)", "\ List all the logical volumes detected. This is the equivalent @@ -468,8 +470,7 @@ This returns a list of the logical volume device names See also C<guestfs_lvs_full>."); ("pvs_full", (RPVList "physvols", []), 12, [], - [TestOutputLength ( - InitEmptyLVM, + [InitEmptyLVM, TestOutputLength ( [["pvs"]], 1)], "list the LVM physical volumes (PVs)", "\ @@ -477,8 +478,7 @@ List all the physical volumes detected. This is the equivalent of the L<pvs(8)> command. The \"full\" version includes all fields."); ("vgs_full", (RVGList "volgroups", []), 13, [], - [TestOutputLength ( - InitEmptyLVM, + [InitEmptyLVM, TestOutputLength ( [["pvs"]], 1)], "list the LVM volume groups (VGs)", "\ @@ -486,8 +486,7 @@ List all the volumes groups detected. This is the equivalent of the L<vgs(8)> command. The \"full\" version includes all fields."); ("lvs_full", (RLVList "logvols", []), 14, [], - [TestOutputLength ( - InitEmptyLVM, + [InitEmptyLVM, TestOutputLength ( [["pvs"]], 1)], "list the LVM logical volumes (LVs)", "\ @@ -495,12 +494,10 @@ List all the logical volumes detected. This is the equivalent of the L<lvs(8)> command. The \"full\" version includes all fields."); ("read_lines", (RStringList "lines", [String "path"]), 15, [], - [TestOutputList ( - InitEmpty, + [InitEmpty, TestOutputList ( [["write_file"; "/new"; "line1\r\nline2\nline3"; "0"]; ["read_lines"; "/new"]], ["line1"; "line2"; "line3"]); - TestOutputList ( - InitEmpty, + InitEmpty, TestOutputList ( [["write_file"; "/new"; ""; "0"]; ["read_lines"; "/new"]], [])], "read file as lines", @@ -675,45 +672,38 @@ This is just a shortcut for listing C<guestfs_aug_match> C<path/*> and sorting the resulting nodes into alphabetical order."); ("rm", (RErr, [String "path"]), 29, [], - [TestRun ( - InitEmpty, + [InitEmpty, TestRun [["touch"; "/new"]; - ["rm"; "/new"]]); - TestLastFail ( - InitEmpty, - [["rm"; "/new"]]); - TestLastFail ( - InitEmpty, + ["rm"; "/new"]]; + InitEmpty, TestLastFail + [["rm"; "/new"]]; + InitEmpty, TestLastFail [["mkdir"; "/new"]; - ["rm"; "/new"]])], + ["rm"; "/new"]]], "remove a file", "\ Remove the single file C<path>."); ("rmdir", (RErr, [String "path"]), 30, [], - [TestRun ( - InitEmpty, + [InitEmpty, TestRun [["mkdir"; "/new"]; - ["rmdir"; "/new"]]); - TestLastFail ( - InitEmpty, - [["rmdir"; "/new"]]); - TestLastFail ( - InitEmpty, + ["rmdir"; "/new"]]; + InitEmpty, TestLastFail + [["rmdir"; "/new"]]; + InitEmpty, TestLastFail [["touch"; "/new"]; - ["rmdir"; "/new"]])], + ["rmdir"; "/new"]]], "remove a directory", "\ Remove the single directory C<path>."); ("rm_rf", (RErr, [String "path"]), 31, [], - [TestOutputFalse ( - InitEmpty, + [InitEmpty, TestOutputFalse [["mkdir"; "/new"]; ["mkdir"; "/new/foo"]; ["touch"; "/new/foo/bar"]; ["rm_rf"; "/new"]; - ["exists"; "/new"]])], + ["exists"; "/new"]]], "remove a file or directory recursively", "\ Remove the file or directory C<path>, recursively removing the @@ -721,27 +711,25 @@ contents if its a directory. This is like the C<rm -rf> shell command."); ("mkdir", (RErr, [String "path"]), 32, [], - [TestOutputTrue ( - InitEmpty, + [InitEmpty, TestOutputTrue [["mkdir"; "/new"]; - ["is_dir"; "/new"]])], + ["is_dir"; "/new"]]; + InitEmpty, TestLastFail + [["mkdir"; "/new/foo/bar"]]], "create a directory", "\ Create a directory named C<path>."); ("mkdir_p", (RErr, [String "path"]), 33, [], - [TestOutputTrue ( - InitEmpty, + [InitEmpty, TestOutputTrue [["mkdir_p"; "/new/foo/bar"]; - ["is_dir"; "/new/foo/bar"]]); - TestOutputTrue ( - InitEmpty, + ["is_dir"; "/new/foo/bar"]]; + InitEmpty, TestOutputTrue [["mkdir_p"; "/new/foo/bar"]; - ["is_dir"; "/new/foo"]]); - TestOutputTrue ( - InitEmpty, + ["is_dir"; "/new/foo"]]; + InitEmpty, TestOutputTrue [["mkdir_p"; "/new/foo/bar"]; - ["is_dir"; "/new"]])], + ["is_dir"; "/new"]]], "create a directory and parents", "\ Create a directory named C<path>, creating any parent directories @@ -763,6 +751,200 @@ Change the file owner to C<owner> and group to C<group>. Only numeric uid and gid are supported. If you want to use names, you will need to locate and parse the password file yourself (Augeas support makes this relatively easy)."); + + ("exists", (RBool "existsflag", [String "path"]), 36, [], + [InitEmpty, TestOutputTrue ( + [["touch"; "/new"]; + ["exists"; "/new"]]); + InitEmpty, TestOutputTrue ( + [["mkdir"; "/new"]; + ["exists"; "/new"]])], + "test if file or directory exists", + "\ +This returns C<true> if and only if there is a file, directory +(or anything) with the given C<path> name. + +See also C<guestfs_is_file>, C<guestfs_is_dir>, C<guestfs_stat>."); + + ("is_file", (RBool "fileflag", [String "path"]), 37, [], + [InitEmpty, TestOutputTrue ( + [["touch"; "/new"]; + ["is_file"; "/new"]]); + InitEmpty, TestOutputFalse ( + [["mkdir"; "/new"]; + ["is_file"; "/new"]])], + "test if file exists", + "\ +This returns C<true> if and only if there is a file +with the given C<path> name. Note that it returns false for +other objects like directories. + +See also C<guestfs_stat>."); + + ("is_dir", (RBool "dirflag", [String "path"]), 38, [], + [InitEmpty, TestOutputFalse ( + [["touch"; "/new"]; + ["is_dir"; "/new"]]); + InitEmpty, TestOutputTrue ( + [["mkdir"; "/new"]; + ["is_dir"; "/new"]])], + "test if file exists", + "\ +This returns C<true> if and only if there is a directory +with the given C<path> name. Note that it returns false for +other objects like files. + +See also C<guestfs_stat>."); + + ("pvcreate", (RErr, [String "device"]), 39, [], + [InitNone, TestOutputList ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; + ["pvcreate"; "/dev/sda1"]; + ["pvcreate"; "/dev/sda2"]; + ["pvcreate"; "/dev/sda3"]; + ["pvs"]], ["/dev/sda1"; "/dev/sda2"; "/dev/sda3"])], + "create an LVM physical volume", + "\ +This creates an LVM physical volume on the named C<device>, +where C<device> should usually be a partition name such +as C</dev/sda1>."); + + ("vgcreate", (RErr, [String "volgroup"; StringList "physvols"]), 40, [], + [InitNone, TestOutputList ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; + ["pvcreate"; "/dev/sda1"]; + ["pvcreate"; "/dev/sda2"]; + ["pvcreate"; "/dev/sda3"]; + ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"]; + ["vgcreate"; "VG2"; "/dev/sda3"]; + ["vgs"]], ["VG1"; "VG2"])], + "create an LVM volume group", + "\ +This creates an LVM volume group called C<volgroup> +from the non-empty list of physical volumes C<physvols>."); + + ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [], + [InitNone, TestOutputList ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ",10 ,20 ,"]; + ["pvcreate"; "/dev/sda1"]; + ["pvcreate"; "/dev/sda2"]; + ["pvcreate"; "/dev/sda3"]; + ["vgcreate"; "VG1"; "/dev/sda1 /dev/sda2"]; + ["vgcreate"; "VG2"; "/dev/sda3"]; + ["lvcreate"; "LV1"; "VG1"; "50"]; + ["lvcreate"; "LV2"; "VG1"; "50"]; + ["lvcreate"; "LV3"; "VG2"; "50"]; + ["lvcreate"; "LV4"; "VG2"; "50"]; + ["lvcreate"; "LV5"; "VG2"; "50"]; + ["lvs"]], + ["/dev/VG1/LV1"; "/dev/VG1/LV2"; + "/dev/VG2/LV3"; "/dev/VG2/LV4"; "/dev/VG2/LV5"])], + "create an LVM volume group", + "\ +This creates an LVM volume group called C<logvol> +on the volume group C<volgroup>, with C<size> megabytes."); + + ("mkfs", (RErr, [String "fstype"; String "device"]), 42, [], + [InitNone, TestOutput ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + ["mkfs"; "ext2"; "/dev/sda1"]; + ["mount"; "/dev/sda1"; "/"]; + ["write_file"; "/new"; "new file contents"; "0"]; + ["cat"; "/new"]], "new file contents")], + "make a filesystem", + "\ +This creates a filesystem on C<device> (usually a partition +of LVM logical volume). The filesystem type is C<fstype>, for +example C<ext3>."); + + ("sfdisk", (RErr, [String "device"; + Int "cyls"; Int "heads"; Int "sectors"; + StringList "lines"]), 43, [DangerWillRobinson], + [], + "create partitions on a block device", + "\ +This is a direct interface to the L<sfdisk(8)> program for creating +partitions on block devices. + +C<device> should be a block device, for example C</dev/sda>. + +C<cyls>, C<heads> and C<sectors> are the number of cylinders, heads +and sectors on the device, which are passed directly to sfdisk as +the I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any +of these, then the corresponding parameter is omitted. Usually for +'large' disks, you can just pass C<0> for these, but for small +(floppy-sized) disks, sfdisk (or rather, the kernel) cannot work +out the right geometry and you will need to tell it. + +C<lines> is a list of lines that we feed to C<sfdisk>. For more +information refer to the L<sfdisk(8)> manpage. + +To create a single partition occupying the whole disk, you would +pass C<lines> as a single element list, when the single element being +the string C<,> (comma)."); + + ("write_file", (RErr, [String "path"; String "content"; Int "size"]), 44, [ProtocolLimitWarning], + [InitNone, TestOutput ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + ["mkfs"; "ext2"; "/dev/sda1"]; + ["mount"; "/dev/sda1"; "/"]; + ["write_file"; "/new"; "new file contents"; "0"]; + ["cat"; "/new"]], "new file contents")], + "Create a file", + "\ +This call creates a file called C<path>. The contents of the +file is the string C<content> (which can contain any 8 bit data), +with length C<size>. + +As a special case, if C<size> is C<0> +then the length is calculated using C<strlen> (so in this case +the content cannot contain embedded ASCII NULs)."); + + ("umount", (RErr, [String "pathordevice"]), 45, [FishAlias "unmount"], + [InitNone, TestOutputList ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + ["mkfs"; "ext2"; "/dev/sda1"]; + ["mount"; "/dev/sda1"; "/"]; + ["mounts"]], ["/dev/sda1"]); + InitNone, TestOutputList ( + [["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + ["mkfs"; "ext2"; "/dev/sda1"]; + ["mount"; "/dev/sda1"; "/"]; + ["umount"; "/"]; + ["mounts"]], [])], + "unmount a filesystem", + "\ +This unmounts the given filesystem. The filesystem may be +specified either by its mountpoint (path) or the device which +contains the filesystem."); + + ("mounts", (RStringList "devices", []), 46, [], + [InitEmpty, TestOutputList ( + [["mounts"]], ["/dev/sda1"])], + "show mounted filesystems", + "\ +This returns the list of currently mounted filesystems. It returns +the list of devices (eg. C</dev/sda1>, C</dev/VG/LV>). + +Some internal mounts are not shown."); + + ("umount_all", (RErr, []), 47, [FishAlias "unmount-all"], + [InitEmpty, TestOutputList ( + [["umount_all"]; + ["mounts"]], [])], + "unmount all filesystems", + "\ +This unmounts all mounted filesystems. + +Some internal mounts are not unmounted by this call."); + + ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson], + [], + "remove all LVM LVs, VGs and PVs", + "\ +This command removes all LVM logical volumes, volume groups +and physical volumes."); + ] let all_functions = non_daemon_functions @ daemon_functions @@ -884,6 +1066,17 @@ let rec replace_str s s1 s2 = s' ^ s2 ^ replace_str s'' s1 s2 ) +let rec string_split sep str = + let len = String.length str in + let seplen = String.length sep in + let i = find str sep in + if i = -1 then [str] + else ( + let s' = String.sub str 0 i in + let s'' = String.sub str (i+seplen) (len-i-seplen) in + s' :: string_split sep s'' + ) + let rec find_map f = function | [] -> raise Not_found | x :: xs -> @@ -898,7 +1091,15 @@ let iteri f xs = in loop 0 xs -let name_of_argt = function String n | OptString n | Bool n | Int n -> n +let mapi f xs = + let rec loop i = function + | [] -> [] + | x :: xs -> let r = f i x in r :: loop (i+1) xs + in + loop 0 xs + +let name_of_argt = function + | String n | OptString n | StringList n | Bool n | Int n -> n (* Check function names etc. for consistency. *) let check_functions () = @@ -1089,9 +1290,9 @@ I<The caller must call C<guestfs_free_lvm_vg_list> after use>.\n\n" I<The caller must call C<guestfs_free_lvm_lv_list> after use>.\n\n" ); if List.mem ProtocolLimitWarning flags then - pr "Because of the message protocol, there is a transfer limit -of somewhere between 2MB and 4MB. To transfer large files you should use -FTP.\n\n"; + pr "%s\n\n" protocol_limit_warning; + if List.mem DangerWillRobinson flags then + pr "%s\n\n" danger_will_robinson; ) all_functions_sorted and generate_structs_pod () = @@ -1169,6 +1370,7 @@ and generate_xdr () = function | String n -> pr " string %s<>;\n" n | OptString n -> pr " str *%s;\n" n + | StringList n -> pr " str %s<>;\n" n | Bool n -> pr " bool %s;\n" n | Int n -> pr " int %s;\n" n ) args; @@ -1427,6 +1629,9 @@ and generate_client_actions () = pr " args.%s = (char *) %s;\n" n n | OptString n -> pr " args.%s = %s ? (char **) &%s : NULL;\n" n n n + | StringList n -> + pr " args.%s.%s_val = (char **) %s;\n" n n n; + pr " for (args.%s.%s_len = 0; %s[args.%s.%s_len]; args.%s.%s_len++) ;\n" n n n n n n n; | Bool n -> pr " args.%s = %s;\n" n n | Int n -> @@ -1556,6 +1761,7 @@ and generate_daemon_actions () = function | String n | OptString n -> pr " const char *%s;\n" n + | StringList n -> pr " char **%s;\n" n | Bool n -> pr " int %s;\n" n | Int n -> pr " int %s;\n" n ) args @@ -1575,6 +1781,10 @@ and generate_daemon_actions () = function | String n -> pr " %s = args.%s;\n" n n | OptString n -> pr " %s = args.%s ? *args.%s : NULL;\n" n n n + | StringList n -> + pr " args.%s.%s_val = realloc (args.%s.%s_val, sizeof (char *) * (args.%s.%s_len+1));\n" n n n n n n; + pr " args.%s.%s_val[args.%s.%s_len] = NULL;\n" n n n n; + pr " %s = args.%s.%s_val;\n" n n n | Bool n -> pr " %s = args.%s;\n" n n | Int n -> pr " %s = args.%s;\n" n n ) args; @@ -1586,8 +1796,8 @@ and generate_daemon_actions () = pr ";\n"; pr " if (r == %s)\n" error_code; - pr " /* do_%s has already called reply_with_error, so just return */\n" name; - pr " return;\n"; + pr " /* do_%s has already called reply_with_error */\n" name; + pr " goto done;\n"; pr "\n"; (match fst style with @@ -1633,6 +1843,16 @@ and generate_daemon_actions () = pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_ret, (char *) &ret);\n" name ); + (* Free the args. *) + (match snd style with + | [] -> + pr "done: ;\n"; + | _ -> + pr "done:\n"; + pr " xdr_free ((xdrproc_t) xdr_guestfs_%s_args, (char *) &args);\n" + name + ); + pr "}\n\n"; ) daemon_functions; @@ -1823,20 +2043,459 @@ and generate_daemon_actions () = and generate_tests () = generate_header CStyle GPLv2; - pr "#include <stdio.h>\n"; - pr "#include <stdlib.h>\n"; - pr "#include <string.h>\n"; - pr "\n"; - pr "#include \"guestfs.h\"\n"; + pr "\ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> + +#include \"guestfs.h\" + +static guestfs_h *g; +static int suppress_error = 0; + +static void print_error (guestfs_h *g, void *data, const char *msg) +{ + if (!suppress_error) + fprintf (stderr, \"%%s\\n\", msg); +} + +static void print_strings (char * const * const argv) +{ + int argc; + + for (argc = 0; argv[argc] != NULL; ++argc) + printf (\"\\t%%s\\n\", argv[argc]); +} + +"; + + let test_names = + List.map ( + fun (name, _, _, _, tests, _, _) -> + mapi (generate_one_test name) tests + ) all_functions in + let test_names = List.concat test_names in + let nr_tests = List.length test_names in + + pr "\ +int main (int argc, char *argv[]) +{ + char c = 0; + int failed = 0; + const char *srcdir; + int fd; + char buf[256]; + + g = guestfs_create (); + if (g == NULL) { + printf (\"guestfs_create FAILED\\n\"); + exit (1); + } + + guestfs_set_error_handler (g, print_error, NULL); + + srcdir = getenv (\"srcdir\"); + if (!srcdir) srcdir = \".\"; + guestfs_set_path (g, srcdir); + + snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir); + fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); + if (fd == -1) { + perror (buf); + exit (1); + } + if (lseek (fd, %d, SEEK_SET) == -1) { + perror (\"lseek\"); + close (fd); + unlink (buf); + exit (1); + } + if (write (fd, &c, 1) == -1) { + perror (\"write\"); + close (fd); + unlink (buf); + exit (1); + } + if (close (fd) == -1) { + perror (buf); + unlink (buf); + exit (1); + } + if (guestfs_add_drive (g, buf) == -1) { + printf (\"guestfs_add_drive %%s FAILED\\n\", buf); + exit (1); + } + + snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir); + fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); + if (fd == -1) { + perror (buf); + exit (1); + } + if (lseek (fd, %d, SEEK_SET) == -1) { + perror (\"lseek\"); + close (fd); + unlink (buf); + exit (1); + } + if (write (fd, &c, 1) == -1) { + perror (\"write\"); + close (fd); + unlink (buf); + exit (1); + } + if (close (fd) == -1) { + perror (buf); + unlink (buf); + exit (1); + } + if (guestfs_add_drive (g, buf) == -1) { + printf (\"guestfs_add_drive %%s FAILED\\n\", buf); + exit (1); + } + + snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir); + fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); + if (fd == -1) { + perror (buf); + exit (1); + } + if (lseek (fd, %d, SEEK_SET) == -1) { + perror (\"lseek\"); + close (fd); + unlink (buf); + exit (1); + } + if (write (fd, &c, 1) == -1) { + perror (\"write\"); + close (fd); + unlink (buf); + exit (1); + } + if (close (fd) == -1) { + perror (buf); + unlink (buf); + exit (1); + } + if (guestfs_add_drive (g, buf) == -1) { + printf (\"guestfs_add_drive %%s FAILED\\n\", buf); + exit (1); + } + + if (guestfs_launch (g) == -1) { + printf (\"guestfs_launch FAILED\\n\"); + exit (1); + } + if (guestfs_wait_ready (g) == -1) { + printf (\"guestfs_wait_ready FAILED\\n\"); + exit (1); + } + +" (500 * 1024 * 1024) (50 * 1024 * 1024) (10 * 1024 * 1024); + + iteri ( + fun i test_name -> + pr " printf (\"%3d/%3d %s\\n\");\n" (i+1) nr_tests test_name; + pr " if (%s () == -1) {\n" test_name; + pr " printf (\"%s FAILED\\n\");\n" test_name; + pr " failed++;\n"; + pr " }\n"; + ) test_names; pr "\n"; + pr " guestfs_close (g);\n"; + pr " snprintf (buf, sizeof buf, \"%%s/test1.img\", srcdir);\n"; + pr " unlink (buf);\n"; + pr " snprintf (buf, sizeof buf, \"%%s/test2.img\", srcdir);\n"; + pr " unlink (buf);\n"; + pr " snprintf (buf, sizeof buf, \"%%s/test3.img\", srcdir);\n"; + pr " unlink (buf);\n"; + pr "\n"; + pr " if (failed > 0) {\n"; + pr " printf (\"***** %%d / %d tests FAILED *****\\n\", failed);\n" + nr_tests; + pr " exit (1);\n"; + pr " }\n"; + pr "\n"; - pr "int main (int argc, char *argv[])\n"; - pr "{\n"; pr " exit (0);\n"; pr "}\n" +and generate_one_test name i (init, test) = + let test_name = sprintf "test_%s_%d" name i in + + pr "static int %s (void)\n" test_name; + pr "{\n"; + + (match init with + | InitNone -> + pr " /* InitNone for %s (%d) */\n" name i; + List.iter (generate_test_command_call test_name) + [["umount_all"]; + ["lvm_remove_all"]] + | InitEmpty -> + pr " /* InitEmpty for %s (%d): create ext2 on /dev/sda1 */\n" name i; + List.iter (generate_test_command_call test_name) + [["umount_all"]; + ["lvm_remove_all"]; + ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + ["mkfs"; "ext2"; "/dev/sda1"]; + ["mount"; "/dev/sda1"; "/"]] + | InitEmptyLVM -> + pr " /* InitEmptyLVM for %s (%d): create ext2 on /dev/VG/LV */\n" + name i; + List.iter (generate_test_command_call test_name) + [["umount_all"]; + ["lvm_remove_all"]; + ["sfdisk"; "/dev/sda"; "0"; "0"; "0"; ","]; + ["pvcreate"; "/dev/sda1"]; + ["vgcreate"; "VG"; "/dev/sda1"]; + ["lvcreate"; "LV"; "VG"; "8"]; + ["mkfs"; "ext2"; "/dev/VG/LV"]; + ["mount"; "/dev/VG/LV"; "/"]] + ); + + let get_seq_last = function + | [] -> + failwithf "%s: you cannot use [] (empty list) when expecting a command" + test_name + | seq -> + let seq = List.rev seq in + List.rev (List.tl seq), List.hd seq + in + + (match test with + | TestRun seq -> + pr " /* TestRun for %s (%d) */\n" name i; + List.iter (generate_test_command_call test_name) seq + | TestOutput (seq, expected) -> + pr " /* TestOutput for %s (%d) */\n" name i; + let seq, last = get_seq_last seq in + let test () = + pr " if (strcmp (r, \"%s\") != 0) {\n" (c_quote expected); + pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r);\n" test_name (c_quote expected); + pr " return -1;\n"; + pr " }\n" + in + List.iter (generate_test_command_call test_name) seq; + generate_test_command_call ~test test_name last + | TestOutputList (seq, expected) -> + pr " /* TestOutputList for %s (%d) */\n" name i; + let seq, last = get_seq_last seq in + let test () = + iteri ( + fun i str -> + pr " if (!r[%d]) {\n" i; + pr " fprintf (stderr, \"%s: short list returned from command\\n\");\n" test_name; + pr " print_strings (r);\n"; + pr " return -1;\n"; + pr " }\n"; + pr " if (strcmp (r[%d], \"%s\") != 0) {\n" i (c_quote str); + pr " fprintf (stderr, \"%s: expected \\\"%s\\\" but got \\\"%%s\\\"\\n\", r[%d]);\n" test_name (c_quote str) i; + pr " return -1;\n"; + pr " }\n" + ) expected; + pr " if (r[%d] != NULL) {\n" (List.length expected); + pr " fprintf (stderr, \"%s: extra elements returned from command\\n\");\n" + test_name; + pr " print_strings (r);\n"; + pr " return -1;\n"; + pr " }\n" + in + List.iter (generate_test_command_call test_name) seq; + generate_test_command_call ~test test_name last + | TestOutputInt (seq, expected) -> + pr " /* TestOutputInt for %s (%d) */\n" name i; + let seq, last = get_seq_last seq in + let test () = + pr " if (r != %d) {\n" expected; + pr " fprintf (stderr, \"%s: expected %d but got %%d\\n\", r);\n" + test_name expected; + pr " return -1;\n"; + pr " }\n" + in + List.iter (generate_test_command_call test_name) seq; + generate_test_command_call ~test test_name last + | TestOutputTrue seq -> + pr " /* TestOutputTrue for %s (%d) */\n" name i; + let seq, last = get_seq_last seq in + let test () = + pr " if (!r) {\n"; + pr " fprintf (stderr, \"%s: expected true, got false\\n\");\n" + test_name; + pr " return -1;\n"; + pr " }\n" + in + List.iter (generate_test_command_call test_name) seq; + generate_test_command_call ~test test_name last + | TestOutputFalse seq -> + pr " /* TestOutputFalse for %s (%d) */\n" name i; + let seq, last = get_seq_last seq in + let test () = + pr " if (r) {\n"; + pr " fprintf (stderr, \"%s: expected false, got true\\n\");\n" + test_name; + pr " return -1;\n"; + pr " }\n" + in + List.iter (generate_test_command_call test_name) seq; + generate_test_command_call ~test test_name last + | TestOutputLength (seq, expected) -> + pr " /* TestOutputLength for %s (%d) */\n" name i; + let seq, last = get_seq_last seq in + let test () = + pr " int j;\n"; + pr " for (j = 0; j < %d; ++j)\n" expected; + pr " if (r[j] == NULL) {\n"; + pr " fprintf (stderr, \"%s: short list returned\\n\");\n" + test_name; + pr " print_strings (r);\n"; + pr " return -1;\n"; + pr " }\n"; + pr " if (r[j] != NULL) {\n"; + pr " fprintf (stderr, \"%s: long list returned\\n\");\n" + test_name; + pr " print_strings (r);\n"; + pr " return -1;\n"; + pr " }\n" + in + List.iter (generate_test_command_call test_name) seq; + generate_test_command_call ~test test_name last + | TestLastFail seq -> + pr " /* TestLastFail for %s (%d) */\n" name i; + let seq, last = get_seq_last seq in + List.iter (generate_test_command_call test_name) seq; + generate_test_command_call test_name ~expect_error:true last + ); + + pr " return 0;\n"; + pr "}\n"; + pr "\n"; + test_name + +(* Generate the code to run a command, leaving the result in 'r'. + * If you expect to get an error then you should set expect_error:true. + *) +and generate_test_command_call ?(expect_error = false) ?test test_name cmd = + match cmd with + | [] -> assert false + | name :: args -> + (* Look up the command to find out what args/ret it has. *) + let style = + try + let _, style, _, _, _, _, _ = + List.find (fun (n, _, _, _, _, _, _) -> n = name) all_functions in + style + with Not_found -> + failwithf "%s: in test, command %s was not found" test_name name in + + if List.length (snd style) <> List.length args then + failwithf "%s: in test, wrong number of args given to %s" + test_name name; + + pr " {\n"; + + List.iter ( + function + | String _, _ + | OptString _, _ + | Int _, _ + | Bool _, _ -> () + | StringList n, arg -> + pr " char *%s[] = {\n" n; + let strs = string_split " " arg in + List.iter ( + fun str -> pr " \"%s\",\n" (c_quote str) + ) strs; + pr " NULL\n"; + pr " };\n"; + ) (List.combine (snd style) args); + + let error_code = + match fst style with + | RErr | RInt _ | RBool _ -> pr " int r;\n"; "-1" + | RConstString _ -> pr " const char *r;\n"; "NULL" + | RString _ -> pr " char *r;\n"; "NULL" + | RStringList _ -> + pr " char **r;\n"; + pr " int i;\n"; + "NULL" + | RIntBool _ -> + pr " struct guestfs_int_bool *r;\n"; + "NULL" + | RPVList _ -> + pr " struct guestfs_lvm_pv_list *r;\n"; + "NULL" + | RVGList _ -> + pr " struct guestfs_lvm_vg_list *r;\n"; + "NULL" + | RLVList _ -> + pr " struct guestfs_lvm_lv_list *r;\n"; + "NULL" in + + pr " suppress_error = %d;\n" (if expect_error then 1 else 0); + pr " r = guestfs_%s (g" name; + + (* Generate the parameters. *) + List.iter ( + function + | String _, arg -> pr ", \"%s\"" (c_quote arg) + | OptString _, arg -> + if arg = "NULL" then pr ", NULL" else pr ", \"%s\"" (c_quote arg) + | StringList n, _ -> + pr ", %s" n + | Int _, arg -> + let i = + try int_of_string arg + with Failure "int_of_string" -> + failwithf "%s: expecting an int, but got '%s'" test_name arg in + pr ", %d" i + | Bool _, arg -> + let b = bool_of_string arg in pr ", %d" (if b then 1 else 0) + ) (List.combine (snd style) args); + + pr ");\n"; + if not expect_error then + pr " if (r == %s)\n" error_code + else + pr " if (r != %s)\n" error_code; + pr " return -1;\n"; + + (* Insert the test code. *) + (match test with + | None -> () + | Some f -> f () + ); + + (match fst style with + | RErr | RInt _ | RBool _ | RConstString _ -> () + | RString _ -> pr " free (r);\n" + | RStringList _ -> + pr " for (i = 0; r[i] != NULL; ++i)\n"; + pr " free (r[i]);\n"; + pr " free (r);\n" + | RIntBool _ -> + pr " guestfs_free_int_bool (r);\n" + | RPVList _ -> + pr " guestfs_free_lvm_pv_list (r);\n" + | RVGList _ -> + pr " guestfs_free_lvm_vg_list (r);\n" + | RLVList _ -> + pr " guestfs_free_lvm_lv_list (r);\n" + ); + + pr " }\n" + +and c_quote str = + let str = replace_str str "\r" "\\r" in + let str = replace_str str "\n" "\\n" in + let str = replace_str str "\t" "\\t" in + str + (* Generate a lot of different functions for guestfish. *) and generate_fish_cmds () = generate_header CStyle GPLv2; @@ -1893,11 +2552,19 @@ and generate_fish_cmds () = let warnings = if List.mem ProtocolLimitWarning flags then - "\n\nBecause of the message protocol, there is a transfer limit -of somewhere between 2MB and 4MB. To transfer large files you should use -FTP." + ("\n\n" ^ protocol_limit_warning) else "" in + (* For DangerWillRobinson commands, we should probably have + * guestfish prompt before allowing you to use them (especially + * in interactive mode). XXX + *) + let warnings = + warnings ^ + if List.mem DangerWillRobinson flags then + ("\n\n" ^ danger_will_robinson) + else "" in + let describe_alias = if name <> alias then sprintf "\n\nYou can use '%s' as an alias for this command." alias @@ -1977,8 +2644,9 @@ FTP." ); List.iter ( function - | String n -> pr " const char *%s;\n" n + | String n | OptString n -> pr " const char *%s;\n" n + | StringList n -> pr " char **%s;\n" n | Bool n -> pr " int %s;\n" n | Int n -> pr " int %s;\n" n ) (snd style); @@ -1998,6 +2666,8 @@ FTP." | OptString name -> pr " %s = strcmp (argv[%d], \"\") != 0 ? argv[%d] : NULL;\n" name i i + | StringList name -> + pr " %s = parse_string_list (argv[%d]);\n" name i | Bool name -> pr " %s = is_true (argv[%d]) ? 1 : 0;\n" name i | Int name -> @@ -2115,12 +2785,19 @@ and generate_fish_actions_pod () = function | String n -> pr " %s" n | OptString n -> pr " %s" n + | StringList n -> pr " %s,..." n | Bool _ -> pr " true|false" | Int n -> pr " %s" n ) (snd style); pr "\n"; pr "\n"; - pr "%s\n\n" longdesc + pr "%s\n\n" longdesc; + + if List.mem ProtocolLimitWarning flags then + pr "%s\n\n" protocol_limit_warning; + + if List.mem DangerWillRobinson flags then + pr "%s\n\n" danger_will_robinson ) all_functions_sorted (* Generate a C function prototype. *) @@ -2169,6 +2846,7 @@ and generate_prototype ?(extern = true) ?(static = false) ?(semicolon = true) function | String n -> next (); pr "const char *%s" n | OptString n -> next (); pr "const char *%s" n + | StringList n -> next (); pr "char * const* const %s" n | Bool n -> next (); pr "int %s" n | Int n -> next (); pr "int %s" n ) (snd style); @@ -2190,9 +2868,10 @@ and generate_call_args ?handle style = if !comma then pr ", "; comma := true; match arg with - | String n -> pr "%s" n - | OptString n -> pr "%s" n - | Bool n -> pr "%s" n + | String n + | OptString n + | StringList n + | Bool n | Int n -> pr "%s" n ) (snd style); pr ")" @@ -2339,18 +3018,23 @@ and generate_ocaml_c () = List.iter ( fun (name, style, _, _, _, _, _) -> + let params = + "gv" :: List.map (fun arg -> name_of_argt arg ^ "v") (snd style) in + pr "CAMLprim value\n"; - pr "ocaml_guestfs_%s (value gv" name; - List.iter ( - fun arg -> pr ", value %sv" (name_of_argt arg) - ) (snd style); + pr "ocaml_guestfs_%s (value %s" name (List.hd params); + List.iter (pr ", value %s") (List.tl params); pr ")\n"; pr "{\n"; - pr " CAMLparam%d (gv" (1 + (List.length (snd style))); - List.iter ( - fun arg -> pr ", %sv" (name_of_argt arg) - ) (snd style); - pr ");\n"; + + (match params with + | p1 :: p2 :: p3 :: p4 :: p5 :: rest -> + pr " CAMLparam5 (%s);\n" (String.concat ", " [p1; p2; p3; p4; p5]); + pr " CAMLxparam%d (%s);\n" + (List.length rest) (String.concat ", " rest) + | ps -> + pr " CAMLparam%d (%s);\n" (List.length ps) (String.concat ", " ps) + ); pr " CAMLlocal1 (rv);\n"; pr "\n"; @@ -2367,6 +3051,8 @@ and generate_ocaml_c () = pr " const char *%s =\n" n; pr " %sv != Val_int (0) ? String_val (Field (%sv, 0)) : NULL;\n" n n + | StringList n -> + pr " char **%s = ocaml_guestfs_strings_val (%sv);\n" n n | Bool n -> pr " int %s = Bool_val (%sv);\n" n n | Int n -> @@ -2402,6 +3088,14 @@ and generate_ocaml_c () = generate_call_args ~handle:"g" style; pr ";\n"; pr " caml_leave_blocking_section ();\n"; + + List.iter ( + function + | StringList n -> + pr " ocaml_guestfs_free_strings (%s);\n" n; + | String _ | OptString _ | Bool _ | Int _ -> () + ) (snd style); + pr " if (r == %s)\n" error_code; pr " ocaml_guestfs_raise_error (g, \"%s\");\n" name; pr "\n"; @@ -2436,7 +3130,18 @@ and generate_ocaml_c () = pr " CAMLreturn (rv);\n"; pr "}\n"; - pr "\n" + pr "\n"; + + if List.length params > 5 then ( + pr "CAMLprim value\n"; + pr "ocaml_guestfs_%s_byte (value *argv, int argn)\n" name; + pr "{\n"; + pr " return ocaml_guestfs_%s (argv[0]" name; + iteri (fun i _ -> pr ", argv[%d]" i) (List.tl params); + pr ");\n"; + pr "}\n"; + pr "\n" + ) ) all_functions and generate_ocaml_lvm_structure_decls () = @@ -2462,6 +3167,7 @@ and generate_ocaml_prototype ?(is_external = false) name style = function | String _ -> pr "string -> " | OptString _ -> pr "string option -> " + | StringList _ -> pr "string array -> " | Bool _ -> pr "bool -> " | Int _ -> pr "int -> " ) (snd style); @@ -2477,7 +3183,12 @@ and generate_ocaml_prototype ?(is_external = false) name style = | RVGList _ -> pr "lvm_vg array" | RLVList _ -> pr "lvm_lv array" ); - if is_external then pr " = \"ocaml_guestfs_%s\"" name; + if is_external then ( + pr " = "; + if List.length (snd style) + 1 > 5 then + pr "\"ocaml_guestfs_%s_byte\" " name; + pr "\"ocaml_guestfs_%s\"" name + ); pr "\n" (* Generate Perl xs code, a sort of crazy variation of C with macros. *) @@ -2539,6 +3250,35 @@ error_handler (guestfs_h *g, last_error = strdup (msg); } +/* http://www.perlmonks.org/?node_id=680842 */ +static char ** +XS_unpack_charPtrPtr (SV *arg) { + char **ret; + AV *av; + I32 i; + + if (!arg || !SvOK (arg) || !SvROK (arg) || SvTYPE (SvRV (arg)) != SVt_PVAV) { + croak (\"array reference expected\"); + } + + av = (AV *)SvRV (arg); + ret = (char **)malloc (av_len (av) + 1 + 1); + + for (i = 0; i <= av_len (av); i++) { + SV **elem = av_fetch (av, i, 0); + + if (!elem || !*elem) { + croak (\"missing element in list\"); + } + + ret[i] = SvPV_nolen (*elem); + } + + ret[i + 1] = NULL; + + return ret; +} + MODULE = Sys::Guestfs PACKAGE = Sys::Guestfs guestfs_h * @@ -2581,17 +3321,32 @@ DESTROY (g) function | String n -> pr " char *%s;\n" n | OptString n -> pr " char *%s;\n" n + | StringList n -> pr " char **%s;\n" n | Bool n -> pr " int %s;\n" n | Int n -> pr " int %s;\n" n ) (snd style); + + let do_cleanups () = + List.iter ( + function + | String _ + | OptString _ + | Bool _ + | Int _ -> () + | StringList n -> pr " free (%s);\n" n + ) (snd style) + in + (* Code. *) (match fst style with | RErr -> pr " PPCODE:\n"; pr " if (guestfs_%s " name; generate_call_args ~handle:"g" style; - pr " == -1)\n"; - pr " croak (\"%s: %%s\", last_error);\n" name + pr " == -1) {\n"; + do_cleanups (); + pr " croak (\"%s: %%s\", last_error);\n" name; + pr " }\n" | RInt n | RBool n -> pr "PREINIT:\n"; @@ -2600,8 +3355,10 @@ DESTROY (g) pr " %s = guestfs_%s " n name; generate_call_args ~handle:"g" style; pr ";\n"; - pr " if (%s == -1)\n" n; + pr " if (%s == -1) {\n" n; + do_cleanups (); pr " croak (\"%s: %%s\", last_error);\n" name; + pr " }\n"; pr " RETVAL = newSViv (%s);\n" n; pr " OUTPUT:\n"; pr " RETVAL\n" @@ -2612,8 +3369,10 @@ DESTROY (g) pr " %s = guestfs_%s " n name; generate_call_args ~handle:"g" style; pr ";\n"; - pr " if (%s == NULL)\n" n; + pr " if (%s == NULL) {\n" n; + do_cleanups (); pr " croak (\"%s: %%s\", last_error);\n" name; + pr " }\n"; pr " RETVAL = newSVpv (%s, 0);\n" n; pr " OUTPUT:\n"; pr " RETVAL\n" @@ -2624,8 +3383,10 @@ DESTROY (g) pr " %s = guestfs_%s " n name; generate_call_args ~handle:"g" style; pr ";\n"; - pr " if (%s == NULL)\n" n; + pr " if (%s == NULL) {\n" n; + do_cleanups (); pr " croak (\"%s: %%s\", last_error);\n" name; + pr " }\n"; pr " RETVAL = newSVpv (%s, 0);\n" n; pr " free (%s);\n" n; pr " OUTPUT:\n"; @@ -2638,8 +3399,10 @@ DESTROY (g) pr " %s = guestfs_%s " n name; generate_call_args ~handle:"g" style; pr ";\n"; - pr " if (%s == NULL)\n" n; + pr " if (%s == NULL) {\n" n; + do_cleanups (); pr " croak (\"%s: %%s\", last_error);\n" name; + pr " }\n"; pr " for (n = 0; %s[n] != NULL; ++n) /**/;\n" n; pr " EXTEND (SP, n);\n"; pr " for (i = 0; i < n; ++i) {\n"; @@ -2654,8 +3417,10 @@ DESTROY (g) pr " r = guestfs_%s " name; generate_call_args ~handle:"g" style; pr ";\n"; - pr " if (r == NULL)\n"; + pr " if (r == NULL) {\n"; + do_cleanups (); pr " croak (\"%s: %%s\", last_error);\n" name; + pr " }\n"; pr " EXTEND (SP, 2);\n"; pr " PUSHs (sv_2mortal (newSViv (r->i)));\n"; pr " PUSHs (sv_2mortal (newSViv (r->b)));\n"; @@ -2667,6 +3432,9 @@ DESTROY (g) | RLVList n -> generate_perl_lvm_code "lv" lv_cols name style n; ); + + do_cleanups (); + pr "\n" ) all_functions @@ -2797,9 +3565,9 @@ sub new { pr "\n\n"; pr "%s\n\n" longdesc; if List.mem ProtocolLimitWarning flags then - pr "Because of the message protocol, there is a transfer limit -of somewhere between 2MB and 4MB. To transfer large files you should use -FTP.\n\n"; + pr "%s\n\n" protocol_limit_warning; + if List.mem DangerWillRobinson flags then + pr "%s\n\n" danger_will_robinson ) all_functions_sorted; (* End of file. *) @@ -2844,7 +3612,11 @@ and generate_perl_prototype name style = fun arg -> if !comma then pr ", "; comma := true; - pr "%s" (name_of_argt arg) + match arg with + | String n | OptString n | Bool n | Int n -> + pr "$%s" n + | StringList n -> + pr "\\@%s" n ) (snd style); pr ");" diff --git a/src/guestfs-actions.c b/src/guestfs-actions.c index 25892cd0..669ca767 100644 --- a/src/guestfs-actions.c +++ b/src/guestfs-actions.c @@ -2540,3 +2540,934 @@ int guestfs_chown (guestfs_h *g, return 0; } +struct exists_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; + struct guestfs_exists_ret ret; +}; + +static void exists_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct exists_rv *rv = (struct exists_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_exists: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_exists: failed to parse reply error"); + return; + } + goto done; + } + if (!xdr_guestfs_exists_ret (xdr, &rv->ret)) { + error (g, "guestfs_exists: failed to parse reply"); + return; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_exists (guestfs_h *g, + const char *path) +{ + struct guestfs_exists_args args; + struct exists_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_exists called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.path = (char *) path; + serial = dispatch (g, GUESTFS_PROC_EXISTS, + (xdrproc_t) xdr_guestfs_exists_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = exists_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_exists failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_EXISTS, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return rv.ret.existsflag; +} + +struct is_file_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; + struct guestfs_is_file_ret ret; +}; + +static void is_file_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct is_file_rv *rv = (struct is_file_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_is_file: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_is_file: failed to parse reply error"); + return; + } + goto done; + } + if (!xdr_guestfs_is_file_ret (xdr, &rv->ret)) { + error (g, "guestfs_is_file: failed to parse reply"); + return; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_is_file (guestfs_h *g, + const char *path) +{ + struct guestfs_is_file_args args; + struct is_file_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_is_file called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.path = (char *) path; + serial = dispatch (g, GUESTFS_PROC_IS_FILE, + (xdrproc_t) xdr_guestfs_is_file_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = is_file_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_is_file failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_IS_FILE, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return rv.ret.fileflag; +} + +struct is_dir_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; + struct guestfs_is_dir_ret ret; +}; + +static void is_dir_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct is_dir_rv *rv = (struct is_dir_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_is_dir: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_is_dir: failed to parse reply error"); + return; + } + goto done; + } + if (!xdr_guestfs_is_dir_ret (xdr, &rv->ret)) { + error (g, "guestfs_is_dir: failed to parse reply"); + return; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_is_dir (guestfs_h *g, + const char *path) +{ + struct guestfs_is_dir_args args; + struct is_dir_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_is_dir called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.path = (char *) path; + serial = dispatch (g, GUESTFS_PROC_IS_DIR, + (xdrproc_t) xdr_guestfs_is_dir_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = is_dir_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_is_dir failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_IS_DIR, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return rv.ret.dirflag; +} + +struct pvcreate_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void pvcreate_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct pvcreate_rv *rv = (struct pvcreate_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_pvcreate: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_pvcreate: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_pvcreate (guestfs_h *g, + const char *device) +{ + struct guestfs_pvcreate_args args; + struct pvcreate_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_pvcreate called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.device = (char *) device; + serial = dispatch (g, GUESTFS_PROC_PVCREATE, + (xdrproc_t) xdr_guestfs_pvcreate_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = pvcreate_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_pvcreate failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_PVCREATE, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + +struct vgcreate_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void vgcreate_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct vgcreate_rv *rv = (struct vgcreate_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_vgcreate: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_vgcreate: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_vgcreate (guestfs_h *g, + const char *volgroup, + char * const* const physvols) +{ + struct guestfs_vgcreate_args args; + struct vgcreate_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_vgcreate called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.volgroup = (char *) volgroup; + args.physvols.physvols_val = (char **) physvols; + for (args.physvols.physvols_len = 0; physvols[args.physvols.physvols_len]; args.physvols.physvols_len++) ; + serial = dispatch (g, GUESTFS_PROC_VGCREATE, + (xdrproc_t) xdr_guestfs_vgcreate_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = vgcreate_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_vgcreate failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_VGCREATE, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + +struct lvcreate_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void lvcreate_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct lvcreate_rv *rv = (struct lvcreate_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_lvcreate: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_lvcreate: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_lvcreate (guestfs_h *g, + const char *logvol, + const char *volgroup, + int mbytes) +{ + struct guestfs_lvcreate_args args; + struct lvcreate_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_lvcreate called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.logvol = (char *) logvol; + args.volgroup = (char *) volgroup; + args.mbytes = mbytes; + serial = dispatch (g, GUESTFS_PROC_LVCREATE, + (xdrproc_t) xdr_guestfs_lvcreate_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = lvcreate_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_lvcreate failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LVCREATE, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + +struct mkfs_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void mkfs_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct mkfs_rv *rv = (struct mkfs_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_mkfs: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_mkfs: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_mkfs (guestfs_h *g, + const char *fstype, + const char *device) +{ + struct guestfs_mkfs_args args; + struct mkfs_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_mkfs called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.fstype = (char *) fstype; + args.device = (char *) device; + serial = dispatch (g, GUESTFS_PROC_MKFS, + (xdrproc_t) xdr_guestfs_mkfs_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = mkfs_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_mkfs failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_MKFS, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + +struct sfdisk_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void sfdisk_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct sfdisk_rv *rv = (struct sfdisk_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_sfdisk: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_sfdisk: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_sfdisk (guestfs_h *g, + const char *device, + int cyls, + int heads, + int sectors, + char * const* const lines) +{ + struct guestfs_sfdisk_args args; + struct sfdisk_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_sfdisk called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.device = (char *) device; + args.cyls = cyls; + args.heads = heads; + args.sectors = sectors; + args.lines.lines_val = (char **) lines; + for (args.lines.lines_len = 0; lines[args.lines.lines_len]; args.lines.lines_len++) ; + serial = dispatch (g, GUESTFS_PROC_SFDISK, + (xdrproc_t) xdr_guestfs_sfdisk_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = sfdisk_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_sfdisk failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_SFDISK, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + +struct write_file_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void write_file_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct write_file_rv *rv = (struct write_file_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_write_file: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_write_file: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_write_file (guestfs_h *g, + const char *path, + const char *content, + int size) +{ + struct guestfs_write_file_args args; + struct write_file_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_write_file called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.path = (char *) path; + args.content = (char *) content; + args.size = size; + serial = dispatch (g, GUESTFS_PROC_WRITE_FILE, + (xdrproc_t) xdr_guestfs_write_file_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = write_file_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_write_file failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_WRITE_FILE, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + +struct umount_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void umount_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct umount_rv *rv = (struct umount_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_umount: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_umount: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_umount (guestfs_h *g, + const char *pathordevice) +{ + struct guestfs_umount_args args; + struct umount_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_umount called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + args.pathordevice = (char *) pathordevice; + serial = dispatch (g, GUESTFS_PROC_UMOUNT, + (xdrproc_t) xdr_guestfs_umount_args, (char *) &args); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = umount_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_umount failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_UMOUNT, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + +struct mounts_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; + struct guestfs_mounts_ret ret; +}; + +static void mounts_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct mounts_rv *rv = (struct mounts_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_mounts: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_mounts: failed to parse reply error"); + return; + } + goto done; + } + if (!xdr_guestfs_mounts_ret (xdr, &rv->ret)) { + error (g, "guestfs_mounts: failed to parse reply"); + return; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +char **guestfs_mounts (guestfs_h *g) +{ + struct mounts_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_mounts called from the wrong state, %d != READY", + g->state); + return NULL; + } + + memset (&rv, 0, sizeof rv); + + serial = dispatch (g, GUESTFS_PROC_MOUNTS, NULL, NULL); + if (serial == -1) + return NULL; + + rv.cb_done = 0; + g->reply_cb_internal = mounts_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_mounts failed, see earlier error messages"); + return NULL; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_MOUNTS, serial) == -1) + return NULL; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return NULL; + } + + /* caller will free this, but we need to add a NULL entry */ + rv.ret.devices.devices_val = safe_realloc (g, rv.ret.devices.devices_val, + sizeof (char *) * (rv.ret.devices.devices_len + 1)); + rv.ret.devices.devices_val[rv.ret.devices.devices_len] = NULL; + return rv.ret.devices.devices_val; +} + +struct umount_all_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void umount_all_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct umount_all_rv *rv = (struct umount_all_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_umount_all: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_umount_all: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_umount_all (guestfs_h *g) +{ + struct umount_all_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_umount_all called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + serial = dispatch (g, GUESTFS_PROC_UMOUNT_ALL, NULL, NULL); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = umount_all_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_umount_all failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_UMOUNT_ALL, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + +struct lvm_remove_all_rv { + int cb_done; /* flag to indicate callback was called */ + struct guestfs_message_header hdr; + struct guestfs_message_error err; +}; + +static void lvm_remove_all_cb (guestfs_h *g, void *data, XDR *xdr) +{ + struct lvm_remove_all_rv *rv = (struct lvm_remove_all_rv *) data; + + if (!xdr_guestfs_message_header (xdr, &rv->hdr)) { + error (g, "guestfs_lvm_remove_all: failed to parse reply header"); + return; + } + if (rv->hdr.status == GUESTFS_STATUS_ERROR) { + if (!xdr_guestfs_message_error (xdr, &rv->err)) { + error (g, "guestfs_lvm_remove_all: failed to parse reply error"); + return; + } + goto done; + } + done: + rv->cb_done = 1; + main_loop.main_loop_quit (g); +} + +int guestfs_lvm_remove_all (guestfs_h *g) +{ + struct lvm_remove_all_rv rv; + int serial; + + if (g->state != READY) { + error (g, "guestfs_lvm_remove_all called from the wrong state, %d != READY", + g->state); + return -1; + } + + memset (&rv, 0, sizeof rv); + + serial = dispatch (g, GUESTFS_PROC_LVM_REMOVE_ALL, NULL, NULL); + if (serial == -1) + return -1; + + rv.cb_done = 0; + g->reply_cb_internal = lvm_remove_all_cb; + g->reply_cb_internal_data = &rv; + main_loop.main_loop_run (g); + g->reply_cb_internal = NULL; + g->reply_cb_internal_data = NULL; + if (!rv.cb_done) { + error (g, "guestfs_lvm_remove_all failed, see earlier error messages"); + return -1; + } + + if (check_reply_header (g, &rv.hdr, GUESTFS_PROC_LVM_REMOVE_ALL, serial) == -1) + return -1; + + if (rv.hdr.status == GUESTFS_STATUS_ERROR) { + error (g, "%s", rv.err.error); + return -1; + } + + return 0; +} + diff --git a/src/guestfs-actions.h b/src/guestfs-actions.h index 06f1485b..d40ef150 100644 --- a/src/guestfs-actions.h +++ b/src/guestfs-actions.h @@ -66,3 +66,16 @@ extern int guestfs_mkdir (guestfs_h *handle, const char *path); extern int guestfs_mkdir_p (guestfs_h *handle, const char *path); extern int guestfs_chmod (guestfs_h *handle, int mode, const char *path); extern int guestfs_chown (guestfs_h *handle, int owner, int group, const char *path); +extern int guestfs_exists (guestfs_h *handle, const char *path); +extern int guestfs_is_file (guestfs_h *handle, const char *path); +extern int guestfs_is_dir (guestfs_h *handle, const char *path); +extern int guestfs_pvcreate (guestfs_h *handle, const char *device); +extern int guestfs_vgcreate (guestfs_h *handle, const char *volgroup, char * const* const physvols); +extern int guestfs_lvcreate (guestfs_h *handle, const char *logvol, const char *volgroup, int mbytes); +extern int guestfs_mkfs (guestfs_h *handle, const char *fstype, const char *device); +extern int guestfs_sfdisk (guestfs_h *handle, const char *device, int cyls, int heads, int sectors, char * const* const lines); +extern int guestfs_write_file (guestfs_h *handle, const char *path, const char *content, int size); +extern int guestfs_umount (guestfs_h *handle, const char *pathordevice); +extern char **guestfs_mounts (guestfs_h *handle); +extern int guestfs_umount_all (guestfs_h *handle); +extern int guestfs_lvm_remove_all (guestfs_h *handle); diff --git a/src/guestfs_protocol.c b/src/guestfs_protocol.c index 781c2daf..8e868126 100644 --- a/src/guestfs_protocol.c +++ b/src/guestfs_protocol.c @@ -619,6 +619,214 @@ xdr_guestfs_chown_args (XDR *xdrs, guestfs_chown_args *objp) } bool_t +xdr_guestfs_exists_args (XDR *xdrs, guestfs_exists_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_exists_ret (XDR *xdrs, guestfs_exists_ret *objp) +{ + register int32_t *buf; + + if (!xdr_bool (xdrs, &objp->existsflag)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_is_file_args (XDR *xdrs, guestfs_is_file_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_is_file_ret (XDR *xdrs, guestfs_is_file_ret *objp) +{ + register int32_t *buf; + + if (!xdr_bool (xdrs, &objp->fileflag)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_is_dir_args (XDR *xdrs, guestfs_is_dir_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_is_dir_ret (XDR *xdrs, guestfs_is_dir_ret *objp) +{ + register int32_t *buf; + + if (!xdr_bool (xdrs, &objp->dirflag)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_pvcreate_args (XDR *xdrs, guestfs_pvcreate_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_vgcreate_args (XDR *xdrs, guestfs_vgcreate_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->volgroup, ~0)) + return FALSE; + if (!xdr_array (xdrs, (char **)&objp->physvols.physvols_val, (u_int *) &objp->physvols.physvols_len, ~0, + sizeof (str), (xdrproc_t) xdr_str)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_lvcreate_args (XDR *xdrs, guestfs_lvcreate_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->logvol, ~0)) + return FALSE; + if (!xdr_string (xdrs, &objp->volgroup, ~0)) + return FALSE; + if (!xdr_int (xdrs, &objp->mbytes)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_mkfs_args (XDR *xdrs, guestfs_mkfs_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->fstype, ~0)) + return FALSE; + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_sfdisk_args (XDR *xdrs, guestfs_sfdisk_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, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + 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->cyls); + IXDR_PUT_LONG(buf, objp->heads); + IXDR_PUT_LONG(buf, objp->sectors); + } + if (!xdr_array (xdrs, (char **)&objp->lines.lines_val, (u_int *) &objp->lines.lines_len, ~0, + sizeof (str), (xdrproc_t) xdr_str)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + if (!xdr_string (xdrs, &objp->device, ~0)) + return FALSE; + buf = XDR_INLINE (xdrs, 3 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + 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->cyls = IXDR_GET_LONG(buf); + objp->heads = IXDR_GET_LONG(buf); + objp->sectors = IXDR_GET_LONG(buf); + } + if (!xdr_array (xdrs, (char **)&objp->lines.lines_val, (u_int *) &objp->lines.lines_len, ~0, + sizeof (str), (xdrproc_t) xdr_str)) + return FALSE; + return TRUE; + } + + if (!xdr_string (xdrs, &objp->device, ~0)) + 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_array (xdrs, (char **)&objp->lines.lines_val, (u_int *) &objp->lines.lines_len, ~0, + sizeof (str), (xdrproc_t) xdr_str)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_write_file_args (XDR *xdrs, guestfs_write_file_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->path, ~0)) + return FALSE; + if (!xdr_string (xdrs, &objp->content, ~0)) + return FALSE; + if (!xdr_int (xdrs, &objp->size)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_umount_args (XDR *xdrs, guestfs_umount_args *objp) +{ + register int32_t *buf; + + if (!xdr_string (xdrs, &objp->pathordevice, ~0)) + return FALSE; + return TRUE; +} + +bool_t +xdr_guestfs_mounts_ret (XDR *xdrs, guestfs_mounts_ret *objp) +{ + register int32_t *buf; + + if (!xdr_array (xdrs, (char **)&objp->devices.devices_val, (u_int *) &objp->devices.devices_len, ~0, + sizeof (str), (xdrproc_t) xdr_str)) + return FALSE; + return TRUE; +} + +bool_t xdr_guestfs_procedure (XDR *xdrs, guestfs_procedure *objp) { register int32_t *buf; diff --git a/src/guestfs_protocol.h b/src/guestfs_protocol.h index 508bc4e3..fedd0074 100644 --- a/src/guestfs_protocol.h +++ b/src/guestfs_protocol.h @@ -337,6 +337,95 @@ struct guestfs_chown_args { }; typedef struct guestfs_chown_args guestfs_chown_args; +struct guestfs_exists_args { + char *path; +}; +typedef struct guestfs_exists_args guestfs_exists_args; + +struct guestfs_exists_ret { + bool_t existsflag; +}; +typedef struct guestfs_exists_ret guestfs_exists_ret; + +struct guestfs_is_file_args { + char *path; +}; +typedef struct guestfs_is_file_args guestfs_is_file_args; + +struct guestfs_is_file_ret { + bool_t fileflag; +}; +typedef struct guestfs_is_file_ret guestfs_is_file_ret; + +struct guestfs_is_dir_args { + char *path; +}; +typedef struct guestfs_is_dir_args guestfs_is_dir_args; + +struct guestfs_is_dir_ret { + bool_t dirflag; +}; +typedef struct guestfs_is_dir_ret guestfs_is_dir_ret; + +struct guestfs_pvcreate_args { + char *device; +}; +typedef struct guestfs_pvcreate_args guestfs_pvcreate_args; + +struct guestfs_vgcreate_args { + char *volgroup; + struct { + u_int physvols_len; + str *physvols_val; + } physvols; +}; +typedef struct guestfs_vgcreate_args guestfs_vgcreate_args; + +struct guestfs_lvcreate_args { + char *logvol; + char *volgroup; + int mbytes; +}; +typedef struct guestfs_lvcreate_args guestfs_lvcreate_args; + +struct guestfs_mkfs_args { + char *fstype; + char *device; +}; +typedef struct guestfs_mkfs_args guestfs_mkfs_args; + +struct guestfs_sfdisk_args { + char *device; + int cyls; + int heads; + int sectors; + struct { + u_int lines_len; + str *lines_val; + } lines; +}; +typedef struct guestfs_sfdisk_args guestfs_sfdisk_args; + +struct guestfs_write_file_args { + char *path; + char *content; + int size; +}; +typedef struct guestfs_write_file_args guestfs_write_file_args; + +struct guestfs_umount_args { + char *pathordevice; +}; +typedef struct guestfs_umount_args guestfs_umount_args; + +struct guestfs_mounts_ret { + struct { + u_int devices_len; + str *devices_val; + } devices; +}; +typedef struct guestfs_mounts_ret guestfs_mounts_ret; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -373,7 +462,20 @@ enum guestfs_procedure { GUESTFS_PROC_MKDIR_P = 33, GUESTFS_PROC_CHMOD = 34, GUESTFS_PROC_CHOWN = 35, - GUESTFS_PROC_dummy = 35 + 1, + GUESTFS_PROC_EXISTS = 36, + GUESTFS_PROC_IS_FILE = 37, + GUESTFS_PROC_IS_DIR = 38, + GUESTFS_PROC_PVCREATE = 39, + GUESTFS_PROC_VGCREATE = 40, + GUESTFS_PROC_LVCREATE = 41, + GUESTFS_PROC_MKFS = 42, + GUESTFS_PROC_SFDISK = 43, + GUESTFS_PROC_WRITE_FILE = 44, + GUESTFS_PROC_UMOUNT = 45, + GUESTFS_PROC_MOUNTS = 46, + GUESTFS_PROC_UMOUNT_ALL = 47, + GUESTFS_PROC_LVM_REMOVE_ALL = 48, + GUESTFS_PROC_dummy = 48 + 1, }; typedef enum guestfs_procedure guestfs_procedure; #define GUESTFS_MESSAGE_MAX 4194304 @@ -459,6 +561,20 @@ extern bool_t xdr_guestfs_mkdir_args (XDR *, guestfs_mkdir_args*); extern bool_t xdr_guestfs_mkdir_p_args (XDR *, guestfs_mkdir_p_args*); extern bool_t xdr_guestfs_chmod_args (XDR *, guestfs_chmod_args*); extern bool_t xdr_guestfs_chown_args (XDR *, guestfs_chown_args*); +extern bool_t xdr_guestfs_exists_args (XDR *, guestfs_exists_args*); +extern bool_t xdr_guestfs_exists_ret (XDR *, guestfs_exists_ret*); +extern bool_t xdr_guestfs_is_file_args (XDR *, guestfs_is_file_args*); +extern bool_t xdr_guestfs_is_file_ret (XDR *, guestfs_is_file_ret*); +extern bool_t xdr_guestfs_is_dir_args (XDR *, guestfs_is_dir_args*); +extern bool_t xdr_guestfs_is_dir_ret (XDR *, guestfs_is_dir_ret*); +extern bool_t xdr_guestfs_pvcreate_args (XDR *, guestfs_pvcreate_args*); +extern bool_t xdr_guestfs_vgcreate_args (XDR *, guestfs_vgcreate_args*); +extern bool_t xdr_guestfs_lvcreate_args (XDR *, guestfs_lvcreate_args*); +extern bool_t xdr_guestfs_mkfs_args (XDR *, guestfs_mkfs_args*); +extern bool_t xdr_guestfs_sfdisk_args (XDR *, guestfs_sfdisk_args*); +extern bool_t xdr_guestfs_write_file_args (XDR *, guestfs_write_file_args*); +extern bool_t xdr_guestfs_umount_args (XDR *, guestfs_umount_args*); +extern bool_t xdr_guestfs_mounts_ret (XDR *, guestfs_mounts_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*); @@ -514,6 +630,20 @@ extern bool_t xdr_guestfs_mkdir_args (); extern bool_t xdr_guestfs_mkdir_p_args (); extern bool_t xdr_guestfs_chmod_args (); extern bool_t xdr_guestfs_chown_args (); +extern bool_t xdr_guestfs_exists_args (); +extern bool_t xdr_guestfs_exists_ret (); +extern bool_t xdr_guestfs_is_file_args (); +extern bool_t xdr_guestfs_is_file_ret (); +extern bool_t xdr_guestfs_is_dir_args (); +extern bool_t xdr_guestfs_is_dir_ret (); +extern bool_t xdr_guestfs_pvcreate_args (); +extern bool_t xdr_guestfs_vgcreate_args (); +extern bool_t xdr_guestfs_lvcreate_args (); +extern bool_t xdr_guestfs_mkfs_args (); +extern bool_t xdr_guestfs_sfdisk_args (); +extern bool_t xdr_guestfs_write_file_args (); +extern bool_t xdr_guestfs_umount_args (); +extern bool_t xdr_guestfs_mounts_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 41116b53..c547d0b3 100644 --- a/src/guestfs_protocol.x +++ b/src/guestfs_protocol.x @@ -262,6 +262,72 @@ struct guestfs_chown_args { string path<>; }; +struct guestfs_exists_args { + string path<>; +}; + +struct guestfs_exists_ret { + bool existsflag; +}; + +struct guestfs_is_file_args { + string path<>; +}; + +struct guestfs_is_file_ret { + bool fileflag; +}; + +struct guestfs_is_dir_args { + string path<>; +}; + +struct guestfs_is_dir_ret { + bool dirflag; +}; + +struct guestfs_pvcreate_args { + string device<>; +}; + +struct guestfs_vgcreate_args { + string volgroup<>; + str physvols<>; +}; + +struct guestfs_lvcreate_args { + string logvol<>; + string volgroup<>; + int mbytes; +}; + +struct guestfs_mkfs_args { + string fstype<>; + string device<>; +}; + +struct guestfs_sfdisk_args { + string device<>; + int cyls; + int heads; + int sectors; + str lines<>; +}; + +struct guestfs_write_file_args { + string path<>; + string content<>; + int size; +}; + +struct guestfs_umount_args { + string pathordevice<>; +}; + +struct guestfs_mounts_ret { + str devices<>; +}; + enum guestfs_procedure { GUESTFS_PROC_MOUNT = 1, GUESTFS_PROC_SYNC = 2, @@ -298,6 +364,19 @@ enum guestfs_procedure { GUESTFS_PROC_MKDIR_P = 33, GUESTFS_PROC_CHMOD = 34, GUESTFS_PROC_CHOWN = 35, + GUESTFS_PROC_EXISTS = 36, + GUESTFS_PROC_IS_FILE = 37, + GUESTFS_PROC_IS_DIR = 38, + GUESTFS_PROC_PVCREATE = 39, + GUESTFS_PROC_VGCREATE = 40, + GUESTFS_PROC_LVCREATE = 41, + GUESTFS_PROC_MKFS = 42, + GUESTFS_PROC_SFDISK = 43, + GUESTFS_PROC_WRITE_FILE = 44, + GUESTFS_PROC_UMOUNT = 45, + GUESTFS_PROC_MOUNTS = 46, + GUESTFS_PROC_UMOUNT_ALL = 47, + GUESTFS_PROC_LVM_REMOVE_ALL = 48, GUESTFS_PROC_dummy }; @@ -22,10 +22,3943 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <unistd.h> +#include <sys/types.h> +#include <fcntl.h> #include "guestfs.h" +static guestfs_h *g; +static int suppress_error = 0; + +static void print_error (guestfs_h *g, void *data, const char *msg) +{ + if (!suppress_error) + fprintf (stderr, "%s\n", msg); +} + +static void print_strings (char * const * const argv) +{ + int argc; + + for (argc = 0; argv[argc] != NULL; ++argc) + printf ("\t%s\n", argv[argc]); +} + +static int test_mount_0 (void) +{ + /* InitNone for mount (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutput for mount (0) */ + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_write_file (g, "/new", "new file contents", 0); + if (r == -1) + return -1; + } + { + char *r; + suppress_error = 0; + r = guestfs_cat (g, "/new"); + if (r == NULL) + return -1; + if (strcmp (r, "new file contents") != 0) { + fprintf (stderr, "test_mount_0: expected \"new file contents\" but got \"%s\"\n", r); + return -1; + } + free (r); + } + return 0; +} + +static int test_sync_0 (void) +{ + /* InitNone for sync (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestRun for sync (0) */ + { + int r; + suppress_error = 0; + r = guestfs_sync (g); + if (r == -1) + return -1; + } + return 0; +} + +static int test_touch_0 (void) +{ + /* InitEmpty for touch (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputTrue for touch (0) */ + { + int r; + suppress_error = 0; + r = guestfs_touch (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_exists (g, "/new"); + if (r == -1) + return -1; + if (!r) { + fprintf (stderr, "test_touch_0: expected true, got false\n"); + return -1; + } + } + return 0; +} + +static int test_cat_0 (void) +{ + /* InitEmpty for cat (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutput for cat (0) */ + { + int r; + suppress_error = 0; + r = guestfs_write_file (g, "/new", "new file contents", 0); + if (r == -1) + return -1; + } + { + char *r; + suppress_error = 0; + r = guestfs_cat (g, "/new"); + if (r == NULL) + return -1; + if (strcmp (r, "new file contents") != 0) { + fprintf (stderr, "test_cat_0: expected \"new file contents\" but got \"%s\"\n", r); + return -1; + } + free (r); + } + return 0; +} + +static int test_ls_0 (void) +{ + /* InitEmpty for ls (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputList for ls (0) */ + { + int r; + suppress_error = 0; + r = guestfs_touch (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_touch (g, "/newer"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_touch (g, "/newest"); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_ls (g, "/"); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_ls_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "lost+found") != 0) { + fprintf (stderr, "test_ls_0: expected \"lost+found\" but got \"%s\"\n", r[0]); + return -1; + } + if (!r[1]) { + fprintf (stderr, "test_ls_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[1], "new") != 0) { + fprintf (stderr, "test_ls_0: expected \"new\" but got \"%s\"\n", r[1]); + return -1; + } + if (!r[2]) { + fprintf (stderr, "test_ls_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[2], "newer") != 0) { + fprintf (stderr, "test_ls_0: expected \"newer\" but got \"%s\"\n", r[2]); + return -1; + } + if (!r[3]) { + fprintf (stderr, "test_ls_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[3], "newest") != 0) { + fprintf (stderr, "test_ls_0: expected \"newest\" but got \"%s\"\n", r[3]); + return -1; + } + if (r[4] != NULL) { + fprintf (stderr, "test_ls_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_list_devices_0 (void) +{ + /* InitNone for list_devices (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutputList for list_devices (0) */ + { + char **r; + int i; + suppress_error = 0; + r = guestfs_list_devices (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_list_devices_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "/dev/sda") != 0) { + fprintf (stderr, "test_list_devices_0: expected \"/dev/sda\" but got \"%s\"\n", r[0]); + return -1; + } + if (!r[1]) { + fprintf (stderr, "test_list_devices_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[1], "/dev/sdb") != 0) { + fprintf (stderr, "test_list_devices_0: expected \"/dev/sdb\" but got \"%s\"\n", r[1]); + return -1; + } + if (!r[2]) { + fprintf (stderr, "test_list_devices_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[2], "/dev/sdc") != 0) { + fprintf (stderr, "test_list_devices_0: expected \"/dev/sdc\" but got \"%s\"\n", r[2]); + return -1; + } + if (r[3] != NULL) { + fprintf (stderr, "test_list_devices_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_list_partitions_0 (void) +{ + /* InitEmpty for list_partitions (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputList for list_partitions (0) */ + { + char **r; + int i; + suppress_error = 0; + r = guestfs_list_partitions (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_list_partitions_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "/dev/sda1") != 0) { + fprintf (stderr, "test_list_partitions_0: expected \"/dev/sda1\" but got \"%s\"\n", r[0]); + return -1; + } + if (r[1] != NULL) { + fprintf (stderr, "test_list_partitions_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_list_partitions_1 (void) +{ + /* InitNone for list_partitions (1) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutputList for list_partitions (1) */ + { + char *lines[] = { + ",10", + ",20", + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_list_partitions (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_list_partitions_1: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "/dev/sda1") != 0) { + fprintf (stderr, "test_list_partitions_1: expected \"/dev/sda1\" but got \"%s\"\n", r[0]); + return -1; + } + if (!r[1]) { + fprintf (stderr, "test_list_partitions_1: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[1], "/dev/sda2") != 0) { + fprintf (stderr, "test_list_partitions_1: expected \"/dev/sda2\" but got \"%s\"\n", r[1]); + return -1; + } + if (!r[2]) { + fprintf (stderr, "test_list_partitions_1: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[2], "/dev/sda3") != 0) { + fprintf (stderr, "test_list_partitions_1: expected \"/dev/sda3\" but got \"%s\"\n", r[2]); + return -1; + } + if (r[3] != NULL) { + fprintf (stderr, "test_list_partitions_1: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_pvs_0 (void) +{ + /* InitEmptyLVM for pvs (0): create ext2 on /dev/VG/LV */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda1", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG", physvols); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV", "VG", 8); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/VG/LV"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/VG/LV", "/"); + if (r == -1) + return -1; + } + /* TestOutputList for pvs (0) */ + { + char **r; + int i; + suppress_error = 0; + r = guestfs_pvs (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_pvs_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "/dev/sda1") != 0) { + fprintf (stderr, "test_pvs_0: expected \"/dev/sda1\" but got \"%s\"\n", r[0]); + return -1; + } + if (r[1] != NULL) { + fprintf (stderr, "test_pvs_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_pvs_1 (void) +{ + /* InitNone for pvs (1) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutputList for pvs (1) */ + { + char *lines[] = { + ",10", + ",20", + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda2"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda3"); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_pvs (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_pvs_1: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "/dev/sda1") != 0) { + fprintf (stderr, "test_pvs_1: expected \"/dev/sda1\" but got \"%s\"\n", r[0]); + return -1; + } + if (!r[1]) { + fprintf (stderr, "test_pvs_1: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[1], "/dev/sda2") != 0) { + fprintf (stderr, "test_pvs_1: expected \"/dev/sda2\" but got \"%s\"\n", r[1]); + return -1; + } + if (!r[2]) { + fprintf (stderr, "test_pvs_1: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[2], "/dev/sda3") != 0) { + fprintf (stderr, "test_pvs_1: expected \"/dev/sda3\" but got \"%s\"\n", r[2]); + return -1; + } + if (r[3] != NULL) { + fprintf (stderr, "test_pvs_1: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_vgs_0 (void) +{ + /* InitEmptyLVM for vgs (0): create ext2 on /dev/VG/LV */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda1", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG", physvols); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV", "VG", 8); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/VG/LV"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/VG/LV", "/"); + if (r == -1) + return -1; + } + /* TestOutputList for vgs (0) */ + { + char **r; + int i; + suppress_error = 0; + r = guestfs_vgs (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_vgs_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "VG") != 0) { + fprintf (stderr, "test_vgs_0: expected \"VG\" but got \"%s\"\n", r[0]); + return -1; + } + if (r[1] != NULL) { + fprintf (stderr, "test_vgs_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_vgs_1 (void) +{ + /* InitNone for vgs (1) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutputList for vgs (1) */ + { + char *lines[] = { + ",10", + ",20", + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda2"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda3"); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda1", + "/dev/sda2", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG1", physvols); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda3", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG2", physvols); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_vgs (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_vgs_1: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "VG1") != 0) { + fprintf (stderr, "test_vgs_1: expected \"VG1\" but got \"%s\"\n", r[0]); + return -1; + } + if (!r[1]) { + fprintf (stderr, "test_vgs_1: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[1], "VG2") != 0) { + fprintf (stderr, "test_vgs_1: expected \"VG2\" but got \"%s\"\n", r[1]); + return -1; + } + if (r[2] != NULL) { + fprintf (stderr, "test_vgs_1: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_lvs_0 (void) +{ + /* InitEmptyLVM for lvs (0): create ext2 on /dev/VG/LV */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda1", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG", physvols); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV", "VG", 8); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/VG/LV"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/VG/LV", "/"); + if (r == -1) + return -1; + } + /* TestOutputList for lvs (0) */ + { + char **r; + int i; + suppress_error = 0; + r = guestfs_lvs (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_lvs_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "/dev/VG/LV") != 0) { + fprintf (stderr, "test_lvs_0: expected \"/dev/VG/LV\" but got \"%s\"\n", r[0]); + return -1; + } + if (r[1] != NULL) { + fprintf (stderr, "test_lvs_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_lvs_1 (void) +{ + /* InitNone for lvs (1) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutputList for lvs (1) */ + { + char *lines[] = { + ",10", + ",20", + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda2"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda3"); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda1", + "/dev/sda2", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG1", physvols); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda3", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG2", physvols); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV1", "VG1", 50); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV2", "VG1", 50); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV3", "VG2", 50); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_lvs (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_lvs_1: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "/dev/VG1/LV1") != 0) { + fprintf (stderr, "test_lvs_1: expected \"/dev/VG1/LV1\" but got \"%s\"\n", r[0]); + return -1; + } + if (!r[1]) { + fprintf (stderr, "test_lvs_1: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[1], "/dev/VG1/LV2") != 0) { + fprintf (stderr, "test_lvs_1: expected \"/dev/VG1/LV2\" but got \"%s\"\n", r[1]); + return -1; + } + if (!r[2]) { + fprintf (stderr, "test_lvs_1: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[2], "/dev/VG2/LV3") != 0) { + fprintf (stderr, "test_lvs_1: expected \"/dev/VG2/LV3\" but got \"%s\"\n", r[2]); + return -1; + } + if (r[3] != NULL) { + fprintf (stderr, "test_lvs_1: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_pvs_full_0 (void) +{ + /* InitEmptyLVM for pvs_full (0): create ext2 on /dev/VG/LV */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda1", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG", physvols); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV", "VG", 8); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/VG/LV"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/VG/LV", "/"); + if (r == -1) + return -1; + } + /* TestOutputLength for pvs_full (0) */ + { + char **r; + int i; + suppress_error = 0; + r = guestfs_pvs (g); + if (r == NULL) + return -1; + int j; + for (j = 0; j < 1; ++j) + if (r[j] == NULL) { + fprintf (stderr, "test_pvs_full_0: short list returned\n"); + print_strings (r); + return -1; + } + if (r[j] != NULL) { + fprintf (stderr, "test_pvs_full_0: long list returned\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_vgs_full_0 (void) +{ + /* InitEmptyLVM for vgs_full (0): create ext2 on /dev/VG/LV */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda1", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG", physvols); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV", "VG", 8); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/VG/LV"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/VG/LV", "/"); + if (r == -1) + return -1; + } + /* TestOutputLength for vgs_full (0) */ + { + char **r; + int i; + suppress_error = 0; + r = guestfs_pvs (g); + if (r == NULL) + return -1; + int j; + for (j = 0; j < 1; ++j) + if (r[j] == NULL) { + fprintf (stderr, "test_vgs_full_0: short list returned\n"); + print_strings (r); + return -1; + } + if (r[j] != NULL) { + fprintf (stderr, "test_vgs_full_0: long list returned\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_lvs_full_0 (void) +{ + /* InitEmptyLVM for lvs_full (0): create ext2 on /dev/VG/LV */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda1", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG", physvols); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV", "VG", 8); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/VG/LV"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/VG/LV", "/"); + if (r == -1) + return -1; + } + /* TestOutputLength for lvs_full (0) */ + { + char **r; + int i; + suppress_error = 0; + r = guestfs_pvs (g); + if (r == NULL) + return -1; + int j; + for (j = 0; j < 1; ++j) + if (r[j] == NULL) { + fprintf (stderr, "test_lvs_full_0: short list returned\n"); + print_strings (r); + return -1; + } + if (r[j] != NULL) { + fprintf (stderr, "test_lvs_full_0: long list returned\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_read_lines_0 (void) +{ + /* InitEmpty for read_lines (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputList for read_lines (0) */ + { + int r; + suppress_error = 0; + r = guestfs_write_file (g, "/new", "line1\r\nline2\nline3", 0); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_read_lines (g, "/new"); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_read_lines_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "line1") != 0) { + fprintf (stderr, "test_read_lines_0: expected \"line1\" but got \"%s\"\n", r[0]); + return -1; + } + if (!r[1]) { + fprintf (stderr, "test_read_lines_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[1], "line2") != 0) { + fprintf (stderr, "test_read_lines_0: expected \"line2\" but got \"%s\"\n", r[1]); + return -1; + } + if (!r[2]) { + fprintf (stderr, "test_read_lines_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[2], "line3") != 0) { + fprintf (stderr, "test_read_lines_0: expected \"line3\" but got \"%s\"\n", r[2]); + return -1; + } + if (r[3] != NULL) { + fprintf (stderr, "test_read_lines_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_read_lines_1 (void) +{ + /* InitEmpty for read_lines (1): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputList for read_lines (1) */ + { + int r; + suppress_error = 0; + r = guestfs_write_file (g, "/new", "", 0); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_read_lines (g, "/new"); + if (r == NULL) + return -1; + if (r[0] != NULL) { + fprintf (stderr, "test_read_lines_1: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_rm_0 (void) +{ + /* InitEmpty for rm (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestRun for rm (0) */ + { + int r; + suppress_error = 0; + r = guestfs_touch (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_rm (g, "/new"); + if (r == -1) + return -1; + } + return 0; +} + +static int test_rm_1 (void) +{ + /* InitEmpty for rm (1): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestLastFail for rm (1) */ + { + int r; + suppress_error = 1; + r = guestfs_rm (g, "/new"); + if (r != -1) + return -1; + } + return 0; +} + +static int test_rm_2 (void) +{ + /* InitEmpty for rm (2): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestLastFail for rm (2) */ + { + int r; + suppress_error = 0; + r = guestfs_mkdir (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 1; + r = guestfs_rm (g, "/new"); + if (r != -1) + return -1; + } + return 0; +} + +static int test_rmdir_0 (void) +{ + /* InitEmpty for rmdir (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestRun for rmdir (0) */ + { + int r; + suppress_error = 0; + r = guestfs_mkdir (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_rmdir (g, "/new"); + if (r == -1) + return -1; + } + return 0; +} + +static int test_rmdir_1 (void) +{ + /* InitEmpty for rmdir (1): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestLastFail for rmdir (1) */ + { + int r; + suppress_error = 1; + r = guestfs_rmdir (g, "/new"); + if (r != -1) + return -1; + } + return 0; +} + +static int test_rmdir_2 (void) +{ + /* InitEmpty for rmdir (2): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestLastFail for rmdir (2) */ + { + int r; + suppress_error = 0; + r = guestfs_touch (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 1; + r = guestfs_rmdir (g, "/new"); + if (r != -1) + return -1; + } + return 0; +} + +static int test_rm_rf_0 (void) +{ + /* InitEmpty for rm_rf (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputFalse for rm_rf (0) */ + { + int r; + suppress_error = 0; + r = guestfs_mkdir (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkdir (g, "/new/foo"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_touch (g, "/new/foo/bar"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_rm_rf (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_exists (g, "/new"); + if (r == -1) + return -1; + if (r) { + fprintf (stderr, "test_rm_rf_0: expected false, got true\n"); + return -1; + } + } + return 0; +} + +static int test_mkdir_0 (void) +{ + /* InitEmpty for mkdir (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputTrue for mkdir (0) */ + { + int r; + suppress_error = 0; + r = guestfs_mkdir (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_is_dir (g, "/new"); + if (r == -1) + return -1; + if (!r) { + fprintf (stderr, "test_mkdir_0: expected true, got false\n"); + return -1; + } + } + return 0; +} + +static int test_mkdir_1 (void) +{ + /* InitEmpty for mkdir (1): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestLastFail for mkdir (1) */ + { + int r; + suppress_error = 1; + r = guestfs_mkdir (g, "/new/foo/bar"); + if (r != -1) + return -1; + } + return 0; +} + +static int test_mkdir_p_0 (void) +{ + /* InitEmpty for mkdir_p (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputTrue for mkdir_p (0) */ + { + int r; + suppress_error = 0; + r = guestfs_mkdir_p (g, "/new/foo/bar"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_is_dir (g, "/new/foo/bar"); + if (r == -1) + return -1; + if (!r) { + fprintf (stderr, "test_mkdir_p_0: expected true, got false\n"); + return -1; + } + } + return 0; +} + +static int test_mkdir_p_1 (void) +{ + /* InitEmpty for mkdir_p (1): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputTrue for mkdir_p (1) */ + { + int r; + suppress_error = 0; + r = guestfs_mkdir_p (g, "/new/foo/bar"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_is_dir (g, "/new/foo"); + if (r == -1) + return -1; + if (!r) { + fprintf (stderr, "test_mkdir_p_1: expected true, got false\n"); + return -1; + } + } + return 0; +} + +static int test_mkdir_p_2 (void) +{ + /* InitEmpty for mkdir_p (2): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputTrue for mkdir_p (2) */ + { + int r; + suppress_error = 0; + r = guestfs_mkdir_p (g, "/new/foo/bar"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_is_dir (g, "/new"); + if (r == -1) + return -1; + if (!r) { + fprintf (stderr, "test_mkdir_p_2: expected true, got false\n"); + return -1; + } + } + return 0; +} + +static int test_exists_0 (void) +{ + /* InitEmpty for exists (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputTrue for exists (0) */ + { + int r; + suppress_error = 0; + r = guestfs_touch (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_exists (g, "/new"); + if (r == -1) + return -1; + if (!r) { + fprintf (stderr, "test_exists_0: expected true, got false\n"); + return -1; + } + } + return 0; +} + +static int test_exists_1 (void) +{ + /* InitEmpty for exists (1): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputTrue for exists (1) */ + { + int r; + suppress_error = 0; + r = guestfs_mkdir (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_exists (g, "/new"); + if (r == -1) + return -1; + if (!r) { + fprintf (stderr, "test_exists_1: expected true, got false\n"); + return -1; + } + } + return 0; +} + +static int test_is_file_0 (void) +{ + /* InitEmpty for is_file (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputTrue for is_file (0) */ + { + int r; + suppress_error = 0; + r = guestfs_touch (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_is_file (g, "/new"); + if (r == -1) + return -1; + if (!r) { + fprintf (stderr, "test_is_file_0: expected true, got false\n"); + return -1; + } + } + return 0; +} + +static int test_is_file_1 (void) +{ + /* InitEmpty for is_file (1): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputFalse for is_file (1) */ + { + int r; + suppress_error = 0; + r = guestfs_mkdir (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_is_file (g, "/new"); + if (r == -1) + return -1; + if (r) { + fprintf (stderr, "test_is_file_1: expected false, got true\n"); + return -1; + } + } + return 0; +} + +static int test_is_dir_0 (void) +{ + /* InitEmpty for is_dir (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputFalse for is_dir (0) */ + { + int r; + suppress_error = 0; + r = guestfs_touch (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_is_dir (g, "/new"); + if (r == -1) + return -1; + if (r) { + fprintf (stderr, "test_is_dir_0: expected false, got true\n"); + return -1; + } + } + return 0; +} + +static int test_is_dir_1 (void) +{ + /* InitEmpty for is_dir (1): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputTrue for is_dir (1) */ + { + int r; + suppress_error = 0; + r = guestfs_mkdir (g, "/new"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_is_dir (g, "/new"); + if (r == -1) + return -1; + if (!r) { + fprintf (stderr, "test_is_dir_1: expected true, got false\n"); + return -1; + } + } + return 0; +} + +static int test_pvcreate_0 (void) +{ + /* InitNone for pvcreate (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutputList for pvcreate (0) */ + { + char *lines[] = { + ",10", + ",20", + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda2"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda3"); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_pvs (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_pvcreate_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "/dev/sda1") != 0) { + fprintf (stderr, "test_pvcreate_0: expected \"/dev/sda1\" but got \"%s\"\n", r[0]); + return -1; + } + if (!r[1]) { + fprintf (stderr, "test_pvcreate_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[1], "/dev/sda2") != 0) { + fprintf (stderr, "test_pvcreate_0: expected \"/dev/sda2\" but got \"%s\"\n", r[1]); + return -1; + } + if (!r[2]) { + fprintf (stderr, "test_pvcreate_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[2], "/dev/sda3") != 0) { + fprintf (stderr, "test_pvcreate_0: expected \"/dev/sda3\" but got \"%s\"\n", r[2]); + return -1; + } + if (r[3] != NULL) { + fprintf (stderr, "test_pvcreate_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_vgcreate_0 (void) +{ + /* InitNone for vgcreate (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutputList for vgcreate (0) */ + { + char *lines[] = { + ",10", + ",20", + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda2"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda3"); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda1", + "/dev/sda2", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG1", physvols); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda3", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG2", physvols); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_vgs (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_vgcreate_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "VG1") != 0) { + fprintf (stderr, "test_vgcreate_0: expected \"VG1\" but got \"%s\"\n", r[0]); + return -1; + } + if (!r[1]) { + fprintf (stderr, "test_vgcreate_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[1], "VG2") != 0) { + fprintf (stderr, "test_vgcreate_0: expected \"VG2\" but got \"%s\"\n", r[1]); + return -1; + } + if (r[2] != NULL) { + fprintf (stderr, "test_vgcreate_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_lvcreate_0 (void) +{ + /* InitNone for lvcreate (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutputList for lvcreate (0) */ + { + char *lines[] = { + ",10", + ",20", + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda2"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_pvcreate (g, "/dev/sda3"); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda1", + "/dev/sda2", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG1", physvols); + if (r == -1) + return -1; + } + { + char *physvols[] = { + "/dev/sda3", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_vgcreate (g, "VG2", physvols); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV1", "VG1", 50); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV2", "VG1", 50); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV3", "VG2", 50); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV4", "VG2", 50); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvcreate (g, "LV5", "VG2", 50); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_lvs (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_lvcreate_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "/dev/VG1/LV1") != 0) { + fprintf (stderr, "test_lvcreate_0: expected \"/dev/VG1/LV1\" but got \"%s\"\n", r[0]); + return -1; + } + if (!r[1]) { + fprintf (stderr, "test_lvcreate_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[1], "/dev/VG1/LV2") != 0) { + fprintf (stderr, "test_lvcreate_0: expected \"/dev/VG1/LV2\" but got \"%s\"\n", r[1]); + return -1; + } + if (!r[2]) { + fprintf (stderr, "test_lvcreate_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[2], "/dev/VG2/LV3") != 0) { + fprintf (stderr, "test_lvcreate_0: expected \"/dev/VG2/LV3\" but got \"%s\"\n", r[2]); + return -1; + } + if (!r[3]) { + fprintf (stderr, "test_lvcreate_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[3], "/dev/VG2/LV4") != 0) { + fprintf (stderr, "test_lvcreate_0: expected \"/dev/VG2/LV4\" but got \"%s\"\n", r[3]); + return -1; + } + if (!r[4]) { + fprintf (stderr, "test_lvcreate_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[4], "/dev/VG2/LV5") != 0) { + fprintf (stderr, "test_lvcreate_0: expected \"/dev/VG2/LV5\" but got \"%s\"\n", r[4]); + return -1; + } + if (r[5] != NULL) { + fprintf (stderr, "test_lvcreate_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_mkfs_0 (void) +{ + /* InitNone for mkfs (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutput for mkfs (0) */ + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_write_file (g, "/new", "new file contents", 0); + if (r == -1) + return -1; + } + { + char *r; + suppress_error = 0; + r = guestfs_cat (g, "/new"); + if (r == NULL) + return -1; + if (strcmp (r, "new file contents") != 0) { + fprintf (stderr, "test_mkfs_0: expected \"new file contents\" but got \"%s\"\n", r); + return -1; + } + free (r); + } + return 0; +} + +static int test_write_file_0 (void) +{ + /* InitNone for write_file (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutput for write_file (0) */ + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_write_file (g, "/new", "new file contents", 0); + if (r == -1) + return -1; + } + { + char *r; + suppress_error = 0; + r = guestfs_cat (g, "/new"); + if (r == NULL) + return -1; + if (strcmp (r, "new file contents") != 0) { + fprintf (stderr, "test_write_file_0: expected \"new file contents\" but got \"%s\"\n", r); + return -1; + } + free (r); + } + return 0; +} + +static int test_umount_0 (void) +{ + /* InitNone for umount (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutputList for umount (0) */ + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_mounts (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_umount_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "/dev/sda1") != 0) { + fprintf (stderr, "test_umount_0: expected \"/dev/sda1\" but got \"%s\"\n", r[0]); + return -1; + } + if (r[1] != NULL) { + fprintf (stderr, "test_umount_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_umount_1 (void) +{ + /* InitNone for umount (1) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + /* TestOutputList for umount (1) */ + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_umount (g, "/"); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_mounts (g); + if (r == NULL) + return -1; + if (r[0] != NULL) { + fprintf (stderr, "test_umount_1: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_mounts_0 (void) +{ + /* InitEmpty for mounts (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputList for mounts (0) */ + { + char **r; + int i; + suppress_error = 0; + r = guestfs_mounts (g); + if (r == NULL) + return -1; + if (!r[0]) { + fprintf (stderr, "test_mounts_0: short list returned from command\n"); + print_strings (r); + return -1; + } + if (strcmp (r[0], "/dev/sda1") != 0) { + fprintf (stderr, "test_mounts_0: expected \"/dev/sda1\" but got \"%s\"\n", r[0]); + return -1; + } + if (r[1] != NULL) { + fprintf (stderr, "test_mounts_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + +static int test_umount_all_0 (void) +{ + /* InitEmpty for umount_all (0): create ext2 on /dev/sda1 */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_lvm_remove_all (g); + if (r == -1) + return -1; + } + { + char *lines[] = { + ",", + NULL + }; + int r; + suppress_error = 0; + r = guestfs_sfdisk (g, "/dev/sda", 0, 0, 0, lines); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mkfs (g, "ext2", "/dev/sda1"); + if (r == -1) + return -1; + } + { + int r; + suppress_error = 0; + r = guestfs_mount (g, "/dev/sda1", "/"); + if (r == -1) + return -1; + } + /* TestOutputList for umount_all (0) */ + { + int r; + suppress_error = 0; + r = guestfs_umount_all (g); + if (r == -1) + return -1; + } + { + char **r; + int i; + suppress_error = 0; + r = guestfs_mounts (g); + if (r == NULL) + return -1; + if (r[0] != NULL) { + fprintf (stderr, "test_umount_all_0: extra elements returned from command\n"); + print_strings (r); + return -1; + } + for (i = 0; r[i] != NULL; ++i) + free (r[i]); + free (r); + } + return 0; +} + int main (int argc, char *argv[]) { + char c = 0; + int failed = 0; + const char *srcdir; + int fd; + char buf[256]; + + g = guestfs_create (); + if (g == NULL) { + printf ("guestfs_create FAILED\n"); + exit (1); + } + + guestfs_set_error_handler (g, print_error, NULL); + + srcdir = getenv ("srcdir"); + if (!srcdir) srcdir = "."; + guestfs_set_path (g, srcdir); + + snprintf (buf, sizeof buf, "%s/test1.img", srcdir); + fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); + if (fd == -1) { + perror (buf); + exit (1); + } + if (lseek (fd, 524288000, SEEK_SET) == -1) { + perror ("lseek"); + close (fd); + unlink (buf); + exit (1); + } + if (write (fd, &c, 1) == -1) { + perror ("write"); + close (fd); + unlink (buf); + exit (1); + } + if (close (fd) == -1) { + perror (buf); + unlink (buf); + exit (1); + } + if (guestfs_add_drive (g, buf) == -1) { + printf ("guestfs_add_drive %s FAILED\n", buf); + exit (1); + } + + snprintf (buf, sizeof buf, "%s/test2.img", srcdir); + fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); + if (fd == -1) { + perror (buf); + exit (1); + } + if (lseek (fd, 52428800, SEEK_SET) == -1) { + perror ("lseek"); + close (fd); + unlink (buf); + exit (1); + } + if (write (fd, &c, 1) == -1) { + perror ("write"); + close (fd); + unlink (buf); + exit (1); + } + if (close (fd) == -1) { + perror (buf); + unlink (buf); + exit (1); + } + if (guestfs_add_drive (g, buf) == -1) { + printf ("guestfs_add_drive %s FAILED\n", buf); + exit (1); + } + + snprintf (buf, sizeof buf, "%s/test3.img", srcdir); + fd = open (buf, O_WRONLY|O_CREAT|O_NOCTTY|O_NONBLOCK|O_TRUNC, 0666); + if (fd == -1) { + perror (buf); + exit (1); + } + if (lseek (fd, 10485760, SEEK_SET) == -1) { + perror ("lseek"); + close (fd); + unlink (buf); + exit (1); + } + if (write (fd, &c, 1) == -1) { + perror ("write"); + close (fd); + unlink (buf); + exit (1); + } + if (close (fd) == -1) { + perror (buf); + unlink (buf); + exit (1); + } + if (guestfs_add_drive (g, buf) == -1) { + printf ("guestfs_add_drive %s FAILED\n", buf); + exit (1); + } + + if (guestfs_launch (g) == -1) { + printf ("guestfs_launch FAILED\n"); + exit (1); + } + if (guestfs_wait_ready (g) == -1) { + printf ("guestfs_wait_ready FAILED\n"); + exit (1); + } + + printf (" 1/ 46 test_mount_0\n"); + if (test_mount_0 () == -1) { + printf ("test_mount_0 FAILED\n"); + failed++; + } + printf (" 2/ 46 test_sync_0\n"); + if (test_sync_0 () == -1) { + printf ("test_sync_0 FAILED\n"); + failed++; + } + printf (" 3/ 46 test_touch_0\n"); + if (test_touch_0 () == -1) { + printf ("test_touch_0 FAILED\n"); + failed++; + } + printf (" 4/ 46 test_cat_0\n"); + if (test_cat_0 () == -1) { + printf ("test_cat_0 FAILED\n"); + failed++; + } + printf (" 5/ 46 test_ls_0\n"); + if (test_ls_0 () == -1) { + printf ("test_ls_0 FAILED\n"); + failed++; + } + printf (" 6/ 46 test_list_devices_0\n"); + if (test_list_devices_0 () == -1) { + printf ("test_list_devices_0 FAILED\n"); + failed++; + } + printf (" 7/ 46 test_list_partitions_0\n"); + if (test_list_partitions_0 () == -1) { + printf ("test_list_partitions_0 FAILED\n"); + failed++; + } + printf (" 8/ 46 test_list_partitions_1\n"); + if (test_list_partitions_1 () == -1) { + printf ("test_list_partitions_1 FAILED\n"); + failed++; + } + printf (" 9/ 46 test_pvs_0\n"); + if (test_pvs_0 () == -1) { + printf ("test_pvs_0 FAILED\n"); + failed++; + } + printf (" 10/ 46 test_pvs_1\n"); + if (test_pvs_1 () == -1) { + printf ("test_pvs_1 FAILED\n"); + failed++; + } + printf (" 11/ 46 test_vgs_0\n"); + if (test_vgs_0 () == -1) { + printf ("test_vgs_0 FAILED\n"); + failed++; + } + printf (" 12/ 46 test_vgs_1\n"); + if (test_vgs_1 () == -1) { + printf ("test_vgs_1 FAILED\n"); + failed++; + } + printf (" 13/ 46 test_lvs_0\n"); + if (test_lvs_0 () == -1) { + printf ("test_lvs_0 FAILED\n"); + failed++; + } + printf (" 14/ 46 test_lvs_1\n"); + if (test_lvs_1 () == -1) { + printf ("test_lvs_1 FAILED\n"); + failed++; + } + printf (" 15/ 46 test_pvs_full_0\n"); + if (test_pvs_full_0 () == -1) { + printf ("test_pvs_full_0 FAILED\n"); + failed++; + } + printf (" 16/ 46 test_vgs_full_0\n"); + if (test_vgs_full_0 () == -1) { + printf ("test_vgs_full_0 FAILED\n"); + failed++; + } + printf (" 17/ 46 test_lvs_full_0\n"); + if (test_lvs_full_0 () == -1) { + printf ("test_lvs_full_0 FAILED\n"); + failed++; + } + printf (" 18/ 46 test_read_lines_0\n"); + if (test_read_lines_0 () == -1) { + printf ("test_read_lines_0 FAILED\n"); + failed++; + } + printf (" 19/ 46 test_read_lines_1\n"); + if (test_read_lines_1 () == -1) { + printf ("test_read_lines_1 FAILED\n"); + failed++; + } + printf (" 20/ 46 test_rm_0\n"); + if (test_rm_0 () == -1) { + printf ("test_rm_0 FAILED\n"); + failed++; + } + printf (" 21/ 46 test_rm_1\n"); + if (test_rm_1 () == -1) { + printf ("test_rm_1 FAILED\n"); + failed++; + } + printf (" 22/ 46 test_rm_2\n"); + if (test_rm_2 () == -1) { + printf ("test_rm_2 FAILED\n"); + failed++; + } + printf (" 23/ 46 test_rmdir_0\n"); + if (test_rmdir_0 () == -1) { + printf ("test_rmdir_0 FAILED\n"); + failed++; + } + printf (" 24/ 46 test_rmdir_1\n"); + if (test_rmdir_1 () == -1) { + printf ("test_rmdir_1 FAILED\n"); + failed++; + } + printf (" 25/ 46 test_rmdir_2\n"); + if (test_rmdir_2 () == -1) { + printf ("test_rmdir_2 FAILED\n"); + failed++; + } + printf (" 26/ 46 test_rm_rf_0\n"); + if (test_rm_rf_0 () == -1) { + printf ("test_rm_rf_0 FAILED\n"); + failed++; + } + printf (" 27/ 46 test_mkdir_0\n"); + if (test_mkdir_0 () == -1) { + printf ("test_mkdir_0 FAILED\n"); + failed++; + } + printf (" 28/ 46 test_mkdir_1\n"); + if (test_mkdir_1 () == -1) { + printf ("test_mkdir_1 FAILED\n"); + failed++; + } + printf (" 29/ 46 test_mkdir_p_0\n"); + if (test_mkdir_p_0 () == -1) { + printf ("test_mkdir_p_0 FAILED\n"); + failed++; + } + printf (" 30/ 46 test_mkdir_p_1\n"); + if (test_mkdir_p_1 () == -1) { + printf ("test_mkdir_p_1 FAILED\n"); + failed++; + } + printf (" 31/ 46 test_mkdir_p_2\n"); + if (test_mkdir_p_2 () == -1) { + printf ("test_mkdir_p_2 FAILED\n"); + failed++; + } + printf (" 32/ 46 test_exists_0\n"); + if (test_exists_0 () == -1) { + printf ("test_exists_0 FAILED\n"); + failed++; + } + printf (" 33/ 46 test_exists_1\n"); + if (test_exists_1 () == -1) { + printf ("test_exists_1 FAILED\n"); + failed++; + } + printf (" 34/ 46 test_is_file_0\n"); + if (test_is_file_0 () == -1) { + printf ("test_is_file_0 FAILED\n"); + failed++; + } + printf (" 35/ 46 test_is_file_1\n"); + if (test_is_file_1 () == -1) { + printf ("test_is_file_1 FAILED\n"); + failed++; + } + printf (" 36/ 46 test_is_dir_0\n"); + if (test_is_dir_0 () == -1) { + printf ("test_is_dir_0 FAILED\n"); + failed++; + } + printf (" 37/ 46 test_is_dir_1\n"); + if (test_is_dir_1 () == -1) { + printf ("test_is_dir_1 FAILED\n"); + failed++; + } + printf (" 38/ 46 test_pvcreate_0\n"); + if (test_pvcreate_0 () == -1) { + printf ("test_pvcreate_0 FAILED\n"); + failed++; + } + printf (" 39/ 46 test_vgcreate_0\n"); + if (test_vgcreate_0 () == -1) { + printf ("test_vgcreate_0 FAILED\n"); + failed++; + } + printf (" 40/ 46 test_lvcreate_0\n"); + if (test_lvcreate_0 () == -1) { + printf ("test_lvcreate_0 FAILED\n"); + failed++; + } + printf (" 41/ 46 test_mkfs_0\n"); + if (test_mkfs_0 () == -1) { + printf ("test_mkfs_0 FAILED\n"); + failed++; + } + printf (" 42/ 46 test_write_file_0\n"); + if (test_write_file_0 () == -1) { + printf ("test_write_file_0 FAILED\n"); + failed++; + } + printf (" 43/ 46 test_umount_0\n"); + if (test_umount_0 () == -1) { + printf ("test_umount_0 FAILED\n"); + failed++; + } + printf (" 44/ 46 test_umount_1\n"); + if (test_umount_1 () == -1) { + printf ("test_umount_1 FAILED\n"); + failed++; + } + printf (" 45/ 46 test_mounts_0\n"); + if (test_mounts_0 () == -1) { + printf ("test_mounts_0 FAILED\n"); + failed++; + } + printf (" 46/ 46 test_umount_all_0\n"); + if (test_umount_all_0 () == -1) { + printf ("test_umount_all_0 FAILED\n"); + failed++; + } + + guestfs_close (g); + snprintf (buf, sizeof buf, "%s/test1.img", srcdir); + unlink (buf); + snprintf (buf, sizeof buf, "%s/test2.img", srcdir); + unlink (buf); + snprintf (buf, sizeof buf, "%s/test3.img", srcdir); + unlink (buf); + + if (failed > 0) { + printf ("***** %d / 46 tests FAILED *****\n", failed); + exit (1); + } + exit (0); } |