Added to-xml program.
authorRichard Jones <rjones@redhat.com>
Wed, 15 Apr 2009 11:34:18 +0000 (12:34 +0100)
committerRichard Jones <rjones@redhat.com>
Wed, 15 Apr 2009 11:34:18 +0000 (12:34 +0100)
.gitignore
examples/Makefile.am
examples/README
examples/to-xml.c [new file with mode: 0644]

index 9fb9f04..1b11a24 100644 (file)
@@ -29,8 +29,8 @@ daemon/install-sh
 daemon/missing
 depcomp
 emptydisk
-examples/df
 examples/hello
+examples/to-xml
 fish/guestfish
 guestfish.1
 guestfs.3
index d2187cb..31707b8 100644 (file)
@@ -1,9 +1,13 @@
 # libguestfs examples
 
-noinst_PROGRAMS = hello
+noinst_PROGRAMS = hello to-xml
 
 hello_SOURCES = hello.c
 hello_CFLAGS = -I$(top_builddir)/src -Wall
 hello_LDADD = $(top_builddir)/src/libguestfs.la
 
+to_xml_SOURCES = to-xml.c
+to_xml_CFLAGS = -I$(top_builddir)/src -Wall
+to_xml_LDADD = $(top_builddir)/src/libguestfs.la
+
 CLEANFILES = *~ $(noinst_PROGRAMS)
index 4a6c5d4..77bf6a4 100644 (file)
@@ -4,5 +4,12 @@ libguestfs API.
 As they are examples, these are licensed so they can be freely copied
 and used without any restrictions.
 
-Tip: To enable verbose messages, set environment variable
+Tips:
+
+(1) To enable verbose messages, set environment variable
 LIBGUESTFS_DEBUG=1
+
+(2) If you haven't installed libguestfs, run the examples like this:
+LIBGUESTFS_PATH=. examples/to-xml
+(the path should point to the directory containing vmlinuz.* and
+initramfs.* files).
diff --git a/examples/to-xml.c b/examples/to-xml.c
new file mode 100644 (file)
index 0000000..eba3a7a
--- /dev/null
@@ -0,0 +1,158 @@
+/* This inspects a block device and produces an XML representation of
+ * the partitions, LVM, filesystems that we find there.  This could be
+ * useful as example code of how to do this sort of probing, or to
+ * feed the XML to other programs.
+ *
+ * Usage:
+ *   to-xml guest.img [guest.img ...]
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <guestfs.h>
+
+/* Note that if any API call fails, we can just exit.  The
+ * standard error handler will have printed the error message
+ * to stderr already.
+ */
+#define CALL(call,errcode)                     \
+  if ((call) == (errcode)) exit (1);
+
+static void display_partition (guestfs_h *g, const char *dev);
+static void display_partitions (guestfs_h *g, const char *dev);
+
+int
+main (int argc, char *argv[])
+{
+  guestfs_h *g;
+  int i;
+
+  if (argc < 2 || access (argv[1], F_OK) != 0) {
+    fprintf (stderr, "Usage: to-xml guest.img [guest.img ...]\n");
+    exit (1);
+  }
+
+  if (!(g = guestfs_create ())) {
+    fprintf (stderr, "Cannot create libguestfs handle.\n");
+    exit (1);
+  }
+
+  for (i = 1; i < argc; ++i)
+    CALL (guestfs_add_drive (g, argv[i]), -1);
+
+  CALL (guestfs_launch (g), -1);
+  CALL (guestfs_wait_ready (g), -1);
+
+  printf ("<guestfs-system>\n");
+
+  /* list-devices should return the devices that we just attached?
+   * Better to find out what the kernel thinks are devices anyway ...
+   */
+  char **devices;
+  CALL (devices = guestfs_list_devices (g), NULL);
+  printf ("<devices>\n");
+  for (i = 0; devices[i] != NULL; ++i) {
+    printf ("<device dev=\"%s\">\n", devices[i]);
+    display_partition (g, devices[i]);
+    free (devices[i]);
+    printf ("</device>\n");
+  }
+  free (devices);
+  printf ("</devices>\n");
+
+  /* Now do the same for VGs and LVs.  Note that a VG may span
+   * multiple PVs / block devices, in arbitrary ways, which is
+   * why VGs are in a separate top-level XML class.
+   */
+  char **vgs;
+  char **lvs;
+  printf ("<volgroups>\n");
+  CALL (vgs = guestfs_vgs (g), NULL);
+  CALL (lvs = guestfs_lvs (g), NULL);
+  for (i = 0; vgs[i] != NULL; ++i) {
+    printf ("<volgroup name=\"%s\">\n", vgs[i]);
+
+    /* Just the LVs in this VG. */
+    int len = strlen (vgs[i]);
+    int j;
+    for (j = 0; lvs[j] != NULL; ++j) {
+      if (strncmp (lvs[j], "/dev/", 5) == 0 &&
+         strncmp (&lvs[j][5], vgs[i], len) == 0 &&
+         lvs[j][len+5] == '/') {
+       printf ("<logvol name=\"%s\">\n", lvs[j]);
+       display_partition (g, lvs[j]);
+       printf ("</logvol>\n");
+       free (lvs[j]);
+      }
+    }
+
+    free (vgs[i]);
+    printf ("</volgroup>\n");
+  }
+  free (vgs);
+  free (lvs);
+  printf ("</volgroups>\n");
+
+  guestfs_close (g);
+  printf ("</guestfs-system>\n");
+
+  return 0;
+}
+
+/* Display a partition or LV. */
+static void
+display_partition (guestfs_h *g, const char *dev)
+{
+  char *what;
+
+  CALL (what = guestfs_file (g, dev), NULL);
+
+  if (strstr (what, "boot sector") != NULL)
+    display_partitions (g, dev);
+  else if (strncmp (what, "LVM2", 4) == 0)
+    printf ("<physvol/>\n");
+  else if (strstr (what, "ext2 filesystem data") == 0)
+    printf ("<fs type=\"ext2\"/>\n");
+  else if (strstr (what, "ext3 filesystem data") == 0)
+    printf ("<fs type=\"ext3\"/>\n");
+  else
+    printf ("<unknown/>\n");
+
+  free (what);
+}
+
+/* Display an MBR-formatted boot sector. */
+static void
+display_partitions (guestfs_h *g, const char *dev)
+{
+  /* We can't look into a boot sector which is an LV.  That's
+   * a limitation of sorts of the Linux kernel.  (Actually, we
+   * could do this if we add the kpartx program to libguestfs).
+   */
+  if (strncmp (dev, "/dev/sd", 7) != 0) {
+    printf ("<vm-image dev=\"%s\"/>\n", dev);
+    return;
+  }
+
+  char **parts;
+  int i, len;
+  CALL (parts = guestfs_list_partitions (g), NULL);
+  printf ("<partitions>\n");
+
+  len = strlen (dev);
+  for (i = 0; parts[i] != NULL; ++i) {
+    /* Only display partition if it's in the device. */
+    if (strncmp (parts[i], dev, len) == 0) {
+      printf ("<partition dev=\"%s\">\n", parts[i]);
+      display_partition (g, parts[i]);
+      printf ("</partition>\n");
+    }
+
+    free (parts[i]);
+  }
+  free (parts);
+  printf ("</partitions>\n");
+}