[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libguestfs] [PATCH v2] daemon: collect list of c alled external commands



guestfsd calls many different tools. Keeping track of all of them is
error prone. This patch introduces a new helper macro to put the command
string into its own ELF section:

GUESTFSD_EXT_CMD(C_variable, command_name);

This syntax makes it still possible to grep for used command names.

The actual usage of the collected list could be like this:

objcopy -j .guestfsd_ext_cmds -O binary daemon/guestfsd /dev/stdout | strings | sort -u

The resulting output will be used to tell mkinitrd which programs to
copy into the initrd.

Signed-off-by: Olaf Hering <olaf aepfle de>
---
(still not runtime tested)

v2:
 rename "guestfs" strings to "guestfsd"
 rebase to 1.9.36 and incluce new xfs command

 contrib/intro/libguestfs-intro.html |  3 +-
 daemon/9p.c                         |  3 +-
 daemon/available.c                  |  7 ++--
 daemon/base64.c                     |  6 ++--
 daemon/blkid.c                      | 10 +++---
 daemon/blockdev.c                   |  4 ++-
 daemon/btrfs.c                      | 33 +++++++++++--------
 daemon/checksum.c                   |  6 +++-
 daemon/cmp.c                        |  4 ++-
 daemon/command.c                    | 15 +++++----
 daemon/compress.c                   | 24 ++++++++------
 daemon/cpmv.c                       |  9 ++++--
 daemon/daemon.h                     |  3 ++
 daemon/dd.c                         |  4 ++-
 daemon/debug.c                      | 35 +++++++++++++-------
 daemon/df.c                         |  6 ++--
 daemon/dir.c                        |  4 ++-
 daemon/dmesg.c                      |  4 ++-
 daemon/du.c                         |  4 ++-
 daemon/ext2.c                       | 43 ++++++++++++++-----------
 daemon/file.c                       | 10 ++++--
 daemon/find.c                       |  4 ++-
 daemon/findfs.c                     |  4 ++-
 daemon/fsck.c                       |  4 ++-
 daemon/fstrim.c                     |  6 ++--
 daemon/grub.c                       |  6 ++--
 daemon/guestfsd.c                   |  7 ++--
 daemon/initrd.c                     |  5 ++-
 daemon/inotify.c                    |  4 ++-
 daemon/isoinfo.c                    |  4 ++-
 daemon/labels.c                     |  7 ++--
 daemon/link.c                       |  6 ++--
 daemon/ls.c                         |  6 ++--
 daemon/luks.c                       | 14 ++++----
 daemon/lvm-filter.c                 | 13 +++++---
 daemon/lvm.c                        | 64 +++++++++++++++++++------------------
 daemon/md.c                         | 10 +++---
 daemon/mkfs.c                       |  7 ++--
 daemon/modprobe.c                   |  6 ++--
 daemon/mount.c                      | 13 +++++---
 daemon/ntfs.c                       | 14 +++++---
 daemon/ntfsclone.c                  |  9 ++++--
 daemon/parted.c                     | 25 ++++++++-------
 daemon/rsync.c                      |  6 ++--
 daemon/scrub.c                      | 10 +++---
 daemon/sfdisk.c                     |  9 ++++--
 daemon/swap.c                       | 26 ++++++++-------
 daemon/tar.c                        |  8 +++--
 daemon/xfs.c                        | 16 +++++++---
 daemon/zero.c                       |  6 ++--
 daemon/zerofree.c                   |  6 ++--
 51 Dateien geändert, 357 Zeilen hinzugefügt(+), 205 Zeilen entfernt(-)

diff --git a/contrib/intro/libguestfs-intro.html b/contrib/intro/libguestfs-intro.html
index 380e290..52dcce5 100644
--- a/contrib/intro/libguestfs-intro.html
+++ b/contrib/intro/libguestfs-intro.html
@@ -119,6 +119,7 @@ char *
   return get_blkid_tag (device, "TYPE");
 }
 
+GUESTFSD_EXT_CMD(str_blkid, blkid);
 static char *
 get_blkid_tag (const char *device, const char *tag)
 {
@@ -126,7 +127,7 @@ get_blkid_tag (const char *device, const char *tag)
   int r;
 
   r = commandr (&amp;out, &amp;err,
-                "blkid",
+                str_blkid,
                 "-c", "/dev/null",
                 "-o", "value", "-s", tag, device, NULL);
   if (r != 0 &amp;&amp; r != 2) {
diff --git a/daemon/9p.c b/daemon/9p.c
index 8c0eeb6..49efafc 100644
--- a/daemon/9p.c
+++ b/daemon/9p.c
@@ -33,6 +33,7 @@
 #include "actions.h"
 
 #define BUS_PATH "/sys/bus/virtio/drivers/9pnet_virtio"
+GUESTFSD_EXT_CMD(str_mount, mount);
 
 static char *read_whole_file (const char *filename);
 
@@ -211,7 +212,7 @@ do_mount_9p (const char *mount_tag, const char *mountpoint, const char *options)
   }
 
   r = command (NULL, &err,
-               "mount", "-o", opts, "-t", "9p", mount_tag, mp, NULL);
+               str_mount, "-o", opts, "-t", "9p", mount_tag, mp, NULL);
   if (r == -1) {
     reply_with_error ("%s on %s: %s", mount_tag, mountpoint, err);
     goto out;
diff --git a/daemon/available.c b/daemon/available.c
index 08e72f3..7bd8a3c 100644
--- a/daemon/available.c
+++ b/daemon/available.c
@@ -29,6 +29,9 @@
 #include "actions.h"
 #include "optgroups.h"
 
+GUESTFSD_EXT_CMD(str_grep, grep);
+GUESTFSD_EXT_CMD(str_modprobe, modprobe);
+
 int
 do_available (char *const *groups)
 {
@@ -85,7 +88,7 @@ test_proc_filesystems (const char *filesystem)
 
   snprintf (regex, len, "^[[:space:]]*%s$", filesystem);
 
-  r = commandr (NULL, &err, "grep", regex, "/proc/filesystems", NULL);
+  r = commandr (NULL, &err, str_grep, regex, "/proc/filesystems", NULL);
   if (r == -1 || r >= 2) {
     fprintf (stderr, "grep /proc/filesystems: %s", err);
     free (err);
@@ -100,7 +103,7 @@ test_proc_filesystems (const char *filesystem)
 static void
 modprobe (const char *module)
 {
-  command (NULL, NULL, "modprobe", module, NULL);
+  command (NULL, NULL, str_modprobe, module, NULL);
 }
 
 /* Internal function for testing if a filesystem is available.  Note
diff --git a/daemon/base64.c b/daemon/base64.c
index 215812a..fcbeec8 100644
--- a/daemon/base64.c
+++ b/daemon/base64.c
@@ -27,6 +27,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_base64, base64);
+
 static int
 write_cb (void *fd_ptr, const void *buf, size_t len)
 {
@@ -42,7 +44,7 @@ do_base64_in (const char *file)
   FILE *fp;
   char *cmd;
 
-  if (asprintf_nowarn (&cmd, "base64 -d -i > %R", file) == -1) {
+  if (asprintf_nowarn (&cmd, "%s -d -i > %R", str_base64, file) == -1) {
     err = errno;
     cancel_receive ();
     errno = err;
@@ -102,7 +104,7 @@ do_base64_out (const char *file)
   char *cmd;
   char buf[GUESTFS_MAX_CHUNK_SIZE];
 
-  if (asprintf_nowarn (&cmd, "base64 %R", file) == -1) {
+  if (asprintf_nowarn (&cmd, "%s %R", str_base64, file) == -1) {
     reply_with_perror ("asprintf");
     return -1;
   }
diff --git a/daemon/blkid.c b/daemon/blkid.c
index 7cc7889..b6bc22d 100644
--- a/daemon/blkid.c
+++ b/daemon/blkid.c
@@ -27,6 +27,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_blkid, blkid);
+
 static char *
 get_blkid_tag (const char *device, const char *tag)
 {
@@ -34,7 +36,7 @@ get_blkid_tag (const char *device, const char *tag)
   int r;
 
   r = commandr (&out, &err,
-                "blkid",
+                str_blkid,
                 /* Adding -c option kills all caching, even on RHEL 5. */
                 "-c", "/dev/null",
                 "-o", "value", "-s", tag, device, NULL);
@@ -96,7 +98,7 @@ test_blkid_p_i_opt (void)
   int r;
   char *err;
 
-  r = commandr (NULL, &err, "blkid", "-p", "/dev/null", NULL);
+  r = commandr (NULL, &err, str_blkid, "-p", "/dev/null", NULL);
   if (r == -1) {
     /* This means we couldn't run the blkid command at all. */
   command_failed:
@@ -111,7 +113,7 @@ test_blkid_p_i_opt (void)
   }
   free (err);
 
-  r = commandr (NULL, &err, "blkid", "-i", NULL);
+  r = commandr (NULL, &err, str_blkid, "-i", NULL);
   if (r == -1)
     goto command_failed;
 
@@ -134,7 +136,7 @@ blkid_with_p_i_opt (const char *device)
   char **lines = NULL;
   DECLARE_STRINGSBUF (ret);
 
-  r = command (&out, &err, "blkid", "-c", "/dev/null",
+  r = command (&out, &err, str_blkid, "-c", "/dev/null",
                "-p", "-i", "-o", "export", device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
diff --git a/daemon/blockdev.c b/daemon/blockdev.c
index a7fd2cb..f216bf7 100644
--- a/daemon/blockdev.c
+++ b/daemon/blockdev.c
@@ -28,6 +28,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_blockdev, blockdev);
+
 /* These functions are all about using the blockdev command, so
  * we centralize it in one call.
  */
@@ -38,7 +40,7 @@ call_blockdev (const char *device, const char *switc, int extraarg, int prints)
   int64_t rv;
   char *out, *err;
   const char *argv[] = {
-    "blockdev",
+    str_blockdev,
     switc,
     NULL,
     NULL,
diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 411fdea..8ecde01 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -28,10 +28,15 @@
 #include "actions.h"
 #include "optgroups.h"
 
+GUESTFSD_EXT_CMD(str_btrfs, btrfs);
+GUESTFSD_EXT_CMD(str_btrfstune, btrfstune);
+GUESTFSD_EXT_CMD(str_btrfsck, btrfsck);
+GUESTFSD_EXT_CMD(str_mkfs_btrfs, mkfs.btrfs);
+
 int
 optgroup_btrfs_available (void)
 {
-  return prog_exists ("btrfs") && filesystem_available ("btrfs") > 0;
+  return prog_exists (str_btrfs) && filesystem_available ("btrfs") > 0;
 }
 
 /* Takes optional arguments, consult optargs_bitmask. */
@@ -46,7 +51,7 @@ do_btrfs_filesystem_resize (const char *filesystem, int64_t size)
   size_t i = 0;
   char size_str[32];
 
-  ADD_ARG (argv, i, "btrfs");
+  ADD_ARG (argv, i, str_btrfs);
   ADD_ARG (argv, i, "filesystem");
   ADD_ARG (argv, i, "resize");
 
@@ -109,7 +114,7 @@ do_mkfs_btrfs (char *const *devices,
   char nodesize_s[64];
   char sectorsize_s[64];
 
-  ADD_ARG (argv, i, "mkfs.btrfs");
+  ADD_ARG (argv, i, str_mkfs_btrfs);
 
   /* Optional arguments. */
   if (optargs_bitmask & GUESTFS_MKFS_BTRFS_ALLOCSTART_BITMASK) {
@@ -225,7 +230,7 @@ do_btrfs_subvolume_snapshot (const char *source, const char *dest)
     return -1;
   }
 
-  ADD_ARG (argv, i, "btrfs");
+  ADD_ARG (argv, i, str_btrfs);
   ADD_ARG (argv, i, "subvolume");
   ADD_ARG (argv, i, "snapshot");
   ADD_ARG (argv, i, source_buf);
@@ -261,7 +266,7 @@ do_btrfs_subvolume_delete (const char *subvolume)
     return -1;
   }
 
-  ADD_ARG (argv, i, "btrfs");
+  ADD_ARG (argv, i, str_btrfs);
   ADD_ARG (argv, i, "subvolume");
   ADD_ARG (argv, i, "delete");
   ADD_ARG (argv, i, subvolume_buf);
@@ -295,7 +300,7 @@ do_btrfs_subvolume_create (const char *dest)
     return -1;
   }
 
-  ADD_ARG (argv, i, "btrfs");
+  ADD_ARG (argv, i, str_btrfs);
   ADD_ARG (argv, i, "subvolume");
   ADD_ARG (argv, i, "create");
   ADD_ARG (argv, i, dest_buf);
@@ -331,7 +336,7 @@ do_btrfs_subvolume_list (const char *fs)
     return NULL;
   }
 
-  ADD_ARG (argv, i, "btrfs");
+  ADD_ARG (argv, i, str_btrfs);
   ADD_ARG (argv, i, "subvolume");
   ADD_ARG (argv, i, "list");
   ADD_ARG (argv, i, fs_buf);
@@ -428,7 +433,7 @@ do_btrfs_subvolume_set_default (int64_t id, const char *fs)
     return -1;
   }
 
-  ADD_ARG (argv, i, "btrfs");
+  ADD_ARG (argv, i, str_btrfs);
   ADD_ARG (argv, i, "subvolume");
   ADD_ARG (argv, i, "set-default");
   ADD_ARG (argv, i, buf);
@@ -463,7 +468,7 @@ do_btrfs_filesystem_sync (const char *fs)
     return -1;
   }
 
