diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | Makefile.am | 34 | ||||
-rw-r--r-- | daemon/Makefile.am | 2 | ||||
-rw-r--r-- | daemon/augeas.c | 52 | ||||
-rw-r--r-- | daemon/available.c | 23 | ||||
-rw-r--r-- | daemon/configure.ac | 24 | ||||
-rw-r--r-- | daemon/daemon.h | 17 | ||||
-rw-r--r-- | daemon/inotify.c | 31 | ||||
-rw-r--r-- | daemon/lvm.c | 8 | ||||
-rw-r--r-- | daemon/mknod.c | 18 | ||||
-rw-r--r-- | daemon/modprobe.c | 8 | ||||
-rw-r--r-- | daemon/ntfs.c | 8 | ||||
-rw-r--r-- | daemon/scrub.c | 8 | ||||
-rw-r--r-- | daemon/selinux.c | 21 | ||||
-rw-r--r-- | daemon/swap.c | 19 | ||||
-rw-r--r-- | daemon/xattr.c | 47 | ||||
-rw-r--r-- | daemon/zerofree.c | 8 | ||||
-rw-r--r-- | guestfs.pod | 7 | ||||
-rw-r--r-- | po/POTFILES.in | 1 | ||||
-rwxr-xr-x | src/generator.ml | 200 |
20 files changed, 388 insertions, 151 deletions
@@ -48,6 +48,8 @@ daemon/guestfsd daemon/install-sh daemon/missing daemon/names.c +daemon/optgroups.c +daemon/optgroups.h daemon/stubs.c depcomp .deps @@ -65,6 +67,7 @@ guestfish.1 guestfish-actions.pod guestfs.3 guestfs-actions.pod +guestfs-availability.pod guestfs-structs.pod haskell/Bindtests haskell/Bindtests.hs diff --git a/Makefile.am b/Makefile.am index 9332a10d..bbdb0ed4 100644 --- a/Makefile.am +++ b/Makefile.am @@ -57,8 +57,9 @@ SUBDIRS += haskell endif generator_built = \ - guestfs-structs.pod \ guestfs-actions.pod \ + guestfs-availability.pod \ + guestfs-structs.pod \ guestfish-actions.pod EXTRA_DIST = \ @@ -83,15 +84,23 @@ EXTRA_DIST = \ libguestfs.3 # Manual pages. -# guestfs-actions.pod and guestfs-structs are autogenerated. There is -# no include mechanism for POD, so we have to do it by hand. +# guestfs-actions.pod, guestfs-availability.pod and guestfs-structs +# are autogenerated. There is no include mechanism for POD, so we +# have to do it by hand. man_MANS = guestfs.3 libguestfs.3 guestfish.1 -guestfs.3: guestfs.pod guestfs-actions.pod guestfs-structs.pod +guestfs.3: guestfs.pod \ + guestfs-actions.pod \ + guestfs-availability.pod \ + guestfs-structs.pod sed \ - -e '/@ACTIONS@/rguestfs-actions.pod' -e 's/@ACTIONS@//' \ - -e '/@STRUCTS@/rguestfs-structs.pod' -e 's/@STRUCTS@//' \ + -e '/@ACTIONS@/rguestfs-actions.pod' \ + -e 's/@ACTIONS@//' \ + -e '/@AVAILABILITY@/rguestfs-availability.pod' \ + -e 's/@AVAILABILITY@//' \ + -e '/@STRUCTS@/rguestfs-structs.pod' \ + -e 's/@STRUCTS@//' \ < $< | \ $(POD2MAN) \ --section 3 \ @@ -113,11 +122,18 @@ guestfish.1: guestfish.pod guestfish-actions.pod noinst_DATA = html/guestfs.3.html html/guestfish.1.html -html/guestfs.3.html: guestfs.pod guestfs-actions.pod guestfs-structs.pod +html/guestfs.3.html: guestfs.pod \ + guestfs-actions.pod \ + guestfs-availability.pod \ + guestfs-structs.pod mkdir -p html sed \ - -e '/@ACTIONS@/rguestfs-actions.pod' -e 's/@ACTIONS@//' \ - -e '/@STRUCTS@/rguestfs-structs.pod' -e 's/@STRUCTS@//' \ + -e '/@ACTIONS@/rguestfs-actions.pod' \ + -e 's/@ACTIONS@//' \ + -e '/@AVAILABILITY@/rguestfs-availability.pod' \ + -e 's/@AVAILABILITY@//' \ + -e '/@STRUCTS@/rguestfs-structs.pod' \ + -e 's/@STRUCTS@//' \ < $< | \ pod2html \ --css 'pod.css' \ diff --git a/daemon/Makefile.am b/daemon/Makefile.am index d851e527..9fa8ddab 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -81,6 +81,8 @@ guestfsd_SOURCES = \ mount.c \ names.c \ ntfs.c \ + optgroups.c \ + optgroups.h \ parted.c \ pingdaemon.c \ proto.c \ diff --git a/daemon/augeas.c b/daemon/augeas.c index b56012cd..be53d294 100644 --- a/daemon/augeas.c +++ b/daemon/augeas.c @@ -29,6 +29,7 @@ #include "daemon.h" #include "actions.h" +#include "optgroups.h" #ifdef HAVE_AUGEAS /* The Augeas handle. We maintain a single handle per daemon, which @@ -45,6 +46,18 @@ static augeas *aug = NULL; } \ } \ while (0) + +int +optgroup_augeas_available (void) +{ + return 1; +} +#else /* !HAVE_AUGEAS */ +int +optgroup_augeas_available (void) +{ + return 0; +} #endif /* We need to rewrite the root path so it is based at /sysroot. */ @@ -75,8 +88,7 @@ do_aug_init (const char *root, int flags) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -91,8 +103,7 @@ do_aug_close (void) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -111,8 +122,7 @@ do_aug_defvar (const char *name, const char *expr) } return r; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -133,8 +143,7 @@ do_aug_defnode (const char *name, const char *expr, const char *val) r.b = created; return &r; #else - reply_with_error ("%s is not available", __func__); - return NULL; + NOT_AVAILABLE (-1); #endif } @@ -176,8 +185,7 @@ do_aug_get (const char *path) return v; /* Caller frees. */ #else - reply_with_error ("%s is not available", __func__); - return NULL; + NOT_AVAILABLE (NULL); #endif } @@ -197,8 +205,7 @@ do_aug_set (const char *path, const char *val) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -218,8 +225,7 @@ do_aug_insert (const char *path, const char *label, int before) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -239,8 +245,7 @@ do_aug_rm (const char *path) return r; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -260,8 +265,7 @@ do_aug_mv (const char *src, const char *dest) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -295,8 +299,7 @@ do_aug_match (const char *path) return matches; /* Caller frees. */ #else - reply_with_error ("%s is not available", __func__); - return NULL; + NOT_AVAILABLE (NULL); #endif } @@ -313,8 +316,7 @@ do_aug_save (void) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -331,8 +333,7 @@ do_aug_load (void) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -379,7 +380,6 @@ do_aug_ls (const char *path) sort_strings (matches, count_strings ((void *) matches)); return matches; /* Caller frees. */ #else - reply_with_error ("%s is not available", __func__); - return NULL; + NOT_AVAILABLE (NULL); #endif } diff --git a/daemon/available.c b/daemon/available.c index b43d1820..77fdfa2c 100644 --- a/daemon/available.c +++ b/daemon/available.c @@ -29,9 +29,26 @@ int do_available (char *const *groups) { - if (groups[0] != NULL) { - reply_with_error ("%s: unknown group", groups[0]); - return -1; + int av; + size_t i, j; + + for (i = 0; groups[i] != NULL; ++i) { + for (j = 0; optgroups[j].group != NULL; ++j) { + 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; + } + break; /* out of for (j) loop */ + } + } + + /* Unknown group? */ + if (optgroups[j].group == NULL) { + reply_with_error ("%s: unknown group", groups[i]); + return -1; + } } return 0; diff --git a/daemon/configure.ac b/daemon/configure.ac index a1f54a3b..c6d9d98f 100644 --- a/daemon/configure.ac +++ b/daemon/configure.ac @@ -133,7 +133,7 @@ AC_STRUCT_DIRENT_D_TYPE dnl Check if stat has the required fields. AC_STRUCT_ST_BLOCKS AC_CHECK_MEMBER([struct stat.st_blksize],[ - AC_DEFINE([HAVE_STRUCT_STAT_ST_BLKSIZE],[1],[Define to 1 if 'st_blksize' is a member of 'struct stat'])]) + AC_DEFINE([HAVE_STRUCT_STAT_ST_BLKSIZE],[1],[Define to 1 if 'st_blksize' is a member of 'struct stat'])]) dnl Check for Augeas (now optional). AC_CHECK_LIB([augeas],[aug_match],[ @@ -164,17 +164,17 @@ AC_CHECK_LIB([portablexdr],[xdrmem_create],[],[ dnl Functions which may not be available in older distributions. AC_CHECK_FUNCS([\ - futimens \ - getxattr \ - inotify_init1 \ - lgetxattr \ - listxattr \ - llistxattr \ - lsetxattr \ - lremovexattr \ - mknod \ - removexattr \ - setxattr]) + futimens \ + getxattr \ + inotify_init1 \ + lgetxattr \ + listxattr \ + llistxattr \ + lsetxattr \ + lremovexattr \ + mknod \ + removexattr \ + setxattr]) dnl Headers. AC_CHECK_HEADERS([\ diff --git a/daemon/daemon.h b/daemon/daemon.h index 120c86cc..7ba75990 100644 --- a/daemon/daemon.h +++ b/daemon/daemon.h @@ -105,6 +105,13 @@ extern guestfs_int_lvm_lv_list *parse_command_line_lvs (void); /*-- in proto.c --*/ extern void main_loop (int sock) __attribute__((noreturn)); +/*-- in optgroups.c (auto-generated) --*/ +struct optgroup { + const char *group; /* Name of the optional group. */ + int (*available) (void); /* Function to test availability. */ +}; +extern struct optgroup optgroups[]; + /* ordinary daemon functions use these to indicate errors */ extern void reply_with_error (const char *fs, ...) __attribute__((format (printf,1,2))); @@ -225,6 +232,16 @@ extern void reply (xdrproc_t xdrp, char *ret); } \ while (0) +/* Marks functions which are not available. + * NB. Cannot be used for FileIn functions. + */ +#define NOT_AVAILABLE(errcode) \ + do { \ + reply_with_error ("%s: function not available", __func__); \ + return (errcode); \ + } \ + while (0) + #ifndef __attribute__ # if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) # define __attribute__(x) /* empty */ diff --git a/daemon/inotify.c b/daemon/inotify.c index 465d0b6e..24ce76e2 100644 --- a/daemon/inotify.c +++ b/daemon/inotify.c @@ -31,6 +31,7 @@ #include "../src/guestfs_protocol.h" #include "daemon.h" #include "actions.h" +#include "optgroups.h" #ifdef HAVE_SYS_INOTIFY_H /* Currently open inotify handle, or -1 if not opened. */ @@ -38,6 +39,18 @@ static int inotify_fd = -1; static char inotify_buf[64*1024*1024]; /* Event buffer, [0..posn-1] is valid */ static size_t inotify_posn = 0; + +int +optgroup_inotify_available (void) +{ + return 1; +} +#else /* !HAVE_SYS_INOTIFY_H */ +int +optgroup_inotify_available (void) +{ + return 0; +} #endif /* Because inotify_init does NEED_ROOT, NEED_INOTIFY implies NEED_ROOT. */ @@ -106,8 +119,7 @@ do_inotify_init (int max_events) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -132,8 +144,7 @@ do_inotify_close (void) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -161,8 +172,7 @@ do_inotify_add_watch (const char *path, int mask) return r; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -179,8 +189,7 @@ do_inotify_rm_watch (int wd) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -294,8 +303,7 @@ do_inotify_read (void) free (ret); return NULL; #else - reply_with_error ("%s is not available", __func__); - return NULL; + NOT_AVAILABLE (NULL); #endif } @@ -371,7 +379,6 @@ do_inotify_files (void) unlink ("/tmp/inotify"); return NULL; #else - reply_with_error ("%s is not available", __func__); - return NULL; + NOT_AVAILABLE (NULL); #endif } diff --git a/daemon/lvm.c b/daemon/lvm.c index 3920e95b..564517c5 100644 --- a/daemon/lvm.c +++ b/daemon/lvm.c @@ -26,6 +26,14 @@ #include "daemon.h" #include "c-ctype.h" #include "actions.h" +#include "optgroups.h" + +int +optgroup_lvm2_available (void) +{ + int r = access ("/sbin/lvm", X_OK); + return r == 0; +} /* LVM actions. Keep an eye on liblvm, although at the time * of writing it hasn't progressed very far. diff --git a/daemon/mknod.c b/daemon/mknod.c index 6ff88efa..46a18392 100644 --- a/daemon/mknod.c +++ b/daemon/mknod.c @@ -29,6 +29,21 @@ #include "../src/guestfs_protocol.h" #include "daemon.h" #include "actions.h" +#include "optgroups.h" + +#ifdef HAVE_MKNOD +int +optgroup_mknod_available (void) +{ + return 1; +} +#else +int +optgroup_mknod_available (void) +{ + return 0; +} +#endif int do_mknod (int mode, int devmajor, int devminor, const char *path) @@ -47,8 +62,7 @@ do_mknod (int mode, int devmajor, int devminor, const char *path) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } diff --git a/daemon/modprobe.c b/daemon/modprobe.c index 7e3d1b70..ac62b349 100644 --- a/daemon/modprobe.c +++ b/daemon/modprobe.c @@ -23,6 +23,14 @@ #include "daemon.h" #include "actions.h" +#include "optgroups.h" + +int +optgroup_linuxmodules_available (void) +{ + int r = access ("/sbin/modprobe", X_OK); + return r == 0; +} int do_modprobe (const char *module) diff --git a/daemon/ntfs.c b/daemon/ntfs.c index 85deb654..b3530084 100644 --- a/daemon/ntfs.c +++ b/daemon/ntfs.c @@ -25,6 +25,14 @@ #include "daemon.h" #include "actions.h" +#include "optgroups.h" + +int +optgroup_ntfs3g_available (void) +{ + int r = access ("/bin/ntfs-3g.probe", X_OK); + return r == 0; +} int do_ntfs_3g_probe (int rw, const char *device) diff --git a/daemon/scrub.c b/daemon/scrub.c index 15c8b6c2..e37a1e11 100644 --- a/daemon/scrub.c +++ b/daemon/scrub.c @@ -26,6 +26,14 @@ #include "daemon.h" #include "actions.h" +#include "optgroups.h" + +int +optgroup_scrub_available (void) +{ + int r = access ("/usr/bin/scrub", X_OK); + return r == 0; +} int do_scrub_device (const char *device) diff --git a/daemon/selinux.c b/daemon/selinux.c index 3b4b9ba6..e49e657b 100644 --- a/daemon/selinux.c +++ b/daemon/selinux.c @@ -29,6 +29,21 @@ #include "../src/guestfs_protocol.h" #include "daemon.h" #include "actions.h" +#include "optgroups.h" + +#if defined(HAVE_LIBSELINUX) +int +optgroup_selinux_available (void) +{ + return 1; +} +#else /* !HAVE_LIBSELINUX */ +int +optgroup_selinux_available (void) +{ + return 0; +} +#endif /* !HAVE_LIBSELINUX */ /* setcon is only valid under the following circumstances: * - single threaded @@ -45,8 +60,7 @@ do_setcon (const char *context) return 0; #else - reply_with_error ("%s is not available", __func__); - return -1; + NOT_AVAILABLE (-1); #endif } @@ -71,7 +85,6 @@ do_getcon (void) return r; /* caller frees */ #else - reply_with_error ("%s is not available", __func__); - return NULL; + NOT_AVAILABLE (NULL); #endif } diff --git a/daemon/swap.c b/daemon/swap.c index bcc5f1b1..2d3d9ff4 100644 --- a/daemon/swap.c +++ b/daemon/swap.c @@ -26,6 +26,25 @@ #include "../src/guestfs_protocol.h" #include "daemon.h" #include "actions.h" +#include "optgroups.h" + +/* Convenient place to test for the later version of e2fsprogs + * and util-linux which supports -U parameters to specify UUIDs. + * (Not supported in RHEL 5). + */ +int +optgroup_linuxfsuuid_available (void) +{ + char *err; + int av; + + /* Ignore return code - mkswap --help *will* fail. */ + command (NULL, &err, "/sbin/mkswap", "--help", NULL); + + av = strstr (err, "-U") != NULL; + free (err); + return av; +} static int mkswap (const char *device, const char *flag, const char *value) diff --git a/daemon/xattr.c b/daemon/xattr.c index c218dea1..e58dc7ea 100644 --- a/daemon/xattr.c +++ b/daemon/xattr.c @@ -24,16 +24,23 @@ #include "../src/guestfs_protocol.h" #include "daemon.h" #include "actions.h" +#include "optgroups.h" #if defined(HAVE_ATTR_XATTR_H) || defined(HAVE_SYS_XATTR_H) -#ifdef HAVE_ATTR_XATTR_H -#include <attr/xattr.h> -#else -#ifdef HAVE_SYS_XATTR_H -#include <sys/xattr.h> -#endif -#endif +# ifdef HAVE_ATTR_XATTR_H +# include <attr/xattr.h> +# else +# ifdef HAVE_SYS_XATTR_H +# include <sys/xattr.h> +# endif +# endif + +int +optgroup_linuxxattrs_available (void) +{ + return 1; +} static guestfs_int_xattr_list *getxattrs (const char *path, ssize_t (*listxattr) (const char *path, char *list, size_t size), ssize_t (*getxattr) (const char *path, const char *name, void *value, size_t size)); static int _setxattr (const char *xattr, const char *val, int vallen, const char *path, int (*setxattr) (const char *path, const char *name, const void *value, size_t size, int flags)); @@ -442,54 +449,52 @@ do_lxattrlist (const char *path, char *const *names) } #else /* no xattr.h */ +int +optgroup_linuxxattrs_available (void) +{ + return 0; +} guestfs_int_xattr_list * do_getxattrs (const char *path) { - reply_with_error ("getxattrs: no support for xattrs"); - return NULL; + NOT_AVAILABLE (NULL); } guestfs_int_xattr_list * do_lgetxattrs (const char *path) { - reply_with_error ("lgetxattrs: no support for xattrs"); - return NULL; + NOT_AVAILABLE (NULL); } int do_setxattr (const char *xattr, const char *val, int vallen, const char *path) { - reply_with_error ("setxattr: no support for xattrs"); - return -1; + NOT_AVAILABLE (-1); } int do_lsetxattr (const char *xattr, const char *val, int vallen, const char *path) { - reply_with_error ("lsetxattr: no support for xattrs"); - return -1; + NOT_AVAILABLE (-1); } int do_removexattr (const char *xattr, const char *path) { - reply_with_error ("removexattr: no support for xattrs"); - return -1; + NOT_AVAILABLE (-1); } int do_lremovexattr (const char *xattr, const char *path) { - reply_with_error ("lremovexattr: no support for xattrs"); - return -1; + NOT_AVAILABLE (-1); } guestfs_int_xattr_list * do_lxattrlist (const char *path, char *const *names) { - reply_with_error ("lxattrlist: no support for xattrs"); - return NULL; + NOT_AVAILABLE (NULL); } #endif /* no xattr.h */ diff --git a/daemon/zerofree.c b/daemon/zerofree.c index ffb9b70b..05a547bd 100644 --- a/daemon/zerofree.c +++ b/daemon/zerofree.c @@ -26,6 +26,14 @@ #include "daemon.h" #include "actions.h" +#include "optgroups.h" + +int +optgroup_zerofree_available (void) +{ + int r = access ("/usr/sbin/zerofree", X_OK); + return r == 0; +} int do_zerofree (const char *device) diff --git a/guestfs.pod b/guestfs.pod index 0e7079c2..4a477330 100644 --- a/guestfs.pod +++ b/guestfs.pod @@ -623,6 +623,13 @@ developer to program in confidence against libguestfs. @STRUCTS@ +=head1 AVAILABILITY + +Using L</guestfs_available> you can test availability of +the following groups of functions: + +@AVAILABILITY@ + =head1 STATE MACHINE AND LOW-LEVEL EVENT API Internally, libguestfs is implemented by running a virtual machine diff --git a/po/POTFILES.in b/po/POTFILES.in index 2c7998d7..7707811f 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -37,6 +37,7 @@ daemon/modprobe.c daemon/mount.c daemon/names.c daemon/ntfs.c +daemon/optgroups.c daemon/parted.c daemon/pingdaemon.c daemon/proto.c diff --git a/src/generator.ml b/src/generator.ml index cceb1915..08817c12 100755 --- a/src/generator.ml +++ b/src/generator.ml @@ -175,6 +175,7 @@ type flags = | NotInFish (* do not export via guestfish *) | NotInDocs (* do not add this function to documentation *) | DeprecatedBy of string (* function is deprecated, use .. instead *) + | Optional of string (* function is part of an optional group *) (* You can supply zero or as many tests as you want per API call. * @@ -979,7 +980,7 @@ 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>."); - ("pvs", (RStringList "physvols", []), 9, [], + ("pvs", (RStringList "physvols", []), 9, [Optional "lvm2"], [InitBasicFSonLVM, Always, TestOutputListOfDevices ( [["pvs"]], ["/dev/sda1"]); InitEmpty, Always, TestOutputListOfDevices ( @@ -998,7 +999,7 @@ PVs (eg. C</dev/sda2>). See also C<guestfs_pvs_full>."); - ("vgs", (RStringList "volgroups", []), 10, [], + ("vgs", (RStringList "volgroups", []), 10, [Optional "lvm2"], [InitBasicFSonLVM, Always, TestOutputList ( [["vgs"]], ["VG"]); InitEmpty, Always, TestOutputList ( @@ -1019,7 +1020,7 @@ detected (eg. C<VolGroup00>). See also C<guestfs_vgs_full>."); - ("lvs", (RStringList "logvols", []), 11, [], + ("lvs", (RStringList "logvols", []), 11, [Optional "lvm2"], [InitBasicFSonLVM, Always, TestOutputList ( [["lvs"]], ["/dev/VG/LV"]); InitEmpty, Always, TestOutputList ( @@ -1043,21 +1044,21 @@ This returns a list of the logical volume device names See also C<guestfs_lvs_full>."); - ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [], + ("pvs_full", (RStructList ("physvols", "lvm_pv"), []), 12, [Optional "lvm2"], [], (* XXX how to test? *) "list the LVM physical volumes (PVs)", "\ List all the physical volumes detected. This is the equivalent of the L<pvs(8)> command. The \"full\" version includes all fields."); - ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [], + ("vgs_full", (RStructList ("volgroups", "lvm_vg"), []), 13, [Optional "lvm2"], [], (* XXX how to test? *) "list the LVM volume groups (VGs)", "\ List all the volumes groups detected. This is the equivalent of the L<vgs(8)> command. The \"full\" version includes all fields."); - ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [], + ("lvs_full", (RStructList ("logvols", "lvm_lv"), []), 14, [Optional "lvm2"], [], (* XXX how to test? *) "list the LVM logical volumes (LVs)", "\ @@ -1081,7 +1082,7 @@ Note that this function cannot correctly handle binary files as end of line). For those you need to use the C<guestfs_read_file> function which has a more complex interface."); - ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [], + ("aug_init", (RErr, [Pathname "root"; Int "flags"]), 16, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "create a new Augeas handle", "\ @@ -1132,7 +1133,7 @@ To close the handle, you can call C<guestfs_aug_close>. To find out more about Augeas, see L<http://augeas.net/>."); - ("aug_close", (RErr, []), 26, [], + ("aug_close", (RErr, []), 26, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "close the current Augeas handle", "\ @@ -1141,7 +1142,7 @@ used by it. After calling this, you have to call C<guestfs_aug_init> again before you can use any other Augeas functions."); - ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [], + ("aug_defvar", (RInt "nrnodes", [String "name"; OptString "expr"]), 17, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "define an Augeas variable", "\ @@ -1152,7 +1153,7 @@ undefined. On success this returns the number of nodes in C<expr>, or C<0> if C<expr> evaluates to something which is not a nodeset."); - ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [], + ("aug_defnode", (RStruct ("nrnodescreated", "int_bool"), [String "name"; String "expr"; String "val"]), 18, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "define an Augeas node", "\ @@ -1167,20 +1168,20 @@ On success this returns a pair containing the number of nodes in the nodeset, and a boolean flag if a node was created."); - ("aug_get", (RString "val", [String "augpath"]), 19, [], + ("aug_get", (RString "val", [String "augpath"]), 19, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "look up the value of an Augeas path", "\ Look up the value associated with C<path>. If C<path> matches exactly one node, the C<value> is returned."); - ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [], + ("aug_set", (RErr, [String "augpath"; String "val"]), 20, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "set Augeas path to value", "\ Set the value associated with C<path> to C<value>."); - ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [], + ("aug_insert", (RErr, [String "augpath"; String "label"; Bool "before"]), 21, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "insert a sibling Augeas node", "\ @@ -1192,7 +1193,7 @@ C<path> must match exactly one existing node in the tree, and C<label> must be a label, ie. not contain C</>, C<*> or end with a bracketed index C<[N]>."); - ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [], + ("aug_rm", (RInt "nrnodes", [String "augpath"]), 22, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "remove an Augeas path", "\ @@ -1200,14 +1201,14 @@ Remove C<path> and all of its children. On success this returns the number of entries which were removed."); - ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [], + ("aug_mv", (RErr, [String "src"; String "dest"]), 23, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "move Augeas node", "\ Move the node C<src> to C<dest>. C<src> must match exactly one node. C<dest> is overwritten if it exists."); - ("aug_match", (RStringList "matches", [String "augpath"]), 24, [], + ("aug_match", (RStringList "matches", [String "augpath"]), 24, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "return Augeas nodes which match augpath", "\ @@ -1215,7 +1216,7 @@ Returns a list of paths which match the path expression C<path>. The returned paths are sufficiently qualified so that they match exactly one node in the current tree."); - ("aug_save", (RErr, []), 25, [], + ("aug_save", (RErr, []), 25, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "write all pending Augeas changes to disk", "\ @@ -1224,7 +1225,7 @@ This writes all pending changes to disk. The flags which were passed to C<guestfs_aug_init> affect exactly how files are saved."); - ("aug_load", (RErr, []), 27, [], + ("aug_load", (RErr, []), 27, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "load files into the tree", "\ @@ -1233,7 +1234,7 @@ Load files into the tree. See C<aug_load> in the Augeas documentation for the full gory details."); - ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [], + ("aug_ls", (RStringList "matches", [String "augpath"]), 28, [Optional "augeas"], [], (* XXX Augeas code needs tests. *) "list Augeas nodes under augpath", "\ @@ -1366,7 +1367,7 @@ other objects like files. See also C<guestfs_stat>."); - ("pvcreate", (RErr, [Device "device"]), 39, [], + ("pvcreate", (RErr, [Device "device"]), 39, [Optional "lvm2"], [InitEmpty, Always, TestOutputListOfDevices ( [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; ["pvcreate"; "/dev/sda1"]; @@ -1379,7 +1380,7 @@ This creates an LVM physical volume on the named C<device>, where C<device> should usually be a partition name such as C</dev/sda1>."); - ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [], + ("vgcreate", (RErr, [String "volgroup"; DeviceList "physvols"]), 40, [Optional "lvm2"], [InitEmpty, Always, TestOutputList ( [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; ["pvcreate"; "/dev/sda1"]; @@ -1393,7 +1394,7 @@ as C</dev/sda1>."); This creates an LVM volume group called C<volgroup> from the non-empty list of physical volumes C<physvols>."); - ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [], + ("lvcreate", (RErr, [String "logvol"; String "volgroup"; Int "mbytes"]), 41, [Optional "lvm2"], [InitEmpty, Always, TestOutputList ( [["sfdiskM"; "/dev/sda"; ",100 ,200 ,"]; ["pvcreate"; "/dev/sda1"]; @@ -1544,7 +1545,7 @@ This unmounts all mounted filesystems. Some internal mounts are not unmounted by this call."); - ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson], + ("lvm_remove_all", (RErr, []), 48, [DangerWillRobinson; Optional "lvm2"], [], "remove all LVM LVs, VGs and PVs", "\ @@ -2035,7 +2036,7 @@ There is no comprehensive help for this command. You have to look at the file C<daemon/debug.c> in the libguestfs source to find out what you can do."); - ("lvremove", (RErr, [Device "device"]), 77, [], + ("lvremove", (RErr, [Device "device"]), 77, [Optional "lvm2"], [InitEmpty, Always, TestOutputList ( [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; @@ -2068,7 +2069,7 @@ the path to the LV, such as C</dev/VG/LV>. You can also remove all LVs in a volume group by specifying the VG name, C</dev/VG>."); - ("vgremove", (RErr, [String "vgname"]), 78, [], + ("vgremove", (RErr, [String "vgname"]), 78, [Optional "lvm2"], [InitEmpty, Always, TestOutputList ( [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; @@ -2092,7 +2093,7 @@ Remove an LVM volume group C<vgname>, (for example C<VG>). This also forcibly removes all logical volumes in the volume group (if any)."); - ("pvremove", (RErr, [Device "device"]), 79, [], + ("pvremove", (RErr, [Device "device"]), 79, [Optional "lvm2"], [InitEmpty, Always, TestOutputListOfDevices ( [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; @@ -2387,7 +2388,7 @@ The returned strings are transcoded to UTF-8."); This runs C<hexdump -C> on the given C<path>. The result is the human-readable, canonical hex dump of the file."); - ("zerofree", (RErr, [Device "device"]), 97, [], + ("zerofree", (RErr, [Device "device"]), 97, [Optional "zerofree"], [InitNone, Always, TestOutput ( [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ext3"; "/dev/sda1"]; @@ -2410,7 +2411,7 @@ mounted. It is possible that using this program can damage the filesystem or data on the filesystem."); - ("pvresize", (RErr, [Device "device"]), 98, [], + ("pvresize", (RErr, [Device "device"]), 98, [Optional "lvm2"], [], "resize an LVM physical volume", "\ @@ -2462,7 +2463,7 @@ kernel's idea of the geometry (see C<guestfs_sfdisk_kernel_geometry>). The result is in human-readable format, and not designed to be parsed."); - ("vg_activate_all", (RErr, [Bool "activate"]), 103, [], + ("vg_activate_all", (RErr, [Bool "activate"]), 103, [Optional "lvm2"], [], "activate or deactivate all volume groups", "\ @@ -2474,7 +2475,7 @@ then those devices disappear. This command is the same as running C<vgchange -a y|n>"); - ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [], + ("vg_activate", (RErr, [Bool "activate"; StringList "volgroups"]), 104, [Optional "lvm2"], [], "activate or deactivate some volume groups", "\ @@ -2489,7 +2490,7 @@ This command is the same as running C<vgchange -a y|n volgroups...> Note that if C<volgroups> is an empty list then B<all> volume groups are activated or deactivated."); - ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [], + ("lvresize", (RErr, [Device "device"; Int "mbytes"]), 105, [Optional "lvm2"], [InitNone, Always, TestOutput ( [["part_disk"; "/dev/sda"; "mbr"]; ["pvcreate"; "/dev/sda1"]; @@ -2582,7 +2583,7 @@ This command is only needed because of C<guestfs_resize2fs> "\ Sleep for C<secs> seconds."); - ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [], + ("ntfs_3g_probe", (RInt "status", [Bool "rw"; Device "device"]), 110, [Optional "ntfs3g"], [InitNone, Always, TestOutputInt ( [["part_disk"; "/dev/sda"; "mbr"]; ["mkfs"; "ntfs"; "/dev/sda1"]; @@ -2664,7 +2665,7 @@ It is just a wrapper around the C L<glob(3)> function with flags C<GLOB_MARK|GLOB_BRACE>. See that manual page for more details."); - ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson], + ("scrub_device", (RErr, [Device "device"]), 114, [DangerWillRobinson; Optional "scrub"], [InitNone, Always, TestRun ( (* use /dev/sdc because it's smaller *) [["scrub_device"; "/dev/sdc"]])], "scrub (securely wipe) a device", @@ -2675,7 +2676,7 @@ more difficult. It is an interface to the L<scrub(1)> program. See that manual page for more details."); - ("scrub_file", (RErr, [Pathname "file"]), 115, [], + ("scrub_file", (RErr, [Pathname "file"]), 115, [Optional "scrub"], [InitBasicFS, Always, TestRun ( [["write_file"; "/file"; "content"; "0"]; ["scrub_file"; "/file"]])], @@ -2689,7 +2690,7 @@ The file is I<removed> after scrubbing. It is an interface to the L<scrub(1)> program. See that manual page for more details."); - ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [], + ("scrub_freespace", (RErr, [Pathname "dir"]), 116, [Optional "scrub"], [], (* XXX needs testing *) "scrub (securely wipe) free space", "\ @@ -2884,7 +2885,7 @@ Note that you cannot attach a swap label to a block device (eg. C</dev/sda>), just to a partition. This appears to be a limitation of the kernel or swap tools."); - ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [], + ("mkswap_U", (RErr, [String "uuid"; Device "device"]), 132, [Optional "linuxfsuuid"], (let uuid = uuidgen () in [InitEmpty, Always, TestRun ( [["part_disk"; "/dev/sda"; "mbr"]; @@ -2893,7 +2894,7 @@ a limitation of the kernel or swap tools."); "\ Create a swap partition on C<device> with UUID C<uuid>."); - ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [], + ("mknod", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 133, [Optional "mknod"], [InitBasicFS, Always, TestOutputStruct ( [["mknod"; "0o10777"; "0"; "0"; "/node"]; (* NB: default umask 022 means 0777 -> 0755 in these tests *) @@ -2911,7 +2912,7 @@ constants. C<devmajor> and C<devminor> are the device major and minor numbers, only used when creating block and character special devices."); - ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [], + ("mkfifo", (RErr, [Int "mode"; Pathname "path"]), 134, [Optional "mknod"], [InitBasicFS, Always, TestOutputStruct ( [["mkfifo"; "0o777"; "/node"]; ["stat"; "/node"]], [CompareWithInt ("mode", 0o10755)])], @@ -2921,7 +2922,7 @@ This call creates a FIFO (named pipe) called C<path> with mode C<mode>. It is just a convenient wrapper around C<guestfs_mknod>."); - ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [], + ("mknod_b", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 135, [Optional "mknod"], [InitBasicFS, Always, TestOutputStruct ( [["mknod_b"; "0o777"; "99"; "66"; "/node"]; ["stat"; "/node"]], [CompareWithInt ("mode", 0o60755)])], @@ -2931,7 +2932,7 @@ This call creates a block device node called C<path> with mode C<mode> and device major/minor C<devmajor> and C<devminor>. It is just a convenient wrapper around C<guestfs_mknod>."); - ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [], + ("mknod_c", (RErr, [Int "mode"; Int "devmajor"; Int "devminor"; Pathname "path"]), 136, [Optional "mknod"], [InitBasicFS, Always, TestOutputStruct ( [["mknod_c"; "0o777"; "99"; "66"; "/node"]; ["stat"; "/node"]], [CompareWithInt ("mode", 0o20755)])], @@ -3046,7 +3047,7 @@ C<method> must be one of C<gzip>, C<compress> or C<bzip2>. Since 1.0.63, use C<guestfs_file> instead which can now process compressed files."); - ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [], + ("getxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 141, [Optional "linuxxattrs"], [], "list extended attributes of a file or directory", "\ @@ -3058,7 +3059,7 @@ L<listxattr(2)> and L<getxattr(2)> calls. See also: C<guestfs_lgetxattrs>, L<attr(5)>."); - ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [], + ("lgetxattrs", (RStructList ("xattrs", "xattr"), [Pathname "path"]), 142, [Optional "linuxxattrs"], [], "list extended attributes of a file or directory", "\ @@ -3068,7 +3069,7 @@ of the link itself."); ("setxattr", (RErr, [String "xattr"; String "val"; Int "vallen"; (* will be BufferIn *) - Pathname "path"]), 143, [], + Pathname "path"]), 143, [Optional "linuxxattrs"], [], "set extended attribute of a file or directory", "\ @@ -3080,7 +3081,7 @@ See also: C<guestfs_lsetxattr>, L<attr(5)>."); ("lsetxattr", (RErr, [String "xattr"; String "val"; Int "vallen"; (* will be BufferIn *) - Pathname "path"]), 144, [], + Pathname "path"]), 144, [Optional "linuxxattrs"], [], "set extended attribute of a file or directory", "\ @@ -3088,7 +3089,7 @@ This is the same as C<guestfs_setxattr>, but if C<path> is a symbolic link, then it sets an extended attribute of the link itself."); - ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [], + ("removexattr", (RErr, [String "xattr"; Pathname "path"]), 145, [Optional "linuxxattrs"], [], "remove extended attribute of a file or directory", "\ @@ -3097,7 +3098,7 @@ of the file C<path>. See also: C<guestfs_lremovexattr>, L<attr(5)>."); - ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [], + ("lremovexattr", (RErr, [String "xattr"; Pathname "path"]), 146, [Optional "linuxxattrs"], [], "remove extended attribute of a file or directory", "\ @@ -3397,7 +3398,7 @@ See C<guestfs_swapon_device> for other notes."); This command disables the libguestfs appliance swap on labeled swap partition."); - ("swapon_uuid", (RErr, [String "uuid"]), 176, [], + ("swapon_uuid", (RErr, [String "uuid"]), 176, [Optional "linuxfsuuid"], (let uuid = uuidgen () in [InitEmpty, Always, TestRun ( [["mkswap_U"; uuid; "/dev/sdb"]; @@ -3408,7 +3409,7 @@ labeled swap partition."); This command enables swap to a swap partition with the given UUID. See C<guestfs_swapon_device> for other notes."); - ("swapoff_uuid", (RErr, [String "uuid"]), 177, [], + ("swapoff_uuid", (RErr, [String "uuid"]), 177, [Optional "linuxfsuuid"], [], (* XXX tested by swapon_uuid *) "disable swap on swap partition by UUID", "\ @@ -3426,7 +3427,7 @@ Create a swap file. This command just writes a swap file signature to an existing file. To create the file itself, use something like C<guestfs_fallocate>."); - ("inotify_init", (RErr, [Int "maxevents"]), 179, [], + ("inotify_init", (RErr, [Int "maxevents"]), 179, [Optional "inotify"], [InitISOFS, Always, TestRun ( [["inotify_init"; "0"]])], "create an inotify handle", @@ -3467,7 +3468,7 @@ as exposed by the Linux kernel, which is roughly what we expose via libguestfs. Note that there is one global inotify handle per libguestfs instance."); - ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [], + ("inotify_add_watch", (RInt64 "wd", [Pathname "path"; Int "mask"]), 180, [Optional "inotify"], [InitBasicFS, Always, TestOutputList ( [["inotify_init"; "0"]; ["inotify_add_watch"; "/"; "1073741823"]; @@ -3486,14 +3487,14 @@ Note for non-C or non-Linux callers: the inotify events are defined by the Linux kernel ABI and are listed in C</usr/include/sys/inotify.h>."); - ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [], + ("inotify_rm_watch", (RErr, [Int(*XXX64*) "wd"]), 181, [Optional "inotify"], [], "remove an inotify watch", "\ Remove a previously defined inotify watch. See C<guestfs_inotify_add_watch>."); - ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [], + ("inotify_read", (RStructList ("events", "inotify_event"), []), 182, [Optional "inotify"], [], "return list of inotify events", "\ @@ -3508,7 +3509,7 @@ returns an empty list. The reason is that the call will read events up to the maximum appliance-to-host message size and leave remaining events in the queue."); - ("inotify_files", (RStringList "paths", []), 183, [], + ("inotify_files", (RStringList "paths", []), 183, [Optional "inotify"], [], "return list of watched files that had events", "\ @@ -3516,7 +3517,7 @@ This function is a helpful wrapper around C<guestfs_inotify_read> which just returns a list of pathnames of objects that were touched. The returned pathnames are sorted and deduplicated."); - ("inotify_close", (RErr, []), 184, [], + ("inotify_close", (RErr, []), 184, [Optional "inotify"], [], "close the inotify handle", "\ @@ -3524,7 +3525,7 @@ This closes the inotify handle which was previously opened by inotify_init. It removes all watches, throws away any pending events, and deallocates all resources."); - ("setcon", (RErr, [String "context"]), 185, [], + ("setcon", (RErr, [String "context"]), 185, [Optional "selinux"], [], "set SELinux security context", "\ @@ -3533,7 +3534,7 @@ to the string C<context>. See the documentation about SELINUX in L<guestfs(3)>."); - ("getcon", (RString "context", []), 186, [], + ("getcon", (RString "context", []), 186, [Optional "selinux"], [], "get SELinux security context", "\ @@ -3583,7 +3584,7 @@ to the command: "\ This creates an ext2 external journal on C<device> with label C<label>."); - ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [], + ("mke2journal_U", (RErr, [Int "blocksize"; String "uuid"; Device "device"]), 190, [Optional "linuxfsuuid"], (let uuid = uuidgen () in [InitEmpty, Always, TestOutput ( [["sfdiskM"; "/dev/sda"; ",100 ,"]; @@ -3617,7 +3618,7 @@ an external journal on the journal labeled C<label>. See also C<guestfs_mke2journal_L>."); - ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [], + ("mke2fs_JU", (RErr, [String "fstype"; Int "blocksize"; Device "device"; String "uuid"]), 193, [Optional "linuxfsuuid"], [], "make ext2/3/4 filesystem with external journal", "\ @@ -3626,7 +3627,7 @@ an external journal on the journal with UUID C<uuid>. See also C<guestfs_mke2journal_U>."); - ("modprobe", (RErr, [String "modulename"]), 194, [], + ("modprobe", (RErr, [String "modulename"]), 194, [Optional "linuxmodules"], [InitNone, Always, TestRun [["modprobe"; "fat"]]], "load a kernel module", "\ @@ -3838,7 +3839,7 @@ might cause the protocol message size to be exceeded, causing this call to fail. The caller must split up such requests into smaller groups of names."); - ("lxattrlist", (RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"]), 205, [], + ("lxattrlist", (RStructList ("xattrs", "xattr"), [Pathname "path"; StringList "names"]), 205, [Optional "linuxxattrs"], [], (* XXX *) "lgetxattr on multiple files", "\ @@ -4115,8 +4116,8 @@ The precise libguestfs function groups that may be checked by this command are listed in L<guestfs(3)/AVAILABILITY>. The argument C<groups> is a list of API group names, eg: -C<[\"inotify\", \"part\"]> would check for the availability of -the C<guestfs_inotify_*> functions and C<guestfs_part_*> +C<[\"inotify\", \"augeas\"]> would check for the availability of +the C<guestfs_inotify_*> functions and C<guestfs_aug_*> (partition editing) functions. The command returns no error if I<all> requested groups are available. @@ -4596,6 +4597,26 @@ with correct use of these functions." alt in with Not_found -> None +(* Create list of optional groups. *) +let optgroups = + let h = Hashtbl.create 13 in + List.iter ( + fun (name, _, _, flags, _, _, _) -> + List.iter ( + function + | Optional group -> + let names = try Hashtbl.find h group with Not_found -> [] in + Hashtbl.replace h group (name :: names) + | _ -> () + ) flags + ) daemon_functions; + let groups = Hashtbl.fold (fun k _ ks -> k :: ks) h [] in + let groups = + List.map ( + fun group -> group, List.sort compare (Hashtbl.find h group) + ) groups in + List.sort (fun x y -> compare (fst x) (fst y)) groups + (* Check function names etc. for consistency. *) let check_functions () = let contains_uppercase str = @@ -4919,6 +4940,21 @@ and generate_structs_pod () = pr "\n" ) structs +and generate_availability_pod () = + (* Availability documentation. *) + pr "=over 4\n"; + pr "\n"; + List.iter ( + fun (group, functions) -> + pr "=item B<%s>\n" group; + pr "\n"; + pr "The following functions:\n"; + List.iter (pr "L</guestfs_%s>\n") functions; + pr "\n" + ) optgroups; + pr "=back\n"; + pr "\n" + (* Generate the protocol (XDR) file, 'guestfs_protocol.x' and * indirectly 'guestfs_protocol.h' and 'guestfs_protocol.c'. * @@ -5934,6 +5970,34 @@ and generate_daemon_names () = ) daemon_functions; pr "};\n"; +(* Generate the optional groups for the daemon to implement + * guestfs_available. + *) +and generate_daemon_optgroups_c () = + generate_header CStyle GPLv2; + + pr "#include <config.h>\n"; + pr "\n"; + pr "#include \"daemon.h\"\n"; + pr "#include \"optgroups.h\"\n"; + pr "\n"; + + pr "struct optgroup optgroups[] = {\n"; + List.iter ( + fun (group, _) -> + pr " { \"%s\", optgroup_%s_available },\n" group group + ) optgroups; + pr " { NULL, NULL }\n"; + pr "};\n" + +and generate_daemon_optgroups_h () = + generate_header CStyle GPLv2; + + List.iter ( + fun (group, _) -> + pr "extern int optgroup_%s_available (void);\n" group + ) optgroups + (* Generate the tests. *) and generate_tests () = generate_header CStyle GPLv2; @@ -10302,6 +10366,14 @@ Run it from the top source directory using the command generate_daemon_names (); close (); + let close = output_to "daemon/optgroups.c" in + generate_daemon_optgroups_c (); + close (); + + let close = output_to "daemon/optgroups.h" in + generate_daemon_optgroups_h (); + close (); + let close = output_to "capitests/tests.c" in generate_tests (); close (); @@ -10326,6 +10398,10 @@ Run it from the top source directory using the command generate_actions_pod (); close (); + let close = output_to "guestfs-availability.pod" in + generate_availability_pod (); + close (); + let close = output_to "guestfish-actions.pod" in generate_fish_actions_pod (); close (); |