X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=cat%2Fvirt-cat.c;h=4d37ddab72b25bd69924bf85d5ab7cbdb9773cc7;hp=ebae8952216af9ff7fc9a08ef262b1d804f42762;hb=edd502543adbdc2fa5dda0c015ea7c390bb39f64;hpb=b875f8e115842b37e6c7c9e59cb263a1cbb334aa diff --git a/cat/virt-cat.c b/cat/virt-cat.c index ebae895..4d37dda 100644 --- a/cat/virt-cat.c +++ b/cat/virt-cat.c @@ -1,5 +1,5 @@ /* virt-cat - * Copyright (C) 2010 Red Hat Inc. + * Copyright (C) 2010-2011 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 @@ -13,19 +13,23 @@ * * 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 #include #include +#include #include #include #include +#include #include +#include #include "progname.h" +#include "c-ctype.h" #include "guestfs.h" #include "options.h" @@ -34,12 +38,16 @@ guestfs_h *g; int read_only = 1; +int live = 0; int verbose = 0; int keys_from_stdin = 0; int echo_keys = 0; const char *libvirt_uri = NULL; int inspector = 1; +static int is_windows (guestfs_h *g, const char *root); +static char *windows_path (guestfs_h *g, const char *root, const char *filename); + static inline char * bad_cast (char const *s) { @@ -104,11 +112,9 @@ main (int argc, char *argv[]) }; struct drv *drvs = NULL; struct drv *drv; - char *p, *file = NULL; const char *format = NULL; int c; int option_index; - int next_prepared_drive = 1; g = guestfs_create (); if (g == NULL) { @@ -215,6 +221,7 @@ main (int argc, char *argv[]) */ assert (read_only == 1); assert (inspector == 1); + assert (live == 0); /* User must specify at least one filename on the command line. */ if (optind >= argc || argc - optind < 1) @@ -238,14 +245,147 @@ main (int argc, char *argv[]) free_drives (drvs); unsigned errors = 0; + int windows; + char *root, **roots; + + /* Get root mountpoint. See: fish/inspect.c:inspect_mount */ + roots = guestfs_inspect_get_roots (g); + assert (roots); + assert (roots[0] != NULL); + assert (roots[1] == NULL); + root = roots[0]; + free (roots); + + /* Windows? Special handling is required. */ + windows = is_windows (g, root); + + for (; optind < argc; optind++) { + char *filename_to_free = NULL; + const char *filename = argv[optind]; + + if (windows) { + filename = filename_to_free = windows_path (g, root, filename); + if (filename == NULL) { + errors++; + continue; + } + } - while (optind < argc) { - if (guestfs_download (g, argv[optind], "/dev/stdout") == -1) + if (guestfs_download (g, filename, "/dev/stdout") == -1) errors++; - optind++; + + free (filename_to_free); } + free (root); + guestfs_close (g); exit (errors == 0 ? EXIT_SUCCESS : EXIT_FAILURE); } + +static int +is_windows (guestfs_h *g, const char *root) +{ + char *type; + int w; + + type = guestfs_inspect_get_type (g, root); + if (!type) + return 0; + + w = STREQ (type, "windows"); + free (type); + return w; +} + +static void mount_drive_letter_ro (char drive_letter, const char *root); + +static char * +windows_path (guestfs_h *g, const char *root, const char *path) +{ + char *ret; + size_t i; + + /* If there is a drive letter, rewrite the path. */ + if (c_isalpha (path[0]) && path[1] == ':') { + char drive_letter = c_tolower (path[0]); + /* This returns the newly allocated string. */ + mount_drive_letter_ro (drive_letter, root); + ret = strdup (path + 2); + if (ret == NULL) { + perror ("strdup"); + exit (EXIT_FAILURE); + } + } + else if (!*path) { + ret = strdup ("/"); + if (ret == NULL) { + perror ("strdup"); + exit (EXIT_FAILURE); + } + } + else { + ret = strdup (path); + if (ret == NULL) { + perror ("strdup"); + exit (EXIT_FAILURE); + } + } + + /* Blindly convert any backslashes into forward slashes. Is this good? */ + for (i = 0; i < strlen (ret); ++i) + if (ret[i] == '\\') + ret[i] = '/'; + + /* If this fails, we want to return NULL. */ + char *t = guestfs_case_sensitive_path (g, ret); + free (ret); + ret = t; + + return ret; +} + +static void +mount_drive_letter_ro (char drive_letter, const char *root) +{ + char **drives; + char *device; + size_t i; + + /* Resolve the drive letter using the drive mappings table. */ + drives = guestfs_inspect_get_drive_mappings (g, root); + if (drives == NULL || drives[0] == NULL) { + fprintf (stderr, _("%s: to use Windows drive letters, this must be a Windows guest\n"), + program_name); + exit (EXIT_FAILURE); + } + + device = NULL; + for (i = 0; drives[i] != NULL; i += 2) { + if (c_tolower (drives[i][0]) == drive_letter && drives[i][1] == '\0') { + device = drives[i+1]; + break; + } + } + + if (device == NULL) { + fprintf (stderr, _("%s: drive '%c:' not found.\n"), + program_name, drive_letter); + exit (EXIT_FAILURE); + } + + /* Unmount current disk and remount device. */ + if (guestfs_umount_all (g) == -1) + exit (EXIT_FAILURE); + + if (guestfs_mount_ro (g, device, "/") == -1) + exit (EXIT_FAILURE); + + for (i = 0; drives[i] != NULL; ++i) + free (drives[i]); + free (drives); + /* Don't need to free (device) because that string was in the + * drives array. + */ +}