-  ADD_ARG (argv, i, "btrfs");
+  ADD_ARG (argv, i, str_btrfs);
   ADD_ARG (argv, i, "filesystem");
   ADD_ARG (argv, i, "sync");
   ADD_ARG (argv, i, fs_buf);
@@ -497,7 +502,7 @@ do_btrfs_filesystem_balance (const char *fs)
     return -1;
   }
 
-  ADD_ARG (argv, i, "btrfs");
+  ADD_ARG (argv, i, str_btrfs);
   ADD_ARG (argv, i, "filesystem");
   ADD_ARG (argv, i, "balance");
   ADD_ARG (argv, i, fs_buf);
@@ -536,7 +541,7 @@ do_btrfs_device_add (char *const *devices, const char *fs)
     return -1;
   }
 
-  ADD_ARG (argv, i, "btrfs");
+  ADD_ARG (argv, i, str_btrfs);
   ADD_ARG (argv, i, "device");
   ADD_ARG (argv, i, "add");
 
@@ -579,7 +584,7 @@ do_btrfs_device_delete (char *const *devices, const char *fs)
     return -1;
   }
 
-  ADD_ARG (argv, i, "btrfs");
+  ADD_ARG (argv, i, str_btrfs);
   ADD_ARG (argv, i, "device");
   ADD_ARG (argv, i, "delete");
 
@@ -609,7 +614,7 @@ do_btrfs_set_seeding (const char *device, int svalue)
 
   const char *s_value = svalue ? "1" : "0";
 
-  r = commandr (NULL, &err, "btrfstune", "-S", s_value, device, NULL);
+  r = commandr (NULL, &err, str_btrfstune, "-S", s_value, device, NULL);
   if (r == -1) {
     reply_with_error ("%s: %s", device, err);
     free (err);
@@ -631,7 +636,7 @@ do_btrfs_fsck (const char *device, int64_t superblock, int repair)
   const char *argv[MAX_ARGS];
   char super_s[64];
 
-  ADD_ARG (argv, i, "btrfsck");
+  ADD_ARG (argv, i, str_btrfsck);
 
   /* Optional arguments. */
   if (optargs_bitmask & GUESTFS_BTRFS_FSCK_SUPERBLOCK_BITMASK) {
diff --git a/daemon/checksum.c b/daemon/checksum.c
index 2cc4a2b..f2e040d 100644
--- a/daemon/checksum.c
+++ b/daemon/checksum.c
@@ -29,6 +29,9 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_find, find);
+GUESTFSD_EXT_CMD(str_xargs, xargs);
+
 static const char *
 program_of_csum (const char *csumtype)
 {
@@ -150,7 +153,8 @@ do_checksums_out (const char *csumtype, const char *dir)
   }
 
   char *cmd;
-  if (asprintf_nowarn (&cmd, "cd %Q && find -type f -print0 | xargs -0 %s",
+  if (asprintf_nowarn (&cmd, "cd %Q && %s -type f -print0 | %s -0 %s",
+                       str_find, str_xargs,
                        sysrootdir, program) == -1) {
     reply_with_perror ("asprintf");
     free (sysrootdir);
diff --git a/daemon/cmp.c b/daemon/cmp.c
index 0673403..89da3b8 100644
--- a/daemon/cmp.c
+++ b/daemon/cmp.c
@@ -27,6 +27,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_cmp, cmp);
+
 int
 do_equal (const char *file1, const char *file2)
 {
@@ -47,7 +49,7 @@ do_equal (const char *file1, const char *file2)
     return -1;
   }
 
-  r = commandr (NULL, &err, "cmp", "-s", file1buf, file2buf, NULL);
+  r = commandr (NULL, &err, str_cmp, "-s", file1buf, file2buf, NULL);
 
   free (file1buf);
   free (file2buf);
diff --git a/daemon/command.c b/daemon/command.c
index 7c67d83..5839033 100644
--- a/daemon/command.c
+++ b/daemon/command.c
@@ -28,10 +28,13 @@
 
 #include "ignore-value.h"
 
+GUESTFSD_EXT_CMD(str_mount, mount);
+GUESTFSD_EXT_CMD(str_umount, umount);
+
 static inline void
 umount_ignore_fail (const char *path)
 {
-  ignore_value (command (NULL, NULL, "umount", path, NULL));
+  ignore_value (command (NULL, NULL, str_umount, path, NULL));
 }
 
 char *
@@ -81,15 +84,15 @@ do_command (char *const *argv)
     return NULL;
   }
 
-  r = command (NULL, NULL, "mount", "--bind", "/dev", sysroot_dev, NULL);
+  r = command (NULL, NULL, str_mount, "--bind", "/dev", sysroot_dev, NULL);
   dev_ok = r != -1;
-  r = command (NULL, NULL, "mount", "--bind", "/dev/pts", sysroot_dev_pts, NULL);
+  r = command (NULL, NULL, str_mount, "--bind", "/dev/pts", sysroot_dev_pts, NULL);
   dev_pts_ok = r != -1;
-  r = command (NULL, NULL, "mount", "--bind", "/proc", sysroot_proc, NULL);
+  r = command (NULL, NULL, str_mount, "--bind", "/proc", sysroot_proc, NULL);
   proc_ok = r != -1;
-  r = command (NULL, NULL, "mount", "--bind", "/selinux", sysroot_selinux, NULL);
+  r = command (NULL, NULL, str_mount, "--bind", "/selinux", sysroot_selinux, NULL);
   selinux_ok = r != -1;
-  r = command (NULL, NULL, "mount", "--bind", "/sys", sysroot_sys, NULL);
+  r = command (NULL, NULL, str_mount, "--bind", "/sys", sysroot_sys, NULL);
   sys_ok = r != -1;
 
   CHROOT_IN;
diff --git a/daemon/compress.c b/daemon/compress.c
index b9967d9..3dc398e 100644
--- a/daemon/compress.c
+++ b/daemon/compress.c
@@ -27,6 +27,12 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_compress, compress);
+GUESTFSD_EXT_CMD(str_gzip, gzip);
+GUESTFSD_EXT_CMD(str_bzip2, bzip2);
+GUESTFSD_EXT_CMD(str_xz, xz);
+GUESTFSD_EXT_CMD(str_lzop, lzop);
+
 /* Has one FileOut parameter. */
 static int
 do_compressX_out (const char *file, const char *filter, int is_device)
@@ -118,15 +124,15 @@ get_filter (const char *ctype, int level, char *ret, size_t n)
       reply_with_error ("compress: cannot use optional level parameter with this compression type");
       return -1;
     }
