Add test for qemu broken -machine option (RHBZ#748266).
[libguestfs.git] / src / listfs.c
1 /* libguestfs
2  * Copyright (C) 2010 Red Hat Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library 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 GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <inttypes.h>
25 #include <unistd.h>
26 #include <string.h>
27 #include <sys/stat.h>
28
29 #include "guestfs.h"
30 #include "guestfs-internal.h"
31 #include "guestfs-internal-actions.h"
32 #include "guestfs_protocol.h"
33
34 /* List filesystems.
35  *
36  * The current implementation just uses guestfs_vfs_type and doesn't
37  * try mounting anything, but we reserve the right in future to try
38  * mounting filesystems.
39  */
40
41 static void remove_from_list (char **list, const char *item);
42 static void check_with_vfs_type (guestfs_h *g, const char *dev, char ***ret, size_t *ret_size);
43
44 char **
45 guestfs__list_filesystems (guestfs_h *g)
46 {
47   size_t i;
48   char **ret;
49   size_t ret_size;
50
51   ret = safe_malloc (g, sizeof (char *));
52   ret[0] = NULL;
53   ret_size = 0;
54
55   /* Look to see if any devices directly contain filesystems
56    * (RHBZ#590167).  However vfs-type will fail to tell us anything
57    * useful about devices which just contain partitions, so we also
58    * get the list of partitions and exclude the corresponding devices
59    * by using part-to-dev.
60    */
61   char **devices;
62   devices = guestfs_list_devices (g);
63   if (devices == NULL) {
64     guestfs___free_string_list (ret);
65     return NULL;
66   }
67   char **partitions;
68   partitions = guestfs_list_partitions (g);
69   if (partitions == NULL) {
70     guestfs___free_string_list (devices);
71     guestfs___free_string_list (ret);
72     return NULL;
73   }
74
75   for (i = 0; partitions[i] != NULL; ++i) {
76     char *dev = guestfs_part_to_dev (g, partitions[i]);
77     if (dev)
78       remove_from_list (devices, dev);
79     free (dev);
80   }
81
82   /* Use vfs-type to check for filesystems on devices. */
83   for (i = 0; devices[i] != NULL; ++i)
84     check_with_vfs_type (g, devices[i], &ret, &ret_size);
85   guestfs___free_string_list (devices);
86
87   /* Use vfs-type to check for filesystems on partitions. */
88   for (i = 0; partitions[i] != NULL; ++i)
89     check_with_vfs_type (g, partitions[i], &ret, &ret_size);
90   guestfs___free_string_list (partitions);
91
92   if (guestfs___feature_available (g, "lvm2")) {
93     /* Use vfs-type to check for filesystems on LVs. */
94     char **lvs;
95     lvs = guestfs_lvs (g);
96     if (lvs == NULL) {
97       guestfs___free_string_list (ret);
98       return NULL;
99     }
100
101     for (i = 0; lvs[i] != NULL; ++i)
102       check_with_vfs_type (g, lvs[i], &ret, &ret_size);
103     guestfs___free_string_list (lvs);
104   }
105
106   return ret;
107 }
108
109 /* If 'item' occurs in 'list', remove and free it. */
110 static void
111 remove_from_list (char **list, const char *item)
112 {
113   size_t i;
114
115   for (i = 0; list[i] != NULL; ++i)
116     if (STREQ (list[i], item)) {
117       free (list[i]);
118       for (; list[i+1] != NULL; ++i)
119         list[i] = list[i+1];
120       list[i] = NULL;
121       return;
122     }
123 }
124
125 /* Use vfs-type to look for a filesystem of some sort on 'dev'.
126  * Apart from some types which we ignore, add the result to the
127  * 'ret' string list.
128  */
129 static void
130 check_with_vfs_type (guestfs_h *g, const char *device,
131                      char ***ret, size_t *ret_size)
132 {
133   char *v;
134
135   guestfs_error_handler_cb old_error_cb = g->error_cb;
136   g->error_cb = NULL;
137   char *vfs_type = guestfs_vfs_type (g, device);
138   g->error_cb = old_error_cb;
139
140   if (!vfs_type)
141     v = safe_strdup (g, "unknown");
142   else if (STREQ (vfs_type, "")) {
143     free (vfs_type);
144     v = safe_strdup (g, "unknown");
145   }
146   else {
147     /* Ignore all "*_member" strings.  In libblkid these are returned
148      * for things which are members of some RAID or LVM set, most
149      * importantly "LVM2_member" which is a PV.
150      */
151     size_t n = strlen (vfs_type);
152     if (n >= 7 && STREQ (&vfs_type[n-7], "_member")) {
153       free (vfs_type);
154       return;
155     }
156
157     /* Ignore LUKS-encrypted partitions.  These are also containers. */
158     if (STREQ (vfs_type, "crypto_LUKS")) {
159       free (vfs_type);
160       return;
161     }
162
163     v = vfs_type;
164   }
165
166   /* Extend the return array. */
167   size_t i = *ret_size;
168   *ret_size += 2;
169   *ret = safe_realloc (g, *ret, (*ret_size + 1) * sizeof (char *));
170   (*ret)[i] = safe_strdup (g, device);
171   (*ret)[i+1] = v;
172   (*ret)[i+2] = NULL;
173 }