Rather than passing passwords and cookies (which could contain passwords) to nbdkit via commandline arguments, use the alternate format that nbdkit supports where we can specify a file descriptor which nbdkit will read to get the password or cookies. Signed-off-by: Jonathon Jongsma <jjongsma@xxxxxxxxxx> --- build-aux/syntax-check.mk | 4 +- src/qemu/qemu_nbdkit.c | 162 ++++++++++++++++-- src/qemu/qemu_nbdkitpriv.h | 19 +- src/util/virutil.h | 2 +- .../disk-cdrom-network.args.disk1 | 2 +- .../disk-cdrom-network.args.disk1.pipe.45 | 1 + .../disk-cdrom-network.args.disk2 | 2 +- .../disk-cdrom-network.args.disk2.pipe.47 | 1 + .../disk-network-http.args.disk2 | 2 +- .../disk-network-http.args.disk2.pipe.45 | 1 + .../disk-network-http.args.disk3 | 2 +- .../disk-network-http.args.disk3.pipe.47 | 1 + ...work-source-curl-nbdkit-backing.args.disk0 | 2 +- ...rce-curl-nbdkit-backing.args.disk0.pipe.45 | 1 + .../disk-network-source-curl.args.disk0 | 2 +- ...isk-network-source-curl.args.disk0.pipe.45 | 1 + .../disk-network-source-curl.args.disk1 | 2 +- ...isk-network-source-curl.args.disk1.pipe.47 | 1 + .../disk-network-source-curl.args.disk2 | 2 +- ...isk-network-source-curl.args.disk2.pipe.49 | 1 + tests/qemunbdkittest.c | 57 +++++- 21 files changed, 238 insertions(+), 30 deletions(-) create mode 100644 tests/qemunbdkitdata/disk-cdrom-network.args.disk1.pipe.45 create mode 100644 tests/qemunbdkitdata/disk-cdrom-network.args.disk2.pipe.47 create mode 100644 tests/qemunbdkitdata/disk-network-http.args.disk2.pipe.45 create mode 100644 tests/qemunbdkitdata/disk-network-http.args.disk3.pipe.47 create mode 100644 tests/qemunbdkitdata/disk-network-source-curl-nbdkit-backing.args.disk0.pipe.45 create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk0.pipe.45 create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk1.pipe.47 create mode 100644 tests/qemunbdkitdata/disk-network-source-curl.args.disk2.pipe.49 diff --git a/build-aux/syntax-check.mk b/build-aux/syntax-check.mk index 649eb91acb..c0cf730d13 100644 --- a/build-aux/syntax-check.mk +++ b/build-aux/syntax-check.mk @@ -1363,10 +1363,10 @@ exclude_file_name_regexp--sc_prohibit_strdup = \ ^(docs/|examples/|tests/virnetserverclientmock.c|tests/commandhelper.c|tools/nss/libvirt_nss_(leases|macs)\.c$$) exclude_file_name_regexp--sc_prohibit_close = \ - (\.p[yl]$$|\.spec\.in$$|^docs/|^(src/util/vir(file|event)\.c|src/libvirt-stream\.c|tests/(vir.+mock\.c|commandhelper\.c|qemusecuritymock\.c)|tools/nss/libvirt_nss_(leases|macs)\.c)$$) + (\.p[yl]$$|\.spec\.in$$|^docs/|^(src/util/vir(file|event)\.c|src/libvirt-stream\.c|tests/(vir.+mock\.c|commandhelper\.c|qemusecuritymock\.c|qemunbdkittest\.c)|tools/nss/libvirt_nss_(leases|macs)\.c)$$) exclude_file_name_regexp--sc_prohibit_empty_lines_at_EOF = \ - (^tests/(nodedevmdevctl|virhostcpu|virpcitest|virstoragetest)data/|docs/js/.*\.js|docs/fonts/.*\.woff|\.diff|tests/virconfdata/no-newline\.conf$$) + (^tests/(nodedevmdevctl|virhostcpu|virpcitest|virstoragetest|qemunbdkit)data/|docs/js/.*\.js|docs/fonts/.*\.woff|\.diff|tests/virconfdata/no-newline\.conf$$) exclude_file_name_regexp--sc_prohibit_fork_wrappers = \ (^(src/(util/(vircommand|virdaemon)|lxc/lxc_controller)|tests/testutils)\.c$$) diff --git a/src/qemu/qemu_nbdkit.c b/src/qemu/qemu_nbdkit.c index 0ecf6c6537..2b8e203d16 100644 --- a/src/qemu/qemu_nbdkit.c +++ b/src/qemu/qemu_nbdkit.c @@ -55,6 +55,76 @@ VIR_ENUM_IMPL(qemuNbdkitCaps, "filter-readahead", /* QEMU_NBDKIT_CAPS_FILTER_READAHEAD */ ); + +static void +nbdkitPipeItemFree(NbdkitPipeItem *item) +{ + if (item->buf) { + virSecureErase(item->buf, item->buflen); + g_free(item->buf); + } + + if (item->fd > 0) + VIR_FORCE_CLOSE(item->fd); + + g_free(item); +} + + +void nbdkitPipeDataFree(NbdkitPipeData *self) +{ + size_t i; + + if (!self) + return; + + for (i = 0; i < self->nitems; i++) { + nbdkitPipeItemFree(self->items[i]); + } + + g_free(self->items); + g_free(self); +} + + +static NbdkitPipeItem* +nbdkitPipeItemNew(int fd, void *data, int datalen) +{ + NbdkitPipeItem *d; + + if (!data || datalen == 0) + return NULL; + + d = g_new0(NbdkitPipeItem, 1); + d->fd = fd; + + if (datalen < 0) { + /* -1 indicates a null-terminated string */ + d->buf = g_strdup(data); + d->buflen = strlen(data); + } else { + d->buf = g_malloc(datalen); + memcpy(d->buf, data, datalen); + d->buflen = datalen; + } + + return d; +} + + +static int +nbdkitPipeDataWrite(NbdkitPipeItem *pipe) +{ + if (safewrite(pipe->fd, pipe->buf, pipe->buflen) < 0) { + virReportSystemError(errno, + _("failed to write data to pipe %i for nbdkit"), + pipe->fd); + return -1; + } + return 0; +} + + struct _qemuNbdkitCaps { GObject parent; @@ -71,6 +141,12 @@ struct _qemuNbdkitCaps { G_DEFINE_TYPE(qemuNbdkitCaps, qemu_nbdkit_caps, G_TYPE_OBJECT); +enum { + PIPE_FD_READ = 0, + PIPE_FD_WRITE = 1 +}; + + static void qemuNbdkitCheckCommandCap(qemuNbdkitCaps *nbdkit, virCommand *cmd, @@ -685,12 +761,36 @@ qemuNbdkitInitStorageSource(qemuNbdkitCaps *caps, } +static NbdkitPipeItem* +commandPassDataByPipe(virCommand *cmd, + const char *argName, + char *buf, + size_t buflen) +{ + int fds[2] = { -1, -1 }; + g_autofree char *fdfmt = NULL; + + if (virPipe(fds) < 0) + return NULL; + + /* some nbdkit arguments accept a variation where nbdkit will read the data + * from a file descriptor, e.g. password=-FD */ + fdfmt = g_strdup_printf("-%i", fds[PIPE_FD_READ]); + virCommandAddArgPair(cmd, argName, fdfmt); + virCommandPassFD(cmd, fds[PIPE_FD_READ], VIR_COMMAND_PASS_FD_CLOSE_PARENT); + + return nbdkitPipeItemNew(fds[PIPE_FD_WRITE], (char*)buf, buflen); +} + static int qemuNbdkitProcessBuildCommandCurl(qemuNbdkitProcess *proc, - virCommand *cmd) + virCommand *cmd, + NbdkitPipeData **pipeData) { g_autoptr(virURI) uri = qemuBlockStorageSourceGetURI(proc->source); g_autofree char *uristring = virURIFormat(uri); + g_autoptr(GPtrArray) pipes = + g_ptr_array_new_with_free_func((GDestroyNotify)nbdkitPipeDataFree); /* nbdkit plugin name */ virCommandAddArg(cmd, "curl"); @@ -702,8 +802,9 @@ qemuNbdkitProcessBuildCommandCurl(qemuNbdkitProcess *proc, g_autoptr(virConnect) conn = virGetConnectSecret(); g_autofree uint8_t *secret = NULL; size_t secretlen = 0; - g_autofree char *password = NULL; int secrettype; + virStorageAuthDef *authdef = proc->source->auth; + NbdkitPipeItem *pipe = NULL; virCommandAddArgPair(cmd, "user", proc->source->auth->username); @@ -716,7 +817,7 @@ qemuNbdkitProcessBuildCommandCurl(qemuNbdkitProcess *proc, } if (virSecretGetSecretString(conn, - &proc->source->auth->seclookupdef, + &authdef->seclookupdef, secrettype, &secret, &secretlen) < 0) { @@ -725,18 +826,28 @@ qemuNbdkitProcessBuildCommandCurl(qemuNbdkitProcess *proc, return -1; } - /* ensure that the secret is a NULL-terminated string */ - password = g_strndup((char*)secret, secretlen); - - virCommandAddArgPair(cmd, "password", password); + if (!(pipe = commandPassDataByPipe(cmd, "password", (char*)secret, + secretlen))) { + virSecureErase(secret, secretlen); + return -1; + } virSecureErase(secret, secretlen); - virSecureErase(password, secretlen); + g_ptr_array_add(pipes, pipe); } - if (proc->source->ncookies > 0) - virCommandAddArgPair(cmd, "cookie", - qemuBlockStorageSourceGetCookieString(proc->source)); + /* Create a pipe to send the cookies to the nbdkit process. */ + if (proc->source->ncookies) { + NbdkitPipeItem *pipe = NULL; + g_autofree char *cookies = + qemuBlockStorageSourceGetCookieString(proc->source); + + if (!(pipe = commandPassDataByPipe(cmd, "cookie", cookies, -1))) { + return -1; + } + + g_ptr_array_add(pipes, pipe); + } if (proc->source->sslverify == VIR_TRISTATE_BOOL_NO) { virCommandAddArgPair(cmd, "sslverify", "false"); @@ -747,6 +858,10 @@ qemuNbdkitProcessBuildCommandCurl(qemuNbdkitProcess *proc, virCommandAddArgPair(cmd, "timeout", timeout); } + *pipeData = g_new0(NbdkitPipeData, 1); + (*pipeData)->nitems = pipes->len; + (*pipeData)->items = (NbdkitPipeItem**)g_ptr_array_free(g_steal_pointer(&pipes), false); + return 0; } @@ -781,8 +896,17 @@ qemuNbdkitProcessBuildCommandSSH(qemuNbdkitProcess *proc, } +/* Builds a nbdkit command for the given disk source. + * + * Some sensitive data should be not be passed to nbdkit via commandline, so + * this command may set up one or more pipes and pass the fd of these pipes to + * the nbdkit command. In that case, pipeData will return information about the + * pipes and the information that must be written to that pipe (via + * nbdkitPipeDataWrite()) after the command has been executed. The pipeData + * elements should be freed after writing. */ virCommand * -qemuNbdkitProcessBuildCommand(qemuNbdkitProcess *proc) +qemuNbdkitProcessBuildCommand(qemuNbdkitProcess *proc, + NbdkitPipeData **pipeData) { g_autoptr(virCommand) cmd = virCommandNewArgList(proc->caps->path, "--exit-with-parent", @@ -806,7 +930,7 @@ qemuNbdkitProcessBuildCommand(qemuNbdkitProcess *proc) case VIR_STORAGE_NET_PROTOCOL_FTP: case VIR_STORAGE_NET_PROTOCOL_FTPS: case VIR_STORAGE_NET_PROTOCOL_TFTP: - if (qemuNbdkitProcessBuildCommandCurl(proc, cmd) < 0) + if (qemuNbdkitProcessBuildCommandCurl(proc, cmd, pipeData) < 0) return NULL; break; case VIR_STORAGE_NET_PROTOCOL_SSH: @@ -869,8 +993,10 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc, int exitstatus = 0; int cmdret = 0; int errfd = -1; + g_autoptr(NbdkitPipeData) pipes = NULL; + size_t i; - if (!(cmd = qemuNbdkitProcessBuildCommand(proc))) + if (!(cmd = qemuNbdkitProcessBuildCommand(proc, &pipes))) return -1; virCommandSetErrorFD(cmd, &errfd); @@ -888,6 +1014,14 @@ qemuNbdkitProcessStart(qemuNbdkitProcess *proc, goto error; } + if (pipes) { + for (i = 0; i < pipes->nitems; i++) { + NbdkitPipeItem *pipe = pipes->items[i]; + if (nbdkitPipeDataWrite(pipe) < 0) + goto error; + } + } + if ((rc = virPidFileReadPath(proc->pidfile, &proc->pid)) < 0) { virReportSystemError(-rc, _("Failed to read pidfile %s"), diff --git a/src/qemu/qemu_nbdkitpriv.h b/src/qemu/qemu_nbdkitpriv.h index 64f9bb99d8..a4cc61bb2c 100644 --- a/src/qemu/qemu_nbdkitpriv.h +++ b/src/qemu/qemu_nbdkitpriv.h @@ -27,5 +27,20 @@ #include "qemu_nbdkit.h" -virCommand * -qemuNbdkitProcessBuildCommand(qemuNbdkitProcess *proc); +typedef struct { + int fd; + void *buf; + size_t buflen; +} NbdkitPipeItem; + +typedef struct { + size_t nitems; + NbdkitPipeItem **items; +} NbdkitPipeData; + +void nbdkitPipeDataFree(NbdkitPipeData *pipedata); + +G_DEFINE_AUTOPTR_CLEANUP_FUNC(NbdkitPipeData, nbdkitPipeDataFree); + +virCommand* qemuNbdkitProcessBuildCommand(qemuNbdkitProcess *proc, + NbdkitPipeData **pipeData); diff --git a/src/util/virutil.h b/src/util/virutil.h index ab8511bf8d..094b399859 100644 --- a/src/util/virutil.h +++ b/src/util/virutil.h @@ -186,7 +186,7 @@ char *virGetPassword(void); * * Returns: -1 on error, 0 on success */ -int virPipe(int fds[2]); +int virPipe(int fds[2]) G_NO_INLINE; /* * virPipeQuiet: diff --git a/tests/qemunbdkitdata/disk-cdrom-network.args.disk1 b/tests/qemunbdkitdata/disk-cdrom-network.args.disk1 index 257e331db8..da9e507f1b 100644 --- a/tests/qemunbdkitdata/disk-cdrom-network.args.disk1 +++ b/tests/qemunbdkitdata/disk-cdrom-network.args.disk1 @@ -6,4 +6,4 @@ nbdkit \ protocols=ftps \ url=ftps://host.name:990/url/path/file.iso \ user=testuser \ -password=iscsi-mycluster_myname-secret +password=-44 diff --git a/tests/qemunbdkitdata/disk-cdrom-network.args.disk1.pipe.45 b/tests/qemunbdkitdata/disk-cdrom-network.args.disk1.pipe.45 new file mode 100644 index 0000000000..ccdd4033fc --- /dev/null +++ b/tests/qemunbdkitdata/disk-cdrom-network.args.disk1.pipe.45 @@ -0,0 +1 @@ +iscsi-mycluster_myname-secret \ No newline at end of file diff --git a/tests/qemunbdkitdata/disk-cdrom-network.args.disk2 b/tests/qemunbdkitdata/disk-cdrom-network.args.disk2 index f7879a9f24..0742b29853 100644 --- a/tests/qemunbdkitdata/disk-cdrom-network.args.disk2 +++ b/tests/qemunbdkitdata/disk-cdrom-network.args.disk2 @@ -6,4 +6,4 @@ nbdkit \ protocols=https \ 'url=https://host.name:443/url/path/file.iso?test=val' \ user=testuser \ -password=iscsi-mycluster_myname-secret +password=-46 diff --git a/tests/qemunbdkitdata/disk-cdrom-network.args.disk2.pipe.47 b/tests/qemunbdkitdata/disk-cdrom-network.args.disk2.pipe.47 new file mode 100644 index 0000000000..ccdd4033fc --- /dev/null +++ b/tests/qemunbdkitdata/disk-cdrom-network.args.disk2.pipe.47 @@ -0,0 +1 @@ +iscsi-mycluster_myname-secret \ No newline at end of file diff --git a/tests/qemunbdkitdata/disk-network-http.args.disk2 b/tests/qemunbdkitdata/disk-network-http.args.disk2 index 7286b684a8..767ea881d8 100644 --- a/tests/qemunbdkitdata/disk-network-http.args.disk2 +++ b/tests/qemunbdkitdata/disk-network-http.args.disk2 @@ -4,4 +4,4 @@ nbdkit \ --foreground curl \ protocols=http \ url=http://example.org:1234/test3.img \ -'cookie=test=testcookievalue; test2="blurb"' +cookie=-44 diff --git a/tests/qemunbdkitdata/disk-network-http.args.disk2.pipe.45 b/tests/qemunbdkitdata/disk-network-http.args.disk2.pipe.45 new file mode 100644 index 0000000000..2c42c95930 --- /dev/null +++ b/tests/qemunbdkitdata/disk-network-http.args.disk2.pipe.45 @@ -0,0 +1 @@ +test=testcookievalue; test2="blurb" \ No newline at end of file diff --git a/tests/qemunbdkitdata/disk-network-http.args.disk3 b/tests/qemunbdkitdata/disk-network-http.args.disk3 index da177c9e6d..30dfd15861 100644 --- a/tests/qemunbdkitdata/disk-network-http.args.disk3 +++ b/tests/qemunbdkitdata/disk-network-http.args.disk3 @@ -4,5 +4,5 @@ nbdkit \ --foreground curl \ protocols=https \ 'url=https://example.org:1234/test4.img?par=val&other=ble' \ -'cookie=test=testcookievalue; test2="blurb"' \ +cookie=-46 \ sslverify=false diff --git a/tests/qemunbdkitdata/disk-network-http.args.disk3.pipe.47 b/tests/qemunbdkitdata/disk-network-http.args.disk3.pipe.47 new file mode 100644 index 0000000000..2c42c95930 --- /dev/null +++ b/tests/qemunbdkitdata/disk-network-http.args.disk3.pipe.47 @@ -0,0 +1 @@ +test=testcookievalue; test2="blurb" \ No newline at end of file diff --git a/tests/qemunbdkitdata/disk-network-source-curl-nbdkit-backing.args.disk0 b/tests/qemunbdkitdata/disk-network-source-curl-nbdkit-backing.args.disk0 index b13f5ed628..d5ad545cdc 100644 --- a/tests/qemunbdkitdata/disk-network-source-curl-nbdkit-backing.args.disk0 +++ b/tests/qemunbdkitdata/disk-network-source-curl-nbdkit-backing.args.disk0 @@ -5,4 +5,4 @@ nbdkit \ --readonly curl \ protocols=https \ url=https://https.example.org:8443/path/to/disk1.qcow2 \ -'cookie=cookie1=cookievalue1; cookie2=cookievalue2' +cookie=-44 diff --git a/tests/qemunbdkitdata/disk-network-source-curl-nbdkit-backing.args.disk0.pipe.45 b/tests/qemunbdkitdata/disk-network-source-curl-nbdkit-backing.args.disk0.pipe.45 new file mode 100644 index 0000000000..20af4ae383 --- /dev/null +++ b/tests/qemunbdkitdata/disk-network-source-curl-nbdkit-backing.args.disk0.pipe.45 @@ -0,0 +1 @@ +cookie1=cookievalue1; cookie2=cookievalue2 \ No newline at end of file diff --git a/tests/qemunbdkitdata/disk-network-source-curl.args.disk0 b/tests/qemunbdkitdata/disk-network-source-curl.args.disk0 index 6de42c626f..3ea686e14f 100644 --- a/tests/qemunbdkitdata/disk-network-source-curl.args.disk0 +++ b/tests/qemunbdkitdata/disk-network-source-curl.args.disk0 @@ -5,4 +5,4 @@ nbdkit \ --readonly curl \ protocols=https \ url=https://https.example.org:8443/path/to/disk1.iso \ -'cookie=cookie1=cookievalue1; cookie2=cookievalue2' +cookie=-44 diff --git a/tests/qemunbdkitdata/disk-network-source-curl.args.disk0.pipe.45 b/tests/qemunbdkitdata/disk-network-source-curl.args.disk0.pipe.45 new file mode 100644 index 0000000000..20af4ae383 --- /dev/null +++ b/tests/qemunbdkitdata/disk-network-source-curl.args.disk0.pipe.45 @@ -0,0 +1 @@ +cookie1=cookievalue1; cookie2=cookievalue2 \ No newline at end of file diff --git a/tests/qemunbdkitdata/disk-network-source-curl.args.disk1 b/tests/qemunbdkitdata/disk-network-source-curl.args.disk1 index 9abc1578dd..fb77794b56 100644 --- a/tests/qemunbdkitdata/disk-network-source-curl.args.disk1 +++ b/tests/qemunbdkitdata/disk-network-source-curl.args.disk1 @@ -4,5 +4,5 @@ nbdkit \ --foreground curl \ protocols=https \ 'url=https://https.example.org:8443/path/to/disk5.iso?foo=bar' \ -'cookie=cookie1=cookievalue1; cookie2=cookievalue2' \ +cookie=-46 \ sslverify=false diff --git a/tests/qemunbdkitdata/disk-network-source-curl.args.disk1.pipe.47 b/tests/qemunbdkitdata/disk-network-source-curl.args.disk1.pipe.47 new file mode 100644 index 0000000000..20af4ae383 --- /dev/null +++ b/tests/qemunbdkitdata/disk-network-source-curl.args.disk1.pipe.47 @@ -0,0 +1 @@ +cookie1=cookievalue1; cookie2=cookievalue2 \ No newline at end of file diff --git a/tests/qemunbdkitdata/disk-network-source-curl.args.disk2 b/tests/qemunbdkitdata/disk-network-source-curl.args.disk2 index 1ce11ce618..eab66746ef 100644 --- a/tests/qemunbdkitdata/disk-network-source-curl.args.disk2 +++ b/tests/qemunbdkitdata/disk-network-source-curl.args.disk2 @@ -5,4 +5,4 @@ nbdkit \ --readonly curl \ protocols=http \ url=http://http.example.org:8080/path/to/disk2.iso \ -'cookie=cookie1=cookievalue1; cookie2=cookievalue2; cookie3=cookievalue3' +cookie=-48 diff --git a/tests/qemunbdkitdata/disk-network-source-curl.args.disk2.pipe.49 b/tests/qemunbdkitdata/disk-network-source-curl.args.disk2.pipe.49 new file mode 100644 index 0000000000..5c035e84c5 --- /dev/null +++ b/tests/qemunbdkitdata/disk-network-source-curl.args.disk2.pipe.49 @@ -0,0 +1 @@ +cookie1=cookievalue1; cookie2=cookievalue2; cookie3=cookievalue3 \ No newline at end of file diff --git a/tests/qemunbdkittest.c b/tests/qemunbdkittest.c index c53601dac8..a18567e9b4 100644 --- a/tests/qemunbdkittest.c +++ b/tests/qemunbdkittest.c @@ -13,6 +13,7 @@ #include "virutil.h" #include "virsecret.h" #include "datatypes.h" +#include "virmock.h" #define VIR_FROM_THIS VIR_FROM_QEMU @@ -20,6 +21,41 @@ static virQEMUDriver driver; /* Some mock implementations for testing */ +#define PIPE_FD_START 44 +static int mockpipefd = PIPE_FD_START; +int +virPipe(int fds[2]) +{ + fds[0] = mockpipefd++; + fds[1] = mockpipefd++; + + return 0; +} + +static int (*real_close)(int fd); +static void +init_syms(void) +{ + VIR_MOCK_REAL_INIT(close); +} + +int +close(int fd) +{ + int ret; + + init_syms(); + + if (fd >= PIPE_FD_START) + ret = 0; + else + ret = real_close(fd); + + return ret; +} + + + int virSecretGetSecretString(virConnectPtr conn G_GNUC_UNUSED, virSecretLookupTypeDef *seclookupdef, @@ -124,6 +160,9 @@ testNbdkit(const void *data) size_t i; int ret = 0; + /* restart mock pipe fds so tests are consistent */ + mockpipefd = PIPE_FD_START; + if (!virFileExists(info->infile)) { virReportError(VIR_ERR_INTERNAL_ERROR, "Test input file '%s' is missing", info->infile); @@ -149,9 +188,11 @@ testNbdkit(const void *data) g_autoptr(virCommandDryRunToken) dryRunToken = virCommandDryRunTokenNew(); g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; const char *actualCmdline = NULL; + g_autoptr(NbdkitPipeData) pipes = NULL; + size_t j; virCommandSetDryRun(dryRunToken, &buf, true, true, NULL, NULL); - cmd = qemuNbdkitProcessBuildCommand(srcPriv->nbdkitProcess); + cmd = qemuNbdkitProcessBuildCommand(srcPriv->nbdkitProcess, &pipes); if (virCommandRun(cmd, NULL) < 0) { ret = -1; @@ -163,9 +204,19 @@ testNbdkit(const void *data) continue; } - if (virTestCompareToFileFull(actualCmdline, cmdfile, false) < 0) { + if (virTestCompareToFileFull(actualCmdline, cmdfile, false) < 0) ret = -1; - continue; + + if (pipes) { + for (j = 0; j < pipes->nitems; j++) { + NbdkitPipeItem *item = pipes->items[j]; + g_autofree char *pipefile = g_strdup_printf("%s.pipe.%i", + cmdfile, + item->fd); + + if (virTestCompareToFile(item->buf, pipefile) < 0) + ret = -1; + } } } else { if (virFileExists(cmdfile)) { -- 2.37.1