New API: list-filesystems: list filesystems
authorRichard Jones <rjones@redhat.com>
Wed, 15 Sep 2010 16:22:29 +0000 (17:22 +0100)
committerRichard Jones <rjones@redhat.com>
Wed, 15 Sep 2010 18:42:23 +0000 (19:42 +0100)
This API is a simpler replacement for the guestfish commands
list-devices / list-partitions / lvs, in the case where you are
just examining a guest by hand to see what it contains.

Typical usage and output in guestfish is like this:

$ guestfish --ro -a /dev/vg_trick/F13x64
><fs> run
><fs> list-filesystems
/dev/vda1: ext4
/dev/vg_f13x64/lv_root: ext4
/dev/vg_f13x64/lv_swap: swap

It can also be used to replace programs that try to mount
devices to determine if they are mountable filesystems.

generator/generator_actions.ml
src/inspect.c

index 52c2b7f..2e01507 100644 (file)
@@ -747,7 +747,9 @@ This function cannot decrypt encrypted disks.  The caller
 must do that first (supplying the necessary keys) if the
 disk is encrypted.
 
 must do that first (supplying the necessary keys) if the
 disk is encrypted.
 
-Please read L<guestfs(3)/INSPECTION> for more details.");
+Please read L<guestfs(3)/INSPECTION> for more details.
+
+See also C<guestfs_list_filesystems>.");
 
   ("inspect_get_type", (RString "name", [Device "root"]), -1, [],
    [],
 
   ("inspect_get_type", (RString "name", [Device "root"]), -1, [],
    [],
@@ -955,6 +957,39 @@ it has no effect.");
    "\
 This returns the enable network flag.");
 
    "\
 This returns the enable network flag.");
 
