X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=rescue%2Fvirt-rescue.c;h=9a354b823c7c2f03c800fc560299ac929bd1d05c;hp=dd033aa5711e4b8389d8597e971ae259f1b739b2;hb=edd502543adbdc2fa5dda0c015ea7c390bb39f64;hpb=9bab154d48e367702b65852c3c822341b474ffd2 diff --git a/rescue/virt-rescue.c b/rescue/virt-rescue.c index dd033aa..9a354b8 100644 --- a/rescue/virt-rescue.c +++ b/rescue/virt-rescue.c @@ -13,7 +13,7 @@ * * 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. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include @@ -36,6 +36,8 @@ #include "guestfs.h" #include "options.h" +static void do_suggestion (struct drv *drvs); + /* Currently open libguestfs handle. */ guestfs_h *g; @@ -77,6 +79,8 @@ usage (int status) " --network Enable network\n" " -r|--ro Access read-only\n" " --selinux Enable SELinux\n" + " --smp N Enable SMP with N >= 2 virtual CPUs\n" + " --suggest Suggest mount commands for this guest\n" " -v|--verbose Verbose messages\n" " -V|--version Display version and exit\n" " -w|--rw Mount read-write\n" @@ -115,6 +119,8 @@ main (int argc, char *argv[]) { "ro", 0, 0, 'r' }, { "rw", 0, 0, 'w' }, { "selinux", 0, 0, 0 }, + { "smp", 1, 0, 0 }, + { "suggest", 0, 0, 0 }, { "verbose", 0, 0, 'v' }, { "version", 0, 0, 'V' }, { 0, 0, 0, 0 } @@ -128,6 +134,8 @@ main (int argc, char *argv[]) const char *append = NULL; char *append_full; int memsize = 0; + int smp = 0; + int suggest = 0; g = guestfs_create (); if (g == NULL) { @@ -154,6 +162,19 @@ main (int argc, char *argv[]) format = NULL; else format = optarg; + } else if (STREQ (long_options[option_index].name, "smp")) { + if (sscanf (optarg, "%u", &smp) != 1) { + fprintf (stderr, _("%s: could not parse --smp parameter '%s'\n"), + program_name, optarg); + exit (EXIT_FAILURE); + } + if (smp < 1) { + fprintf (stderr, _("%s: --smp parameter '%s' should be >= 1\n"), + program_name, optarg); + exit (EXIT_FAILURE); + } + } else if (STREQ (long_options[option_index].name, "suggest")) { + suggest = 1; } else { fprintf (stderr, _("%s: unknown long option: %s (%d)\n"), program_name, long_options[option_index].name, option_index); @@ -245,6 +266,12 @@ main (int argc, char *argv[]) } } + /* --suggest flag */ + if (suggest) { + do_suggestion (drvs); + exit (EXIT_SUCCESS); + } + /* These are really constants, but they have to be variables for the * options parsing code. Assert here that they have known-good * values. @@ -270,6 +297,8 @@ main (int argc, char *argv[]) guestfs_set_memsize (g, memsize); if (network) guestfs_set_network (g, 1); + if (smp >= 1) + guestfs_set_smp (g, smp); /* Kernel command line must include guestfs_rescue=1 (see * appliance/init) as well as other options. @@ -294,21 +323,164 @@ main (int argc, char *argv[]) /* We expect launch to fail, so ignore the return value. */ ignore_value (guestfs_launch (g)); - /* launch() expects guestfsd to start. However, virt-rescue doesn't - * run guestfsd, so this will always fail with ECHILD when the - * appliance exits unexpectedly. + guestfs_close (g); + + exit (EXIT_SUCCESS); +} + +static void suggest_filesystems (void); + +static int +compare_keys_len (const void *p1, const void *p2) +{ + const char *key1 = * (char * const *) p1; + const char *key2 = * (char * const *) p2; + return strlen (key1) - strlen (key2); +} + +static size_t +count_strings (char *const *argv) +{ + size_t i; + + for (i = 0; argv[i]; ++i) + ; + return i; +} + +/* virt-rescue --suggest flag does a kind of inspection on the + * drives and suggests mount commands that you should use. + */ +static void +do_suggestion (struct drv *drvs) +{ + char **roots; + size_t i, j; + char *type, *distro, *product_name; + int major, minor; + char **mps; + + /* For inspection, force add_drives to add the drives read-only. */ + read_only = 1; + + /* Add drives. */ + add_drives (drvs, 'a'); + + /* Free up data structures, no longer needed after this point. */ + free_drives (drvs); + + printf (_("Inspecting the virtual machine or disk image ...\n\n")); + fflush (stdout); + + if (guestfs_launch (g) == -1) + exit (EXIT_FAILURE); + + /* Don't use inspect_mount, since for virt-rescue we should allow + * arbitrary disks and disks with more than one OS on them. Let's + * do this using the basic API instead. */ - if (errno != ECHILD) { - fprintf (stderr, "%s: %s\n", program_name, guestfs_last_error (g)); - guestfs_close (g); + roots = guestfs_inspect_os (g); + if (roots == NULL) exit (EXIT_FAILURE); + + if (roots[0] == NULL) { + suggest_filesystems (); + return; } - guestfs_close (g); + printf (_("This disk contains one or more operating systems. You can use these mount\n" + "commands in virt-rescue (at the > prompt) to mount the filesystems.\n\n")); + + for (i = 0; roots[i] != NULL; ++i) { + type = guestfs_inspect_get_type (g, roots[i]); + distro = guestfs_inspect_get_distro (g, roots[i]); + product_name = guestfs_inspect_get_product_name (g, roots[i]); + major = guestfs_inspect_get_major_version (g, roots[i]); + minor = guestfs_inspect_get_minor_version (g, roots[i]); + + printf (_("# %s is the root of a %s operating system\n" + "# type: %s, distro: %s, version: %d.%d\n" + "# %s\n\n"), + roots[i], type ? : "unknown", + type ? : "unknown", distro ? : "unknown", major, minor, + product_name ? : ""); + + mps = guestfs_inspect_get_mountpoints (g, roots[i]); + if (mps == NULL) + exit (EXIT_FAILURE); - exit (EXIT_SUCCESS); + /* Sort by key length, shortest key first, so that we end up + * mounting the filesystems in the correct order. + */ + qsort (mps, count_strings (mps) / 2, 2 * sizeof (char *), + compare_keys_len); + + for (j = 0; mps[j] != NULL; j += 2) { + printf ("mount %s /sysroot%s\n", mps[j+1], mps[j]); + free (mps[j]); + free (mps[j+1]); + } + + /* If it's Linux, print the bind-mounts. */ + if (type && STREQ (type, "linux")) { + printf ("mount --bind /dev /sysroot/dev\n"); + printf ("mount --bind /dev/pts /sysroot/dev/pts\n"); + printf ("mount --bind /proc /sysroot/proc\n"); + printf ("mount --bind /sys /sysroot/sys\n"); + } + + printf ("\n"); + + free (type); + free (distro); + free (product_name); + free (roots[i]); + } + + free (roots); } +/* Inspection failed, so it doesn't contain any OS that we recognise. + * However there might still be filesystems so print some suggestions + * for those. + */ +static void +suggest_filesystems (void) +{ + char **fses; + size_t i; + + fses = guestfs_list_filesystems (g); + if (fses == NULL) + exit (EXIT_FAILURE); + + if (fses[0] == NULL) { + printf (_("This disk contains no filesystems that we recognize.\n\n" + "However you can still use virt-rescue on the disk image, to try to mount\n" + "filesystems that are not recognized by libguestfs, or to create partitions,\n" + "logical volumes and filesystems on a blank disk.\n")); + return; + } + + printf (_("This disk contains one or more filesystems, but we don't recognize any\n" + "operating system. You can use these mount commands in virt-rescue (at the\n" + "> prompt) to mount these filesystems.\n\n")); + + for (i = 0; fses[i] != NULL; i += 2) { + printf (_("# %s has type '%s'\n"), fses[i], fses[i+1]); + + if (STRNEQ (fses[i+1], "swap") && STRNEQ (fses[i+1], "unknown")) + printf ("mount %s /sysroot\n", fses[i]); + + printf ("\n"); + + free (fses[i]); + free (fses[i+1]); + } + free (fses); +} + + /* The following was a nice idea, but in fact it doesn't work. This is * because qemu has some (broken) pty emulation itself. */