From b4d2a01828e5de85e5eee3631f7fe3925a0312ca Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Fri, 10 Apr 2009 18:25:07 +0100 Subject: [PATCH] Added test suite. --- Makefile.am | 2 + daemon/actions.h | 13 + daemon/daemon.h | 31 +- daemon/devsparts.c | 62 + daemon/dir.c | 27 +- daemon/file.c | 74 + daemon/guestfsd.c | 88 +- daemon/lvm.c | 131 ++ daemon/mount.c | 115 ++ daemon/proto.c | 8 +- daemon/stubs.c | 548 ++++++- daemon/sync.c | 1 - fish/cmds.c | 296 ++++ fish/fish.c | 35 +- fish/fish.h | 3 +- guestfish-actions.pod | 141 ++ guestfs-actions.pod | 185 +++ libguestfs.spec.in | 4 + make-initramfs.sh.in | 4 +- ocaml/guestfs.ml | 13 + ocaml/guestfs.mli | 39 + ocaml/guestfs_c.c | 26 + ocaml/guestfs_c.h | 2 + ocaml/guestfs_c_actions.c | 318 ++++ perl/Guestfs.xs | 318 +++- perl/lib/Sys/Guestfs.pm | 169 +- src/generator.ml | 1046 ++++++++++-- src/guestfs-actions.c | 931 +++++++++++ src/guestfs-actions.h | 13 + src/guestfs_protocol.c | 208 +++ src/guestfs_protocol.h | 132 +- src/guestfs_protocol.x | 79 + tests.c | 3933 +++++++++++++++++++++++++++++++++++++++++++++ 33 files changed, 8670 insertions(+), 325 deletions(-) diff --git a/Makefile.am b/Makefile.am index 47954a5..2345018 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 1b35cad..2a9d3d1 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 b2396a1..27d86c9 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -21,6 +21,9 @@ #include #include +#include +#include +#include #include #include @@ -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 b0d7956..324b887 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 7892682..f706466 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 43c875c..0b8b463 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 a243c0b..c701f19 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 7f31c84..55b41f0 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 440ec0d..fd9c8e4 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 93d33c2..42bc6ea 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 1227fa8..4540ca5 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 9ade840..70962df 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 cef38cc..1ab9ea0 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 / help 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 \n\nChange the file owner to C and group to C.\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 \n\nThis returns C if and only if there is a file, directory\n(or anything) with the given C name.\n\nSee also C, C, C."); + else + if (strcasecmp (cmd, "is_file") == 0 || strcasecmp (cmd, "is-file") == 0) + pod2text ("is-file - test if file exists", " is-file \n\nThis returns C if and only if there is a file\nwith the given C name. Note that it returns false for\nother objects like directories.\n\nSee also C."); + else + if (strcasecmp (cmd, "is_dir") == 0 || strcasecmp (cmd, "is-dir") == 0) + pod2text ("is-dir - test if file exists", " is-dir \n\nThis returns C if and only if there is a directory\nwith the given C name. Note that it returns false for\nother objects like files.\n\nSee also C."); + else + if (strcasecmp (cmd, "pvcreate") == 0) + pod2text ("pvcreate - create an LVM physical volume", " pvcreate \n\nThis creates an LVM physical volume on the named C,\nwhere C should usually be a partition name such\nas C."); + else + if (strcasecmp (cmd, "vgcreate") == 0) + pod2text ("vgcreate - create an LVM volume group", " vgcreate \n\nThis creates an LVM volume group called C\nfrom the non-empty list of physical volumes C."); + else + if (strcasecmp (cmd, "lvcreate") == 0) + pod2text ("lvcreate - create an LVM volume group", " lvcreate \n\nThis creates an LVM volume group called C\non the volume group C, with C megabytes."); + else + if (strcasecmp (cmd, "mkfs") == 0) + pod2text ("mkfs - make a filesystem", " mkfs \n\nThis creates a filesystem on C (usually a partition\nof LVM logical volume). The filesystem type is C, for\nexample C."); + else + if (strcasecmp (cmd, "sfdisk") == 0) + pod2text ("sfdisk - create partitions on a block device", " sfdisk \n\nThis is a direct interface to the L program for creating\npartitions on block devices.\n\nC should be a block device, for example C.\n\nC, C and C are the number of cylinders, heads\nand sectors on the device, which are passed directly to sfdisk as\nthe I<-C>, I<-H> and I<-S> parameters. If you pass C<0> for any\nof these, then the corresponding parameter is omitted. Usually for\n'large' disks, you can just pass C<0> for these, but for small\n(floppy-sized) disks, sfdisk (or rather, the kernel) cannot work\nout the right geometry and you will need to tell it.\n\nC is a list of lines that we feed to C. For more\ninformation refer to the L manpage.\n\nTo create a single partition occupying the whole disk, you would\npass C as a single element list, when the single element being\nthe string C<,> (comma).\n\nB."); + else + if (strcasecmp (cmd, "write_file") == 0 || strcasecmp (cmd, "write-file") == 0) + pod2text ("write-file - Create a file", " write-file \n\nThis call creates a file called C. The contents of the\nfile is the string C (which can contain any 8 bit data),\nwith length C.\n\nAs a special case, if C is C<0>\nthen the length is calculated using C (so in this case\nthe content cannot contain embedded ASCII NULs).\n\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 \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, C).\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."); + 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 e845e4d..18b8d45 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -18,6 +18,8 @@ #include +#define _GNU_SOURCE // for strchrnul + #include #include #include @@ -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 6d0892f..3997d6d 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 d47e9bf..50ecfec 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 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 string must be a C<-> (dash). C can be NULL. +=head2 exists + + exists path + +This returns C if and only if there is a file, directory +(or anything) with the given C name. + +See also C, C, C. + =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 if and only if there is a directory +with the given C name. Note that it returns false for +other objects like files. + +See also C. + +=head2 is-file + + is-file path + +This returns C if and only if there is a file +with the given C name. Note that it returns false for +other objects like directories. + +See also C. + =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 instead. +=head2 lvcreate + + lvcreate logvol volgroup mbytes + +This creates an LVM volume group called C +on the volume group C, with C megabytes. + +=head2 lvm-remove-all + + lvm-remove-all + +This command removes all LVM logical volumes, volume groups +and physical volumes. + +B. + =head2 lvs lvs @@ -332,6 +382,14 @@ Create a directory named C. Create a directory named C, creating any parent directories as necessary. This is like the C shell command. +=head2 mkfs + + mkfs fstype device + +This creates a filesystem on C (usually a partition +of LVM logical volume). The filesystem type is C, for +example C. + =head2 mount mount device mountpoint @@ -353,6 +411,23 @@ on the underlying device. The filesystem options C and C 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, C). + +Some internal mounts are not shown. + +=head2 pvcreate + + pvcreate device + +This creates an LVM physical volume on the named C, +where C should usually be a partition name such +as C. + =head2 pvs pvs @@ -437,6 +512,33 @@ If C is true, this turns on verbose messages (to C). Verbose messages are disabled unless the environment variable C is defined and set to C<1>. +=head2 sfdisk + + sfdisk device cyls heads sectors lines,... + +This is a direct interface to the L program for creating +partitions on block devices. + +C should be a block device, for example C. + +C, C and C 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 is a list of lines that we feed to C. For more +information refer to the L manpage. + +To create a single partition occupying the whole disk, you would +pass C as a single element list, when the single element being +the string C<,> (comma). + +B. + =head2 sync sync @@ -455,6 +557,29 @@ Touch acts like the L 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 +from the non-empty list of physical volumes C. + =head2 vgs vgs @@ -474,3 +599,19 @@ See also C. List all the volumes groups detected. This is the equivalent of the L command. The "full" version includes all fields. +=head2 write-file + + write-file path content size + +This call creates a file called C. The contents of the +file is the string C (which can contain any 8 bit data), +with length C. + +As a special case, if C is C<0> +then the length is calculated using C (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 069ea8f..310db2e 100644 --- a/guestfs-actions.pod +++ b/guestfs-actions.pod @@ -300,6 +300,18 @@ C 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 if and only if there is a file, directory +(or anything) with the given C name. + +See also C, C, C. + +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 if and only if there is a directory +with the given C name. Note that it returns false for +other objects like files. + +See also C. + +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 if and only if there is a file +with the given C name. Note that it returns false for +other objects like directories. + +See also C. + +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), or NULL if there was an error. I. +=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 +on the volume group C, with C 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. + =head2 guestfs_lvs char **guestfs_lvs (guestfs_h *handle); @@ -450,6 +512,18 @@ as necessary. This is like the C 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 (usually a partition +of LVM logical volume). The filesystem type is C, for +example C. + +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, C). + +Some internal mounts are not shown. + +This function returns a NULL-terminated array of strings +(like L), or NULL if there was an error. +I. + +=head2 guestfs_pvcreate + + int guestfs_pvcreate (guestfs_h *handle, + const char *device); + +This creates an LVM physical volume on the named C, +where C should usually be a partition name such +as C. + +This function returns 0 on success or -1 on error. + =head2 guestfs_pvs char **guestfs_pvs (guestfs_h *handle); @@ -589,6 +687,40 @@ C 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 program for creating +partitions on block devices. + +C should be a block device, for example C. + +C, C and C 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 is a list of lines that we feed to C. For more +information refer to the L manpage. + +To create a single partition occupying the whole disk, you would +pass C as a single element list, when the single element being +the string C<,> (comma). + +This function returns 0 on success or -1 on error. + +B. + =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 +from the non-empty list of physical volumes C. + +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. The contents of the +file is the string C (which can contain any 8 bit data), +with length C. + +As a special case, if C is C<0> +then the length is calculated using C (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 29c95ff..e4dcaef 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 4579e90..3dbac63 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 32a6b82..58f99dc 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 ecf86f1..1ce1cab 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 600440c..291c430 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 3da41d0..4fb8188 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 6675cf8..6b1a9f6 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 d5f1da6..0f72c28 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 50f5d75..c708a29 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 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-Eaug_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 whose value is the result of evaluating C. @@ -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 whose value is the result of evaluating C. If C is NULL, then C is @@ -141,12 +141,12 @@ undefined. On success this returns the number of nodes in C, or C<0> if C 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. If C matches exactly one node, the C 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-Eaug_close>. To find out more about Augeas, see L. -=item $h->aug_insert (path, label, before); +=item $h->aug_insert ($path, $label, $before); Create a new sibling C