configure: Add --with-extra flag to allow setting the extra version string.
[libguestfs.git] / df / df.c
1 /* virt-df
2  * Copyright (C) 2010-2011 Red Hat Inc.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <string.h>
25 #include <inttypes.h>
26
27 #ifdef HAVE_LIBVIRT
28 #include <libvirt/libvirt.h>
29 #include <libvirt/virterror.h>
30 #endif
31
32 #include "progname.h"
33
34 #include "guestfs.h"
35 #include "options.h"
36 #include "virt-df.h"
37
38 static void try_df (const char *name, const char *uuid, const char *dev, int offset);
39 static int find_dev_in_devices (const char *dev, char **devices);
40
41 /* Since we want this function to be robust against very bad failure
42  * cases (hello, https://bugzilla.kernel.org/show_bug.cgi?id=18792) it
43  * won't exit on guestfs failures.
44  */
45 int
46 df_on_handle (const char *name, const char *uuid, char **devices, int offset)
47 {
48   int ret = -1;
49   size_t i;
50   char **fses = NULL;
51   int free_devices = 0, is_lv;
52
53   if (verbose) {
54     fprintf (stderr, "df_on_handle %s devices=", name);
55     if (devices) {
56       fputc ('[', stderr);
57       for (i = 0; devices[i] != NULL; ++i) {
58         if (i > 0)
59           fputc (' ', stderr);
60         fputs (devices[i], stderr);
61       }
62       fputc (']', stderr);
63     }
64     else
65       fprintf (stderr, "null");
66     fputc ('\n', stderr);
67   }
68
69   if (devices == NULL) {
70     devices = guestfs_list_devices (g);
71     if (devices == NULL)
72       goto cleanup;
73     free_devices = 1;
74   } else {
75     /* Mask LVM for just the devices in the set. */
76     if (guestfs_lvm_set_filter (g, devices) == -1)
77       goto cleanup;
78   }
79
80   /* list-filesystems will return filesystems on every device ... */
81   fses = guestfs_list_filesystems (g);
82   if (fses == NULL)
83     goto cleanup;
84
85   /* ... so we need to filter out only the devices we are interested in. */
86   for (i = 0; fses[i] != NULL; i += 2) {
87     if (STRNEQ (fses[i+1], "") &&
88         STRNEQ (fses[i+1], "swap") &&
89         STRNEQ (fses[i+1], "unknown")) {
90       is_lv = guestfs_is_lv (g, fses[i]);
91       if (is_lv > 0)        /* LVs are OK because of the LVM filter */
92         try_df (name, uuid, fses[i], -1);
93       else if (is_lv == 0) {
94         if (find_dev_in_devices (fses[i], devices))
95           try_df (name, uuid, fses[i], offset);
96       }
97     }
98   }
99
100   ret = 0;
101
102  cleanup:
103   if (fses) {
104     for (i = 0; fses[i] != NULL; ++i)
105       free (fses[i]);
106     free (fses);
107   }
108
109   if (free_devices) {
110     for (i = 0; devices[i] != NULL; ++i)
111       free (devices[i]);
112     free (devices);
113   }
114
115   return ret;
116 }
117
118 static int
119 find_dev_in_devices (const char *dev, char **devices)
120 {
121   size_t i;
122
123   for (i = 0; devices[i] != NULL; ++i) {
124     if (STRPREFIX (dev, devices[i]))
125       return 1;
126   }
127
128   return 0;
129 }
130
131 static void
132 try_df (const char *name, const char *uuid,
133         const char *dev, int offset)
134 {
135   struct guestfs_statvfs *stat = NULL;
136   guestfs_error_handler_cb old_error_cb;
137   void *old_error_data;
138
139   if (verbose)
140     fprintf (stderr, "try_df %s %s %d\n", name, dev, offset);
141
142   /* Try mounting and stating the device.  This might reasonably fail,
143    * so don't show errors.
144    */
145   old_error_cb = guestfs_get_error_handler (g, &old_error_data);
146   guestfs_set_error_handler (g, NULL, NULL);
147
148   if (guestfs_mount_ro (g, dev, "/") == 0) {
149     stat = guestfs_statvfs (g, "/");
150     guestfs_umount_all (g);
151   }
152
153   guestfs_set_error_handler (g, old_error_cb, old_error_data);
154
155   if (stat) {
156     print_stat (name, uuid, dev, offset, stat);
157     guestfs_free_statvfs (stat);
158   }
159 }