daemon: debug segv correct use of dereferencing NULL.
[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 = NULL;
49   size_t ret_size = 0;
50
51   char **devices = NULL;
52   char **partitions = NULL;
53   char **mds = NULL;
54   char **lvs = NULL;
55
56   /* Look to see if any devices directly contain filesystems
57    * (RHBZ#590167).  However vfs-type will fail to tell us anything
58    * useful about devices which just contain partitions, so we also
59    * get the list of partitions and exclude the corresponding devices
60    * by using part-to-dev.
61    */
62   devices = guestfs_list_devices (g);
63   if (devices == NULL) goto error;
64   partitions = guestfs_list_partitions (g);
65   if (partitions == NULL) goto error;
66   mds = guestfs_list_md_devices (g);
67   if (mds == NULL) goto error;
68
69   for (i = 0; partitions[i] != NULL; ++i) {
70     char *dev = guestfs_part_to_dev (g, partitions[i]);
71     if (dev)
72       remove_from_list (devices, dev);
73     free (dev);
74   }
75
76   /* Use vfs-type to check for filesystems on devices. */
77   for (i = 0; devices[i] != NULL; ++i)
78     check_with_vfs_type (g, devices[i], &ret, &ret_size);
79
80   /* Use vfs-type to check for filesystems on partitions. */
81   for (i = 0; partitions[i] != NULL; ++i)
82     check_with_vfs_type (g, partitions[i], &ret, &ret_size);
83
84   /* Use vfs-type to check for filesystems on md devices. */
85   for (i = 0; mds[i] != NULL; ++i)
86     check_with_vfs_type (g, mds[i], &ret, &ret_size);
87
88   if (guestfs___feature_available (g, "lvm2")) {
89     /* Use vfs-type to check for filesystems on LVs. */
90     lvs = guestfs_lvs (g);
91     if (lvs == NULL) goto error;
92
93     for (i = 0; lvs[i] != NULL; ++i)
94       check_with_vfs_type (g, lvs[i], &ret, &ret_size);
95   }
96
97   guestfs___free_string_list (devices);
98   guestfs___free_string_list (partitions);
99   guestfs___free_string_list (mds);
100   if (lvs) guestfs___free_string_list (lvs);
101   return ret;
102
103  error:
104   if (devices) guestfs___free_string_list (devices);
105   if (partitions) guestfs___free_string_list (partitions);
106   if (mds) guestfs___free_string_list (mds);
107   if (lvs) guestfs___free_string_list (lvs);
108   if (ret) guestfs___free_string_list (ret);
109   return NULL;
110 }
111
112 /* If 'item' occurs in 'list', remove and free it. */
113 static void
114 remove_from_list (char **list, const char *item)
115 {
116   size_t i;
117
118   for (i = 0; list[i] != NULL; ++i)
119     if (STREQ (list[i], item)) {
120       free (list[i]);
121       for (; list[i+1] != NULL; ++i)
122         list[i] = list[i+1];
123       list[i] = NULL;
124       return;
125     }
126 }
127
128 /* Use vfs-type to look for a filesystem of some sort on 'dev'.
129  * Apart from some types which we ignore, add the result to the
130  * 'ret' string list.
131  */
132 static void
133 check_with_vfs_type (guestfs_h *g, const char *device,
134                      char ***ret, size_t *ret_size)
135 {
136   char *v;
137
138   guestfs_error_handler_cb old_error_cb = g->error_cb;
139   g->error_cb = NULL;
140   char *vfs_type = guestfs_vfs_type (g, device);
141   g->error_cb = old_error_cb;
142
143   if (!vfs_type)
144     v = safe_strdup (g, "unknown");
145   else if (STREQ (vfs_type, "")) {
146     free (vfs_type);
147     v = safe_strdup (g, "unknown");
148   }
149   else {
150     /* Ignore all "*_member" strings.  In libblkid these are returned
151      * for things which are members of some RAID or LVM set, most
152      * importantly "LVM2_member" which is a PV.
153      */
154     size_t n = strlen (vfs_type);
155     if (n >= 7 && STREQ (&vfs_type[n-7], "_member")) {
156       free (vfs_type);
157       return;
158     }
159
160     /* Ignore LUKS-encrypted partitions.  These are also containers. */
161     if (STREQ (vfs_type, "crypto_LUKS")) {
162       free (vfs_type);
163       return;
164     }
165
166     v = vfs_type;
167   }
168
169   /* Extend the return array. */
170   size_t i = *ret_size;
171   *ret_size += 2;
172   *ret = safe_realloc (g, *ret, (*ret_size + 1) * sizeof (char *));
173   (*ret)[i] = safe_strdup (g, device);
174   (*ret)[i+1] = v;
175   (*ret)[i+2] = NULL;
176 }