/* virt-inspector
- * 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
#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 <libxml/xmlIO.h>
#include <libxml/xmlwriter.h>
guestfs_h *g;
int read_only = 1;
+int live = 0;
int verbose = 0;
int keys_from_stdin = 0;
int echo_keys = 0;
static void output_root (xmlTextWriterPtr xo, char *root);
static void output_mountpoints (xmlTextWriterPtr xo, char *root);
static void output_filesystems (xmlTextWriterPtr xo, char *root);
+static void output_drive_mappings (xmlTextWriterPtr xo, char *root);
static void output_applications (xmlTextWriterPtr xo, char *root);
static void canonicalize (char *dev);
static void free_strings (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) {
*/
assert (read_only == 1);
assert (inspector == 1);
+ assert (live == 0);
/* Must be no extra arguments on the command line. */
if (optind != argc)
output_root (xmlTextWriterPtr xo, char *root)
{
char *str;
- int i;
+ int i, r;
char buf[32];
char canonical_root[strlen (root) + 1];
+ size_t size;
XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "operatingsystem"));
xmlTextWriterWriteElement (xo, BAD_CAST "product_name", BAD_CAST str));
free (str);
+ str = guestfs_inspect_get_product_variant (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ XMLERROR (-1,
+ xmlTextWriterWriteElement (xo, BAD_CAST "product_variant", BAD_CAST str));
+ free (str);
+
i = guestfs_inspect_get_major_version (g, root);
snprintf (buf, sizeof buf, "%d", i);
XMLERROR (-1,
BAD_CAST str));
free (str);
);
+ DISABLE_GUESTFS_ERRORS_FOR (
+ str = guestfs_inspect_get_windows_current_control_set (g, root);
+ if (str)
+ XMLERROR (-1,
+ xmlTextWriterWriteElement (xo, BAD_CAST "windows_current_control_set",
+ BAD_CAST str));
+ free (str);
+ );
+
+ str = guestfs_inspect_get_hostname (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ XMLERROR (-1,
+ xmlTextWriterWriteElement (xo, BAD_CAST "hostname",
+ BAD_CAST str));
+ free (str);
+
+ str = guestfs_inspect_get_format (g, root);
+ if (!str) exit (EXIT_FAILURE);
+ if (STRNEQ (str, "unknown"))
+ XMLERROR (-1,
+ xmlTextWriterWriteElement (xo, BAD_CAST "format",
+ BAD_CAST str));
+ free (str);
+
+ r = guestfs_inspect_is_live (g, root);
+ if (r > 0) {
+ XMLERROR (-1,
+ xmlTextWriterStartElement (xo, BAD_CAST "live"));
+ XMLERROR (-1, xmlTextWriterEndElement (xo));
+ }
+
+ r = guestfs_inspect_is_netinst (g, root);
+ if (r > 0) {
+ XMLERROR (-1,
+ xmlTextWriterStartElement (xo, BAD_CAST "netinst"));
+ XMLERROR (-1, xmlTextWriterEndElement (xo));
+ }
+
+ r = guestfs_inspect_is_multipart (g, root);
+ if (r > 0) {
+ XMLERROR (-1,
+ xmlTextWriterStartElement (xo, BAD_CAST "multipart"));
+ XMLERROR (-1, xmlTextWriterEndElement (xo));
+ }
output_mountpoints (xo, root);
output_filesystems (xo, root);
+ output_drive_mappings (xo, root);
+
+ /* We need to mount everything up in order to read out the list of
+ * applications and the icon, ie. everything below this point.
+ */
+ inspect_mount_root (root);
+
output_applications (xo, root);
+ /* Don't return favicon. XXX Should we? */
+ str = guestfs_inspect_get_icon (g, root, &size,
+ GUESTFS_INSPECT_GET_ICON_FAVICON, 0,
+ -1);
+ if (!str) exit (EXIT_FAILURE);
+ if (size > 0) {
+ XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "icon"));
+ XMLERROR (-1, xmlTextWriterWriteBase64 (xo, str, 0, size));
+ XMLERROR (-1, xmlTextWriterEndElement (xo));
+ }
+ /* Note we must free (str) even if size == 0, because that indicates
+ * there was no icon.
+ */
+ free (str);
+
+ /* Unmount (see inspect_mount_root above). */
+ if (guestfs_umount_all (g) == -1)
+ exit (EXIT_FAILURE);
+
XMLERROR (-1, xmlTextWriterEndElement (xo));
}
}
static int
+compare_keys_nocase (const void *p1, const void *p2)
+{
+ const char *key1 = * (char * const *) p1;
+ const char *key2 = * (char * const *) p2;
+
+ return strcasecmp (key1, key2);
+}
+
+static int
compare_keys_len (const void *p1, const void *p2)
{
const char *key1 = * (char * const *) p1;
}
static void
+output_drive_mappings (xmlTextWriterPtr xo, char *root)
+{
+ char **drive_mappings = NULL;
+ size_t i;
+
+ DISABLE_GUESTFS_ERRORS_FOR (
+ drive_mappings = guestfs_inspect_get_drive_mappings (g, root);
+ );
+ if (drive_mappings == NULL)
+ return;
+
+ if (drive_mappings[0] == NULL) {
+ free_strings (drive_mappings);
+ return;
+ }
+
+ /* Sort by key. */
+ qsort (drive_mappings,
+ count_strings (drive_mappings) / 2, 2 * sizeof (char *),
+ compare_keys_nocase);
+
+ XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "drive_mappings"));
+
+ for (i = 0; drive_mappings[i] != NULL; i += 2) {
+ canonicalize (drive_mappings[i+1]);
+
+ XMLERROR (-1,
+ xmlTextWriterStartElement (xo, BAD_CAST "drive_mapping"));
+ XMLERROR (-1,
+ xmlTextWriterWriteAttribute (xo, BAD_CAST "name",
+ BAD_CAST drive_mappings[i]));
+ XMLERROR (-1,
+ xmlTextWriterWriteString (xo, BAD_CAST drive_mappings[i+1]));
+ XMLERROR (-1, xmlTextWriterEndElement (xo));
+ }
+
+ XMLERROR (-1, xmlTextWriterEndElement (xo));
+
+ free_strings (drive_mappings);
+}
+
+static void
output_applications (xmlTextWriterPtr xo, char *root)
{
struct guestfs_application_list *apps;
size_t i;
- /* We need to mount everything up in order to read out the list of
- * applications.
- */
- inspect_mount_root (root);
-
/* This returns an empty list if we simply couldn't determine the
* applications, so if it returns NULL then it's a real error.
*/
apps = guestfs_inspect_list_applications (g, root);
if (apps == NULL)
exit (EXIT_FAILURE);
- if (guestfs_umount_all (g) == -1)
- exit (EXIT_FAILURE);
XMLERROR (-1, xmlTextWriterStartElement (xo, BAD_CAST "applications"));
(dev[5] == 'h' || dev[5] == 'v') &&
dev[6] == 'd' &&
c_isalpha (dev[7]) &&
- c_isdigit (dev[8]))
+ (c_isdigit (dev[8]) || dev[8] == '\0'))
dev[5] = 's';
}