Richard W.M. Jones
2011-Jan-27 18:02 UTC
[Libguestfs] [PATCH 0/5 REVIEW ONLY] Implement attach-method to attach to existing daemons
I've only done limited testing, but it does let you connect to an existing guestfsd running inside a guest, over virtio-serial. This is not ready to be applied. One thing I've not thought about is how well this fits in with plans to use this mechanism as an alternate way to launch the appliance via libvirt. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org
Richard W.M. Jones
2011-Jan-27 18:02 UTC
[Libguestfs] [PATCH 1/5] daemon: Replace root_mounted global with intelligence.
This is a good general patch -- we should apply it anyway regardless of the rest. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones libguestfs lets you edit virtual machines. Supports shell scripting, bindings from many languages. http://libguestfs.org -------------- next part -------------->From 701ba942339ab3c56b361891496cda6bd2fdbd71 Mon Sep 17 00:00:00 2001From: Richard W.M. Jones <rjones at redhat.com> Date: Thu, 27 Jan 2011 17:27:41 +0000 Subject: [PATCH 1/5] daemon: Replace root_mounted global with intelligence. We used to maintain a global flag 'root_mounted' which tells us if the user has mounted something on root (ie. on the sysroot directory). This flag caused a lot of trouble (eg. RHBZ#599503) because it's hard to keep the flag updated correctly when the user can do arbitrary mounts and also use mkmountpoint. Remove this flag and replace it with a test to see if something is mounted on *or under* the sysroot. (It has to be *or under* because of mkmountpoint and friends). This also replaces a rather convoluted "have we mounted root yet" check in the mount* APIs with a simpler check to see if the mountpoint exists and is an ordinary directory. --- daemon/daemon.h | 4 +- daemon/mount.c | 74 ++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 51 insertions(+), 27 deletions(-) diff --git a/daemon/daemon.h b/daemon/daemon.h index 6845e1b..da991b1 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -107,7 +107,7 @@ extern uint64_t progress_hint; extern uint64_t optargs_bitmask; /*-- in mount.c --*/ -extern int root_mounted; +extern int is_root_mounted (void); /*-- in stubs.c (auto-generated) --*/ extern void dispatch_incoming_message (XDR *); @@ -178,7 +178,7 @@ extern void notify_progress (uint64_t position, uint64_t total); */ #define NEED_ROOT(cancel_stmt,fail_stmt) \ do { \ - if (!root_mounted) { \ + if (!is_root_mounted ()) { \ if ((cancel_stmt) != -2) \ reply_with_error ("%s: you must call 'mount' first to mount the root filesystem", __func__); \ fail_stmt; \ diff --git a/daemon/mount.c b/daemon/mount.c index ccd07c6..c584f81 100644 --- a/daemon/mount.c +++ b/daemon/mount.c @@ -24,12 +24,43 @@ #include <unistd.h> #include <sys/stat.h> #include <sys/types.h> +#include <mntent.h> #include "daemon.h" #include "actions.h" -/* You must mount something on "/" first, hence: */ -int root_mounted = 0; +/* You must mount something on "/" first before many operations. + * Hence we have an internal function which can test if something is + * mounted on *or under* the sysroot directory. (It has to be *or + * under* because of mkmountpoint and friends). + */ +int +is_root_mounted (void) +{ + FILE *fp; + struct mntent *m; + + fp = setmntent ("/etc/mtab", "r"); + if (fp == NULL) { + perror ("/etc/mtab"); + exit (EXIT_FAILURE); + } + + while ((m = getmntent (fp)) != NULL) { + /* Allow a mount directory like "/sysroot". */ + if (sysroot_len > 0 && STREQ (m->mnt_dir, sysroot)) { + gotit: + endmntent (fp); + return 1; + } + /* Or allow a mount directory like "/sysroot/...". */ + if (STRPREFIX (m->mnt_dir, sysroot) && m->mnt_dir[sysroot_len] == '/') + goto gotit; + } + + endmntent (fp); + return 0; +} /* The "simple mount" call offers no complex options, you can just * mount a device on a mountpoint. The variations like mount_ro, @@ -44,25 +75,31 @@ int do_mount_vfs (const char *options, const char *vfstype, const char *device, const char *mountpoint) { - int r, is_root; + int r; char *mp; char *error; + struct stat statbuf; ABS_PATH (mountpoint, 0, return -1); - is_root = STREQ (mountpoint, "/"); - - if (!root_mounted && !is_root) { - reply_with_error ("you must mount something on / first"); - return -1; - } - mp = sysroot_path (mountpoint); if (!mp) { reply_with_perror ("malloc"); return -1; } + /* Check the mountpoint exists and is a directory. */ + if (stat (mp, &statbuf) == -1) { + reply_with_perror ("mount: %s", mountpoint); + free (mp); + return -1; + } + if (!S_ISDIR (statbuf.st_mode)) { + reply_with_perror ("mount: %s: mount point is not a directory", mountpoint); + free (mp); + return -1; + } + if (vfstype) r = command (NULL, &error, "mount", "-o", options, "-t", vfstype, device, mp, NULL); @@ -76,9 +113,6 @@ do_mount_vfs (const char *options, const char *vfstype, return -1; } - if (is_root) - root_mounted = 1; - return 0; } @@ -134,8 +168,6 @@ do_umount (const char *pathordevice) free (err); - /* update root_mounted? */ - return 0; } @@ -324,9 +356,6 @@ do_umount_all (void) free_stringslen (mounts, size); - /* We've unmounted root now, so ... */ - root_mounted = 0; - return 0; } @@ -368,8 +397,8 @@ do_mount_loop (const char *file, const char *mountpoint) } /* Specialized calls mkmountpoint and rmmountpoint are really - * variations on mkdir and rmdir which do no checking and (in the - * mkmountpoint case) set the root_mounted flag. + * variations on mkdir and rmdir which do no checking of the + * is_root_mounted() flag. */ int do_mkmountpoint (const char *path) @@ -388,11 +417,6 @@ do_mkmountpoint (const char *path) return -1; } - /* Set the flag so that filesystems can be mounted here, - * not just on /sysroot. - */ - root_mounted = 1; - return 0; } -- 1.7.3.5
Richard W.M. Jones
2011-Jan-27 18:03 UTC
[Libguestfs] [PATCH 2/5] lib: Move appliance launching to separate function.
-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top -------------- next part -------------->From dde59a9daa5cea68af798db0bd3361a58e64ca29 Mon Sep 17 00:00:00 2001From: Richard W.M. Jones <rjones at redhat.com> Date: Thu, 27 Jan 2011 10:12:34 +0000 Subject: [PATCH 2/5] lib: Move appliance launching to separate function. This is just code motion. --- src/launch.c | 38 ++++++++++++++++++++++++-------------- 1 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/launch.c b/src/launch.c index a7a86b9..775f7a6 100644 --- a/src/launch.c +++ b/src/launch.c @@ -70,6 +70,7 @@ #include "guestfs-internal-actions.h" #include "guestfs_protocol.h" +static int launch_appliance (guestfs_h *g); static int qemu_supports (guestfs_h *g, const char *option); /* Add a string to the current command line. */ @@ -350,32 +351,19 @@ static int is_openable (guestfs_h *g, const char *path, int flags); int guestfs__launch (guestfs_h *g) { - int r; - int wfd[2], rfd[2]; - char unixsock[256]; - struct sockaddr_un addr; - /* Configured? */ - if (!g->cmdline) { - error (g, _("you must call guestfs_add_drive before guestfs_launch")); - return -1; - } - if (g->state != CONFIG) { error (g, _("the libguestfs handle has already been launched")); return -1; } - /* Start the clock ... */ - gettimeofday (&g->launch_t, NULL); - /* Make the temporary directory. */ if (!g->tmpdir) { TMP_TEMPLATE_ON_STACK (dir_template); g->tmpdir = safe_strdup (g, dir_template); if (mkdtemp (g->tmpdir) == NULL) { perrorf (g, _("%s: cannot create temporary directory"), dir_template); - goto cleanup0; + return -1; } } @@ -386,6 +374,28 @@ guestfs__launch (guestfs_h *g) if (chmod (g->tmpdir, 0755) == -1) fprintf (stderr, "chmod: %s: %m (ignored)\n", g->tmpdir); + return launch_appliance (g); +} + +static int +launch_appliance (guestfs_h *g) +{ + int r; + int wfd[2], rfd[2]; + char unixsock[256]; + struct sockaddr_un addr; + + /* At present you must add drives before starting the appliance. In + * future when we enable hotplugging you won't need to do this. + */ + if (!g->cmdline) { + error (g, _("you must call guestfs_add_drive before guestfs_launch")); + return -1; + } + + /* Start the clock ... */ + gettimeofday (&g->launch_t, NULL); + /* Locate and/or build the appliance. */ char *kernel = NULL, *initrd = NULL, *appliance = NULL; if (guestfs___build_appliance (g, &kernel, &initrd, &appliance) == -1) -- 1.7.3.5
Richard W.M. Jones
2011-Jan-27 18:03 UTC
[Libguestfs] [PATCH 3/5] New APIs: set-attach-method, get-attach-method.
-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones New in Fedora 11: Fedora Windows cross-compiler. Compile Windows programs, test, and build Windows installers. Over 70 libraries supprt'd http://fedoraproject.org/wiki/MinGW http://www.annexia.org/fedora_mingw -------------- next part -------------->From 80fe4a6e3e7e97611085ac24c339741a75d3c1c4 Mon Sep 17 00:00:00 2001From: Richard W.M. Jones <rjones at redhat.com> Date: Thu, 27 Jan 2011 11:20:43 +0000 Subject: [PATCH 3/5] New APIs: set-attach-method, get-attach-method. These allow you to get and set the attach method. The format is one of: * appliance * unix:<path> It's stored broken out into an enum and a string in the handle. --- generator/generator_actions.ml | 30 ++++++++++++++++++++++++++ src/guestfs-internal.h | 6 +++++ src/guestfs.c | 45 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 0 deletions(-) diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 77f1358..d7f8266 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -1368,6 +1368,36 @@ part of a set. Please read L<guestfs(3)/INSPECTION> for more details."); + ("set_attach_method", (RErr, [String "attachmethod"], []), -1, [FishAlias "attach-method"], + [], + "set the attach method", + "\ +Set the method that libguestfs uses to connect to the back end +guestfsd daemon. Possible methods are: + +=over 4 + +=item C<appliance> + +Launch an appliance and connect to it. This is the ordinary method +and the default. + +=item C<unix:I<path>> + +Connect to the Unix domain socket I<path>. + +This method lets you connect to an existing daemon or (using +virtio-serial) to a live guest. + +=back"); + + ("get_attach_method", (RString "attachmethod", [], []), -1, [], + [InitNone, Always, TestOutput ( + [["get_attach_method"]], "appliance")], + "get the attach method", + "\ +Return the current attach method. See C<guestfs_set_attach_method>."); + ] (* daemon_functions are any functions which cause some action diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index 194c892..0eb395b 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -84,6 +84,9 @@ /* GuestFS handle and connection. */ enum state { CONFIG, LAUNCHING, READY, BUSY, NO_HANDLE }; +/* Attach method. */ +enum attach_method { ATTACH_METHOD_APPLIANCE = 0, ATTACH_METHOD_UNIX }; + struct guestfs_h { struct guestfs_h *next; /* Linked list of open handles. */ @@ -116,6 +119,9 @@ struct guestfs_h char *qemu; /* Qemu binary. */ char *append; /* Append to kernel command line. */ + enum attach_method attach_method; + char *attach_method_arg; + int memsize; /* Size of RAM (megabytes). */ int selinux; /* selinux enabled? */ diff --git a/src/guestfs.c b/src/guestfs.c index 488b658..6849af0 100644 --- a/src/guestfs.c +++ b/src/guestfs.c @@ -647,6 +647,51 @@ guestfs__get_network (guestfs_h *g) return g->enable_network; } +int +guestfs__set_attach_method (guestfs_h *g, const char *method) +{ + if (STREQ (method, "appliance")) { + g->attach_method = ATTACH_METHOD_APPLIANCE; + free (g->attach_method_arg); + g->attach_method_arg = NULL; + } + else if (STRPREFIX (method, "unix:") && strlen (method) > 5) { + g->attach_method = ATTACH_METHOD_UNIX; + free (g->attach_method_arg); + g->attach_method_arg = safe_strdup (g, method + 5); + /* Note that we don't check the path exists until launch is called. */ + } + else { + error (g, "invalid attach method: %s", method); + return -1; + } + + return 0; +} + +char * +guestfs__get_attach_method (guestfs_h *g) +{ + char *ret; + + switch (g->attach_method) { + case ATTACH_METHOD_APPLIANCE: + ret = safe_strdup (g, "appliance"); + break; + + case ATTACH_METHOD_UNIX: + ret = safe_malloc (g, strlen (g->attach_method_arg) + 5 + 1); + strcpy (ret, "unix:"); + strcat (ret, g->attach_method_arg); + break; + + default: /* keep GCC happy - this is not reached */ + abort (); + } + + return ret; +} + void guestfs_set_log_message_callback (guestfs_h *g, guestfs_log_message_cb cb, void *opaque) -- 1.7.3.5
Richard W.M. Jones
2011-Jan-27 18:03 UTC
[Libguestfs] [PATCH 4/5] lib: Implement attach-method unix:<path>
-- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-top is 'top' for virtual machines. Tiny program with many powerful monitoring features, net stats, disk stats, logging, etc. http://et.redhat.com/~rjones/virt-top -------------- next part -------------->From 77914a698bcd1de409e8da653e9663593890d959 Mon Sep 17 00:00:00 2001From: Richard W.M. Jones <rjones at redhat.com> Date: Thu, 27 Jan 2011 15:54:33 +0000 Subject: [PATCH 4/5] lib: Implement attach-method unix:<path> Allow connections to a Unix domain socket which is connected (via virtio-serial) to a guestfsd running free in an existing guest. In order to use this you have to add the following element to the libvirt XML: <channel type='unix'> <source mode='bind' path='/tmp/socket'/> <target type='virtio' name='org.libguestfs.channel.0'/> </channel> (or perform the equivalent on the qemu command line). Then in guestfish, you can do: guestfish -n \ attach-method unix:/tmp/socket : \ run : \ ll / (or any other commands as desired). Note the '-n' option is necessary to stop autosync, which would try to unmount all of the guest's disks. --- src/launch.c | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/proto.c | 19 +++++++----- 2 files changed, 95 insertions(+), 9 deletions(-) diff --git a/src/launch.c b/src/launch.c index 775f7a6..e50985d 100644 --- a/src/launch.c +++ b/src/launch.c @@ -71,6 +71,7 @@ #include "guestfs_protocol.h" static int launch_appliance (guestfs_h *g); +static int connect_unix_socket (guestfs_h *g, const char *sock); static int qemu_supports (guestfs_h *g, const char *option); /* Add a string to the current command line. */ @@ -374,7 +375,17 @@ guestfs__launch (guestfs_h *g) if (chmod (g->tmpdir, 0755) == -1) fprintf (stderr, "chmod: %s: %m (ignored)\n", g->tmpdir); - return launch_appliance (g); + /* Launch the appliance or attach to an existing daemon. */ + switch (g->attach_method) { + case ATTACH_METHOD_APPLIANCE: + return launch_appliance (g); + + case ATTACH_METHOD_UNIX: + return connect_unix_socket (g, g->attach_method_arg); + + default: + abort (); + } } static int @@ -778,6 +789,78 @@ launch_appliance (guestfs_h *g) return -1; } +/* Alternate attach method: instead of launching the appliance, + * connect to an existing unix socket. + */ +static int +connect_unix_socket (guestfs_h *g, const char *sockpath) +{ + int r; + struct sockaddr_un addr; + + /* Start the clock ... */ + gettimeofday (&g->launch_t, NULL); + + /* Set these to nothing so we don't try to kill random processes or + * read from random file descriptors. + */ + g->pid = 0; + g->recoverypid = 0; + g->fd[0] = -1; + g->fd[1] = -1; + + if (g->verbose) + guestfs___print_timestamped_message (g, "connecting to %s", sockpath); + + g->sock = socket (AF_UNIX, SOCK_STREAM, 0); + if (g->sock == -1) { + perrorf (g, "socket"); + return -1; + } + + addr.sun_family = AF_UNIX; + strncpy (addr.sun_path, sockpath, UNIX_PATH_MAX); + addr.sun_path[UNIX_PATH_MAX-1] = '\0'; + + g->state = LAUNCHING; + + if (connect (g->sock, &addr, sizeof addr) == -1) { + perrorf (g, "bind"); + goto cleanup; + } + + if (fcntl (g->sock, F_SETFL, O_NONBLOCK) == -1) { + perrorf (g, "fcntl"); + goto cleanup; + } + + uint32_t size; + void *buf = NULL; + r = guestfs___recv_from_daemon (g, &size, &buf); + free (buf); + + if (r == -1) return -1; + + if (size != GUESTFS_LAUNCH_FLAG) { + error (g, _("guestfs_launch failed, unexpected initial message from guestfsd")); + goto cleanup; + } + + if (g->verbose) + guestfs___print_timestamped_message (g, "connected"); + + if (g->state != READY) { + error (g, _("contacted guestfsd, but state != READY")); + goto cleanup; + } + + return 0; + + cleanup: + close (g->sock); + return -1; +} + /* Return the location of the tmpdir (eg. "/tmp") and allow users * to override it at runtime using $TMPDIR. * http://www.pathname.com/fhs/pub/fhs-2.3.html#TMPTEMPORARYFILES diff --git a/src/proto.c b/src/proto.c index 0d63af6..549734b 100644 --- a/src/proto.c +++ b/src/proto.c @@ -183,8 +183,8 @@ child_cleanup (guestfs_h *g) if (g->recoverypid > 0) kill (g->recoverypid, 9); waitpid (g->pid, NULL, 0); if (g->recoverypid > 0) waitpid (g->recoverypid, NULL, 0); - close (g->fd[0]); - close (g->fd[1]); + if (g->fd[0] >= 0) close (g->fd[0]); + if (g->fd[1] >= 0) close (g->fd[1]); close (g->sock); g->fd[0] = -1; g->fd[1] = -1; @@ -381,7 +381,8 @@ guestfs___send_to_daemon (guestfs_h *g, const void *v_buf, size_t n) FD_ZERO (&rset); FD_ZERO (&wset); - FD_SET (g->fd[1], &rset); /* Read qemu stdout for log messages & EOF. */ + if (g->fd[1] >= 0) /* Read qemu stdout for log messages & EOF. */ + FD_SET (g->fd[1], &rset); FD_SET (g->sock, &rset); /* Read socket for cancellation & EOF. */ FD_SET (g->sock, &wset); /* Write to socket to send the data. */ @@ -398,7 +399,7 @@ guestfs___send_to_daemon (guestfs_h *g, const void *v_buf, size_t n) return -1; } - if (FD_ISSET (g->fd[1], &rset2)) { + if (g->fd[1] >= 0 && FD_ISSET (g->fd[1], &rset2)) { if (read_log_message_or_eof (g, g->fd[1], 0) == -1) return -1; } @@ -460,7 +461,8 @@ guestfs___recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn) FD_ZERO (&rset); - FD_SET (g->fd[1], &rset); /* Read qemu stdout for log messages & EOF. */ + if (g->fd[1] >= 0) /* Read qemu stdout for log messages & EOF. */ + FD_SET (g->fd[1], &rset); FD_SET (g->sock, &rset); /* Read socket for data & EOF. */ int max_fd = MAX (g->sock, g->fd[1]); @@ -492,7 +494,7 @@ guestfs___recv_from_daemon (guestfs_h *g, uint32_t *size_rtn, void **buf_rtn) return -1; } - if (FD_ISSET (g->fd[1], &rset2)) { + if (g->fd[1] >= 0 && FD_ISSET (g->fd[1], &rset2)) { if (read_log_message_or_eof (g, g->fd[1], 0) == -1) { free (*buf_rtn); *buf_rtn = NULL; @@ -650,7 +652,8 @@ guestfs___accept_from_daemon (guestfs_h *g) FD_ZERO (&rset); - FD_SET (g->fd[1], &rset); /* Read qemu stdout for log messages & EOF. */ + if (g->fd[1] >= 0) /* Read qemu stdout for log messages & EOF. */ + FD_SET (g->fd[1], &rset); FD_SET (g->sock, &rset); /* Read socket for accept. */ int max_fd = MAX (g->sock, g->fd[1]); @@ -674,7 +677,7 @@ guestfs___accept_from_daemon (guestfs_h *g) return -1; } - if (FD_ISSET (g->fd[1], &rset2)) { + if (g->fd[1] >= 0 && FD_ISSET (g->fd[1], &rset2)) { if (read_log_message_or_eof (g, g->fd[1], 1) == -1) return -1; } -- 1.7.3.5
Richard W.M. Jones
2011-Jan-27 18:04 UTC
[Libguestfs] [PATCH 5/5] daemon: Allow -r option to set root directory as sysroot.
When guestfsd is free running, it needs to be invoked with this '-r' option so that it operates on the root directory, not on a /sysroot directory. Rich. -- Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://et.redhat.com/~rjones/virt-df/ -------------- next part -------------->From a87514cad8d2d1d31dcdb706e4a4ce2b0167fe3f Mon Sep 17 00:00:00 2001From: Richard W.M. Jones <rjones at redhat.com> Date: Thu, 27 Jan 2011 16:54:48 +0000 Subject: [PATCH 5/5] daemon: Allow -r option to set root directory as sysroot. This allows the user to set the sysroot directory to be the root directory (normally it is "/sysroot"). --- daemon/daemon.h | 20 ++++++++++++-------- daemon/guestfsd.c | 9 +++++++-- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/daemon/daemon.h b/daemon/daemon.h index da991b1..2253b04 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -253,17 +253,21 @@ extern void notify_progress (uint64_t position, uint64_t total); */ #define CHROOT_IN \ do { \ - int __old_errno = errno; \ - if (chroot (sysroot) == -1) \ - perror ("CHROOT_IN: sysroot"); \ - errno = __old_errno; \ + if (sysroot_len > 0) { \ + int __old_errno = errno; \ + if (chroot (sysroot) == -1) \ + perror ("CHROOT_IN: sysroot"); \ + errno = __old_errno; \ + } \ } while (0) #define CHROOT_OUT \ do { \ - int __old_errno = errno; \ - if (chroot (".") == -1) \ - perror ("CHROOT_OUT: ."); \ - errno = __old_errno; \ + if (sysroot_len > 0) { \ + int __old_errno = errno; \ + if (chroot (".") == -1) \ + perror ("CHROOT_OUT: ."); \ + errno = __old_errno; \ + } \ } while (0) /* Marks functions which are not implemented. diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c index 8d950fa..2db1fb7 100644 --- a/daemon/guestfsd.c +++ b/daemon/guestfsd.c @@ -125,13 +125,13 @@ static void usage (void) { fprintf (stderr, - "guestfsd [-f|--foreground] [-v|--verbose]\n"); + "guestfsd [-f|--foreground] [-v|--verbose] [-r]\n"); } int main (int argc, char *argv[]) { - static const char *options = "fv?"; + static const char *options = "frv?"; static const struct option long_options[] = { { "foreground", 0, 0, 'f' }, { "help", 0, 0, '?' }, @@ -171,6 +171,11 @@ main (int argc, char *argv[]) dont_fork = 1; break; + case 'r': + sysroot = ""; + sysroot_len = 0; + break; + case 'v': verbose = 1; break; -- 1.7.3.5
Seemingly Similar Threads
- [PATCH 0/8 v2 DISCUSSION ONLY] Connecting to live virtual machines
- [PATCH febootstrap 0/8] Add support for building an ext2-based appliance
- [PATCH 0/5] 5 conservative changes to errno handling
- [PATCH 0/8] Implement user cancellation
- [PATCH 0/9] Enhance virt-resize so it can really expand Linux and Windows guests