From 4ba6aa3eaeb112a1468ad9189120d12e1df23709 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Sat, 9 Jun 2012 13:42:13 +0100 Subject: New API: filesystem-available: tests for filesystem availability. This also creates an internal filesystem_available function within the daemon. --- daemon/available.c | 79 ++++++++++++++++++++++++++++++++++++++++++ daemon/daemon.h | 3 ++ generator/generator_actions.ml | 21 ++++++++++- src/MAX_PROC_NR | 2 +- src/guestfs.pod | 10 ++++++ 5 files changed, 113 insertions(+), 2 deletions(-) diff --git a/daemon/available.c b/daemon/available.c index 97f15584..08e72f30 100644 --- a/daemon/available.c +++ b/daemon/available.c @@ -22,9 +22,12 @@ #include #include +#include "c-ctype.h" + #include "guestfs_protocol.h" #include "daemon.h" #include "actions.h" +#include "optgroups.h" int do_available (char *const *groups) @@ -70,3 +73,79 @@ do_available_all_groups (void) return groups.argv; /* caller frees */ } + +/* Search for filesystem in /proc/filesystems, ignoring "nodev". */ +static int +test_proc_filesystems (const char *filesystem) +{ + size_t len = strlen (filesystem) + 32; + char regex[len]; + char *err; + int r; + + snprintf (regex, len, "^[[:space:]]*%s$", filesystem); + + r = commandr (NULL, &err, "grep", regex, "/proc/filesystems", NULL); + if (r == -1 || r >= 2) { + fprintf (stderr, "grep /proc/filesystems: %s", err); + free (err); + return -1; + } + free (err); + + return r == 0; +} + +/* Do modprobe, ignore any errors. */ +static void +modprobe (const char *module) +{ + command (NULL, NULL, "modprobe", module, NULL); +} + +/* Internal function for testing if a filesystem is available. Note + * this must not call reply_with_error functions. + */ +int +filesystem_available (const char *filesystem) +{ + int r; + + r = test_proc_filesystems (filesystem); + if (r == -1 || r > 0) + return r; + + /* Not found: try to modprobe the module, then test again. */ + if (optgroup_linuxmodules_available ()) { + modprobe (filesystem); + + r = test_proc_filesystems (filesystem); + if (r == -1) + return -1; + } + + return r; +} + +int +do_filesystem_available (const char *filesystem) +{ + size_t i, len = strlen (filesystem); + int r; + + for (i = 0; i < len; ++i) { + if (!c_isalnum (filesystem[i]) && filesystem[i] != '_') { + reply_with_error ("filesystem name contains non-alphanumeric characters"); + return -1; + } + } + + r = filesystem_available (filesystem); + if (r == -1) { + reply_with_error ("error testing for filesystem availability; " + "enable verbose mode and look at preceeding output"); + return -1; + } + + return r; +} diff --git a/daemon/daemon.h b/daemon/daemon.h index 9dfaa4f3..af81a9da 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -151,6 +151,9 @@ struct optgroup { }; extern struct optgroup optgroups[]; +/*-- in available.c --*/ +extern int filesystem_available (const char *filesystem); + /*-- in sync.c --*/ /* Use this as a replacement for sync(2). */ extern int sync_disks (void); diff --git a/generator/generator_actions.ml b/generator/generator_actions.ml index 4dc46385..d88d54f2 100644 --- a/generator/generator_actions.ml +++ b/generator/generator_actions.ml @@ -5325,7 +5325,9 @@ versions of libguestfs all you could do would be to speculatively execute a command to find out if the daemon implemented it. See also C. -=back"); +=back + +See also C."); ("dd", (RErr, [Dev_or_Path "src"; Dev_or_Path "dest"], []), 217, [DeprecatedBy "copy_device_to_device"], [InitScratchFS, Always, TestOutputBuffer ( @@ -7241,6 +7243,23 @@ a btrfs filesystem."); Used to check a btrfs filesystem, C is the device file where the filesystem is stored."); + ("filesystem_available", (RBool "fsavail", [String "filesystem"], []), 333, [], + [], + "check if filesystem is available", + "\ +Check whether libguestfs supports the named filesystem. +The argument C is a filesystem name, such as +C. + +You must call C before using this command. + +This is mainly useful as a negative test. If this returns true, +it doesn't mean that a particular filesystem can be mounted, +since filesystems can fail for other reasons such as it being +a later version of the filesystem, or having incompatible features. + +See also C, L."); + ] let all_functions = non_daemon_functions @ daemon_functions diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 6f96da66..55bd0ac4 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -332 +333 diff --git a/src/guestfs.pod b/src/guestfs.pod index afdcb487..bd61c831 100644 --- a/src/guestfs.pod +++ b/src/guestfs.pod @@ -1602,6 +1602,16 @@ supports the functionality. @AVAILABILITY@ +=head2 FILESYSTEM AVAILABLE + +The L call tests whether a +filesystem type is supported by the appliance kernel. + +This is mainly useful as a negative test. If this returns true, +it doesn't mean that a particular filesystem can be mounted, +since filesystems can fail for other reasons such as it being +a later version of the filesystem, or having incompatible features. + =head2 GUESTFISH supported COMMAND In L there is a handy interactive command -- cgit