From e114d9a2d1ffbdc5e894443892b042b281a51d05e8abf2fee1f8efcd75b2846c Mon Sep 17 00:00:00 2001 From: Olaf Hering Date: Thu, 30 Aug 2012 18:40:11 +0000 Subject: [PATCH] - Update to version 1.19.36 Add patch to collect a list of all called binaries from guestfsd patch mkinitrd to copy links (bnc#778149) OBS-URL: https://build.opensuse.org/package/show/Virtualization/libguestfs?expand=0&rev=34 --- ...e-e2prog-hack-only-needed-for-RHEL-5.patch | 375 +++ ...ect-list-of-called-external-commands.patch | 2422 +++++++++++++++++ libguestfs-1.19.35.tar.gz | 3 - libguestfs-1.19.36.tar.gz | 3 + libguestfs.changes | 6 + libguestfs.mkinitrd.boot.sh | 5 +- libguestfs.spec | 35 +- mkinitrd.patch | 11 + 8 files changed, 2852 insertions(+), 8 deletions(-) create mode 100644 0001-daemon-Remove-e2prog-hack-only-needed-for-RHEL-5.patch create mode 100644 0002-daemon-collect-list-of-called-external-commands.patch delete mode 100644 libguestfs-1.19.35.tar.gz create mode 100644 libguestfs-1.19.36.tar.gz create mode 100644 mkinitrd.patch diff --git a/0001-daemon-Remove-e2prog-hack-only-needed-for-RHEL-5.patch b/0001-daemon-Remove-e2prog-hack-only-needed-for-RHEL-5.patch new file mode 100644 index 0000000..9f45fc4 --- /dev/null +++ b/0001-daemon-Remove-e2prog-hack-only-needed-for-RHEL-5.patch @@ -0,0 +1,375 @@ +From 8082d42017b9946b40b3d1ffb27b83a310118cc0 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Thu, 30 Aug 2012 17:29:36 +0100 +Subject: [PATCH 1/2] daemon: Remove e2prog hack (only needed for RHEL 5). + +Instead this patch will be carried out of tree in the oldlinux branch. +--- + daemon/daemon.h | 2 - + daemon/ext2.c | 112 ++++++++------------------------------------------------ + daemon/labels.c | 6 +-- + daemon/mkfs.c | 8 +--- + 4 Dateien geändert, 18 Zeilen hinzugefügt(+), 110 Zeilen entfernt(-) + +diff --git a/daemon/daemon.h b/daemon/daemon.h +index bbe77f9..d17dcbd 100644 +--- a/daemon/daemon.h ++++ b/daemon/daemon.h +@@ -171,8 +171,6 @@ extern int filesystem_available (const char *filesystem); + extern int sync_disks (void); + + /*-- in ext2.c --*/ +-extern int e2prog (char *name); /* Massive hack for RHEL 5. */ +- + /* Confirmed this is true up to ext4 from the Linux sources. */ + #define EXT2_LABEL_MAX 16 + +diff --git a/daemon/ext2.c b/daemon/ext2.c +index 7876e66..943b441 100644 +--- a/daemon/ext2.c ++++ b/daemon/ext2.c +@@ -31,32 +31,6 @@ + + #define MAX_ARGS 64 + +-/* Choose which tools like mke2fs to use. For RHEL 5 (only) there +- * is a special set of tools which support ext2/3/4. eg. On RHEL 5, +- * mke2fs only supports ext2/3, but mke4fs supports ext2/3/4. +- * +- * We specify e4fsprogs in the package list to ensure it is loaded +- * if it exists. +- */ +-int +-e2prog (char *name) +-{ +- char *p = strstr (name, "e2"); +- if (!p) return 0; +- p++; +- +- *p = '4'; +- if (prog_exists (name)) +- return 0; +- +- *p = '2'; +- if (prog_exists (name)) +- return 0; +- +- reply_with_error ("cannot find required program %s", name); +- return -1; +-} +- + char ** + do_tune2fs_l (const char *device) + { +@@ -65,11 +39,7 @@ do_tune2fs_l (const char *device) + char *p, *pend, *colon; + DECLARE_STRINGSBUF (ret); + +- char prog[] = "tune2fs"; +- if (e2prog (prog) == -1) +- return NULL; +- +- r = command (&out, &err, prog, "-l", device, NULL); ++ r = command (&out, &err, "tune2fs", "-l", device, NULL); + if (r == -1) { + reply_with_error ("%s", err); + free (err); +@@ -165,11 +135,7 @@ do_set_e2uuid (const char *device, const char *uuid) + int r; + char *err; + +- char prog[] = "tune2fs"; +- if (e2prog (prog) == -1) +- return -1; +- +- r = command (NULL, &err, prog, "-U", uuid, device, NULL); ++ r = command (NULL, &err, "tune2fs", "-U", uuid, device, NULL); + if (r == -1) { + reply_with_error ("%s", err); + free (err); +@@ -192,17 +158,13 @@ if_not_mounted_run_e2fsck (const char *device) + { + char *err; + int r, mounted; +- char prog[] = "e2fsck"; +- +- if (e2prog (prog) == -1) +- return -1; + + mounted = is_device_mounted (device); + if (mounted == -1) + return -1; + + if (!mounted) { +- r = command (NULL, &err, prog, "-fy", device, NULL); ++ r = command (NULL, &err, "e2fsck", "-fy", device, NULL); + if (r == -1) { + reply_with_error ("%s", err); + free (err); +@@ -220,14 +182,10 @@ do_resize2fs (const char *device) + char *err; + int r; + +- char prog[] = "resize2fs"; +- if (e2prog (prog) == -1) +- return -1; +- + if (if_not_mounted_run_e2fsck (device) == -1) + return -1; + +- r = command (NULL, &err, prog, device, NULL); ++ r = command (NULL, &err, "resize2fs", device, NULL); + if (r == -1) { + reply_with_error ("%s", err); + free (err); +@@ -244,10 +202,6 @@ do_resize2fs_size (const char *device, int64_t size) + char *err; + int r; + +- char prog[] = "resize2fs"; +- if (e2prog (prog) == -1) +- return -1; +- + /* resize2fs itself may impose additional limits. Since we are + * going to use the 'K' suffix however we can only work with whole + * kilobytes. +@@ -265,7 +219,7 @@ do_resize2fs_size (const char *device, int64_t size) + char buf[32]; + snprintf (buf, sizeof buf, "%" PRIi64 "K", size); + +- r = command (NULL, &err, prog, device, buf, NULL); ++ r = command (NULL, &err, "resize2fs", device, buf, NULL); + if (r == -1) { + reply_with_error ("%s", err); + free (err); +@@ -282,14 +236,10 @@ do_resize2fs_M (const char *device) + char *err; + int r; + +- char prog[] = "resize2fs"; +- if (e2prog (prog) == -1) +- return -1; +- + if (if_not_mounted_run_e2fsck (device) == -1) + return -1; + +- r = command (NULL, &err, prog, "-M", device, NULL); ++ r = command (NULL, &err, "resize2fs", "-M", device, NULL); + if (r == -1) { + reply_with_error ("%s", err); + free (err); +@@ -310,10 +260,6 @@ do_e2fsck (const char *device, + char *err; + size_t i = 0; + int r; +- char prog[] = "e2fsck"; +- +- if (e2prog (prog) == -1) +- return -1; + + /* Default if not selected. */ + if (!(optargs_bitmask & GUESTFS_E2FSCK_CORRECT_BITMASK)) +@@ -326,7 +272,7 @@ do_e2fsck (const char *device, + return -1; + } + +- ADD_ARG (argv, i, prog); ++ ADD_ARG (argv, i, "e2fsck"); + ADD_ARG (argv, i, "-f"); + + if (correct) +@@ -369,15 +315,11 @@ do_mke2journal (int blocksize, const char *device) + char *err; + int r; + +- char prog[] = "mke2fs"; +- if (e2prog (prog) == -1) +- return -1; +- + char blocksize_s[32]; + snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize); + + r = command (NULL, &err, +- prog, "-F", "-O", "journal_dev", "-b", blocksize_s, ++ "mke2fs", "-F", "-O", "journal_dev", "-b", blocksize_s, + device, NULL); + if (r == -1) { + reply_with_error ("%s", err); +@@ -395,10 +337,6 @@ do_mke2journal_L (int blocksize, const char *label, const char *device) + char *err; + int r; + +- char prog[] = "mke2fs"; +- if (e2prog (prog) == -1) +- return -1; +- + if (strlen (label) > EXT2_LABEL_MAX) { + reply_with_error ("%s: ext2 labels are limited to %d bytes", + label, EXT2_LABEL_MAX); +@@ -409,7 +347,7 @@ do_mke2journal_L (int blocksize, const char *label, const char *device) + snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize); + + r = command (NULL, &err, +- prog, "-F", "-O", "journal_dev", "-b", blocksize_s, ++ "mke2fs", "-F", "-O", "journal_dev", "-b", blocksize_s, + "-L", label, + device, NULL); + if (r == -1) { +@@ -428,15 +366,11 @@ do_mke2journal_U (int blocksize, const char *uuid, const char *device) + char *err; + int r; + +- char prog[] = "mke2fs"; +- if (e2prog (prog) == -1) +- return -1; +- + char blocksize_s[32]; + snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize); + + r = command (NULL, &err, +- prog, "-F", "-O", "journal_dev", "-b", blocksize_s, ++ "mke2fs", "-F", "-O", "journal_dev", "-b", blocksize_s, + "-U", uuid, + device, NULL); + if (r == -1) { +@@ -456,10 +390,6 @@ do_mke2fs_J (const char *fstype, int blocksize, const char *device, + char *err; + int r; + +- char prog[] = "mke2fs"; +- if (e2prog (prog) == -1) +- return -1; +- + char blocksize_s[32]; + snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize); + +@@ -468,7 +398,7 @@ do_mke2fs_J (const char *fstype, int blocksize, const char *device, + snprintf (jdev, len+32, "device=%s", journal); + + r = command (NULL, &err, +- prog, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s, ++ "mke2fs", "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s, + device, NULL); + if (r == -1) { + reply_with_error ("%s", err); +@@ -487,10 +417,6 @@ do_mke2fs_JL (const char *fstype, int blocksize, const char *device, + char *err; + int r; + +- char prog[] = "mke2fs"; +- if (e2prog (prog) == -1) +- return -1; +- + if (strlen (label) > EXT2_LABEL_MAX) { + reply_with_error ("%s: ext2 labels are limited to %d bytes", + label, EXT2_LABEL_MAX); +@@ -505,7 +431,7 @@ do_mke2fs_JL (const char *fstype, int blocksize, const char *device, + snprintf (jdev, len+32, "device=LABEL=%s", label); + + r = command (NULL, &err, +- prog, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s, ++ "mke2fs", "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s, + device, NULL); + if (r == -1) { + reply_with_error ("%s", err); +@@ -524,10 +450,6 @@ do_mke2fs_JU (const char *fstype, int blocksize, const char *device, + char *err; + int r; + +- char prog[] = "mke2fs"; +- if (e2prog (prog) == -1) +- return -1; +- + char blocksize_s[32]; + snprintf (blocksize_s, sizeof blocksize_s, "%d", blocksize); + +@@ -536,7 +458,7 @@ do_mke2fs_JU (const char *fstype, int blocksize, const char *device, + snprintf (jdev, len+32, "device=UUID=%s", uuid); + + r = command (NULL, &err, +- prog, "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s, ++ "mke2fs", "-F", "-t", fstype, "-J", jdev, "-b", blocksize_s, + device, NULL); + if (r == -1) { + reply_with_error ("%s", err); +@@ -566,7 +488,6 @@ do_tune2fs (const char *device, /* only required parameter */ + size_t i = 0; + int r; + char *err; +- char prog[] = "tune2fs"; + char maxmountcount_s[64]; + char mountcount_s[64]; + char group_s[64]; +@@ -575,10 +496,7 @@ do_tune2fs (const char *device, /* only required parameter */ + char reservedblockscount_s[64]; + char user_s[64]; + +- if (e2prog (prog) == -1) +- return -1; +- +- ADD_ARG (argv, i, prog); ++ ADD_ARG (argv, i, "tune2fs"); + + if (optargs_bitmask & GUESTFS_TUNE2FS_FORCE_BITMASK) { + if (force) +@@ -686,7 +604,7 @@ do_tune2fs (const char *device, /* only required parameter */ + + r = commandv (NULL, &err, argv); + if (r == -1) { +- reply_with_error ("%s: %s: %s", prog, device, err); ++ reply_with_error ("%s: %s", device, err); + free (err); + return -1; + } +diff --git a/daemon/labels.c b/daemon/labels.c +index b28d1b2..5c59a4c 100644 +--- a/daemon/labels.c ++++ b/daemon/labels.c +@@ -33,17 +33,13 @@ e2label (const char *device, const char *label) + int r; + char *err; + +- char prog[] = "e2label"; +- if (e2prog (prog) == -1) +- return -1; +- + if (strlen (label) > EXT2_LABEL_MAX) { + reply_with_error ("%s: ext2 labels are limited to %d bytes", + label, EXT2_LABEL_MAX); + return -1; + } + +- r = command (NULL, &err, prog, device, label, NULL); ++ r = command (NULL, &err, "e2label", device, label, NULL); + if (r == -1) { + reply_with_error ("%s", err); + free (err); +diff --git a/daemon/mkfs.c b/daemon/mkfs.c +index c7ae50d..7d28061 100644 +--- a/daemon/mkfs.c ++++ b/daemon/mkfs.c +@@ -43,7 +43,6 @@ do_mkfs (const char *fstype, const char *device, int blocksize, + char sectorsize_str[32]; + int r; + char *err; +- char mke2fs[] = "mke2fs"; + int extfs = 0; + + if (STREQ (fstype, "ext2") || STREQ (fstype, "ext3") || +@@ -54,11 +53,8 @@ do_mkfs (const char *fstype, const char *device, int blocksize, + * the mkfs program "eats" some options, in particular the -F + * option. + */ +- if (extfs) { +- if (e2prog (mke2fs) == -1) +- return -1; +- ADD_ARG (argv, i, mke2fs); +- } ++ if (extfs) ++ ADD_ARG (argv, i, "mke2fs"); + else + ADD_ARG (argv, i, "mkfs"); + +-- +1.7.11.5 + diff --git a/0002-daemon-collect-list-of-called-external-commands.patch b/0002-daemon-collect-list-of-called-external-commands.patch new file mode 100644 index 0000000..a2dae24 --- /dev/null +++ b/0002-daemon-collect-list-of-called-external-commands.patch @@ -0,0 +1,2422 @@ +From d6f33733cd19aab9e94cb368910ff6add50ad13d Mon Sep 17 00:00:00 2001 +From: Olaf Hering +Date: Thu, 30 Aug 2012 15:37:40 +0200 +Subject: [PATCH 2/2] daemon: collect list of called 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 +--- + 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 (&out, &err, +- "blkid", ++ str_blkid, + "-c", "/dev/null", + "-o", "value", "-s", tag, device, NULL); + if (r != 0 && 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/ | 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 + diff --git a/libguestfs-1.19.35.tar.gz b/libguestfs-1.19.35.tar.gz deleted file mode 100644 index 7177053..0000000 --- a/libguestfs-1.19.35.tar.gz +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c3a2407aa645f6ded169e91ac7a4386c879d9254183d231f097c837c13499a8a -size 8213887 diff --git a/libguestfs-1.19.36.tar.gz b/libguestfs-1.19.36.tar.gz new file mode 100644 index 0000000..6680e6b --- /dev/null +++ b/libguestfs-1.19.36.tar.gz @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3950f164c52444dc1582326d48138da66f8d38e090832ccbb69919765e692f95 +size 8231357 diff --git a/libguestfs.changes b/libguestfs.changes index 31715d0..1c003da 100644 --- a/libguestfs.changes +++ b/libguestfs.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Thu Aug 30 20:37:06 CEST 2012 - ohering@suse.de + +- Update to version 1.19.36 + Add patch to collect a list of all called binaries from guestfsd + ------------------------------------------------------------------- Thu Aug 30 10:24:49 CEST 2012 - ohering@suse.de diff --git a/libguestfs.mkinitrd.boot.sh b/libguestfs.mkinitrd.boot.sh index 0ef924e..c665bf1 100644 --- a/libguestfs.mkinitrd.boot.sh +++ b/libguestfs.mkinitrd.boot.sh @@ -8,15 +8,12 @@ #%modules: virtio_pci #%modules: virtio_scsi # -#%programs: blockdev #%programs: cat #%programs: date #%programs: guestfsd #%programs: ip #%programs: lsmod -#%programs: lvm -#%programs: mdadm -#%programs: parted +#@GUESTFS_EXT_CMDS@ # # from libguestfs-1.19.34/appliance/init: diff --git a/libguestfs.spec b/libguestfs.spec index 6cb37cf..a1012df 100644 --- a/libguestfs.spec +++ b/libguestfs.spec @@ -129,14 +129,17 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-build Summary: Tools for accessing and modifying virtual machine disk images License: LGPL-2.1 Group: System/Filesystems -Version: 1.19.35 +Version: 1.19.36 Release: 0 +Patch1: 0001-daemon-Remove-e2prog-hack-only-needed-for-RHEL-5.patch +Patch2: 0002-daemon-collect-list-of-called-external-commands.patch Patch5: libguestfs-1.13.14-ruby.patch Patch100: libguestfs.perl.install_vendor.patch Patch101: libguestfs.perl.no-rpath.patch Source0: %{name}-%{version}.tar.gz Source10: libguestfs.mkinitrd.boot.sh Source11: libguestfs.mkinitrd.setup.sh +Source42: mkinitrd.patch Recommends: %{name}-data %description @@ -281,6 +284,8 @@ virtual machines. %prep %setup -q +%patch1 -p1 +%patch2 -p1 %patch100 -p1 %patch101 -p1 @@ -321,8 +326,27 @@ rm -f $RPM_BUILD_ROOT/%{_libdir}/*.{l,}a touch %{name}.lang %find_lang %{name} # +cmds="` +objcopy -j .guestfs_ext_cmds -O binary $RPM_BUILD_ROOT/usr/sbin/guestfsd /dev/stdout | +strings | +sort -u +`" +> cmds.txt +for cmd in ls $cmds +do + if test -n "` PATH=$PATH:/sbin:/usr/sbin type -p $cmd `" + then + echo "#%%programs: $cmd" >> cmds.txt + else + echo "# missing: $cmd" >> cmds.txt + fi +done rm -rf mkinitrd cp -av /lib/mkinitrd . +if patch -p0 --dry-run < %{S:42} +then + patch -p0 < %{S:42} +fi for bad in \ setup-dm.sh \ setup-storage.sh @@ -332,6 +356,13 @@ done cp -avL %{S:10} mkinitrd/scripts/boot-guestfs.sh cp -avL %{S:11} mkinitrd/scripts/setup-guestfs.sh chmod 755 mkinitrd/scripts/*guestfs.sh +sed -i~ ' +/^#@GUESTFS_EXT_CMDS@/ { +s@^.*@@ +r cmds.txt +} +' mkinitrd/scripts/boot-guestfs.sh +diff -u mkinitrd/scripts/boot-guestfs.sh~ mkinitrd/scripts/boot-guestfs.sh || : /sbin/mkinitrd_setup \ -s $PWD/mkinitrd/scripts \ -i $PWD/mkinitrd @@ -344,6 +375,8 @@ arch=i686 #? cp -avL /boot/vmlinuz mkinitrd/boot_tmp/vmlinuz.${arch} cp -avL /boot/System.map-${kver} mkinitrd/boot_tmp env PATH=${RPM_BUILD_ROOT}/usr/bin:${RPM_BUILD_ROOT}/usr/sbin:${PATH} \ +#bash -x \ + /sbin/mkinitrd \ -l $PWD/mkinitrd \ -k vmlinuz.${arch} \ diff --git a/mkinitrd.patch b/mkinitrd.patch new file mode 100644 index 0000000..d063c84 --- /dev/null +++ b/mkinitrd.patch @@ -0,0 +1,11 @@ +--- mkinitrd/scripts/setup-prepare.sh.orig 2012-08-30 18:06:04.000000000 +0000 ++++ mkinitrd/scripts/setup-prepare.sh 2012-08-30 18:14:06.000000000 +0000 +@@ -29,7 +29,7 @@ + if [ -h "$1" ]; then + lnkTarget=$(readlink $1) + if [ -e $lnkTarget ];then +- cp -a $lnkTarget $2/$lnkTarget ++ cp -a --remove-destination $lnkTarget $2/ + else + # This link points to something in the same directory + lnkSrc="$1"