[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