[Libguestfs] [PATCH v3 5/5] fish: Reimplement -i option using new C-based inspection.
Richard W.M. Jones
rjones at redhat.com
Mon Aug 2 17:14:36 UTC 2010
--
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://et.redhat.com/~rjones/libguestfs/
See what it can do: http://et.redhat.com/~rjones/libguestfs/recipes.html
-------------- next part --------------
>From c81043ede1d98092361685da5759aea57800733c Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones at redhat.com>
Date: Mon, 2 Aug 2010 17:43:23 +0100
Subject: [PATCH 5/5] fish: Reimplement -i option using new C-based inspection.
Don't shell out to virt-inspector. Instead, use the new C-based
inspection APIs.
This is much faster.
The new syntax is slightly different:
guestfish -a disk.img -i
guestfish -d guest -i
However, the old syntax still works.
---
fish/Makefile.am | 1 +
fish/fish.c | 154 +++++++++++++---------------------------------------
fish/fish.h | 3 +
fish/guestfish.pod | 37 +++++++------
fish/inspect.c | 78 ++++++++++++++++++++++++++
po/POTFILES.in | 1 +
6 files changed, 139 insertions(+), 135 deletions(-)
create mode 100644 fish/inspect.c
diff --git a/fish/Makefile.am b/fish/Makefile.am
index cd16733..9bc5b73 100644
--- a/fish/Makefile.am
+++ b/fish/Makefile.am
@@ -44,6 +44,7 @@ guestfish_SOURCES = \
fish.c \
fish.h \
glob.c \
+ inspect.c \
lcd.c \
man.c \
more.c \
diff --git a/fish/fish.c b/fish/fish.c
index 71b9827..9968119 100644
--- a/fish/fish.c
+++ b/fish/fish.c
@@ -81,7 +81,6 @@ static void cleanup_readline (void);
#ifdef HAVE_LIBREADLINE
static void add_history_line (const char *);
#endif
-static void print_shell_quote (FILE *stream, const char *str);
/* Currently open libguestfs handle. */
guestfs_h *g;
@@ -125,7 +124,7 @@ usage (int status)
" -d|--domain guest Add disks from libvirt guest\n"
" -D|--no-dest-paths Don't tab-complete paths from guest fs\n"
" -f|--file file Read commands from file\n"
- " -i|--inspector Run virt-inspector to get disk mountpoints\n"
+ " -i|--inspector Automatically mount filesystems\n"
" --keys-from-stdin Read passphrases from stdin\n"
" --listen Listen for remote commands\n"
" -m|--mount dev[:mnt] Mount dev on mnt (if omitted, /)\n"
@@ -227,7 +226,7 @@ main (int argc, char *argv[])
* using it just above.
*
* getopt_long uses argv[0], so give it the sanitized name. Save a copy
- * of the original, in case it's needed in virt-inspector mode, below.
+ * of the original, in case it's needed below.
*/
char *real_argv0 = argv[0];
argv[0] = bad_cast (program_name);
@@ -397,115 +396,46 @@ main (int argc, char *argv[])
}
}
- /* Inspector mode invalidates most of the other arguments. */
- if (inspector) {
- if (drvs || mps || remote_control_listen || remote_control ||
- guestfs_get_selinux (g)) {
- fprintf (stderr, _("%s: cannot use -i option with -a, -m, -N, "
- "--listen, --remote or --selinux\n"),
- program_name);
- exit (EXIT_FAILURE);
- }
- if (optind >= argc) {
- fprintf (stderr,
- _("%s: -i requires a libvirt domain or path(s) to disk image(s)\n"),
- program_name);
- exit (EXIT_FAILURE);
- }
-
- char *cmd;
- size_t cmdlen;
- FILE *fp = open_memstream (&cmd, &cmdlen);
- if (fp == NULL) {
- perror ("open_memstream");
- exit (EXIT_FAILURE);
- }
-
- fprintf (fp, "virt-inspector");
+ /* Old-style -i syntax? Since -a/-d/-N and -i was disallowed
+ * previously, if we have -i without any drives but with something
+ * on the command line, it must be old-style syntax.
+ */
+ if (inspector && drvs == NULL && optind < argc) {
while (optind < argc) {
- fputc (' ', fp);
- print_shell_quote (fp, argv[optind]);
- optind++;
- }
-
- if (read_only)
- fprintf (fp, " --ro-fish");
- else
- fprintf (fp, " --fish");
-
- if (fclose (fp) == -1) {
- perror ("fclose");
- exit (EXIT_FAILURE);
- }
-
- if (verbose)
- fprintf (stderr,
- "%s -i: running: %s\n", program_name, cmd);
-
- FILE *pp = popen (cmd, "r");
- if (pp == NULL) {
- perror (cmd);
- exit (EXIT_FAILURE);
- }
-
- char *cmd2;
- fp = open_memstream (&cmd2, &cmdlen);
- if (fp == NULL) {
- perror ("open_memstream");
- exit (EXIT_FAILURE);
- }
-
- fprintf (fp, "%s", real_argv0);
-
- if (guestfs_get_verbose (g))
- fprintf (fp, " -v");
- if (!guestfs_get_autosync (g))
- fprintf (fp, " -n");
- if (guestfs_get_trace (g))
- fprintf (fp, " -x");
-
- char *insp = NULL;
- size_t insplen;
- if (getline (&insp, &insplen, pp) == -1) {
- perror (cmd);
- exit (EXIT_FAILURE);
- }
- fprintf (fp, " %s", insp);
-
- if (pclose (pp) == -1) {
- perror (cmd);
- exit (EXIT_FAILURE);
- }
-
- if (fclose (fp) == -1) {
- perror ("fclose");
- exit (EXIT_FAILURE);
- }
-
- if (verbose)
- fprintf (stderr,
- "%s -i: running: %s\n", program_name, cmd2);
+ if (strchr (argv[optind], '/') ||
+ access (argv[optind], F_OK) == 0) { /* simulate -a option */
+ drv = malloc (sizeof (struct drv));
+ if (!drv) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+ drv->type = drv_a;
+ drv->a.filename = argv[optind];
+ drv->next = drvs;
+ drvs = drv;
+ } else { /* simulate -d option */
+ drv = malloc (sizeof (struct drv));
+ if (!drv) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+ drv->type = drv_d;
+ drv->d.guest = argv[optind];
+ drv->next = drvs;
+ drvs = drv;
+ }
- int r = system (cmd2);
- if (r == -1) {
- perror (cmd2);
- exit (EXIT_FAILURE);
+ optind++;
}
-
- free (cmd);
- free (cmd2);
- free (insp);
-
- exit (WEXITSTATUS (r));
}
/* If we've got drives to add, add them now. */
add_drives (drvs, 'a');
- /* If we've got mountpoints or prepared drives, we must launch the
- * guest and mount them.
+ /* If we've got mountpoints or prepared drives or -i option, we must
+ * launch the guest and mount them.
*/
- if (next_prepared_drive > 1 || mps != NULL) {
+ if (next_prepared_drive > 1 || mps != NULL || inspector) {
/* RHBZ#612178: If --listen flag is given, then we will fork into
* the background in rc_listen(). However you can't do this while
* holding a libguestfs handle open because the recovery process
@@ -518,6 +448,10 @@ main (int argc, char *argv[])
guestfs_set_recovery_proc (g, 0);
if (launch () == -1) exit (EXIT_FAILURE);
+
+ if (inspector)
+ inspect_mount ();
+
prepare_drives (drvs);
mount_mps (mps);
}
@@ -1839,17 +1773,3 @@ read_key (const char *param)
return ret;
}
-
-static void
-print_shell_quote (FILE *stream, const char *str)
-{
-#define SAFE(c) (c_isalnum((c)) || \
- (c) == '/' || (c) == '-' || (c) == '_' || (c) == '.')
- int i;
-
- for (i = 0; str[i]; ++i) {
- if (!SAFE(str[i]))
- putc ('\\', stream);
- putc (str[i], stream);
- }
-}
diff --git a/fish/fish.h b/fish/fish.h
index bf1f81c..6f8ccd0 100644
--- a/fish/fish.h
+++ b/fish/fish.h
@@ -96,6 +96,9 @@ extern int do_echo (const char *cmd, int argc, char *argv[]);
/* in edit.c */
extern int do_edit (const char *cmd, int argc, char *argv[]);
+/* in inspect.c */
+extern void inspect_mount (void);
+
/* in lcd.c */
extern int do_lcd (const char *cmd, int argc, char *argv[]);
diff --git a/fish/guestfish.pod b/fish/guestfish.pod
index 8daebc8..cf1140a 100644
--- a/fish/guestfish.pod
+++ b/fish/guestfish.pod
@@ -16,9 +16,9 @@ guestfish - the libguestfs Filesystem Interactive SHell
guestfish -d libvirt-domain
- guestfish -i libvirt-domain
+ guestfish -a disk.img -i
- guestfish -i disk.img [disk.img ...]
+ guestfish -d libvirt-domain -i
=head1 WARNING
@@ -75,13 +75,14 @@ Edit C</boot/grub/grub.conf> interactively:
--mount /dev/sda1:/boot \
edit /boot/grub/grub.conf
-=head2 Using virt-inspector
+=head2 Mount disks automatically
-Use the I<-i> option to get virt-inspector to mount
-the filesystems automatically as they would be mounted
-in the virtual machine:
+Use the I<-i> option to automatically mount the
+disks from a virtual machine:
- guestfish --ro -i disk.img cat /etc/group
+ guestfish --ro -a disk.img -i cat /etc/group
+
+ guestfish --ro -d libvirt-domain -i cat /etc/group
=head2 As a script interpreter
@@ -170,28 +171,28 @@ scripts, use:
=item B<-i> | B<--inspector>
-Run virt-inspector on the named libvirt domain or list of disk
-images. If virt-inspector is available and if it can identify
-the domain or disk images, then partitions will be mounted
-correctly at start-up.
+Using L<virt-inspector(1)> code, inspect the disks looking for
+an operating system and mount filesystems as they would be
+mounted on the real virtual machine.
Typical usage is either:
- guestfish -i myguest
+ guestfish -d myguest -i
(for an inactive libvirt domain called I<myguest>), or:
- guestfish --ro -i myguest
+ guestfish --ro -d myguest -i
(for active domains, readonly), or specify the block device directly:
- guestfish -i /dev/Guests/MyGuest
+ guestfish -a /dev/Guests/MyGuest -i
+
+Note that the command line syntax changed slightly over older
+versions of guestfish. You can still use the old syntax:
-You cannot use I<-a>, I<-m>, I<-N>, I<--listen>, I<--remote> or
-I<--selinux> in conjunction with this option, and options other than
-I<--ro> might not behave correctly.
+ guestfish [--ro] -i disk.img
-See also: L<virt-inspector(1)>.
+ guestfish [--ro] -i libvirt-domain
=item B<--keys-from-stdin>
diff --git a/fish/inspect.c b/fish/inspect.c
new file mode 100644
index 0000000..3d46e1d
--- /dev/null
+++ b/fish/inspect.c
@@ -0,0 +1,78 @@
+/* guestfish - the filesystem interactive shell
+ * Copyright (C) 2010 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "fish.h"
+
+static int
+compare_keys (const void *p1, const void *p2)
+{
+ const char *key1 = * (char * const *) p1;
+ const char *key2 = * (char * const *) p2;
+ return strlen (key1) - strlen (key2);
+}
+
+void
+inspect_mount (void)
+{
+ char **roots = guestfs_inspect_os (g);
+ if (roots == NULL)
+ exit (EXIT_FAILURE);
+
+ if (roots[0] == NULL) {
+ fprintf (stderr, _("guestfish: no operating system was found on this disk\n"));
+ exit (EXIT_FAILURE);
+ }
+
+ if (roots[1] != NULL) {
+ fprintf (stderr, _("guestfish: multi-boot operating systems are not supported by the -i option\n"));
+ exit (EXIT_FAILURE);
+ }
+
+ char *root = roots[0];
+ free (roots);
+
+ char **mountpoints = guestfs_inspect_get_mountpoints (g, root);
+ if (mountpoints == NULL)
+ exit (EXIT_FAILURE);
+
+ /* Sort by key length, shortest key first, so that we end up
+ * mounting the filesystems in the correct order.
+ */
+ qsort (mountpoints, count_strings (mountpoints) / 2, 2 * sizeof (char *),
+ compare_keys);
+
+ size_t i;
+ for (i = 0; mountpoints[i] != NULL; i += 2) {
+ int r;
+ if (!read_only)
+ r = guestfs_mount_options (g, "", mountpoints[i+1], mountpoints[i]);
+ else
+ r = guestfs_mount_ro (g, mountpoints[i+1], mountpoints[i]);
+ if (r == -1)
+ exit (EXIT_FAILURE);
+ }
+
+ free (root);
+ free_strings (mountpoints);
+}
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e463bbb..843e8e0 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -76,6 +76,7 @@ fish/echo.c
fish/edit.c
fish/fish.c
fish/glob.c
+fish/inspect.c
fish/lcd.c
fish/man.c
fish/more.c
--
1.7.1
More information about the Libguestfs
mailing list