From 7fe2b338e4102a23ecd2f89b447b7618f0e93312 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Wed, 15 Apr 2009 12:34:18 +0100 Subject: [PATCH] Added to-xml program. --- .gitignore | 2 +- examples/Makefile.am | 6 +- examples/README | 9 ++- examples/to-xml.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 examples/to-xml.c diff --git a/.gitignore b/.gitignore index 9fb9f04..1b11a24 100644 --- a/.gitignore +++ b/.gitignore @@ -29,8 +29,8 @@ daemon/install-sh daemon/missing depcomp emptydisk -examples/df examples/hello +examples/to-xml fish/guestfish guestfish.1 guestfs.3 diff --git a/examples/Makefile.am b/examples/Makefile.am index d2187cb..31707b8 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -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) diff --git a/examples/README b/examples/README index 4a6c5d4..77bf6a4 100644 --- a/examples/README +++ b/examples/README @@ -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 index 0000000..eba3a7a --- /dev/null +++ b/examples/to-xml.c @@ -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 +#include +#include +#include + +#include + +/* 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 ("\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 ("\n"); + for (i = 0; devices[i] != NULL; ++i) { + printf ("\n", devices[i]); + display_partition (g, devices[i]); + free (devices[i]); + printf ("\n"); + } + free (devices); + printf ("\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 ("\n"); + CALL (vgs = guestfs_vgs (g), NULL); + CALL (lvs = guestfs_lvs (g), NULL); + for (i = 0; vgs[i] != NULL; ++i) { + printf ("\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 ("\n", lvs[j]); + display_partition (g, lvs[j]); + printf ("\n"); + free (lvs[j]); + } + } + + free (vgs[i]); + printf ("\n"); + } + free (vgs); + free (lvs); + printf ("\n"); + + guestfs_close (g); + printf ("\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 ("\n"); + else if (strstr (what, "ext2 filesystem data") == 0) + printf ("\n"); + else if (strstr (what, "ext3 filesystem data") == 0) + printf ("\n"); + else + printf ("\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 ("\n", dev); + return; + } + + char **parts; + int i, len; + CALL (parts = guestfs_list_partitions (g), NULL); + printf ("\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 ("\n", parts[i]); + display_partition (g, parts[i]); + printf ("\n"); + } + + free (parts[i]); + } + free (parts); + printf ("\n"); +} -- 1.8.3.1