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