+/* Kernel info for virtual domains.
+ * (C) Copyright 2008-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 <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include <getopt.h>
+
+#include <libvirt/libvirt.h>
+#include <libvirt/virterror.h>
+
+#include "internal.h"
+
+/* Global flags. */
+int csv = 0;
+int debug = 0;
+
+/* Linked list of registered tools. */
+static struct tool *tools = NULL;
+
+/* Currently selected tool (may be NULL). */
+struct tool *tool = NULL;
+
+/* External DB location. */
+static const char *externaldb = DATADIR "/" PACKAGE_NAME "/kerneldb";
+static int fail_if_no_externaldb = 0;
+
+/* URI and libvirt connection. */
+static const char *uri = NULL;
+static virConnectPtr conn = NULL;
+
+/* If -t option was passed, this is the filename of the test image. */
+static const char *test_image = NULL;
+
+/* If --list-kernels was passed. */
+static int list_kernels = 0;
+
+/* Local functions. */
+static void load_externaldb (const char *, int);
+static void do_list_kernels (void) ATTRIBUTE_NORETURN;
+static void usage (void) ATTRIBUTE_NORETURN;
+
+static virDomainPtr *get_named_domains (char * const*, int);
+static virDomainPtr *get_all_domains (void);
+
+int
+main (int argc, char *argv[])
+{
+ int c;
+
+ /* argv[0] can be the name of the tool, or if not recognized then
+ * the name of the tool must be the first anonymous argument.
+ */
+ if (argv[0]) {
+ const char *prog = strrchr (argv[0], '/');
+
+ if (!prog)
+ prog = argv[0];
+
+ if (STRCASEEQLEN (prog+1, "virt-", 5)) {
+ struct tool *t;
+
+ prog += 6;
+
+ for (t = tools; t != NULL; t = t->next) {
+ if (STRCASEEQ (prog, t->name)) {
+ tool = t;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Parse command line parameters. */
+ while (1) {
+ static const char *shortopts = "A:E:T:W:c:dt:x:?";
+ static struct option longopts[] = {
+ { "arch", required_argument, 0, 'A' },
+ { "endian", required_argument, 0, 'E' },
+ { "kernel-min", required_argument, 0, 0 },
+ { "kernel-max", required_argument, 0, 0 },
+ { "text", required_argument, 0, 'T' },
+ { "wordsize", required_argument, 0, 'W' },
+ { "connect", required_argument, 0, 'c' },
+ { "csv", no_argument, 0, 0 },
+ { "debug", no_argument, 0, 'd' },
+ { "help", no_argument, 0, '?' },
+ { "list-kernels", no_argument, 0, 0 },
+ { "image", required_argument, 0, 't' },
+ { "externaldb", required_argument, 0, 'x' },
+ { "version", no_argument, 0, 0 }
+ };
+ int option_index = 0;
+
+ c = getopt_long (argc, argv, shortopts, longopts, &option_index);
+ if (c == -1) break;
+
+ switch (c) {
+ case 0: { /* longopt without short equivalent */
+ const char *longopt_name = longopts[option_index].name;
+
+ if (STRCASEEQ (longopt_name, "csv")) /* csv output */
+ csv = 1;
+ /* list kernels and exit */
+ else if (STRCASEEQ (longopt_name, "list-kernels"))
+ list_kernels = 1;
+ /* set kernel-min */
+ else if (STRCASEEQ (longopt_name, "kernel-min"))
+ NOT_IMPL;
+ /* set kernel-max */
+ else if (STRCASEEQ (longopt_name, "kernel-max"))
+ NOT_IMPL;
+ /* display version and exit */
+ else if (STRCASEEQ (longopt_name, "version")) {
+ printf ("%s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ exit (0);
+ }
+ else
+ INTERNAL_ERROR; /* this shouldn't happen */
+
+ break;
+ }
+
+ case 'A': /* set architecture */
+ NOT_IMPL;
+ case 'E': /* set endianness */
+ NOT_IMPL;
+ case 'T': /* set text address */
+ NOT_IMPL;
+ case 'W': /* set wordsize */
+ NOT_IMPL;
+
+ case 'c': /* connect to URI */
+ uri = optarg;
+ break;
+
+ case 'd': /* enable debugging */
+ debug = 1;
+ break;
+
+ case 't': /* load kernel image */
+ test_image = optarg;
+ break;
+
+ case 'x': /* location of external database */
+ externaldb = optarg;
+ fail_if_no_externaldb = 1;
+ break;
+
+ case '?': /* print help */
+ usage ();
+
+ default:
+ INTERNAL_ERROR; /* this shouldn't happen */
+ }
+ } /* while */
+
+ /* Load the external database / kernel updates, if necessary. */
+ load_externaldb (externaldb, fail_if_no_externaldb);
+
+ /* If asked, list kernels and exit. */
+ if (list_kernels)
+ do_list_kernels ();
+
+ /* If we haven't got a tool name yet, then the first anon parameter
+ * must be a tool name.
+ */
+ if (!tool) {
+ if (optind < argc) {
+ const char *p;
+ struct tool *t;
+
+ p = argv[optind++];
+
+ for (t = tools; t != NULL; t = t->next) {
+ if (STRCASEEQ (p, t->name)) {
+ tool = t;
+ goto found_tool;
+ }
+ }
+
+ error (_("'%s' is not a recognized virt-kernel-info tool.\n\nMake sure you specify the virt-kernel-info tool as the first argument on the command line. To get a list of recognized tools, use 'virt-kernel-info --help'."), p);
+ } else
+ error (_("Could not work out which virt-kernel-info tool you are trying to use.\n\nMake sure you specify the virt-kernel-info tool as the first argument on the command line. To get a list of recognized tools, use 'virt-kernel-info --help'."));
+
+ found_tool: ;
+ }
+
+ /* We should have worked out which tool it is by now. */
+ assert (tool != NULL);
+
+ /* If -t was passed, then we load that forensic image, else we have
+ * to connect to libvirt.
+ */
+ if (test_image) {
+ if (optind < argc)
+ error (_("If '-t' is passed then there shouldn't be any additional command line arguments."));
+
+ NOT_IMPL;
+ }
+ else {
+ virDomainPtr *doms;
+
+ /* Connect to libvirt. */
+ conn = virConnectOpenReadOnly (uri);
+ if (!conn)
+ error (_("failed to connect to hypervisor '%s'.\nWhen connecting to some hypervisors you may need to be running as root.\nThere may be a more detailed error message above this, but if not then we didn't print one because libvirt's virterror mechanism is next to useless."),
+ uri != NULL ? uri : _("default"));
+
+ /* Extra parameters are a list of domain names, IDs or UUIDs. */
+ if (optind < argc)
+ doms = get_named_domains (&argv[optind], argc - optind);
+ else
+ doms = get_all_domains ();
+
+ /* Act on each domain. */
+ NOT_IMPL;
+ }
+
+ exit (0);
+}
+
+/* Usage. */
+static void usage (void)
+{
+ struct tool *t;
+
+ printf (_("\
+virt-kernel-info: Tools for providing information about virtual machines\n\
+\n\
+General usage is:\n\
+ <tool> [-options]\n\
+ <tool> [-options] [domain-name|ID|UUID ...]\n\
+ <tool> [-options] -t <image>\n\
+where <tool> is 'virt-ps', 'virt-dmesg' etc. (full list below) or a\n\
+subtool such as 'virt-kernel-info ps', 'virt-kernel-info capture' etc.\n\
+\n\
+General options:\n\
+ --connect | -c <libvirt-uri> Connect to URI (default: autodetect)\n\
+ --csv Output in CSV format for spreadsheets etc.\n\
+ --debug Print extra debugging information\n\
+ --list-kernels List known kernels, then exit\n\
+ --image | -t <image> Examine saved image (see: virt-kernel-info capture)\n\
+ --externaldb | -x <externaldb> Load/override external kernels database\n\
+ --version Print program name and version, then exit\n\
+\n\
+These options may be used to override automatic detection of guest\n\
+architecture, endianness, kernel location, etc.:\n\
+ -A | --arch auto | <arch> | ...\n\
+ -E | --endian auto | le | be\n\
+ --kernel-min auto | <arch> | ... | 0x<addr>\n\
+ --kernel-max auto | <arch> | ... | 0x<addr>\n\
+ -T | --text auto | <arch> | ... | 0x<addr>\n\
+ -W | --wordsize auto | 32 | 64\n\
+where <arch> is the name of an architecture such as i386, x86-64, etc.\n\
+\n\
+List of tools:\n\
+"));
+
+ for (t = tools; t != NULL; t = t->next) {
+ printf ("\n");
+
+ if (t->external_cmd)
+ printf (" virt-%-12s - %s\n", t->name, t->summary);
+ else
+ printf (" virt-kernel-info %8s - %s\n", t->name, t->summary);
+
+ printf ("%s", t->description);
+ if (t->next) printf ("\n");
+ }
+
+ exit (0);
+}
+
+static void
+load_externaldb (const char *externaldb, int fail_if_no_externaldb)
+{
+
+
+
+
+
+
+
+
+ NOT_IMPL;
+}
+
+static void
+do_list_kernels (void)
+{
+ NOT_IMPL;
+}
+
+static virDomainPtr *
+get_named_domains (char * const *domains, int nr_domains)
+{
+ NOT_IMPL;
+}
+
+static virDomainPtr *
+get_all_domains (void)
+{
+ NOT_IMPL;
+}
+
+/* Tools register themselves by calling this function. Note that the
+ * function is called from constructors. In particular it is called
+ * before main(). Also can be called in unspecified order.
+ */
+void
+register_tool (struct tool *tool)
+{
+ struct tool *t, **p;
+
+ /* Insertion sort. */
+ p = &tools;
+ for (t = tools; t != NULL; t = t->next) {
+ if (strcmp (t->name, tool->name) < 0)
+ goto insert;
+ p = &t->next;
+ }
+ insert:
+ tool->next = *p;
+ *p = tool;
+}
+
+/* Warning, error message functions. See internal.h for usage. */
+static void
+message (const char *pre, const char *fs, va_list args)
+{
+ fprintf (stderr, "%s-%s: %s: ", PACKAGE_NAME, PACKAGE_VERSION, pre);
+ vfprintf (stderr, fs, args);
+ fprintf (stderr, "\n");
+}
+
+void
+error (const char *fs, ...)
+{
+ va_list args;
+ va_start (args, fs);
+ message (_("error"), fs, args);
+ va_end (args);
+ exit (1);
+}
+
+void
+warning (const char *fs, ...)
+{
+ va_list args;
+ va_start (args, fs);
+ message (_("warning"), fs, args);
+ va_end (args);
+}
+
+void
+internal_error (const char *fs, ...)
+{
+ va_list args;
+ va_start (args, fs);
+ message (_("internal error"), fs, args);
+ va_end (args);
+ abort ();
+}