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