63e896da75a9a9d1bc581d2e01943b09fc874ebc
[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 static void display_ext23 (guestfs_h *g, const char *dev, const char *fstype);
27
28 int
29 main (int argc, char *argv[])
30 {
31   guestfs_h *g;
32   int i;
33
34   if (argc < 2 || access (argv[1], F_OK) != 0) {
35     fprintf (stderr, "Usage: to-xml guest.img [guest.img ...]\n");
36     exit (1);
37   }
38
39   if (!(g = guestfs_create ())) {
40     fprintf (stderr, "Cannot create libguestfs handle.\n");
41     exit (1);
42   }
43
44   for (i = 1; i < argc; ++i)
45     CALL (guestfs_add_drive (g, argv[i]), -1);
46
47   CALL (guestfs_launch (g), -1);
48   CALL (guestfs_wait_ready (g), -1);
49
50   printf ("<guestfs-system>\n");
51
52   /* list-devices should return the devices that we just attached?
53    * Better to find out what the kernel thinks are devices anyway ...
54    */
55   char **devices;
56   CALL (devices = guestfs_list_devices (g), NULL);
57   printf ("<devices>\n");
58   for (i = 0; devices[i] != NULL; ++i) {
59     printf ("<device dev=\"%s\">\n", devices[i]);
60     display_partition (g, devices[i]);
61     free (devices[i]);
62     printf ("</device>\n");
63   }
64   free (devices);
65   printf ("</devices>\n");
66
67   /* Now do the same for VGs and LVs.  Note that a VG may span
68    * multiple PVs / block devices, in arbitrary ways, which is
69    * why VGs are in a separate top-level XML class.
70    */
71   char **vgs;
72   char **lvs;
73   printf ("<volgroups>\n");
74   CALL (vgs = guestfs_vgs (g), NULL);
75   CALL (lvs = guestfs_lvs (g), NULL);
76   for (i = 0; vgs[i] != NULL; ++i) {
77     printf ("<volgroup name=\"%s\">\n", vgs[i]);
78
79     /* Just the LVs in this VG. */
80     int len = strlen (vgs[i]);
81     int j;
82     for (j = 0; lvs[j] != NULL; ++j) {
83       if (strncmp (lvs[j], "/dev/", 5) == 0 &&
84           strncmp (&lvs[j][5], vgs[i], len) == 0 &&
85           lvs[j][len+5] == '/') {
86         printf ("<logvol name=\"%s\">\n", lvs[j]);
87         display_partition (g, lvs[j]);
88         printf ("</logvol>\n");
89         free (lvs[j]);
90       }
91     }
92
93     free (vgs[i]);
94     printf ("</volgroup>\n");
95   }
96   free (vgs);
97   free (lvs);
98   printf ("</volgroups>\n");
99
100   guestfs_close (g);
101   printf ("</guestfs-system>\n");
102
103   return 0;
104 }
105
106 /* Display a partition or LV. */
107 static void
108 display_partition (guestfs_h *g, const char *dev)
109 {
110   char *what;
111
112   CALL (what = guestfs_file (g, dev), NULL);
113
114   if (strstr (what, "boot sector") != NULL)
115     display_partitions (g, dev);
116   else if (strncmp (what, "LVM2", 4) == 0)
117     printf ("<physvol/>\n");
118   else if (strstr (what, "ext2 filesystem data") != NULL)
119     display_ext23 (g, dev, "ext2");
120   else if (strstr (what, "ext3 filesystem data") != NULL)
121     display_ext23 (g, dev, "ext3");
122   else if (strstr (what, "Linux/i386 swap file") != NULL)
123     printf ("<linux-swap/>\n");
124   else
125     printf ("<unknown/>\n");
126
127   free (what);
128 }
129
130 /* Display an MBR-formatted boot sector. */
131 static void
132 display_partitions (guestfs_h *g, const char *dev)
133 {
134   /* We can't look into a boot sector which is an LV.  That's
135    * a limitation of sorts of the Linux kernel.  (Actually, we
136    * could do this if we add the kpartx program to libguestfs).
137    */
138   if (strncmp (dev, "/dev/sd", 7) != 0) {
139     printf ("<vm-image dev=\"%s\"/>\n", dev);
140     return;
141   }
142
143   char **parts;
144   int i, len;
145   CALL (parts = guestfs_list_partitions (g), NULL);
146   printf ("<partitions>\n");
147
148   len = strlen (dev);
149   for (i = 0; parts[i] != NULL; ++i) {
150     /* Only display partition if it's in the device. */
151     if (strncmp (parts[i], dev, len) == 0) {
152       printf ("<partition dev=\"%s\">\n", parts[i]);
153       display_partition (g, parts[i]);
154       printf ("</partition>\n");
155     }
156
157     free (parts[i]);
158   }
159   free (parts);
160   printf ("</partitions>\n");
161 }
162
163 /* Display some details on the ext2/3 filesystem on dev. */
164 static void
165 display_ext23 (guestfs_h *g, const char *dev, const char *fstype)
166 {
167   char **sbfields;
168   int i;
169
170   printf ("<fs type=\"%s\">\n", fstype);
171   CALL (sbfields = guestfs_tune2fs_l (g, dev), NULL);
172
173   for (i = 0; sbfields[i] != NULL; i += 2) {
174     /* Just pick out a few important fields to display.  There
175      * is much more that could be displayed here.
176      */
177     if (strcmp (sbfields[i], "Filesystem UUID") == 0)
178       printf ("<uuid>%s</uuid>\n", sbfields[i+1]);
179     else if (strcmp (sbfields[i], "Block size") == 0)
180       printf ("<blocksize>%s</blocksize>\n", sbfields[i+1]);
181
182     free (sbfields[i]);
183     free (sbfields[i+1]);
184   }
185   free (sbfields);
186
187   printf ("</fs>\n");
188 }