Implement libvirt calls.
[virt-kernel-info.git] / src / main.c
index 5de205a..787ec4c 100644 (file)
@@ -24,6 +24,8 @@
 #include <string.h>
 #include <assert.h>
 #include <getopt.h>
+#include <errno.h>
+#include <limits.h>
 
 #include <libvirt/libvirt.h>
 #include <libvirt/virterror.h>
@@ -245,26 +247,34 @@ static void usage (void)
   struct tool *t;
 
   printf (_("\
+\n\
 virt-kernel-info: Tools for providing information about virtual machines\n\
 \n\
 General usage is:\n\
+\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\
+where <tool> is 'virt-dmesg' etc. (full list below) or a subtool\n\
+such as 'virt-kernel-info dmesg', '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\
+  -c | --connect <libvirt-uri>\n\
+                        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\
+  -t | --image <image>  Examine saved image (see: virt-kernel-info capture)\n\
+  --version             Print program name and version, then exit\n\
+  -x | --externaldb <externaldb>\n\
+                        Load/override external kernels database\n\
 \n\
 These options may be used to override automatic detection of guest\n\
-architecture, endianness, kernel location, etc.:\n\
+architecture, endianness, kernel location, etc.  The default for all\n\
+of them is 'auto':\n\
+\n\
   -A | --arch      auto | <arch> | ...\n\
   -E | --endian    auto | le | be\n\
   --kernel-min     auto | <arch> | ... | 0x<addr>\n\
@@ -294,15 +304,7 @@ List of tools:\n\
 static void
 load_externaldb (const char *externaldb, int fail_if_no_externaldb)
 {
-
-
-
-
-
-
-
-
-  NOT_IMPL;
+  //NOT_IMPL;
 }
 
 static void
@@ -311,16 +313,99 @@ do_list_kernels (void)
   NOT_IMPL;
 }
 
+static void
+discard_virterror (void *user_data, virErrorPtr err)
+{
+  /* nothing */
+}
+
+/* Get all running domains, named by domname/ID/UUID. */
 static virDomainPtr *
-get_named_domains (char * const *domains, int nr_domains)
+get_named_domains (char * const *domains, int n)
 {
-  NOT_IMPL;
+  assert (conn != NULL);
+
+  virDomainPtr *doms = malloc (sizeof (virDomainPtr) * (n+1));
+  if (doms == NULL) {
+    perror ("malloc");
+    exit (1);
+  }
+
+  /* Discard 'domain not found' errors from libvirt while we
+   * run this loop.
+   */
+  virConnSetErrorFunc (conn, NULL, discard_virterror);
+
+  int i;
+  for (i = 0; i < n; ++i) {
+    /* Try in the order: UUID, name, ID. */
+    doms[i] = virDomainLookupByUUIDString (conn, domains[i]);
+    if (!doms[i]) {
+      doms[i] = virDomainLookupByName (conn, domains[i]);
+      if (!doms[i] && domains[i][0] >= '0' && domains[i][0] <= '9') {
+        errno = 0;
+        char *endptr;
+        int id = strtol (domains[i], &endptr, 10);
+        if ((errno == ERANGE && (id == LONG_MAX || id == LONG_MIN)) ||
+            (errno != 0 && id == 0)) {
+          perror ("strtol");
+          exit (EXIT_FAILURE);
+        }
+        if (endptr == domains[i])
+          error (_("no digits found while trying to parse ID '%s'"),
+                 domains[i]);
+        if (*endptr)
+          error (_("parse error, extra digits after ID '%s'"),
+                 domains[i]);
+        doms[i] = virDomainLookupByID (conn, id);
+      }
+    }
+
+    if (!doms[i])
+      error (_("%s: libvirt guest not found (use name, UUID or ID here)"),
+             domains[i]);
+
+    if (!virDomainIsActive (doms[i]))
+      error (_("%s: this domain is inactive.  This program only works on running guests."),
+             virDomainGetName (doms[i]));
+  }
+
+  /* Restore default virterror behaviour. */
+  virConnSetErrorFunc (conn, NULL, NULL);
+
+  return doms;
 }
 
+/* Get all (running) domains. */
 static virDomainPtr *
 get_all_domains (void)
 {
-  NOT_IMPL;
+  assert (conn != NULL);
+
+  int n;
+  n = virConnectNumOfDomains (conn);
+  if (n == -1)
+    error (_("failed to get number of domains"));
+
+  int ids[n];
+  n = virConnectListDomains (conn, ids, n);
+  if (n == -1)
+    error (_("failed to list domains"));
+
+  int i, j;
+  virDomainPtr *doms = malloc (sizeof (virDomainPtr) * (n+1));
+  if (doms == NULL) {
+    perror ("malloc");
+    exit (1);
+  }
+  for (i = 0; i < n; ++i) {
+    /* Ignore failures, but don't increment 'j' if that happens. */
+    doms[j] = virDomainLookupByID (conn, ids[i]);
+    if (doms[j]) j++;
+  }
+
+  doms[j] = NULL;
+  return doms;
 }
 
 /* Tools register themselves by calling this function.  Note that the
@@ -348,7 +433,7 @@ register_tool (struct tool *tool)
 static void
 message (const char *pre, const char *fs, va_list args)
 {
-  fprintf (stderr, "%s-%s: %s: ", PACKAGE_NAME, PACKAGE_VERSION, pre);
+  fprintf (stderr, "%s: %s: ", PACKAGE_NAME, pre);
   vfprintf (stderr, fs, args);
   fprintf (stderr, "\n");
 }