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
 daemon/missing
 depcomp
 emptydisk
-examples/df
 examples/hello
 examples/hello
+examples/to-xml
 fish/guestfish
 guestfish.1
 guestfs.3
 fish/guestfish
 guestfish.1
 guestfs.3
index d2187cb..31707b8 100644 (file)
@@ -1,9 +1,13 @@
 # libguestfs examples
 
 # 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
 
 
 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)
 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.
 
 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
 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");
+}