/* 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
*
* 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 <config.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <inttypes.h>
#include <unistd.h>
#include <getopt.h>
+#include <locale.h>
#include <assert.h>
+#include <libintl.h>
#include "progname.h"
+#include "c-ctype.h"
#include "guestfs.h"
#include "options.h"
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)
{
*/
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)
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.
+ */
+}