Files
libguestfs/lib/listfs.c
Richard W.M. Jones f161c9ea57 Rename src/ to lib/
2017-01-26 15:05:46 +00:00

246 lines
7.1 KiB
C

/* libguestfs
* Copyright (C) 2010 Red Hat Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "guestfs.h"
#include "guestfs-internal.h"
#include "guestfs-internal-actions.h"
/* List filesystems.
*
* The current implementation just uses guestfs_vfs_type and doesn't
* try mounting anything, but we reserve the right in future to try
* mounting filesystems.
*/
static void remove_from_list (char **list, const char *item);
static int check_with_vfs_type (guestfs_h *g, const char *dev, struct stringsbuf *sb);
static int is_mbr_partition_type_42 (guestfs_h *g, const char *partition);
char **
guestfs_impl_list_filesystems (guestfs_h *g)
{
size_t i;
DECLARE_STRINGSBUF (ret);
const char *lvm2[] = { "lvm2", NULL };
const int has_lvm2 = guestfs_feature_available (g, (char **) lvm2);
const char *ldm[] = { "ldm", NULL };
const int has_ldm = guestfs_feature_available (g, (char **) ldm);
CLEANUP_FREE_STRING_LIST char **devices = NULL;
CLEANUP_FREE_STRING_LIST char **partitions = NULL;
CLEANUP_FREE_STRING_LIST char **mds = NULL;
CLEANUP_FREE_STRING_LIST char **lvs = NULL;
CLEANUP_FREE_STRING_LIST char **ldmvols = NULL;
CLEANUP_FREE_STRING_LIST char **ldmparts = NULL;
/* Look to see if any devices directly contain filesystems
* (RHBZ#590167). However vfs-type will fail to tell us anything
* useful about devices which just contain partitions, so we also
* get the list of partitions and exclude the corresponding devices
* by using part-to-dev.
*/
devices = guestfs_list_devices (g);
if (devices == NULL) goto error;
partitions = guestfs_list_partitions (g);
if (partitions == NULL) goto error;
mds = guestfs_list_md_devices (g);
if (mds == NULL) goto error;
for (i = 0; partitions[i] != NULL; ++i) {
CLEANUP_FREE char *dev = guestfs_part_to_dev (g, partitions[i]);
if (dev)
remove_from_list (devices, dev);
}
/* Use vfs-type to check for filesystems on devices. */
for (i = 0; devices[i] != NULL; ++i)
if (check_with_vfs_type (g, devices[i], &ret) == -1)
goto error;
/* Use vfs-type to check for filesystems on partitions. */
for (i = 0; partitions[i] != NULL; ++i) {
if (has_ldm == 0 || ! is_mbr_partition_type_42 (g, partitions[i])) {
if (check_with_vfs_type (g, partitions[i], &ret) == -1)
goto error;
}
}
/* Use vfs-type to check for filesystems on md devices. */
for (i = 0; mds[i] != NULL; ++i)
if (check_with_vfs_type (g, mds[i], &ret) == -1)
goto error;
if (has_lvm2 > 0) {
/* Use vfs-type to check for filesystems on LVs. */
lvs = guestfs_lvs (g);
if (lvs == NULL) goto error;
for (i = 0; lvs[i] != NULL; ++i)
if (check_with_vfs_type (g, lvs[i], &ret) == -1)
goto error;
}
if (has_ldm > 0) {
/* Use vfs-type to check for filesystems on Windows dynamic disks. */
ldmvols = guestfs_list_ldm_volumes (g);
if (ldmvols == NULL) goto error;
for (i = 0; ldmvols[i] != NULL; ++i)
if (check_with_vfs_type (g, ldmvols[i], &ret) == -1)
goto error;
ldmparts = guestfs_list_ldm_partitions (g);
if (ldmparts == NULL) goto error;
for (i = 0; ldmparts[i] != NULL; ++i)
if (check_with_vfs_type (g, ldmparts[i], &ret) == -1)
goto error;
}
/* Finish off the list and return it. */
guestfs_int_end_stringsbuf (g, &ret);
return ret.argv;
error:
guestfs_int_free_stringsbuf (&ret);
return NULL;
}
/* If 'item' occurs in 'list', remove and free it. */
static void
remove_from_list (char **list, const char *item)
{
size_t i;
for (i = 0; list[i] != NULL; ++i)
if (STREQ (list[i], item)) {
free (list[i]);
for (; list[i+1] != NULL; ++i)
list[i] = list[i+1];
list[i] = NULL;
return;
}
}
/* Use vfs-type to look for a filesystem of some sort on 'dev'.
* Apart from some types which we ignore, add the result to the
* 'ret' string list.
*/
static int
check_with_vfs_type (guestfs_h *g, const char *device, struct stringsbuf *sb)
{
const char *v;
CLEANUP_FREE char *vfs_type = NULL;
guestfs_push_error_handler (g, NULL, NULL);
vfs_type = guestfs_vfs_type (g, device);
guestfs_pop_error_handler (g);
if (!vfs_type)
v = "unknown";
else if (STREQ (vfs_type, ""))
v = "unknown";
else if (STREQ (vfs_type, "btrfs")) {
CLEANUP_FREE_BTRFSSUBVOLUME_LIST struct guestfs_btrfssubvolume_list *vols =
guestfs_btrfs_subvolume_list (g, device);
if (vols == NULL)
return -1;
const int64_t default_volume =
guestfs_btrfs_subvolume_get_default (g, device);
for (size_t i = 0; i < vols->len; i++) {
struct guestfs_btrfssubvolume *this = &vols->val[i];
/* Ignore the default subvolume. We get it by simply mounting
* the whole device of this btrfs filesystem.
*/
if (this->btrfssubvolume_id == (uint64_t) default_volume)
continue;
guestfs_int_add_sprintf (g, sb,
"btrfsvol:%s/%s",
device, this->btrfssubvolume_path);
guestfs_int_add_string (g, sb, "btrfs");
}
v = vfs_type;
}
else {
/* Ignore all "*_member" strings. In libblkid these are returned
* for things which are members of some RAID or LVM set, most
* importantly "LVM2_member" which is a PV.
*/
const size_t n = strlen (vfs_type);
if (n >= 7 && STREQ (&vfs_type[n-7], "_member"))
return 0;
/* Ignore LUKS-encrypted partitions. These are also containers. */
if (STREQ (vfs_type, "crypto_LUKS"))
return 0;
v = vfs_type;
}
guestfs_int_add_string (g, sb, device);
guestfs_int_add_string (g, sb, v);
return 0;
}
/* We should ignore partitions that have MBR type byte 0x42, because
* these are members of a Windows dynamic disk group. Trying to read
* them will cause errors (RHBZ#887520). Assuming that libguestfs was
* compiled with ldm support, we'll get the filesystems on these later.
*/
static int
is_mbr_partition_type_42 (guestfs_h *g, const char *partition)
{
CLEANUP_FREE char *device = NULL;
int partnum;
int mbr_id;
int ret = 0;
guestfs_push_error_handler (g, NULL, NULL);
partnum = guestfs_part_to_partnum (g, partition);
if (partnum == -1)
goto out;
device = guestfs_part_to_dev (g, partition);
if (device == NULL)
goto out;
mbr_id = guestfs_part_get_mbr_id (g, device, partnum);
ret = mbr_id == 0x42;
out:
guestfs_pop_error_handler (g);
return ret;
}