eba3a7a3d6d8ebb8ee8289ad1a42cb9f62936f13
[libguestfs.git] / examples / to-xml.c
1 /* This inspects a block device and produces an XML representation of
2  * the partitions, LVM, filesystems that we find there.  This could be
3  * useful as example code of how to do this sort of probing, or to
4  * feed the XML to other programs.
5  *
6  * Usage:
7  *   to-xml guest.img [guest.img ...]
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <unistd.h>
14
15 #include <guestfs.h>
16
17 /* Note that if any API call fails, we can just exit.  The
18  * standard error handler will have printed the error message
19  * to stderr already.
20  */
21 #define CALL(call,errcode)                      \
22   if ((call) == (errcode)) exit (1);
23
24 static void display_partition (guestfs_h *g, const char *dev);
25 static void display_partitions (guestfs_h *g, const char *dev);
26
27 int
28 main (int argc, char *argv[])
29 {
30   guestfs_h *g;
31   int i;
32
33   if (argc < 2 || access (argv[1], F_OK) != 0) {
34     fprintf (stderr, "Usage: to-xml guest.img [guest.img ...]\n");
35     exit (1);
36   }
37
38   if (!(g = guestfs_create ())) {
39     fprintf (stderr, "Cannot create libguestfs handle.\n");
40     exit (1);
41   }
42
43   for (i = 1; i < argc; ++i)
44     CALL (guestfs_add_drive (g, argv[i]), -1);
45
46   CALL (guestfs_launch (g), -1);
47   CALL (guestfs_wait_ready (g), -1);
48
49   printf ("<guestfs-system>\n");
50
51   /* list-devices should return the devices that we just attached?
52    * Better to find out what the kernel thinks are devices anyway ...
53    */
54   char **devices;
55   CALL (devices = guestfs_list_devices (g), NULL);
56   printf ("<devices>\n");
57   for (i = 0; devices[i] != NULL; ++i) {
58     printf ("<device dev=\"%s\">\n", devices[i]);
59     display_partition (g, devices[i]);
60     free (devices[i]);
61     printf ("</device>\n");
62   }
63   free (devices);
64   printf ("</devices>\n");
65
66   /* Now do the same for VGs and LVs.  Note that a VG may span
67    * multiple PVs / block devices, in arbitrary ways, which is
68    * why VGs are in a separate top-level XML class.
69    */
70   char **vgs;
71   char **lvs;
72   printf ("<volgroups>\n");
73   CALL (vgs = guestfs_vgs (g), NULL);
74   CALL (lvs = guestfs_lvs (g), NULL);
75   for (i = 0; vgs[i] != NULL; ++i) {
76     printf ("<volgroup name=\"%s\">\n", vgs[i]);
77
78     /* Just the LVs in this VG. */
79     int len = strlen (vgs[i]);
80     int j;
81     for (j = 0; lvs[j] != NULL; ++j) {
82       if (strncmp (lvs[j], "/dev/", 5) == 0 &&
83           strncmp (&lvs[j][5], vgs[i], len) == 0 &&
84           lvs[j][len+5] == '/') {
85         printf ("<logvol name=\"%s\">\n", lvs[j]);
86         display_partition (g, lvs[j]);
87         printf ("</logvol>\n");
88         free (lvs[j]);
89       }
90     }
91
92     free (vgs[i]);
93     printf ("</volgroup>\n");
94   }
95   free (vgs);
96   free (lvs);
97   printf ("</volgroups>\n");
98
99   guestfs_close (g);
100   printf ("</guestfs-system>\n");
101
102   return 0;
103 }
104
105 /* Display a partition or LV. */
106 static void
107 display_partition (guestfs_h *g, const char *dev)
108 {
109   char *what;
110
111   CALL (what = guestfs_file (g, dev), NULL);
112
113   if (strstr (what, "boot sector") != NULL)
114     display_partitions (g, dev);
115   else if (strncmp (what, "LVM2", 4) == 0)
116     printf ("<physvol/>\n");
117   else if (strstr (what, "ext2 filesystem data") == 0)
118     printf ("<fs type=\"ext2\"/>\n");
119   else if (strstr (what, "ext3 filesystem data") == 0)
120     printf ("<fs type=\"ext3\"/>\n");
121   else
122     printf ("<unknown/>\n");
123
124   free (what);
125 }
126
127 /* Display an MBR-formatted boot sector. */
128 static void
129 display_partitions (guestfs_h *g, const char *dev)
130 {
131   /* We can't look into a boot sector which is an LV.  That's
132    * a limitation of sorts of the Linux kernel.  (Actually, we
133    * could do this if we add the kpartx program to libguestfs).
134    */
135   if (strncmp (dev, "/dev/sd", 7) != 0) {
136     printf ("<vm-image dev=\"%s\"/>\n", dev);
137     return;
138   }
139
140   char **parts;
141   int i, len;
142   CALL (parts = guestfs_list_partitions (g), NULL);
143   printf ("<partitions>\n");
144
145   len = strlen (dev);
146   for (i = 0; parts[i] != NULL; ++i) {
147     /* Only display partition if it's in the device. */
148     if (strncmp (parts[i], dev, len) == 0) {
149       printf ("<partition dev=\"%s\">\n", parts[i]);
150       display_partition (g, parts[i]);
151       printf ("</partition>\n");
152     }
153
154     free (parts[i]);
155   }
156   free (parts);
157   printf ("</partitions>\n");
158 }