+  ("list_filesystems", (RHashtable "fses", []), -1, [],
+   [],
+   "list filesystems",
+   "\
+This inspection command looks for filesystems on partitions,
+block devices and logical volumes, returning a list of devices
+containing filesystems and their type.
+
+The return value is a hash, where the keys are the devices
+containing filesystems, and the values are the filesystem types.
+For example:
+
+ \"/dev/sda1\" => \"ntfs\"
+ \"/dev/sda2\" => \"ext2\"
+ \"/dev/vg_guest/lv_root\" => \"ext4\"
+ \"/dev/vg_guest/lv_swap\" => \"swap\"
+
+The value can have the special value \"unknown\", meaning the
+content of the device is undetermined or empty.
+\"swap\" means a Linux swap partition.
+
+This command runs other libguestfs commands, which might include
+C<guestfs_mount> and C<guestfs_umount>, and therefore you should
+use this soon after launch and only when nothing is mounted.
+
+Not all of the filesystems returned will be mountable.  In
+particular, swap partitions are returned in the list.  Also
+this command does not check that each filesystem
+found is valid and mountable, and some filesystems might
+be mountable but require special options.  Filesystems may
+not all belong to a single logical operating system
+(use C<guestfs_inspect_os> to look for OSes).");
+
 ]
 
 (* daemon_functions are any functions which cause some action
 ]
 
 (* daemon_functions are any functions which cause some action
@@ -1064,7 +1099,9 @@ should probably use C<guestfs_readdir> instead.");
    "\
 List all the block devices.
 
    "\
 List all the block devices.
 
-The full block device names are returned, eg. C</dev/sda>");
+The full block device names are returned, eg. C</dev/sda>.
+
+See also C<guestfs_list_filesystems>.");
 
   ("list_partitions", (RStringList "partitions", []), 8, [],
    [InitBasicFS, Always, TestOutputListOfDevices (
 
   ("list_partitions", (RStringList "partitions", []), 8, [],
    [InitBasicFS, Always, TestOutputListOfDevices (
@@ -1079,7 +1116,9 @@ List all the partitions detected on all block devices.
 The full partition device names are returned, eg. C</dev/sda1>
 
 This does not return logical volumes.  For that you will need to
 The full partition device names are returned, eg. C</dev/sda1>
 
 This does not return logical volumes.  For that you will need to
-call C<guestfs_lvs>.");
+call C<guestfs_lvs>.
+
+See also C<guestfs_list_filesystems>.");
 
   ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"],
    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
 
   ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"],
    [InitBasicFSonLVM, Always, TestOutputListOfDevices (
@@ -1143,7 +1182,7 @@ of the L<lvs(8)> command.
 This returns a list of the logical volume device names
 (eg. C</dev/VolGroup00/LogVol00>).
 
 This returns a list of the logical volume device names
 (eg. C</dev/VolGroup00/LogVol00>).
 
-See also C<guestfs_lvs_full>.");
+See also C<guestfs_lvs_full>, C<guestfs_list_filesystems>.");
 
   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"],
    [], (* XXX how to test? *)
 
   ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"],
    [], (* XXX how to test? *)
index 74ae29f..11a5374 100644 (file)
@@ -1295,3 +1295,140 @@ guestfs__inspect_get_filesystems (guestfs_h *g, const char *root)
 
   return ret;
 }
 
   return ret;
 }
+
+/* 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 void check_with_vfs_type (guestfs_h *g, const char *dev, char ***ret, size_t *ret_size);
+
+char **
+guestfs__list_filesystems (guestfs_h *g)
+{
+  size_t i;
+  char **ret;
+  size_t ret_size;
+
+  ret = safe_malloc (g, sizeof (char *));
+  ret[0] = NULL;
+  ret_size = 0;
+
+  /* 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.
+   */
+  char **devices;
+  devices = guestfs_list_devices (g);
+  if (devices == NULL) {
+    free_string_list (ret);
+    return NULL;
+  }
+  char **partitions;
+  partitions = guestfs_list_partitions (g);
+  if (partitions == NULL) {
+    free_string_list (devices);
+    free_string_list (ret);
+    return NULL;
+  }
+
+  for (i = 0; partitions[i] != NULL; ++i) {
+    char *dev = guestfs_part_to_dev (g, partitions[i]);
+    if (dev)
+      remove_from_list (devices, dev);
+    free (dev);
+  }
+
+  /* Use vfs-type to check for filesystems on devices. */
+  for (i = 0; devices[i] != NULL; ++i)
+    check_with_vfs_type (g, devices[i], &ret, &ret_size);
+  free_string_list (devices);
+
+  /* Use vfs-type to check for filesystems on partitions. */
+  for (i = 0; partitions[i] != NULL; ++i)
+    check_with_vfs_type (g, partitions[i], &ret, &ret_size);
+  free_string_list (partitions);
+
+  if (feature_available (g, "lvm2")) {
+    /* Use vfs-type to check for filesystems on LVs. */
+    char **lvs;
+    lvs = guestfs_lvs (g);
+    if (lvs == NULL) {
+      free_string_list (ret);
+      return NULL;
+    }
+
+    for (i = 0; lvs[i] != NULL; ++i)
+      check_with_vfs_type (g, lvs[i], &ret, &ret_size);
+    free_string_list (lvs);
+  }
+
+  return ret;
+}
+
+/* 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 void
+check_with_vfs_type (guestfs_h *g, const char *device,
+                     char ***ret, size_t *ret_size)
+{
+  char *v;
+
+  guestfs_error_handler_cb old_error_cb = g->error_cb;
+  g->error_cb = NULL;
+  char *vfs_type = guestfs_vfs_type (g, device);
+  g->error_cb = old_error_cb;
+
+  if (!vfs_type)
+    v = safe_strdup (g, "unknown");
+  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.
+     */
+    size_t n = strlen (vfs_type);
+    if (n >= 7 && STREQ (&vfs_type[n-7], "_member")) {
+      free (vfs_type);
+      return;
+    }
+
+    /* Ignore LUKS-encrypted partitions.  These are also containers. */
+    if (STREQ (vfs_type, "crypto_LUKS")) {
+      free (vfs_type);
+      return;
+    }
+
+    v = vfs_type;
+  }
+
+  /* Extend the return array. */
+  size_t i = *ret_size;
+  *ret_size += 2;
+  *ret = safe_realloc (g, *ret, (*ret_size + 1) * sizeof (char *));
+  (*ret)[i] = safe_strdup (g, device);
+  (*ret)[i+1] = v;
+  (*ret)[i+2] = NULL;
+}