diff --git a/daemon/available.c b/daemon/available.c index d0322bc97..7a8ede0d1 100644 --- a/daemon/available.c +++ b/daemon/available.c @@ -33,8 +33,8 @@ GUESTFSD_EXT_CMD(str_grep, grep); GUESTFSD_EXT_CMD(str_modprobe, modprobe); -int -do_available (char *const *groups) +static int +available (char *const *groups, int error_on_unavailable) { int av; size_t i, j; @@ -44,8 +44,12 @@ do_available (char *const *groups) if (STREQ (groups[i], optgroups[j].group)) { av = optgroups[j].available (); if (!av) { - reply_with_error ("%s: group not available", optgroups[j].group); - return -1; + if (error_on_unavailable) { + reply_with_error ("%s: group not available", optgroups[j].group); + return -1; + } + else + return 0; } break; /* out of for (j) loop */ } @@ -58,6 +62,23 @@ do_available (char *const *groups) } } + /* All specified groups available. */ + return 1; +} + +int +do_feature_available (char *const *groups) +{ + return available (groups, 0); +} + +int +do_available (char *const *groups) +{ + if (available (groups, 1) == -1) + return -1; + + /* No error, so all groups available, just returns no error. */ return 0; } diff --git a/edit/virt-edit.c b/edit/virt-edit.c index 60824d15e..d75cd85a5 100644 --- a/edit/virt-edit.c +++ b/edit/virt-edit.c @@ -57,7 +57,6 @@ static void edit (const char *filename, const char *root); static char *edit_interactively (const char *tmpfile); static char *edit_non_interactively (const char *tmpfile); static int copy_attributes (const char *src, const char *dest); -static int feature_available (guestfs_h *g, const char *feature); static int is_windows (guestfs_h *g, const char *root); static char *windows_path (guestfs_h *g, const char *root, const char *filename); static char *generate_random_name (const char *filename); @@ -513,11 +512,12 @@ static int copy_attributes (const char *src, const char *dest) { CLEANUP_FREE_STAT struct guestfs_stat *stat = NULL; + const char *linuxxattrs[] = { "linuxxattrs", NULL }; int has_linuxxattrs; CLEANUP_FREE char *selinux_context = NULL; size_t selinux_context_size; - has_linuxxattrs = feature_available (g, "linuxxattrs"); + has_linuxxattrs = guestfs_feature_available (g, (char **) linuxxattrs); /* Get the mode. */ stat = guestfs_stat (g, src); @@ -553,22 +553,6 @@ copy_attributes (const char *src, const char *dest) return 0; } -static int -feature_available (guestfs_h *g, const char *feature) -{ - /* If there's an error we should ignore it, so to do that we have to - * temporarily replace the error handler with a null one. - */ - guestfs_push_error_handler (g, NULL, NULL); - - const char *groups[] = { feature, NULL }; - int r = guestfs_available (g, (char * const *) groups); - - guestfs_pop_error_handler (g); - - return r == 0 ? 1 : 0; -} - static int is_windows (guestfs_h *g, const char *root) { diff --git a/fish/edit.c b/fish/edit.c index 05a272b77..217852517 100644 --- a/fish/edit.c +++ b/fish/edit.c @@ -182,11 +182,12 @@ static int copy_attributes (const char *src, const char *dest) { struct guestfs_stat *stat; + const char *linuxxattrs[] = { "linuxxattrs", NULL }; int has_linuxxattrs; CLEANUP_FREE char *selinux_context = NULL; size_t selinux_context_size; - has_linuxxattrs = feature_available (g, "linuxxattrs"); + has_linuxxattrs = guestfs_feature_available (g, (char **) linuxxattrs); /* Get the mode. */ stat = guestfs_stat (g, src); diff --git a/fish/fish.c b/fish/fish.c index db06734ca..2651012a3 100644 --- a/fish/fish.c +++ b/fish/fish.c @@ -1921,19 +1921,3 @@ progress_callback (guestfs_h *g, void *data, progress_bar_set (bar, position, total); } - -int -feature_available (guestfs_h *g, const char *feature) -{ - /* If there's an error we should ignore it, so to do that we have to - * temporarily replace the error handler with a null one. - */ - guestfs_push_error_handler (g, NULL, NULL); - - const char *groups[] = { feature, NULL }; - int r = guestfs_available (g, (char * const *) groups); - - guestfs_pop_error_handler (g); - - return r == 0 ? 1 : 0; -} diff --git a/fish/fish.h b/fish/fish.h index 908697925..df22e34e7 100644 --- a/fish/fish.h +++ b/fish/fish.h @@ -50,7 +50,6 @@ extern void free_file_in (char *s); extern char *file_out (const char *arg); extern void extended_help_message (void); extern void progress_callback (guestfs_h *g, void *data, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len); -extern int feature_available (guestfs_h *g, const char *feature); /* in cmds.c (auto-generated) */ extern void list_commands (void); diff --git a/fish/glob.c b/fish/glob.c index 62b5ef8c2..baaef5ab8 100644 --- a/fish/glob.c +++ b/fish/glob.c @@ -165,6 +165,7 @@ expand_devicename (guestfs_h *g, const char *device) char **pp = NULL; char **ret = NULL; size_t size = 0; + const char *lvm2[] = { "lvm2", NULL }; pp = guestfs_list_devices (g); if (pp == NULL) goto error; @@ -181,7 +182,7 @@ expand_devicename (guestfs_h *g, const char *device) if (add_strings_matching (pp, device, &ret, &size) == -1) goto error; guestfs___free_string_list (pp); - if (feature_available (g, "lvm2")) { + if (guestfs_feature_available (g, (char **) lvm2)) { pp = guestfs_lvs (g); if (pp == NULL) goto error; if (add_strings_matching (pp, device, &ret, &size) == -1) goto error; diff --git a/format/format.c b/format/format.c index 8c641f162..842adee0b 100644 --- a/format/format.c +++ b/format/format.c @@ -54,7 +54,6 @@ static int have_wipefs; static void parse_vg_lv (const char *lvm); static int do_format (void); static int do_rescan (char **devices); -static int feature_available (guestfs_h *g, const char *feature); static void __attribute__((noreturn)) usage (int status) @@ -234,6 +233,8 @@ main (int argc, char *argv[]) * to completely restart the guest. Hence this complex retry logic. */ for (retries = 0; retries <= 1; ++retries) { + const char *wipefs[] = { "wipefs", NULL }; + /* Add domains/drives from the command line (for a single guest). */ add_drives (drvs, 'a'); @@ -241,7 +242,7 @@ main (int argc, char *argv[]) exit (EXIT_FAILURE); /* Test if the wipefs API is available. */ - have_wipefs = feature_available (g, "wipefs"); + have_wipefs = guestfs_feature_available (g, (char **) wipefs); /* Perform the format. */ retry = do_format (); @@ -431,19 +432,3 @@ do_rescan (char **devices) return errors ? 1 : 0; } - -static int -feature_available (guestfs_h *g, const char *feature) -{ - /* If there's an error we should ignore it, so to do that we have to - * temporarily replace the error handler with a null one. - */ - guestfs_push_error_handler (g, NULL, NULL); - - const char *groups[] = { feature, NULL }; - int r = guestfs_available (g, (char * const *) groups); - - guestfs_pop_error_handler (g); - - return r == 0 ? 1 : 0; -} diff --git a/generator/actions.ml b/generator/actions.ml index daf6c6210..3b03a6bde 100644 --- a/generator/actions.ml +++ b/generator/actions.ml @@ -597,7 +597,7 @@ I Don't use this call to test for availability of features. In enterprise distributions we backport features from later versions into earlier versions, making this an unreliable way to test for features. -Use C instead." }; +Use C or C instead." }; { defaults with name = "set_selinux"; @@ -7375,6 +7375,12 @@ I =item * +C is the same as this call, but +with a slightly simpler to use API: that call returns a boolean +true/false instead of throwing an error. + +=item * + You must call C before calling this function. The reason is because we don't know what groups are @@ -7949,10 +7955,11 @@ allows you to specify the new size (in bytes) explicitly." }; This command returns a list of all optional groups that this daemon knows about. Note this returns both supported and unsupported groups. To find out which ones the daemon can actually support -you have to call C on each member of the -returned list. +you have to call C / C +on each member of the returned list. -See also C and L." }; +See also C, C +and L." }; { defaults with name = "fallocate64"; @@ -9798,7 +9805,8 @@ 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." }; +See also C, C, +L." }; { defaults with name = "fstrim"; @@ -10903,6 +10911,20 @@ Parse a mountable string." }; This is only used to debug RHBZ#914931. Note that this deliberately crashes guestfsd." }; + { defaults with + name = "feature_available"; + style = RBool "isavailable", [StringList "groups"], []; + proc_nr = Some 398; + tests = [ + InitNone, Always, TestOutputTrue [["feature_available"; ""]] + ]; + shortdesc = "test availability of some parts of the API"; + longdesc = "\ +This is the same as C, but unlike that +call it returns a simple true/false boolean result, instead +of throwing an exception if a feature is not found. For +other documentation see C." }; + ] (* Non-API meta-commands available only in guestfish. diff --git a/generator/perl.ml b/generator/perl.ml index 38e5c6502..707da70e5 100644 --- a/generator/perl.ml +++ b/generator/perl.ml @@ -1037,15 +1037,10 @@ containing useful introspection information about the method } To test if particular features are supported by the current -build, use the L method like the example below. Note +build, use the L method like the example below. Note that the appliance must be launched first. - $g->available ( [\"augeas\"] ); - -Since the L method croaks if the feature is not supported, -you might also want to wrap this in an eval and return a boolean. -In fact this has already been done for you: use -L. + $g->feature_available ( [\"augeas\"] ); For further discussion on this topic, refer to L. diff --git a/resize/common_utils.ml b/resize/common_utils.ml index 3861c71c5..0f71810a8 100644 --- a/resize/common_utils.ml +++ b/resize/common_utils.ml @@ -143,10 +143,6 @@ let error fs = in ksprintf display fs -let feature_available (g : Guestfs.guestfs) names = - try g#available names; true - with G.Error _ -> false - let read_whole_file path = let buf = Buffer.create 16384 in let chan = open_in path in diff --git a/resize/resize.ml b/resize/resize.ml index 74a5a47e1..d78630341 100644 --- a/resize/resize.ml +++ b/resize/resize.ml @@ -177,9 +177,9 @@ read the man page virt-resize(1). let g = new G.guestfs () in g#add_drive "/dev/null"; g#launch (); - if feature_available g [| "ntfsprogs"; "ntfs3g" |] then + if g#feature_available [| "ntfsprogs"; "ntfs3g" |] then printf "ntfs\n"; - if feature_available g [| "btrfs" |] then + if g#feature_available [| "btrfs" |] then printf "btrfs\n"; exit 0 ); @@ -222,8 +222,8 @@ let connect_both_disks () = g#lvm_set_filter [|"/dev/sda"|]; (* Update features available in the daemon. *) - ntfs_available := feature_available g [|"ntfsprogs"; "ntfs3g"|]; - btrfs_available := feature_available g [|"btrfs"|]; + ntfs_available := g#feature_available [|"ntfsprogs"; "ntfs3g"|]; + btrfs_available := g#feature_available [|"btrfs"|]; g diff --git a/sparsify/sparsify.ml b/sparsify/sparsify.ml index e653deda9..819a14576 100644 --- a/sparsify/sparsify.ml +++ b/sparsify/sparsify.ml @@ -112,9 +112,9 @@ read the man page virt-sparsify(1). let g = new G.guestfs () in g#add_drive "/dev/null"; g#launch (); - if feature_available g [| "ntfsprogs"; "ntfs3g" |] then + if g#feature_available [| "ntfsprogs"; "ntfs3g" |] then printf "ntfs\n"; - if feature_available g [| "btrfs" |] then + if g#feature_available [| "btrfs" |] then printf "btrfs\n"; exit 0 ); diff --git a/src/MAX_PROC_NR b/src/MAX_PROC_NR index 8b84f5708..7ea3cf600 100644 --- a/src/MAX_PROC_NR +++ b/src/MAX_PROC_NR @@ -1 +1 @@ -397 +398 diff --git a/src/guestfs-internal.h b/src/guestfs-internal.h index f86082446..34d3bd78e 100644 --- a/src/guestfs-internal.h +++ b/src/guestfs-internal.h @@ -630,7 +630,6 @@ extern char *guestfs___drive_name (size_t index, char *ret); /* inspect.c */ extern void guestfs___free_inspect_info (guestfs_h *g); -extern int guestfs___feature_available (guestfs_h *g, const char *feature); extern char *guestfs___download_to_tmp (guestfs_h *g, struct inspect_fs *fs, const char *filename, const char *basename, uint64_t max_size); extern struct inspect_fs *guestfs___search_for_root (guestfs_h *g, const char *root); diff --git a/src/inspect.c b/src/inspect.c index db0934974..157370f7c 100644 --- a/src/inspect.c +++ b/src/inspect.c @@ -515,23 +515,6 @@ guestfs___free_inspect_info (guestfs_h *g) g->fses = NULL; } -/* In the Perl code this is a public function. */ -int -guestfs___feature_available (guestfs_h *g, const char *feature) -{ - const char *groups[] = { feature, NULL }; - int r; - - /* If there's an error we should ignore it, so to do that we have to - * temporarily replace the error handler with a null one. - */ - guestfs_push_error_handler (g, NULL, NULL); - r = guestfs_available (g, (char * const *) groups); - guestfs_pop_error_handler (g); - - return r == 0 ? 1 : 0; -} - /* Download a guest file to a local temporary file. The file is * cached in the temporary directory, and is not downloaded again. * diff --git a/src/listfs.c b/src/listfs.c index 024e7a090..eb4019deb 100644 --- a/src/listfs.c +++ b/src/listfs.c @@ -48,6 +48,8 @@ guestfs__list_filesystems (guestfs_h *g) size_t i; char **ret = NULL; size_t ret_size = 0; + const char *lvm2[] = { "lvm2", NULL }; + const char *ldm[] = { "ldm", NULL }; CLEANUP_FREE_STRING_LIST char **devices = NULL; CLEANUP_FREE_STRING_LIST char **partitions = NULL; @@ -89,7 +91,7 @@ guestfs__list_filesystems (guestfs_h *g) for (i = 0; mds[i] != NULL; ++i) check_with_vfs_type (g, mds[i], &ret, &ret_size); - if (guestfs___feature_available (g, "lvm2")) { + if (guestfs_feature_available (g, (char **) lvm2)) { /* Use vfs-type to check for filesystems on LVs. */ lvs = guestfs_lvs (g); if (lvs == NULL) goto error; @@ -98,7 +100,7 @@ guestfs__list_filesystems (guestfs_h *g) check_with_vfs_type (g, lvs[i], &ret, &ret_size); } - if (guestfs___feature_available (g, "ldm")) { + if (guestfs_feature_available (g, (char **) ldm)) { /* Use vfs-type to check for filesystems on Windows dynamic disks. */ ldmvols = guestfs_list_ldm_volumes (g); if (ldmvols == NULL) goto error; diff --git a/tests/btrfs/test-btrfs-subvolume-default.pl b/tests/btrfs/test-btrfs-subvolume-default.pl index b95571393..85b150506 100755 --- a/tests/btrfs/test-btrfs-subvolume-default.pl +++ b/tests/btrfs/test-btrfs-subvolume-default.pl @@ -22,7 +22,6 @@ use strict; use warnings; use Sys::Guestfs; -use Sys::Guestfs::Lib qw(feature_available); # Allow the test to be skipped since btrfs is often broken. exit 77 if $ENV{SKIP_TEST_BTRFS_SUBVOLUME_DEFAULT_PL}; @@ -40,7 +39,7 @@ $g->add_drive ($testimg, format => "raw"); $g->launch (); # If btrfs is not available, bail. -unless (feature_available ($g, "btrfs")) { +unless ($g->feature_available (["btrfs"])) { warn "$0: skipping test because btrfs is not available\n"; exit 77; } diff --git a/tests/charsets/test-charset-fidelity.c b/tests/charsets/test-charset-fidelity.c index c3a476e4e..a5a4f5dfa 100644 --- a/tests/charsets/test-charset-fidelity.c +++ b/tests/charsets/test-charset-fidelity.c @@ -68,7 +68,6 @@ static void test_latin1 (guestfs_h *g, const struct filesystem *fs); static void test_latin2 (guestfs_h *g, const struct filesystem *fs); static void test_chinese (guestfs_h *g, const struct filesystem *fs); static void ignore_lost_and_found (char **); -static int feature_available (guestfs_h *g, const char *feature); int main (int argc, char *argv[]) @@ -126,7 +125,9 @@ main (int argc, char *argv[]) static void test_filesystem (guestfs_h *g, const struct filesystem *fs) { - if (fs->fs_feature && !feature_available (g, fs->fs_feature)) { + const char *feature[] = { fs->fs_feature, NULL }; + + if (fs->fs_feature && !guestfs_feature_available (g, (char **) feature)) { printf ("skipped test of %s because %s feature not available\n", fs->fs_name, fs->fs_feature); return; @@ -427,19 +428,3 @@ ignore_lost_and_found (char **files) } files[j] = NULL; } - -static int -feature_available (guestfs_h *g, const char *feature) -{ - /* If there's an error we should ignore it, so to do that we have to - * temporarily replace the error handler with a null one. - */ - guestfs_push_error_handler (g, NULL, NULL); - - const char *groups[] = { feature, NULL }; - int r = guestfs_available (g, (char * const *) groups); - - guestfs_pop_error_handler (g); - - return r == 0 ? 1 : 0; -} diff --git a/tests/selinux/run-test.pl b/tests/selinux/run-test.pl index f55b1fbf1..980eedf83 100755 --- a/tests/selinux/run-test.pl +++ b/tests/selinux/run-test.pl @@ -19,7 +19,6 @@ use strict; use warnings; use Sys::Guestfs; -use Sys::Guestfs::Lib qw(feature_available); # These are two SELinux labels that we assume everyone is allowed to # set under any policy. @@ -111,7 +110,7 @@ close FILE or die "$testimg: $!"; $g->add_drive ($testimg, format => "raw"); $g->launch (); -unless (feature_available ($g, "linuxxattrs")) { +unless ($g->feature_available (["linuxxattrs"])) { print "$prog $test_type $test_via: test skipped because 'linuxxattrs' feature not available.\n"; $g->close (); unlink $testimg; diff --git a/tools/test-virt-make-fs.sh b/tools/test-virt-make-fs.sh index 316d959b1..af73f63a7 100755 --- a/tools/test-virt-make-fs.sh +++ b/tools/test-virt-make-fs.sh @@ -23,13 +23,13 @@ set -e # Check which filesystems are supported by the appliance. eval $( -perl -MSys::Guestfs '-MSys::Guestfs::Lib qw(feature_available)' -e ' +perl -MSys::Guestfs -e ' $g = Sys::Guestfs->new(); $g->add_drive ("/dev/null"); $g->launch (); - feature_available ($g, "ntfs3g") and print "ntfs3g_available=yes\n"; - feature_available ($g, "ntfsprogs") and print "ntfsprogs_available=yes\n"; - feature_available ($g, "btrfs") and print "btrfs_available=yes\n"; + $g->feature_available (["ntfs3g"]) and print "ntfs3g_available=yes\n"; + $g->feature_available (["ntfsprogs"]) and print "ntfsprogs_available=yes\n"; + $g->feature_available (["btrfs"]) and print "btrfs_available=yes\n"; ') # Allow btrfs to be disabled when btrfs is broken (eg. RHBZ#863978). diff --git a/tools/virt-make-fs b/tools/virt-make-fs index a8cf56bc9..d29e7df4c 100755 --- a/tools/virt-make-fs +++ b/tools/virt-make-fs @@ -20,7 +20,6 @@ use warnings; use strict; use Sys::Guestfs; -use Sys::Guestfs::Lib qw(feature_available); use Pod::Usage; use Getopt::Long; @@ -457,7 +456,7 @@ eval { $g->add_drive ($output, format => $format); $g->launch (); - if ($type eq "ntfs" && !feature_available ($g, "ntfs3g", "ntfsprogs")) { + if ($type eq "ntfs" && !$g->feature_available (["ntfs3g", "ntfsprogs"])) { die __"virt-make-fs: NTFS support was disabled when libguestfs was compiled\n" }