-    snprintf (ret, n, "compress -c");
+    snprintf (ret, n, "%s -c", str_compress);
     return 0;
   }
   else if (STREQ (ctype, "gzip")) {
     CHECK_SUPPORTED ("gzip");
     if (level == -1)
-      snprintf (ret, n, "gzip -c");
+      snprintf (ret, n, "%s -c", str_gzip);
     else if (level >= 1 && level <= 9)
-      snprintf (ret, n, "gzip -c -%d", level);
+      snprintf (ret, n, "%s -c -%d", str_gzip, level);
     else {
       reply_with_error ("gzip: incorrect value for level parameter");
       return -1;
@@ -136,9 +142,9 @@ get_filter (const char *ctype, int level, char *ret, size_t n)
   else if (STREQ (ctype, "bzip2")) {
     CHECK_SUPPORTED ("bzip2");
     if (level == -1)
-      snprintf (ret, n, "bzip2 -c");
+      snprintf (ret, n, "%s -c", str_bzip2);
     else if (level >= 1 && level <= 9)
-      snprintf (ret, n, "bzip2 -c -%d", level);
+      snprintf (ret, n, "%s -c -%d", str_bzip2, level);
     else {
       reply_with_error ("bzip2: incorrect value for level parameter");
       return -1;
@@ -148,9 +154,9 @@ get_filter (const char *ctype, int level, char *ret, size_t n)
   else if (STREQ (ctype, "xz")) {
     CHECK_SUPPORTED ("xz");
     if (level == -1)
-      snprintf (ret, n, "xz -c");
+      snprintf (ret, n, "%s -c", str_xz);
     else if (level >= 0 && level <= 9)
-      snprintf (ret, n, "xz -c -%d", level);
+      snprintf (ret, n, "%s -c -%d", str_xz, level);
     else {
       reply_with_error ("xz: incorrect value for level parameter");
       return -1;
@@ -160,9 +166,9 @@ get_filter (const char *ctype, int level, char *ret, size_t n)
   else if (STREQ (ctype, "lzop")) {
     CHECK_SUPPORTED ("lzop");
     if (level == -1)
-      snprintf (ret, n, "lzop -c");
+      snprintf (ret, n, "%s -c", str_lzop);
     else if (level >= 1 && level <= 9)
-      snprintf (ret, n, "lzop -c -%d", level);
+      snprintf (ret, n, "%s -c -%d", str_lzop, level);
     else {
       reply_with_error ("lzop: incorrect value for level parameter");
       return -1;
diff --git a/daemon/cpmv.c b/daemon/cpmv.c
index ba7de2b..c182f68 100644
--- a/daemon/cpmv.c
+++ b/daemon/cpmv.c
@@ -25,24 +25,27 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_cp, cp);
+GUESTFSD_EXT_CMD(str_mv, mv);
+
 static int cpmv_cmd (const char *cmd, const char *flags, const char *src, const char *dest);
 
 int
 do_cp (const char *src, const char *dest)
 {
-  return cpmv_cmd ("cp", NULL, src, dest);
+  return cpmv_cmd (str_cp, NULL, src, dest);
 }
 
 int
 do_cp_a (const char *src, const char *dest)
 {
-  return cpmv_cmd ("cp", "-a", src, dest);
+  return cpmv_cmd (str_cp, "-a", src, dest);
 }
 
 int
 do_mv (const char *src, const char *dest)
 {
-  return cpmv_cmd ("mv", NULL, src, dest);
+  return cpmv_cmd (str_mv, NULL, src, dest);
 }
 
 static int
diff --git a/daemon/daemon.h b/daemon/daemon.h
index d17dcbd..a483208 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -96,6 +96,9 @@ extern char **split_lines (char *str);
 #define commandv(out,err,argv) commandvf((out),(err),0,(argv))
 #define commandrv(out,err,argv) commandrvf((out),(err),0,(argv))
 
+#define __external_command __attribute__((__section__(".guestfsd_ext_cmds")))
+#define GUESTFSD_EXT_CMD(___ext_cmd_var, ___ext_cmd_str) static const char ___ext_cmd_var[] __external_command = #___ext_cmd_str
+
 #define COMMAND_FLAG_FD_MASK                   (1024-1)
 #define COMMAND_FLAG_FOLD_STDOUT_ON_STDERR     1024
 #define COMMAND_FLAG_CHROOT_COPY_FILE_TO_STDIN 2048
diff --git a/daemon/dd.c b/daemon/dd.c
index 8bc4aab..7184ab6 100644
--- a/daemon/dd.c
+++ b/daemon/dd.c
@@ -27,6 +27,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_dd, dd);
+
 int
 do_dd (const char *src, const char *dest)
 {
@@ -58,7 +60,7 @@ do_dd (const char *src, const char *dest)
     return -1;
   }
 
-  r = command (NULL, &err, "dd", "bs=1024K", if_arg, of_arg, NULL);
+  r = command (NULL, &err, str_dd, "bs=1024K", if_arg, of_arg, NULL);
   free (if_arg);
   free (of_arg);
 
diff --git a/daemon/debug.c b/daemon/debug.c
index 97d21f0..39bda48 100644
--- a/daemon/debug.c
+++ b/daemon/debug.c
@@ -32,6 +32,15 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_printenv, printenv);
+GUESTFSD_EXT_CMD(str_ldd, ldd);
+GUESTFSD_EXT_CMD(str_ls, ls);
+GUESTFSD_EXT_CMD(str_find, find);
+GUESTFSD_EXT_CMD(str_xargs, xargs);
+GUESTFSD_EXT_CMD(str_file, file);
+GUESTFSD_EXT_CMD(str_grep, grep);
+GUESTFSD_EXT_CMD(str_gawk, gawk);
+
 /* This command exposes debugging information, internals and
  * status.  There is no comprehensive documentation for this
  * command.  You have to look at the source code in this file
@@ -275,7 +284,7 @@ debug_env (const char *subcmd, size_t argc, char *const *const argv)
   int r;
   char *out, *err;
 
-  r = command (&out, &err, "printenv", NULL);
+  r = command (&out, &err, str_printenv, NULL);
   if (r == -1) {
     reply_with_error ("printenv: %s", err);
     free (out);
@@ -318,13 +327,17 @@ debug_binaries (const char *subcmd, size_t argc, char *const *const argv)
 {
   int r;
   char *out, *err;
-
-  const char cmd[] =
-    "find / -xdev -type f -executable "
-    "| xargs file -i "
-    "| grep application/x-executable "
-    "| gawk -F: '{print $1}'";
-
+  char cmd[123];
+
+  if (snprintf(cmd, sizeof(cmd),
+    "%s / -xdev -type f -executable "
+    "| %s %s -i "
+    "| %s application/x-executable "
+    "| %s -F: '{print $1}'",
+    str_find, str_xargs, str_file, str_grep, str_gawk) >= sizeof(cmd)) {
+      reply_with_error ("find: %s", err);
+      return NULL;
+  }
   r = command (&out, &err, "sh", "-c", cmd, NULL);
   if (r == -1) {
     reply_with_error ("find: %s", err);
@@ -358,7 +371,7 @@ debug_ldd (const char *subcmd, size_t argc, char *const *const argv)
    * Also 'ldd' randomly sends messages to stderr and errors to stdout
    * depending on the phase of the moon.
    */
-  r = command (&out, &err, "ldd", "-r", argv[0], NULL);
+  r = command (&out, &err, str_ldd, "-r", argv[0], NULL);
   if (r == -1) {
     reply_with_error ("ldd: %s: %s", argv[0], err);
     free (out);
@@ -389,7 +402,7 @@ debug_ls (const char *subcmd, size_t argc, char *const *const argv)
   const char *cargv[len+3];
   size_t i;
 
-  cargv[0] = "ls";
+  cargv[0] = str_ls;
   cargv[1] = "-a";
   for (i = 0; i < len; ++i)
     cargv[2+i] = argv[i];
@@ -419,7 +432,7 @@ debug_ll (const char *subcmd, size_t argc, char *const *const argv)
   const char *cargv[len+3];
   size_t i;
 
-  cargv[0] = "ls";
+  cargv[0] = str_ls;
   cargv[1] = "-la";
   for (i = 0; i < len; ++i)
     cargv[2+i] = argv[i];
diff --git a/daemon/df.c b/daemon/df.c
index 14954d2..e723685 100644
--- a/daemon/df.c
+++ b/daemon/df.c
@@ -27,6 +27,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_df, df);
+
 char *
 do_df (void)
 {
@@ -35,7 +37,7 @@ do_df (void)
 
   NEED_ROOT (, return NULL);
 
-  r = command (&out, &err, "df", NULL);
+  r = command (&out, &err, str_df, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (out);
@@ -56,7 +58,7 @@ do_df_h (void)
 
   NEED_ROOT (, return NULL);
 
-  r = command (&out, &err, "df", "-h", NULL);
+  r = command (&out, &err, str_df, "-h", NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (out);
diff --git a/daemon/dir.c b/daemon/dir.c
index 3b18d48..aed45d6 100644
--- a/daemon/dir.c
+++ b/daemon/dir.c
@@ -29,6 +29,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_rm, rm);
+
 int
 do_rmdir (const char *path)
 {
@@ -67,7 +69,7 @@ do_rm_rf (const char *path)
     return -1;
   }
 
-  r = command (NULL, &err, "rm", "-rf", buf, NULL);
+  r = command (NULL, &err, str_rm, "-rf", buf, NULL);
   free (buf);
 
   /* rm -rf is never supposed to fail.  I/O errors perhaps? */
diff --git a/daemon/dmesg.c b/daemon/dmesg.c
index 5e98a18..69d4f37 100644
--- a/daemon/dmesg.c
+++ b/daemon/dmesg.c
@@ -27,13 +27,15 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_dmesg, dmesg);
+
 char *
 do_dmesg (void)
 {
   char *out, *err;
   int r;
 
-  r = command (&out, &err, "dmesg", NULL);
+  r = command (&out, &err, str_dmesg, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (out);
diff --git a/daemon/du.c b/daemon/du.c
index 62f1142..4392bef 100644
--- a/daemon/du.c
+++ b/daemon/du.c
@@ -28,6 +28,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_du, du);
+
 int64_t
 do_du (const char *path)
 {
@@ -45,7 +47,7 @@ do_du (const char *path)
 
   pulse_mode_start ();
 
-  r = command (&out, &err, "du", "-s", buf, NULL);
+  r = command (&out, &err, str_du, "-s", buf, NULL);
   free (buf);
   if (r == -1) {
     pulse_mode_cancel ();
diff --git a/daemon/ext2.c b/daemon/ext2.c
index 943b441..40b36d2 100644
--- a/daemon/ext2.c
+++ b/daemon/ext2.c
@@ -31,6 +31,13 @@
 
 #define MAX_ARGS 64
 
+GUESTFSD_EXT_CMD(str_tune2fs, tune2fs);
+GUESTFSD_EXT_CMD(str_e2fsck, e2fsck);
+GUESTFSD_EXT_CMD(str_resize2fs, resize2fs);
+GUESTFSD_EXT_CMD(str_mke2fs, mke2fs);
+GUESTFSD_EXT_CMD(str_lsattr, lsattr);
+GUESTFSD_EXT_CMD(str_chattr, chattr);
+
 char **
 do_tune2fs_l (const char *device)
 {
@@ -39,7 +46,7 @@ do_tune2fs_l (const char *device)
   char *p, *pend, *colon;
   DECLARE_STRINGSBUF (ret);
 
-  r = command (&out, &err, "tune2fs", "-l", device, NULL);
+  r = command (&out, &err, str_tune2fs, "-l", device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -135,7 +142,7 @@ do_set_e2uuid (const char *device, const char *uuid)
   int r;
   char *err;
 
-  r = command (NULL, &err, "tune2fs", "-U", uuid, device, NULL);
+  r = command (NULL, &err, str_tune2fs, "-U", uuid, device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -164,7 +171,7 @@ if_not_mounted_run_e2fsck (const char *device)
     return -1;
 
   if (!mounted) {
-    r = command (NULL, &err, "e2fsck", "-fy", device, NULL);
+    r = command (NULL, &err, str_e2fsck, "-fy", device, NULL);
     if (r == -1) {
       reply_with_error ("%s", err);
       free (err);
@@ -185,7 +192,7 @@ do_resize2fs (const char *device)
   if (if_not_mounted_run_e2fsck (device) == -1)
     return -1;
 
-  r = command (NULL, &err, "resize2fs", device, NULL);
+  r = command (NULL, &err, str_resize2fs, device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -219,7 +226,7 @@ do_resize2fs_size (const char *device, int64_t size)
   char buf[32];
   snprintf (buf, sizeof buf, "%" PRIi64 "K", size);
 
-  r = command (NULL, &err, "resize2fs", device, buf, NULL);
+  r = command (NULL, &err, str_resize2fs, device, buf, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -239,7 +246,7 @@ do_resize2fs_M (const char *device)
   if (if_not_mounted_run_e2fsck (device) == -1)
     return -1;
 
-  r = command (NULL, &err, "resize2fs", "-M", device, NULL);
+  r = command (NULL, &err, str_resize2fs, "-M", device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -272,7 +279,7 @@ do_e2fsck (const char *device,
     return -1;
   }
 
-  ADD_ARG (argv, i, "e2fsck");
+  ADD_ARG (argv, i, str_e2fsck);
   ADD_ARG (argv, i, "-f");
 
   if (correct)
@@ -319,7 +326,7 @@ do_mke2journal (int blocksize, const char *device)
   snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
 
   r = command (NULL, &err,
-               "mke2fs", "-F", "-O", "journal_dev", "-b", blocksize_s,
+               str_mke2fs, "-F", "-O", "journal_dev", "-b", blocksize_s,
                device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
@@ -347,7 +354,7 @@ do_mke2journal_L (int blocksize, const char *label, const char *device)
   snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
 
   r = command (NULL, &err,
-               "mke2fs", "-F", "-O", "journal_dev", "-b", blocksize_s,
+               str_mke2fs, "-F", "-O", "journal_dev", "-b", blocksize_s,
                "-L", label,
                device, NULL);
   if (r == -1) {
@@ -370,7 +377,7 @@ do_mke2journal_U (int blocksize, const char *uuid, const char *device)
   snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize);
 
   r = command (NULL, &err,
-               "mke2fs", "-F", "-O", "journal_dev", "-b", blocksize_s,
+               str_mke2fs, "-F", "-O", "journal_dev", "-b", blocksize_s,
                "-U", uuid,
                device, NULL);
   if (r == -1) {
@@ -398,7 +405,7 @@ do_mke2fs_J (const char *fstype, int blocksize, const char *device,
   snprintf (jdev, len+32, "device=%s", journal);
 
   r = command (NULL, &err,
-               "mke2fs", "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
+               str_mke2fs, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
                device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
@@ -431,7 +438,7 @@ do_mke2fs_JL (const char *fstype, int blocksize, const char *device,
   snprintf (jdev, len+32, "device=LABEL=%s", label);
 
   r = command (NULL, &err,
-               "mke2fs", "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
+               str_mke2fs, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
                device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
@@ -458,7 +465,7 @@ do_mke2fs_JU (const char *fstype, int blocksize, const char *device,
   snprintf (jdev, len+32, "device=UUID=%s", uuid);
 
   r = command (NULL, &err,
-               "mke2fs", "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
+               str_mke2fs, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s,
                device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
@@ -496,7 +503,7 @@ do_tune2fs (const char *device, /* only required parameter */
   char reservedblockscount_s[64];
   char user_s[64];
 
-  ADD_ARG (argv, i, "tune2fs");
+  ADD_ARG (argv, i, str_tune2fs);
 
   if (optargs_bitmask & GUESTFS_TUNE2FS_FORCE_BITMASK) {
     if (force)
@@ -635,7 +642,7 @@ do_get_e2attrs (const char *filename)
     return NULL;
   }
 
-  r = command (&out, &err, "lsattr", "-d", "--", buf, NULL);
+  r = command (&out, &err, str_lsattr, "-d", "--", buf, NULL);
   free (buf);
   if (r == -1) {
     reply_with_error ("%s: %s: %s", "lsattr", filename, err);
@@ -729,7 +736,7 @@ do_set_e2attrs (const char *filename, const char *attrs, int clear)
     return -1;
   }
 
-  r = command (NULL, &err, "chattr", attr_arg, "--", buf, NULL);
+  r = command (NULL, &err, str_chattr, attr_arg, "--", buf, NULL);
   free (buf);
   if (r == -1) {
     reply_with_error ("%s: %s: %s", "chattr", filename, err);
@@ -755,7 +762,7 @@ do_get_e2generation (const char *filename)
     return -1;
   }
 
-  r = command (&out, &err, "lsattr", "-dv", "--", buf, NULL);
+  r = command (&out, &err, str_lsattr, "-dv", "--", buf, NULL);
   free (buf);
   if (r == -1) {
     reply_with_error ("%s: %s: %s", "lsattr", filename, err);
@@ -793,7 +800,7 @@ do_set_e2generation (const char *filename, int64_t generation)
   snprintf (generation_str, sizeof generation_str,
             "%" PRIu64, (uint64_t) generation);
 
-  r = command (NULL, &err, "chattr", "-v", generation_str, "--", buf, NULL);
+  r = command (NULL, &err, str_chattr, "-v", generation_str, "--", buf, NULL);
   free (buf);
   if (r == -1) {
     reply_with_error ("%s: %s: %s", "chattr", filename, err);
diff --git a/daemon/file.c b/daemon/file.c
index 2756755..a5b3e85 100644
--- a/daemon/file.c
+++ b/daemon/file.c
@@ -29,6 +29,10 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_file, file);
+GUESTFSD_EXT_CMD(str_zcat, zcat);
+GUESTFSD_EXT_CMD(str_bzcat, bzcat);
+
 int
 do_touch (const char *path)
 {
@@ -473,7 +477,7 @@ do_file (const char *path)
   const char *flags = is_dev ? "-zbsL" : "-zb";
 
   char *out, *err;
-  int r = command (&out, &err, "file", flags, path, NULL);
+  int r = command (&out, &err, str_file, flags, path, NULL);
   free (buf);
 
   if (r == -1) {
@@ -503,9 +507,9 @@ do_zfile (const char *method, const char *path)
   char line[256];
 
   if (STREQ (method, "gzip") || STREQ (method, "compress"))
-    zcat = "zcat";
+    zcat = str_zcat;
   else if (STREQ (method, "bzip2"))
-    zcat = "bzcat";
+    zcat = str_bzcat;
   else {
     reply_with_error ("unknown method");
     return NULL;
diff --git a/daemon/find.c b/daemon/find.c
index 2ee2cf5..060d584 100644
--- a/daemon/find.c
+++ b/daemon/find.c
@@ -30,6 +30,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_find, find);
+
 static int
 input_to_nul (FILE *fp, char *buf, size_t maxlen)
 {
@@ -89,7 +91,7 @@ do_find0 (const char *dir)
 
   sysrootdirlen = strlen (sysrootdir);
 
-  if (asprintf_nowarn (&cmd, "find %Q -print0", sysrootdir) == -1) {
+  if (asprintf_nowarn (&cmd, "%s %Q -print0", str_find, sysrootdir) == -1) {
     reply_with_perror ("asprintf");
     free (sysrootdir);
     return -1;
diff --git a/daemon/findfs.c b/daemon/findfs.c
index 55d2d2e..3dd74b4 100644
--- a/daemon/findfs.c
+++ b/daemon/findfs.c
@@ -26,6 +26,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_findfs, findfs);
+
 static char *
 findfs (const char *tag, const char *label_or_uuid)
 {
@@ -42,7 +44,7 @@ findfs (const char *tag, const char *label_or_uuid)
   snprintf (arg, len, "%s=%s", tag, label_or_uuid);
 
   char *out, *err;
-  int r = command (&out, &err, "findfs", arg, NULL);
+  int r = command (&out, &err, str_findfs, arg, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (out);
diff --git a/daemon/fsck.c b/daemon/fsck.c
index 7e835a7..aa3537e 100644
--- a/daemon/fsck.c
+++ b/daemon/fsck.c
@@ -26,13 +26,15 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_fsck, fsck);
+
 int
 do_fsck (const char *fstype, const char *device)
 {
   char *err;
   int r;
 
-  r = commandr (NULL, &err, "fsck", "-a", "-t", fstype, device, NULL);
+  r = commandr (NULL, &err, str_fsck, "-a", "-t", fstype, device, NULL);
   if (r == -1) {
     reply_with_error ("%s: %s", device, err);
     free (err);
diff --git a/daemon/fstrim.c b/daemon/fstrim.c
index e2daf6a..ea47c95 100644
--- a/daemon/fstrim.c
+++ b/daemon/fstrim.c
@@ -30,10 +30,12 @@
 
 #define MAX_ARGS 64
 
+GUESTFSD_EXT_CMD(str_fstrim, fstrim);
+
 int
 optgroup_fstrim_available (void)
 {
-  return prog_exists ("fstrim");
+  return prog_exists (str_fstrim);
 }
 
 /* Takes optional arguments, consult optargs_bitmask. */
@@ -47,7 +49,7 @@ do_fstrim (const char *path,
   char *err;
   int r;
 
-  ADD_ARG (argv, i, "fstrim");
+  ADD_ARG (argv, i, str_fstrim);
 
   if ((optargs_bitmask & GUESTFS_FSTRIM_OFFSET_BITMASK)) {
     if (offset < 0) {
diff --git a/daemon/grub.c b/daemon/grub.c
index 9cd4f6e..cb1fac2 100644
--- a/daemon/grub.c
+++ b/daemon/grub.c
@@ -26,10 +26,12 @@
 #include "actions.h"
 #include "optgroups.h"
 
+GUESTFSD_EXT_CMD(str_grub_install, grub-install);
+
 int
 optgroup_grub_available (void)
 {
-  return prog_exists ("grub-install");
+  return prog_exists (str_grub_install);
 }
 
 int
@@ -44,7 +46,7 @@ do_grub_install (const char *root, const char *device)
     return -1;
   }
 
-  r = command (NULL, &err, "grub-install", buf, device, NULL);
+  r = command (NULL, &err, str_grub_install, buf, device, NULL);
   free (buf);
 
   if (r == -1) {
diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c
index 80175e0..e6d5fde 100644
--- a/daemon/guestfsd.c
+++ b/daemon/guestfsd.c
@@ -53,6 +53,9 @@
 
 #include "daemon.h"
 
+GUESTFSD_EXT_CMD(str_udevadm, udevadm);
+GUESTFSD_EXT_CMD(str_udevsettle, udevsettle);
+
 static char *read_cmdline (void);
 
 #ifndef MAX
@@ -1294,6 +1297,6 @@ random_name (char *template)
 void
 udev_settle (void)
 {
-  (void) command (NULL, NULL, "udevadm", "settle", NULL);
-  (void) command (NULL, NULL, "udevsettle", NULL);
+  (void) command (NULL, NULL, str_udevadm, "settle", NULL);
+  (void) command (NULL, NULL, str_udevsettle, NULL);
 }
diff --git a/daemon/initrd.c b/daemon/initrd.c
index 2ded14a..d9bc0f7 100644
--- a/daemon/initrd.c
+++ b/daemon/initrd.c
@@ -30,6 +30,9 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_zcat, zcat);
+GUESTFSD_EXT_CMD(str_cpio, cpio);
+
 char **
 do_initrd_list (const char *path)
 {
@@ -40,7 +43,7 @@ do_initrd_list (const char *path)
   size_t len;
 
   /* "zcat /sysroot/<path> | cpio --quiet -it", but path must be quoted. */
-  if (asprintf_nowarn (&cmd, "zcat %R | cpio --quiet -it", path) == -1) {
+  if (asprintf_nowarn (&cmd, "%s %R | %s --quiet -it", str_zcat, path, str_cpio) == -1) {
     reply_with_perror ("asprintf");
     return NULL;
   }
diff --git a/daemon/inotify.c b/daemon/inotify.c
index ed425b8..cb0a366 100644
--- a/daemon/inotify.c
+++ b/daemon/inotify.c
@@ -35,6 +35,8 @@
 #include "optgroups.h"
 
 #ifdef HAVE_SYS_INOTIFY_H
+GUESTFSD_EXT_CMD(str_sort, sort);
+
 /* Currently open inotify handle, or -1 if not opened. */
 static int inotify_fd = -1;
 
@@ -318,7 +320,7 @@ do_inotify_files (void)
     return NULL;
   }
 
-  snprintf (cmd, sizeof cmd, "sort -u > %s", tempfile);
+  snprintf (cmd, sizeof cmd, "%s -u > %s", str_sort, tempfile);
 
   fp = popen (cmd, "w");
   if (fp == NULL) {
diff --git a/daemon/isoinfo.c b/daemon/isoinfo.c
index c0ee1c9..d117b40 100644
--- a/daemon/isoinfo.c
+++ b/daemon/isoinfo.c
@@ -30,6 +30,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_isoinfo, isoinfo);
+
 static int
 parse_uint32 (uint32_t *ret, const char *str)
 {
@@ -244,7 +246,7 @@ isoinfo (const char *path)
   /* --debug is necessary to get additional fields, in particular
    * the date & time fields.
    */
-  r = command (&out, &err, "isoinfo", "--debug", "-d", "-i", path, NULL);
+  r = command (&out, &err, str_isoinfo, "--debug", "-d", "-i", path, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     goto done;
diff --git a/daemon/labels.c b/daemon/labels.c
index 5c59a4c..ead6b46 100644
--- a/daemon/labels.c
+++ b/daemon/labels.c
@@ -27,6 +27,9 @@
 #include "actions.h"
 #include "optgroups.h"
 
+GUESTFSD_EXT_CMD(str_e2label, e2label);
+GUESTFSD_EXT_CMD(str_ntfslabel, ntfslabel);
+
 static int
 e2label (const char *device, const char *label)
 {
@@ -39,7 +42,7 @@ e2label (const char *device, const char *label)
     return -1;
   }
 
-  r = command (NULL, &err, "e2label", device, label, NULL);
+  r = command (NULL, &err, str_e2label, device, label, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -60,7 +63,7 @@ ntfslabel (const char *device, const char *label)
    * characters and return an error.  This is not so easy since we
    * don't have the required libraries.
    */
-  r = command (NULL, &err, "ntfslabel", device, label, NULL);
+  r = command (NULL, &err, str_ntfslabel, device, label, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
diff --git a/daemon/link.c b/daemon/link.c
index 4536f00..6abe3ca 100644
--- a/daemon/link.c
+++ b/daemon/link.c
@@ -28,6 +28,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_ln, ln);
+
 char *
 do_readlink (const char *path)
 {
@@ -132,11 +134,11 @@ _link (const char *flag, int symbolic, const char *target, const char *linkname)
 
   if (flag)
     r = command (NULL, &err,
-                 "ln", flag, "--", /* target could begin with '-' */
+                 str_ln, flag, "--", /* target could begin with '-' */
                  buf_target ? : target, buf_linkname, NULL);
   else
     r = command (NULL, &err,
-                 "ln", "--",
+                 str_ln, "--",
                  buf_target ? : target, buf_linkname, NULL);
   free (buf_linkname);
   free (buf_target);
diff --git a/daemon/ls.c b/daemon/ls.c
index 5adf5ef..b2de9e5 100644
--- a/daemon/ls.c
+++ b/daemon/ls.c
@@ -30,6 +30,8 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_ls, ls);
+
 /* Has one FileOut parameter. */
 int
 do_ls0 (const char *path)
@@ -112,7 +114,7 @@ do_ll (const char *path)
     return NULL;
   }
 
-  r = command (&out, &err, "ls", "-la", spath, NULL);
+  r = command (&out, &err, str_ls, "-la", spath, NULL);
   free (spath);
   if (r == -1) {
     reply_with_error ("%s", err);
@@ -138,7 +140,7 @@ do_llz (const char *path)
     return NULL;
   }
 
-  r = command (&out, &err, "ls", "-laZ", spath, NULL);
+  r = command (&out, &err, str_ls, "-laZ", spath, NULL);
   free (spath);
   if (r == -1) {
     reply_with_error ("%s", err);
diff --git a/daemon/luks.c b/daemon/luks.c
index 02620ef..3e3b456 100644
--- a/daemon/luks.c
+++ b/daemon/luks.c
@@ -28,10 +28,12 @@
 
 #define MAX_ARGS 64
 
+GUESTFSD_EXT_CMD(str_cryptsetup, cryptsetup);
+
 int
 optgroup_luks_available (void)
 {
-  return prog_exists ("cryptsetup");
+  return prog_exists (str_cryptsetup);
 }
 
 /* Callers must also call remove_temp (tempfile). */
@@ -100,7 +102,7 @@ luks_open (const char *device, const char *key, const char *mapname,
   const char *argv[MAX_ARGS];
   size_t i = 0;
 
-  ADD_ARG (argv, i, "cryptsetup");
+  ADD_ARG (argv, i, str_cryptsetup);
   ADD_ARG (argv, i, "-d");
   ADD_ARG (argv, i, tempfile);
   if (readonly) ADD_ARG (argv, i, "--readonly");
@@ -150,7 +152,7 @@ do_luks_close (const char *device)
   const char *mapname = &device[12];
 
   char *err;
-  int r = command (NULL, &err, "cryptsetup", "luksClose", mapname, NULL);
+  int r = command (NULL, &err, str_cryptsetup, "luksClose", mapname, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -176,7 +178,7 @@ luks_format (const char *device, const char *key, int keyslot,
   char keyslot_s[16];
   size_t i = 0;
 
-  ADD_ARG (argv, i, "cryptsetup");
+  ADD_ARG (argv, i, str_cryptsetup);
   ADD_ARG (argv, i, "-q");
   if (cipher) {
     ADD_ARG (argv, i, "--cipher");
@@ -238,7 +240,7 @@ do_luks_add_key (const char *device, const char *key, const char *newkey,
   char keyslot_s[16];
   size_t i = 0;
 
-  ADD_ARG (argv, i, "cryptsetup");
+  ADD_ARG (argv, i, str_cryptsetup);
   ADD_ARG (argv, i, "-q");
   ADD_ARG (argv, i, "-d");
   ADD_ARG (argv, i, keyfile);
@@ -277,7 +279,7 @@ do_luks_kill_slot (const char *device, const char *key, int keyslot)
   char keyslot_s[16];
   size_t i = 0;
 
-  ADD_ARG (argv, i, "cryptsetup");
+  ADD_ARG (argv, i, str_cryptsetup);
   ADD_ARG (argv, i, "-q");
   ADD_ARG (argv, i, "-d");
   ADD_ARG (argv, i, tempfile);
diff --git a/daemon/lvm-filter.c b/daemon/lvm-filter.c
index 5eb2402..cde773d 100644
--- a/daemon/lvm-filter.c
+++ b/daemon/lvm-filter.c
@@ -31,6 +31,11 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_lvm, lvm);
+GUESTFSD_EXT_CMD(str_vgchange, vgchange);
+GUESTFSD_EXT_CMD(str_cp, cp);
+GUESTFSD_EXT_CMD(str_rm, rm);
+
 /* This runs during daemon start up and creates a complete copy of
  * /etc/lvm so that we can modify it as we desire.  We set
  * LVM_SYSTEM_DIR to point to the copy.
@@ -65,7 +70,7 @@ copy_lvm (void)
   }
 
   /* Hopefully no dotfiles in there ... XXX */
-  snprintf (cmd, sizeof cmd, "cp -a /etc/lvm/* %s", lvm_system_dir);
+  snprintf (cmd, sizeof cmd, "%s -a /etc/lvm/* %s", str_cp, lvm_system_dir);
   r = system (cmd);
   if (r == -1) {
     perror (cmd);
@@ -92,7 +97,7 @@ rm_lvm_system_dir (void)
 {
   char cmd[64];
 
-  snprintf (cmd, sizeof cmd, "rm -rf %s", lvm_system_dir);
+  snprintf (cmd, sizeof cmd, "%s -rf %s", str_rm, lvm_system_dir);
   ignore_value (system (cmd));
 }
 
@@ -189,7 +194,7 @@ static int
 vgchange (const char *vgchange_flag)
 {
   char *err;
-  int r = command (NULL, &err, "lvm", "vgchange", vgchange_flag, NULL);
+  int r = command (NULL, &err, str_lvm, str_vgchange, vgchange_flag, NULL);
   if (r == -1) {
     reply_with_error ("vgchange: %s", err);
     free (err);
@@ -224,7 +229,7 @@ rescan (void)
   unlink (lvm_cache);
 
   char *err;
-  int r = command (NULL, &err, "lvm", "vgscan", NULL);
+  int r = command (NULL, &err, str_lvm, "vgscan", NULL);
   if (r == -1) {
     reply_with_error ("vgscan: %s", err);
     free (err);
diff --git a/daemon/lvm.c b/daemon/lvm.c
index 5f0c3a6..24473f4 100644
--- a/daemon/lvm.c
+++ b/daemon/lvm.c
@@ -32,10 +32,12 @@
 #include "actions.h"
 #include "optgroups.h"
 
+GUESTFSD_EXT_CMD(str_lvm, lvm);
+
 int
 optgroup_lvm2_available (void)
 {
-  return prog_exists ("lvm");
+  return prog_exists (str_lvm);
 }
 
 /* LVM actions.  Keep an eye on liblvm, although at the time
@@ -105,7 +107,7 @@ do_pvs (void)
   int r;
 
   r = command (&out, &err,
-               "lvm", "pvs", "-o", "pv_name", "--noheadings", NULL);
+               str_lvm, "pvs", "-o", "pv_name", "--noheadings", NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (out);
@@ -125,7 +127,7 @@ do_vgs (void)
   int r;
 
   r = command (&out, &err,
-               "lvm", "vgs", "-o", "vg_name", "--noheadings", NULL);
+               str_lvm, "vgs", "-o", "vg_name", "--noheadings", NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (out);
@@ -145,7 +147,7 @@ do_lvs (void)
   int r;
 
   r = command (&out, &err,
-               "lvm", "lvs",
+               str_lvm, "lvs",
                "-o", "vg_name,lv_name", "--noheadings",
                "--separator", "/", NULL);
   if (r == -1) {
@@ -189,7 +191,7 @@ do_pvcreate (const char *device)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "pvcreate", device, NULL);
+               str_lvm, "pvcreate", device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -216,7 +218,7 @@ do_vgcreate (const char *volgroup, char *const *physvols)
     reply_with_perror ("malloc");
     return -1;
   }
-  argv[0] = "lvm";
+  argv[0] = str_lvm;
   argv[1] = "vgcreate";
   argv[2] = volgroup;
   for (i = 3; i <= argc; ++i)
@@ -248,7 +250,7 @@ do_lvcreate (const char *logvol, const char *volgroup, int mbytes)
   snprintf (size, sizeof size, "%d", mbytes);
 
   r = command (NULL, &err,
-               "lvm", "lvcreate",
+               str_lvm, "lvcreate",
                "-L", size, "-n", logvol, volgroup, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
@@ -278,7 +280,7 @@ do_lvcreate_free (const char *logvol, const char *volgroup, int percent)
   snprintf (size, sizeof size, "%d%%FREE", percent);
 
   r = command (NULL, &err,
-               "lvm", "lvcreate",
+               str_lvm, "lvcreate",
                "-l", size, "-n", logvol, volgroup, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
@@ -303,7 +305,7 @@ do_lvresize (const char *logvol, int mbytes)
   snprintf (size, sizeof size, "%d", mbytes);
 
   r = command (NULL, &err,
-               "lvm", "lvresize",
+               str_lvm, "lvresize",
                "--force", "-L", size, logvol, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
@@ -330,7 +332,7 @@ do_lvresize_free (const char *logvol, int percent)
   snprintf (size, sizeof size, "+%d%%FREE", percent);
 
   r = command (NULL, &err,
-               "lvm", "lvresize", "-l", size, logvol, NULL);
+               str_lvm, "lvresize", "-l", size, logvol, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -361,10 +363,10 @@ do_lvm_remove_all (void)
     /* Deactivate the LV first.  On Ubuntu, lvremove '-f' option
      * does not remove active LVs reliably.
      */
-    (void) command (NULL, NULL, "lvm", "lvchange", "-an", xs[i], NULL);
+    (void) command (NULL, NULL, str_lvm, "lvchange", "-an", xs[i], NULL);
     udev_settle ();
 
-    r = command (NULL, &err, "lvm", "lvremove", "-f", xs[i], NULL);
+    r = command (NULL, &err, str_lvm, "lvremove", "-f", xs[i], NULL);
     if (r == -1) {
       reply_with_error ("lvremove: %s: %s", xs[i], err);
       free (err);
@@ -382,10 +384,10 @@ do_lvm_remove_all (void)
 
   for (i = 0; xs[i] != NULL; ++i) {
     /* Deactivate the VG first, see note above. */
-    (void) command (NULL, NULL, "lvm", "vgchange", "-an", xs[i], NULL);
+    (void) command (NULL, NULL, str_lvm, "vgchange", "-an", xs[i], NULL);
     udev_settle ();
 
-    r = command (NULL, &err, "lvm", "vgremove", "-f", xs[i], NULL);
+    r = command (NULL, &err, str_lvm, "vgremove", "-f", xs[i], NULL);
     if (r == -1) {
       reply_with_error ("vgremove: %s: %s", xs[i], err);
       free (err);
@@ -402,7 +404,7 @@ do_lvm_remove_all (void)
     return -1;
 
   for (i = 0; xs[i] != NULL; ++i) {
-    r = command (NULL, &err, "lvm", "pvremove", "-f", xs[i], NULL);
+    r = command (NULL, &err, str_lvm, "pvremove", "-f", xs[i], NULL);
     if (r == -1) {
       reply_with_error ("pvremove: %s: %s", xs[i], err);
       free (err);
@@ -426,7 +428,7 @@ do_lvremove (const char *device)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "lvremove", "-f", device, NULL);
+               str_lvm, "lvremove", "-f", device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -447,7 +449,7 @@ do_vgremove (const char *device)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "vgremove", "-f", device, NULL);
+               str_lvm, "vgremove", "-f", device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -468,7 +470,7 @@ do_pvremove (const char *device)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "pvremove", "-ff", device, NULL);
+               str_lvm, "pvremove", "-ff", device, NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -489,7 +491,7 @@ do_pvresize (const char *device)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "pvresize", device, NULL);
+               str_lvm, "pvresize", device, NULL);
   if (r == -1) {
     reply_with_error ("%s: %s", device, err);
     free (err);
@@ -510,7 +512,7 @@ do_pvresize_size (const char *device, int64_t size)
   snprintf (buf, sizeof buf, "%" PRIi64 "b", size);
 
   r = command (NULL, &err,
-               "lvm", "pvresize",
+               str_lvm, "pvresize",
                "--setphysicalvolumesize", buf,
                device, NULL);
   if (r == -1) {
@@ -537,7 +539,7 @@ do_vg_activate (int activate, char *const *volgroups)
     return -1;
   }
 
-  argv[0] = "lvm";
+  argv[0] = str_lvm;
   argv[1] = "vgchange";
   argv[2] = "-a";
   argv[3] = activate ? "y" : "n";
@@ -574,7 +576,7 @@ do_lvrename (const char *logvol, const char *newlogvol)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "lvrename",
+               str_lvm, "lvrename",
                logvol, newlogvol, NULL);
   if (r == -1) {
     reply_with_error ("%s -> %s: %s", logvol, newlogvol, err);
@@ -596,7 +598,7 @@ do_vgrename (const char *volgroup, const char *newvolgroup)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "vgrename",
+               str_lvm, "vgrename",
                volgroup, newvolgroup, NULL);
   if (r == -1) {
     reply_with_error ("%s -> %s: %s", volgroup, newvolgroup, err);
@@ -617,7 +619,7 @@ get_lvm_field (const char *cmd, const char *field, const char *device)
   char *out;
   char *err;
   int r = command (&out, &err,
-                   "lvm", cmd,
+                   str_lvm, cmd,
                    "--unbuffered", "--noheadings", "-o", field,
                    device, NULL);
   if (r == -1) {
@@ -657,7 +659,7 @@ get_lvm_fields (const char *cmd, const char *field, const char *device)
   char *out;
   char *err;
   int r = command (&out, &err,
-                   "lvm", cmd,
+                   str_lvm, cmd,
                    "--unbuffered", "--noheadings", "-o", field,
                    device, NULL);
   if (r == -1) {
@@ -701,7 +703,7 @@ do_vgscan (void)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "vgscan", NULL);
+               str_lvm, "vgscan", NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -893,7 +895,7 @@ do_vgmeta (const char *vg, size_t *size_r)
 
   close (fd);
 
-  r = command (NULL, &err, "lvm", "vgcfgbackup", "-f", tmp, vg, NULL);
+  r = command (NULL, &err, str_lvm, "vgcfgbackup", "-f", tmp, vg, NULL);
   if (r == -1) {
     reply_with_error ("vgcfgbackup: %s", err);
     free (err);
@@ -968,7 +970,7 @@ do_pvchange_uuid (const char *device)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "pvchange", "-u", device, NULL);
+               str_lvm, "pvchange", "-u", device, NULL);
   if (r == -1) {
     reply_with_error ("%s: %s", device, err);
     free (err);
@@ -989,7 +991,7 @@ do_pvchange_uuid_all (void)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "pvchange", "-u", "-a", NULL);
+               str_lvm, "pvchange", "-u", "-a", NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
@@ -1010,7 +1012,7 @@ do_vgchange_uuid (const char *vg)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "vgchange", "-u", vg, NULL);
+               str_lvm, "vgchange", "-u", vg, NULL);
   if (r == -1) {
     reply_with_error ("%s: %s", vg, err);
     free (err);
@@ -1031,7 +1033,7 @@ do_vgchange_uuid_all (void)
   int r;
 
   r = command (NULL, &err,
-               "lvm", "vgchange", "-u", NULL);
+               str_lvm, "vgchange", "-u", NULL);
   if (r == -1) {
     reply_with_error ("%s", err);
     free (err);
diff --git a/daemon/md.c b/daemon/md.c
index 0e2f704..4281b4e 100644
--- a/daemon/md.c
+++ b/daemon/md.c
@@ -29,10 +29,12 @@
 #include "optgroups.h"
 #include "c-ctype.h"
 
+GUESTFSD_EXT_CMD(str_mdadm, mdadm);
+
 int
 optgroup_mdadm_available (void)
 {
-  return prog_exists ("mdadm");
+  return prog_exists (str_mdadm);
 }
 
 static size_t
@@ -121,7 +123,7 @@ do_md_create (const char *name, char *const *devices,
   const char *argv[MAX_ARGS];
   size_t i = 0;
 
-  ADD_ARG (argv, i, "mdadm");
+  ADD_ARG (argv, i, str_mdadm);
   ADD_ARG (argv, i, "--create");
   /* --run suppresses "Continue creating array" question */
   ADD_ARG (argv, i, "--run");
@@ -244,7 +246,7 @@ do_md_detail(const char *md)
 
   DECLARE_STRINGSBUF (ret);
 
-  const char *mdadm[] = { "mdadm", "-D", "--export", md, NULL };
+  const char *mdadm[] = { str_mdadm, "-D", "--export", md, NULL };
   r = commandv (&out, &err, mdadm);
   if (r == -1) {
     reply_with_error ("%s", err);
@@ -319,7 +321,7 @@ do_md_stop(const char *md)
   int r;
   char *err = NULL;
 
-  const char *mdadm[] = { "mdadm", "--stop", md, NULL};
+  const char *mdadm[] = { str_mdadm, "--stop", md, NULL};
   r = commandv(NULL, &err, mdadm);
   if (r == -1) {
     reply_with_error("%s", err);
diff --git a/daemon/mkfs.c b/daemon/mkfs.c
index 7d28061..241d346 100644
--- a/daemon/mkfs.c
+++ b/daemon/mkfs.c
@@ -31,6 +31,9 @@
 
 #define MAX_ARGS 64
 
+GUESTFSD_EXT_CMD(str_mke2fs, mke2fs);
+GUESTFSD_EXT_CMD(str_mkfs, mkfs);
+
 /* Takes optional arguments, consult optargs_bitmask. */
 int
 do_mkfs (const char *fstype, const char *device, int blocksize,
@@ -54,9 +57,9 @@ do_mkfs (const char *fstype, const char *device, int blocksize,
    * option.
    */
   if (extfs)
-    ADD_ARG (argv, i, "mke2fs");
+    ADD_ARG (argv, i, str_mke2fs);
   else
-    ADD_ARG (argv, i, "mkfs");
+    ADD_ARG (argv, i, str_mkfs);
 
   ADD_ARG (argv, i, "-t");
   ADD_ARG (argv, i, fstype);
diff --git a/daemon/modprobe.c b/daemon/modprobe.c
index 1063043..3f45270 100644
--- a/daemon/modprobe.c
+++ b/daemon/modprobe.c
@@ -25,17 +25,19 @@
 #include "actions.h"
 #include "optgroups.h"
 
+GUESTFSD_EXT_CMD(str_modprobe, modprobe);
+
 int
 optgroup_linuxmodules_available (void)
 {
-  return prog_exists ("modprobe");
+  return prog_exists (str_modprobe);
 }
 
 int
 do_modprobe (const char *module)
 {
   char *err;
-  int r = command (NULL, &err, "modprobe", module, NULL);
+  int r = command (NULL, &err, str_modprobe, module, NULL);
 
   if (r == -1) {
     reply_with_error ("%s", err);
diff --git a/daemon/mount.c b/daemon/mount.c
index bd27f94..c84faaf 100644
--- a/daemon/mount.c
+++ b/daemon/mount.c
@@ -31,6 +31,9 @@
 
 #define MAX_ARGS 64
 
+GUESTFSD_EXT_CMD(str_mount, mount);
+GUESTFSD_EXT_CMD(str_umount, umount);
+
 /* You must mount something on "/" first before many operations.
  * Hence we have an internal function which can test if something is
  * mounted on *or under* the sysroot directory.  (It has to be *or
@@ -150,10 +153,10 @@ do_mount_vfs (const char *options, const char *vfstype,
 
   if (vfstype)
     r = command (NULL, &error,
-                 "mount", "-o", options, "-t", vfstype, device, mp, NULL);
+                 str_mount, "-o", options, "-t", vfstype, device, mp, NULL);
   else
     r = command (NULL, &error,
-                 "mount", "-o", options, device, mp, NULL);
+                 str_mount, "-o", options, device, mp, NULL);
   free (mp);
   if (r == -1) {
     reply_with_error ("%s on %s (options: '%s'): %s",
@@ -213,7 +216,7 @@ do_umount (const char *pathordevice,
   /* Use the external /bin/umount program, so that /etc/mtab is kept
    * updated.
    */
-  ADD_ARG (argv, i, "umount");
+  ADD_ARG (argv, i, str_umount);
 
   if (force)
     ADD_ARG (argv, i, "-f");
@@ -382,7 +385,7 @@ do_umount_all (void)
 
   /* Unmount them. */
   for (i = 0; i < mounts.size; ++i) {
-    r = command (NULL, &err, "umount", mounts.argv[i], NULL);
+    r = command (NULL, &err, str_umount, mounts.argv[i], NULL);
     if (r == -1) {
       reply_with_error ("umount: %s: %s", mounts.argv[i], err);
       free (err);
@@ -422,7 +425,7 @@ do_mount_loop (const char *file, const char *mountpoint)
     return -1;
   }
 
-  r = command (NULL, &error, "mount", "-o", "loop", buf, mp, NULL);
+  r = command (NULL, &error, str_mount, "-o", "loop", buf, mp, NULL);
   free (mp);
   free (buf);
   if (r == -1) {
diff --git a/daemon/ntfs.c b/daemon/ntfs.c
index 2dedc26..613b9c3 100644
--- a/daemon/ntfs.c
+++ b/daemon/ntfs.c
@@ -30,16 +30,20 @@
 
 #define MAX_ARGS 64
 
+GUESTFSD_EXT_CMD(str_ntfs3g_probe, ntfs-3g.probe);
+GUESTFSD_EXT_CMD(str_ntfsresize, ntfsresize);
+GUESTFSD_EXT_CMD(str_ntfsfix, ntfsfix);
+
 int
 optgroup_ntfs3g_available (void)
 {
-  return prog_exists ("ntfs-3g.probe");
+  return prog_exists (str_ntfs3g_probe);
 }
 
 int
 optgroup_ntfsprogs_available (void)
 {
-  return prog_exists ("ntfsresize");
+  return prog_exists (str_ntfsresize);
 }
 
 int
@@ -51,7 +55,7 @@ do_ntfs_3g_probe (int rw, const char *device)
 
   rw_flag = rw ? "-w" : "-r";
 
-  r = commandr (NULL, &err, "ntfs-3g.probe", rw_flag, device, NULL);
+  r = commandr (NULL, &err, str_ntfs3g_probe, rw_flag, device, NULL);
   if (r == -1) {
     reply_with_error ("%s: %s", device, err);
     free (err);
@@ -72,7 +76,7 @@ do_ntfsresize (const char *device, int64_t size, int force)
   size_t i = 0;
   char size_str[32];
 
-  ADD_ARG (argv, i, "ntfsresize");
+  ADD_ARG (argv, i, str_ntfsresize);
   ADD_ARG (argv, i, "-P");
 
   if (optargs_bitmask & GUESTFS_NTFSRESIZE_SIZE_BITMASK) {
@@ -119,7 +123,7 @@ do_ntfsfix (const char *device, int clearbadsectors)
   int r;
   char *err;
 
-  ADD_ARG (argv, i, "ntfsfix");
+  ADD_ARG (argv, i, str_ntfsfix);
 
   if ((optargs_bitmask & GUESTFS_NTFSFIX_CLEARBADSECTORS_BITMASK) &&
       clearbadsectors)
diff --git a/daemon/ntfsclone.c b/daemon/ntfsclone.c
index 4287edb..bf97eaf 100644
--- a/daemon/ntfsclone.c
+++ b/daemon/ntfsclone.c
@@ -30,6 +30,8 @@
 #include "actions.h"
 #include "optgroups.h"
 
+GUESTFSD_EXT_CMD(str_ntfsclone, ntfsclone);
+
 /* Read the error file.  Returns a string that the caller must free. */
 static char *
 read_error_file (char *error_file)
@@ -80,8 +82,8 @@ do_ntfsclone_in (const char *device)
   close (fd);
 
   /* Construct the command. */
-  if (asprintf_nowarn (&cmd, "ntfsclone -O %s --restore-image - 2> %s",
-                       device, error_file) == -1) {
+  if (asprintf_nowarn (&cmd, "%s -O %s --restore-image - 2> %s",
+                       str_ntfsclone, device, error_file) == -1) {
     err = errno;
     r = cancel_receive ();
     errno = err;
@@ -157,7 +159,8 @@ do_ntfsclone_out (const char *device,
   char buf[GUESTFS_MAX_CHUNK_SIZE];
 
   /* Construct the ntfsclone command. */
-  if (asprintf (&cmd, "ntfsclone -o - --save-image%s%s%s%s%s %s",
+  if (asprintf (&cmd, "%s -o - --save-image%s%s%s%s%s %s",
+                str_ntfsclone,
                 (optargs_bitmask & GUESTFS_NTFSCLONE_OUT_METADATAONLY_BITMASK) && metadataonly ? " --metadata" : "",
                 (optargs_bitmask & GUESTFS_NTFSCLONE_OUT_RESCUE_BITMASK) && rescue ? " --rescue" : "",
                 (optargs_bitmask & GUESTFS_NTFSCLONE_OUT_IGNOREFSCHECK_BITMASK) && ignorefscheck ? " --ignore-fs-check" : "",
diff --git a/daemon/parted.c b/daemon/parted.c
index ceefc4a..cc9a84b 100644
--- a/daemon/parted.c
+++ b/daemon/parted.c
@@ -28,6 +28,9 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_parted, parted);
+GUESTFSD_EXT_CMD(str_sfdisk, sfdisk);
+
 /* Notes:
  *
  * Parted 1.9 sends error messages to stdout, hence use of the
@@ -82,7 +85,7 @@ do_part_init (const char *device, const char *parttype)
   udev_settle ();
 
   r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
-                "parted", "-s", "--", device, "mklabel", parttype, NULL);
+                str_parted, "-s", "--", device, "mklabel", parttype, NULL);
   if (r == -1) {
     reply_with_error ("parted: %s: %s", device, err);
     free (err);
@@ -137,7 +140,7 @@ do_part_add (const char *device, const char *prlogex,
    * this as a bug in the parted mkpart command.
    */
   r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
-                "parted", "-s", "--",
+                str_parted, "-s", "--",
                 device, "mkpart", prlogex, startstr, endstr, NULL);
   if (r == -1) {
     reply_with_error ("parted: %s: %s", device, err);
@@ -168,7 +171,7 @@ do_part_del (const char *device, int partnum)
   udev_settle ();
 
   r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
-                "parted", "-s", "--", device, "rm", partnum_str, NULL);
+                str_parted, "-s", "--", device, "rm", partnum_str, NULL);
   if (r == -1) {
     reply_with_error ("parted: %s: %s", device, err);
     free (err);
@@ -209,7 +212,7 @@ do_part_disk (const char *device, const char *parttype)
   udev_settle ();
 
   r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
-                "parted", "-s", "--",
+                str_parted, "-s", "--",
                 device,
                 "mklabel", parttype,
                 /* See comment about about the parted mkpart command. */
@@ -245,7 +248,7 @@ do_part_set_bootable (const char *device, int partnum, int bootable)
   udev_settle ();
 
   r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
-                "parted", "-s", "--",
+                str_parted, "-s", "--",
                 device, "set", partstr, "boot", bootable ? "on" : "off", NULL);
   if (r == -1) {
     reply_with_error ("parted: %s: %s", device, err);
@@ -277,7 +280,7 @@ do_part_set_name (const char *device, int partnum, const char *name)
   udev_settle ();
 
   r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
-                "parted", "-s", "--", device, "name", partstr, name, NULL);
+                str_parted, "-s", "--", device, "name", partstr, name, NULL);
   if (r == -1) {
     reply_with_error ("parted: %s: %s", device, err);
     free (err);
@@ -333,7 +336,7 @@ test_parted_m_opt (void)
     return result;
 
   char *err = NULL;
-  int r = commandr (NULL, &err, "parted", "-s", "-m", "/dev/null", NULL);
+  int r = commandr (NULL, &err, str_parted, "-s", "-m", "/dev/null", NULL);
   if (r == -1) {
     /* Test failed, eg. missing or completely unusable parted binary. */
     reply_with_error ("could not run 'parted' command");
@@ -356,11 +359,11 @@ print_partition_table (const char *device, int parted_has_m_opt)
   int r;
 
   if (parted_has_m_opt)
-    r = command (&out, &err, "parted", "-m", "--", device,
+    r = command (&out, &err, str_parted, "-m", "--", device,
                  "unit", "b",
                  "print", NULL);
   else
-    r = command (&out, &err, "parted", "-s", "--", device,
+    r = command (&out, &err, str_parted, "-s", "--", device,
                  "unit", "b",
                  "print", NULL);
   if (r == -1) {
@@ -744,7 +747,7 @@ do_part_get_mbr_id (const char *device, int partnum)
 
   udev_settle ();
 
-  r = command (&out, &err, "sfdisk", "--print-id", device, partnum_str, NULL);
+  r = command (&out, &err, str_sfdisk, "--print-id", device, partnum_str, NULL);
   if (r == -1) {
     reply_with_error ("sfdisk --print-id: %s", err);
     free (out);
@@ -786,7 +789,7 @@ do_part_set_mbr_id (const char *device, int partnum, int idbyte)
 
   udev_settle ();
 
-  r = command (NULL, &err, "sfdisk",
+  r = command (NULL, &err, str_sfdisk,
                "--change-id", device, partnum_str, idbyte_str, NULL);
   if (r == -1) {
     reply_with_error ("sfdisk --change-id: %s", err);
diff --git a/daemon/rsync.c b/daemon/rsync.c
index 95f0f86..e4a7237 100644
--- a/daemon/rsync.c
+++ b/daemon/rsync.c
@@ -30,10 +30,12 @@
 
 #define MAX_ARGS 64
 
+GUESTFSD_EXT_CMD(str_rsync, rsync);
+
 int
 optgroup_rsync_available (void)
 {
-  return prog_exists ("rsync");
+  return prog_exists (str_rsync);
 }
 
 static int
@@ -46,7 +48,7 @@ rsync (const char *src, const char *src_orig,
   int r;
   char *err;
 
-  ADD_ARG (argv, i, "rsync");
+  ADD_ARG (argv, i, str_rsync);
 
   if (archive)
     ADD_ARG (argv, i, "--archive");
diff --git a/daemon/scrub.c b/daemon/scrub.c
index 2cef69d..cce8da5 100644
--- a/daemon/scrub.c
+++ b/daemon/scrub.c
@@ -28,10 +28,12 @@
 #include "actions.h"
 #include "optgroups.h"
 
+GUESTFSD_EXT_CMD(str_scrub, scrub);
+
 int
 optgroup_scrub_available (void)
 {
-  return prog_exists ("scrub");
+  return prog_exists (str_scrub);
 }
 
 int
@@ -40,7 +42,7 @@ do_scrub_device (const char *device)
   char *err;
   int r;
 
-  r = command (NULL, &err, "scrub", device, NULL);
+  r = command (NULL, &err, str_scrub, device, NULL);
   if (r == -1) {
     reply_with_error ("%s: %s", device, err);
     free (err);
@@ -66,7 +68,7 @@ do_scrub_file (const char *file)
     return -1;
   }
 
-  r = command (NULL, &err, "scrub", "-r", buf, NULL);
+  r = command (NULL, &err, str_scrub, "-r", buf, NULL);
   free (buf);
   if (r == -1) {
     reply_with_error ("%s: %s", file, err);
@@ -93,7 +95,7 @@ do_scrub_freespace (const char *dir)
     return -1;
   }
 
-  r = command (NULL, &err, "scrub", "-X", buf, NULL);
+  r = command (NULL, &err, str_scrub, "-X", buf, NULL);
   free (buf);
   if (r == -1) {
     reply_with_error ("%s: %s", dir, err);
diff --git a/daemon/sfdisk.c b/daemon/sfdisk.c
index 8221ffa..1ce6962 100644
--- a/daemon/sfdisk.c
+++ b/daemon/sfdisk.c
@@ -29,6 +29,9 @@
 #include "daemon.h"
 #include "actions.h"
 
+GUESTFSD_EXT_CMD(str_sfdisk, sfdisk);
+GUESTFSD_EXT_CMD(str_blockdev, blockdev);
+
 static int
 sfdisk (const char *device, int n, int cyls, int heads, int sectors,
         const char *extra_flag,
@@ -38,7 +41,7 @@ sfdisk (const char *device, int n, int cyls, int heads, int sectors,
   char buf[256];
   int i;
 
-  strcpy (buf, "sfdisk");
+  strcpy (buf, str_sfdisk);
 
   if (n > 0)
     sprintf (buf + strlen (buf), " -N %d", n);
@@ -101,7 +104,7 @@ sfdisk (const char *device, int n, int cyls, int heads, int sectors,
    * other component.  In any case, reread the partition table
    * unconditionally here.
    */
-  (void) command (NULL, NULL, "blockdev", "--rereadpt", device, NULL);
+  (void) command (NULL, NULL, str_blockdev, "--rereadpt", device, NULL);
 
   udev_settle ();
 
@@ -136,7 +139,7 @@ sfdisk_flag (const char *device, const char *flag)
   char *out, *err;
   int r;
 
-  r = command (&out, &err, "sfdisk", flag, device, NULL);
+  r = command (&out, &err, str_sfdisk, flag, device, NULL);
   if (r == -1) {
     reply_with_error ("%s: %s", device, err);
     free (out);
diff --git a/daemon/swap.c b/daemon/swap.c
index 8f1b59d..cf25e23 100644
--- a/daemon/swap.c
+++ b/daemon/swap.c
@@ -30,6 +30,10 @@
 
 #include "ignore-value.h"
 
+GUESTFSD_EXT_CMD(str_mkswap, mkswap);
+GUESTFSD_EXT_CMD(str_swapon, swapon);
+GUESTFSD_EXT_CMD(str_swapoff, swapoff);
+
 /* Confirmed this is true for Linux swap partitions from the Linux sources. */
 #define SWAP_LABEL_MAX 16
 
@@ -49,7 +53,7 @@ optgroup_linuxfsuuid_available (void)
    * return code.
    */
   ignore_value (commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR,
-                          "mkswap", "--help", NULL));
+                          str_mkswap, "--help", NULL));
 
   av = strstr (err, "-U") != NULL;
   free (err);
@@ -66,7 +70,7 @@ do_mkswap (const char *device, const char *label, const char *uuid)
   int r;
   char *err;
 
-  ADD_ARG (argv, i, "mkswap");
+  ADD_ARG (argv, i, str_mkswap);
   ADD_ARG (argv, i, "-f");
 
   if (optargs_bitmask & GUESTFS_MKSWAP_LABEL_BITMASK) {
@@ -129,7 +133,7 @@ do_mkswap_file (const char *path)
     return -1;
   }
 
-  r = command (NULL, &err, "mkswap", "-f", buf, NULL);
+  r = command (NULL, &err, str_mkswap, "-f", buf, NULL);
   free (buf);
 
   if (r == -1) {
@@ -173,13 +177,13 @@ swaponoff (const char *cmd, const char *flag, const char *value)
 int
 do_swapon_device (const char *device)
 {
-  return swaponoff ("swapon", NULL, device);
+  return swaponoff (str_swapon, NULL, device);
 }
 
 int
 do_swapoff_device (const char *device)
 {
-  return swaponoff ("swapoff", NULL, device);
+  return swaponoff (str_swapoff, NULL, device);
 }
 
 int
@@ -194,7 +198,7 @@ do_swapon_file (const char *path)
     return -1;
   }
 
-  r = swaponoff ("swapon", NULL, buf);
+  r = swaponoff (str_swapon, NULL, buf);
   free (buf);
   return r;
 }
@@ -211,7 +215,7 @@ do_swapoff_file (const char *path)
     return -1;
   }
 
-  r = swaponoff ("swapoff", NULL, buf);
+  r = swaponoff (str_swapoff, NULL, buf);
   free (buf);
   return r;
 }
@@ -225,7 +229,7 @@ do_swapon_label (const char *label)
     return -1;
   }
 
-  return swaponoff ("swapon", "-L", label);
+  return swaponoff (str_swapon, "-L", label);
 }
 
 int
@@ -237,17 +241,17 @@ do_swapoff_label (const char *label)
     return -1;
   }
 
-  return swaponoff ("swapoff", "-L", label);
+  return swaponoff (str_swapoff, "-L", label);
 }
 
 int
 do_swapon_uuid (const char *uuid)
 {
-  return swaponoff ("swapon", "-U", uuid);
+  return swaponoff (str_swapon, "-U", uuid);
 }
 
 int
 do_swapoff_uuid (const char *uuid)
 {
-  return swaponoff ("swapoff", "-U", uuid);
+  return swaponoff (str_swapoff, "-U", uuid);
 }
diff --git a/daemon/tar.c b/daemon/tar.c
index 13f87e7..dc4ddc2 100644
--- a/daemon/tar.c
+++ b/daemon/tar.c
@@ -30,6 +30,8 @@
 #include "actions.h"
 #include "optgroups.h"
 
+GUESTFSD_EXT_CMD(str_tar, tar);
+
 int
 optgroup_xz_available (void)
 {
@@ -155,7 +157,8 @@ do_tar_in (const char *dir, const char *compress)
   close (fd);
 
   /* "tar -C /sysroot%s -xf -" but we have to quote the dir. */
-  if (asprintf_nowarn (&cmd, "tar -C %R%s -xf - %s2> %s",
+  if (asprintf_nowarn (&cmd, "%s -C %R%s -xf - %s2> %s",
+                       str_tar,
                        dir, filter,
                        chown_supported ? "" : "--no-same-owner ",
                        error_file) == -1) {
@@ -321,7 +324,8 @@ do_tar_out (const char *dir, const char *compress, int numericowner,
   }
 
   /* "tar -C /sysroot%s -cf - ." but we have to quote the dir. */
-  if (asprintf_nowarn (&cmd, "tar -C %R%s%s%s -cf - .",
+  if (asprintf_nowarn (&cmd, "%s -C %R%s%s%s -cf - .",
+                       str_tar,
                        dir, filter,
                        numericowner ? " --numeric-owner" : "",
                        excludes_args) == -1) {
diff --git a/daemon/xfs.c b/daemon/xfs.c
index 5c65db1..90c99b2 100644
--- a/daemon/xfs.c
+++ b/daemon/xfs.c
@@ -30,10 +30,16 @@
 
 #define MAX_ARGS 64
 
+GUESTFSD_EXT_CMD(str_mkfs_xfs, mkfs.xfs);
+GUESTFSD_EXT_CMD(str_xfs_admin, xfs_admin);
+GUESTFSD_EXT_CMD(str_xfs_info, xfs_info);
+GUESTFSD_EXT_CMD(str_xfs_growfs, xfs_growfs);
+GUESTFSD_EXT_CMD(str_xfs_repair, xfs_repair);
+
 int
 optgroup_xfs_available (void)
 {
-  return prog_exists ("mkfs.xfs");
+  return prog_exists (str_mkfs_xfs);
 }
 
 static char *
@@ -330,7 +336,7 @@ do_xfs_info (const char *pathordevice)
     return NULL;
   }
 
-  r = command (&out, &err, "xfs_info", buf, NULL);
+  r = command (&out, &err, str_xfs_info, buf, NULL);
   free (buf);
   if (r == -1) {
     reply_with_error ("%s", err);
@@ -374,7 +380,7 @@ do_xfs_growfs (const char *path,
     return -1;
   }
 
-  ADD_ARG (argv, i, "xfs_growfs");
+  ADD_ARG (argv, i, str_xfs_growfs);
 
   /* Optional arguments */
   if (!(optargs_bitmask & GUESTFS_XFS_GROWFS_DATASEC_BITMASK))
@@ -471,7 +477,7 @@ do_xfs_admin (const char *device,
   const char *argv[MAX_ARGS];
   size_t i = 0;
 
-  ADD_ARG (argv, i, "xfs_admin");
+  ADD_ARG (argv, i, str_xfs_admin);
 
   /* Optional arguments */
   if (!(optargs_bitmask & GUESTFS_XFS_ADMIN_EXTUNWRITTEN_BITMASK))
@@ -548,7 +554,7 @@ do_xfs_repair (const char *device,
   size_t i = 0;
   int is_device;
 
-  ADD_ARG (argv, i, "xfs_repair");
+  ADD_ARG (argv, i, str_xfs_repair);
 
   /* Optional arguments */
   if (optargs_bitmask & GUESTFS_XFS_REPAIR_FORCELOGZERO_BITMASK) {
diff --git a/daemon/zero.c b/daemon/zero.c
index 14aef75..1a66881 100644
--- a/daemon/zero.c
+++ b/daemon/zero.c
@@ -30,6 +30,8 @@
 #include "actions.h"
 #include "optgroups.h"
 
+GUESTFSD_EXT_CMD(str_wipefs, wipefs);
+
 static const char zero_buf[4096];
 
 int
@@ -77,7 +79,7 @@ do_zero (const char *device)
 int
 optgroup_wipefs_available (void)
 {
-  return prog_exists ("wipefs");
+  return prog_exists (str_wipefs);
 }
 
 int
@@ -86,7 +88,7 @@ do_wipefs (const char *device)
   int r;
   char *err = NULL;
 
-  const char *wipefs[] = {"wipefs", "-a", device, NULL};
+  const char *wipefs[] = {str_wipefs, "-a", device, NULL};
   r = commandv (NULL, &err, wipefs);
   if (r == -1) {
     reply_with_error ("%s", err);
diff --git a/daemon/zerofree.c b/daemon/zerofree.c
index e9be8fc..17338f4 100644
--- a/daemon/zerofree.c
+++ b/daemon/zerofree.c
@@ -28,10 +28,12 @@
 #include "actions.h"
 #include "optgroups.h"
 
+GUESTFSD_EXT_CMD(str_zerofree, zerofree);
+
 int
 optgroup_zerofree_available (void)
 {
-  return prog_exists ("zerofree");
+  return prog_exists (str_zerofree);
 }
 
 int
@@ -40,7 +42,7 @@ do_zerofree (const char *device)
   char *err;
   int r;
 
-  r = command (NULL, &err, "zerofree", device, NULL);
+  r = command (NULL, &err, str_zerofree, device, NULL);
   if (r == -1) {
     reply_with_error ("%s: %s", device, err);
     free (err);
-- 
1.7.11.5


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]