From nobody Tue May 7 14:19:43 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1534909086524673.2486744413479; Tue, 21 Aug 2018 20:38:06 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.25]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4A7AC85A04; Wed, 22 Aug 2018 03:38:02 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 439CE2010D0A; Wed, 22 Aug 2018 03:38:01 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 5FC2018005D0; Wed, 22 Aug 2018 03:37:58 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.phx2.redhat.com [10.5.11.25]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w7M3bumJ026206 for ; Tue, 21 Aug 2018 23:37:56 -0400 Received: by smtp.corp.redhat.com (Postfix) id 9A2C32010D5A; Wed, 22 Aug 2018 03:37:56 +0000 (UTC) Received: from mx1.redhat.com (ext-mx02.extmail.prod.ext.phx2.redhat.com [10.5.110.26]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 8F0052010D56 for ; Wed, 22 Aug 2018 03:37:53 +0000 (UTC) Received: from m97134.mail.qiye.163.com (m97134.mail.qiye.163.com [220.181.97.134]) by mx1.redhat.com (Postfix) with ESMTP id 3648085A04 for ; Wed, 22 Aug 2018 03:37:47 +0000 (UTC) Received: from localhost.localdomain (unknown [58.56.27.130]) by smtp5 (Coremail) with SMTP id huCowAD3XWKI2nxbH6k+AQ--.166S2; Wed, 22 Aug 2018 11:37:44 +0800 (CST) From: Shi Lei To: libvir-list@redhat.com Date: Wed, 22 Aug 2018 11:37:34 +0800 Message-Id: <1534909054-11584-1-git-send-email-shi_lei@massclouds.com> X-CM-TRANSID: huCowAD3XWKI2nxbH6k+AQ--.166S2 X-Coremail-Antispam: 1Uf129KBjvAXoWDXw47Cw4rWF18Gr15ZFyDtrb_yoWrurykZo Z7Xrs3t3W8Kr1xGFWqk3W7KFW3Xr4jv3Wayr1rKF9Yga4qqwn8X3s5AF43Ga95ArW0y3y5 XFn5t343Ka1Iqr93n29KB7ZKAUJUUUU8529EdanIXcx71UUUUU7v73VFW2AGmfu7bjvjm3 AaLaJ3UbIYCTnIWIevJa73UjIFyTuYvjxUFv30UUUUU X-Originating-IP: [58.56.27.130] X-CM-SenderInfo: pvklsz1hl6ztxvvfz0xxgvhudrp/1tbidAmqT1n5ecVSaQAAs- X-Greylist: Sender passed SPF test, Sender IP whitelisted by DNSRBL, ACL 212 matched, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Wed, 22 Aug 2018 03:37:50 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Wed, 22 Aug 2018 03:37:50 +0000 (UTC) for IP:'220.181.97.134' DOMAIN:'m97134.mail.qiye.163.com' HELO:'m97134.mail.qiye.163.com' FROM:'shi_lei@massclouds.com' RCPT:'' X-RedHat-Spam-Score: 1.273 * (RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H2, RCVD_IN_RP_RNBL) 220.181.97.134 m97134.mail.qiye.163.com 220.181.97.134 m97134.mail.qiye.163.com X-Scanned-By: MIMEDefang 2.78 on 10.5.110.26 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.25 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH] Take DryRun code out of virCommand* code flow X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.25 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Wed, 22 Aug 2018 03:38:04 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Since dry-run of cmd is just for tests now, it would be better to remove dry-run code and move them to testutils. Then the code flow in virCommand* could be more general. There are 3 steps in this patch: 1. Introduce a new global hook (of virExecHook type) which will be called in code flow just before the cmd->hook. The global hook is also called in child process. If it returns 1, the child process will exit with status in advance and the parent will process io and wait for the child normall= y. It prepares for registering dry-run and anything else. The virCommandSetPreExecHook is modified for registering both types of h= ooks. 2. Implement virTestSetDryRun with dry-run code in "testutils.c". It substitutes for virCommandSetDryRun. The virTestSetDryRun invokes virCommandSetPreExecHook to register a function on the global hook which will fill in cmdline buffer and call callback for tests. 3. Remove all dryrun code in "vircommand.c" and remove virCommandSetDryRun = API. Diffs from old dry-run: The new global hook is called in child process. So dryrun-callback for tests should write to stdout/stderr when they need output something. Now the opaque argument for dryrun-callback cannot be inout. In "tests/viri= scsitest.c", iface_created in opaque of callback is an inout argument. There's a bit complicated to transfer it between the child and its parent. So this patch = use a temporary file to do that. =20 Signed-off-by: Shi Lei --- docs/internals/command.html.in | 33 +++++- src/libvirt_private.syms | 4 +- src/qemu/qemu_process.c | 8 +- src/util/vircommand.c | 151 ++++++++++++---------------- src/util/vircommand.h | 18 +++- src/util/vircommandpriv.h | 19 ++-- tests/networkxml2firewalltest.c | 7 +- tests/nwfilterebiptablestest.c | 32 +++--- tests/nwfilterxml2firewalltest.c | 6 +- tests/testutils.c | 210 +++++++++++++++++++++++++++++++++++= ++++ tests/testutils.h | 2 + tests/virfirewalltest.c | 71 ++++++------- tests/viriscsitest.c | 120 ++++++++++++++++------ tests/virkmodtest.c | 10 +- tests/virnetdevbandwidthtest.c | 6 +- 15 files changed, 482 insertions(+), 215 deletions(-) diff --git a/docs/internals/command.html.in b/docs/internals/command.html.in index 43f51a4..44478f0 100644 --- a/docs/internals/command.html.in +++ b/docs/internals/command.html.in @@ -398,17 +398,40 @@ virCommandSetWorkingDirectory(cmd, LOCALSTATEDIR);

Any additional hooks

=20

- If anything else is needed, it is possible to request a hook - function that is called in the child after the fork, as the + If anything else is needed, it is possible to request hook + functions that are called in the child after the fork, as the last thing before changing directories, dropping capabilities, - and executing the new process. If hook(opaque) returns - non-zero, then the child process will not be run. + and executing the new process. + + There are two types of hooks: +

    +
  • Global hook takes effect to all command. + Setting global hook if passing NULL to @cmd. +
  • +
  • Command hook takes effect only to the command. + Passing the pointer of the command to @cmd. +
  • +
+ + If hook(opaque) returns -1, then the child process will not be + run for error. And if it returns 1, the child process will exit + with status in advance and this mode is used for command dryrun. + + Since @hook runs in the child, it should be careful to avoid + any functions that are not async-signal-safe. + + For global hook, Passing NULL for @cmd, @hook and @opaque to + cancel the effect.

=20
-virCommandSetPreExecHook(cmd, hook, opaque);
+virCommandSetPreExecHook(NULL, hook, opaque); /* global hook */
+virCommandSetPreExecHook(cmd, hook, opaque); /* command hook */
+
+virCommandSetPreExecHook(NULL, NULL, NULL); /* cancel global hook */
 
=20 +

Logging commands

=20

diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 47ea35f..f4aca6f 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1602,7 +1602,10 @@ virCommandDaemonize; virCommandDoAsyncIO; virCommandExec; virCommandFree; +virCommandGetArgs; +virCommandGetEnv; virCommandGetGID; +virCommandGetInputBuffer; virCommandGetUID; virCommandHandshakeNotify; virCommandHandshakeWait; @@ -1621,7 +1624,6 @@ virCommandRunAsync; virCommandRunNul; virCommandRunRegex; virCommandSetAppArmorProfile; -virCommandSetDryRun; virCommandSetErrorBuffer; virCommandSetErrorFD; virCommandSetGID; diff --git a/src/qemu/qemu_process.c b/src/qemu/qemu_process.c index ab74938..f7a5dbd 100644 --- a/src/qemu/qemu_process.c +++ b/src/qemu/qemu_process.c @@ -2656,7 +2656,9 @@ qemuProcessKillManagedPRDaemon(virDomainObjPtr vm) =20 =20 static int -qemuProcessStartPRDaemonHook(void *opaque) +qemuProcessStartPRDaemonHook(void *opaque, + virCommandPtr ptr ATTRIBUTE_UNUSED, + int *status ATTRIBUTE_UNUSED) { virDomainObjPtr vm =3D opaque; size_t i, nfds =3D 0; @@ -2972,7 +2974,9 @@ struct qemuProcessHookData { virQEMUDriverConfigPtr cfg; }; =20 -static int qemuProcessHook(void *data) +static int qemuProcessHook(void *data, + virCommandPtr ptr ATTRIBUTE_UNUSED, + int *status ATTRIBUTE_UNUSED) { struct qemuProcessHookData *h =3D data; qemuDomainObjPrivatePtr priv =3D h->vm->privateData; diff --git a/src/util/vircommand.c b/src/util/vircommand.c index 8be3fdf..53aee7a 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -138,11 +138,9 @@ struct _virCommand { int mask; }; =20 -/* See virCommandSetDryRun for description for this variable */ -static virBufferPtr dryRunBuffer; -static virCommandDryRunCallback dryRunCallback; -static void *dryRunOpaque; -static int dryRunStatus; +/* See virCommandSetPreExecHook for these variable */ +static virExecHook preExecHook; +static void *preExecOpaque; =20 /* * virCommandFDIsSet: @@ -717,12 +715,32 @@ virExec(virCommandPtr cmd) virProcessSetMaxCoreSize(0, cmd->maxCore) < 0) goto fork_error; =20 + if (preExecHook) { + int status =3D 0; + ret =3D preExecHook(preExecOpaque, cmd, &status); + if (ret < 0) + goto fork_error; + + if (ret =3D=3D 1) { + /* Child skips followed steps and exits with status in advance= . */ + ret =3D status; + goto fork_error; + } + } + if (cmd->hook) { + int status =3D 0; VIR_DEBUG("Run hook %p %p", cmd->hook, cmd->opaque); - ret =3D cmd->hook(cmd->opaque); + ret =3D cmd->hook(cmd->opaque, cmd, &status); VIR_DEBUG("Done hook %d", ret); if (ret < 0) goto fork_error; + + if (ret =3D=3D 1) { + /* Child skips followed steps and exits with status in advance= . */ + ret =3D status; + goto fork_error; + } } =20 # if defined(WITH_SECDRIVER_SELINUX) @@ -1733,6 +1751,13 @@ virCommandSetInputBuffer(virCommandPtr cmd, const ch= ar *inbuf) } =20 =20 +const char * +virCommandGetInputBuffer(virCommandPtr cmd) +{ + return (const char *) cmd->inbuf; +} + + /** * virCommandSetOutputBuffer: * @cmd: the command to modify @@ -1879,7 +1904,9 @@ virCommandSetErrorFD(virCommandPtr cmd, int *errfd) =20 /** * virCommandSetPreExecHook: - * @cmd: the command to modify + * @cmd: the command pointer or NULL. + * NonNull, means that it registers a hook for the command + * Null, means that it registers the global PreExecHook * @hook: the hook to run * @opaque: argument to pass to the hook * @@ -1887,13 +1914,30 @@ virCommandSetErrorFD(virCommandPtr cmd, int *errfd) * directories, dropping capabilities, and executing the new process. * Force the child to fail if HOOK does not return zero. * + * There are two types of hooks: + * 1. Global hook take effect to all command. + * Setting global hook if passing NULL to @cmd. + * 2. Command hook take effect only to the command. + * Passing the pointer of the command to @cmd. + * * Since @hook runs in the child, it should be careful to avoid * any functions that are not async-signal-safe. + + * For global hook, Passing NULL for @cmd, @hook and @opaque to cancel + * the effect. */ void virCommandSetPreExecHook(virCommandPtr cmd, virExecHook hook, void *opaque) { - if (!cmd || cmd->has_error) + if (!cmd) { + /* Global hook */ + preExecHook =3D hook; + preExecOpaque =3D opaque; + return; + } + + /* Command hook */ + if (cmd->has_error) return; =20 if (cmd->hook) { @@ -2017,11 +2061,6 @@ virCommandProcessIO(virCommandPtr cmd) size_t inoff =3D 0; int ret =3D 0; =20 - if (dryRunBuffer || dryRunCallback) { - VIR_DEBUG("Dry run requested, skipping I/O processing"); - return 0; - } - /* With an input buffer, feed data to child * via pipe */ if (cmd->inbuf) @@ -2439,31 +2478,6 @@ virCommandRunAsync(virCommandPtr cmd, pid_t *pid) goto cleanup; } =20 - str =3D virCommandToString(cmd); - if (dryRunBuffer || dryRunCallback) { - dryRunStatus =3D 0; - if (!str) { - /* error already reported by virCommandToString */ - goto cleanup; - } - - if (dryRunBuffer) { - VIR_DEBUG("Dry run requested, appending stringified " - "command to dryRunBuffer=3D%p", dryRunBuffer); - virBufferAdd(dryRunBuffer, str, -1); - virBufferAddChar(dryRunBuffer, '\n'); - } - if (dryRunCallback) { - dryRunCallback((const char *const*)cmd->args, - (const char *const*)cmd->env, - cmd->inbuf, cmd->outbuf, cmd->errbuf, - &dryRunStatus, dryRunOpaque); - } - ret =3D 0; - goto cleanup; - } - - VIR_DEBUG("About to run %s", str ? str : cmd->args[0]); ret =3D virExec(cmd); VIR_DEBUG("Command result %d, with PID %d", ret, (int)cmd->pid); @@ -2537,16 +2551,6 @@ virCommandWait(virCommandPtr cmd, int *exitstatus) return -1; } =20 - if (dryRunBuffer || dryRunCallback) { - VIR_DEBUG("Dry run requested, returning status %d", - dryRunStatus); - if (exitstatus) - *exitstatus =3D dryRunStatus; - else if (dryRunStatus) - return -1; - return 0; - } - if (cmd->pid =3D=3D -1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("command is not yet running")); @@ -2878,48 +2882,21 @@ virCommandDoAsyncIO(virCommandPtr cmd) cmd->flags |=3D VIR_EXEC_ASYNC_IO | VIR_EXEC_NONBLOCK; } =20 -/** - * virCommandSetDryRun: - * @buf: buffer to store stringified commands - * @callback: callback to process input/output/args - * - * Sometimes it's desired to not actually run given command, but - * see its string representation without having to change the - * callee. Unit testing serves as a great example. In such cases, - * the callee constructs the command and calls it via - * virCommandRun* API. The virCommandSetDryRun allows you to - * modify this behavior: once called, every call to - * virCommandRun* results in command string representation being - * appended to @buf instead of being executed. If @callback is - * provided, then it is invoked with the argv, env and stdin - * data string for the command. It is expected to fill the stdout - * and stderr data strings and exit status variables. - * - * The strings stored in @buf are escaped for a shell and - * separated by a newline. For example: - * - * virBuffer buffer =3D VIR_BUFFER_INITIALIZER; - * virCommandSetDryRun(&buffer); - * - * virCommandPtr echocmd =3D virCommandNewArgList("/bin/echo", "Hello worl= d", NULL); - * virCommandRun(echocmd, NULL); - * - * After this, the @buffer should contain: - * - * /bin/echo 'Hello world'\n - * - * To cancel this effect pass NULL for @buf and @callback. - */ -void -virCommandSetDryRun(virBufferPtr buf, - virCommandDryRunCallback cb, - void *opaque) + +const char *const* +virCommandGetArgs(virCommandPtr cmd) +{ + return (const char *const*) cmd->args; +} + + +const char *const* +virCommandGetEnv(virCommandPtr cmd) { - dryRunBuffer =3D buf; - dryRunCallback =3D cb; - dryRunOpaque =3D opaque; + return (const char *const*) cmd->env; } =20 + #ifndef WIN32 /** * virCommandRunRegex: diff --git a/src/util/vircommand.h b/src/util/vircommand.h index 90bcc6c..9f322d8 100644 --- a/src/util/vircommand.h +++ b/src/util/vircommand.h @@ -29,10 +29,22 @@ typedef struct _virCommand virCommand; typedef virCommand *virCommandPtr; =20 -/* This will execute in the context of the first child +/* + * virExecHook: + * @data: opaque for this hook + * @cmd: pointer to virCommand + * @status: get status for exit status of the child, + * valid only if return code is 1. + * + * This will execute in the context of the first child * after fork() but before execve(). As such, it is unsafe to - * call any function that is not async-signal-safe. */ -typedef int (*virExecHook)(void *data); + * call any function that is not async-signal-safe. + * + * Returns: 0 on success, + * -1 on usage error (errno is ENOMEM on OOM), + * 1 to notify child exit with status from child in advance + */ +typedef int (*virExecHook)(void *data, virCommandPtr cmd, int *status); =20 pid_t virFork(void) ATTRIBUTE_RETURN_CHECK; =20 diff --git a/src/util/vircommandpriv.h b/src/util/vircommandpriv.h index 8930299..f2b6063 100644 --- a/src/util/vircommandpriv.h +++ b/src/util/vircommandpriv.h @@ -20,7 +20,7 @@ */ =20 #ifndef __VIR_COMMAND_PRIV_H_ALLOW__ -# error "vircommandpriv.h may only be included by vircommand.c or test sui= tes" +# error "vircommandpriv.h may only be included by vircommand.c or testutil= s.c" #endif =20 #ifndef __VIR_COMMAND_PRIV_H__ @@ -28,16 +28,13 @@ =20 # include "vircommand.h" =20 -typedef void (*virCommandDryRunCallback)(const char *const*args, - const char *const*env, - const char *input, - char **output, - char **error, - int *status, - void *opaque); +const char *const* +virCommandGetArgs(virCommandPtr cmd); =20 -void virCommandSetDryRun(virBufferPtr buf, - virCommandDryRunCallback cb, - void *opaque); +const char *const* +virCommandGetEnv(virCommandPtr cmd); + +const char * +virCommandGetInputBuffer(virCommandPtr cmd); =20 #endif /* __VIR_COMMAND_PRIV_H__ */ diff --git a/tests/networkxml2firewalltest.c b/tests/networkxml2firewalltes= t.c index 242b645..196c0b1 100644 --- a/tests/networkxml2firewalltest.c +++ b/tests/networkxml2firewalltest.c @@ -31,9 +31,6 @@ # define __VIR_FIREWALL_PRIV_H_ALLOW__ # include "virfirewallpriv.h" =20 -# define __VIR_COMMAND_PRIV_H_ALLOW__ -# include "vircommandpriv.h" - # define VIR_FROM_THIS VIR_FROM_NONE =20 static const char *abs_top_srcdir; @@ -53,7 +50,7 @@ static int testCompareXMLToArgvFiles(const char *xml, virNetworkDefPtr def =3D NULL; int ret =3D -1; =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 if (!(def =3D virNetworkDefParseFile(xml))) goto cleanup; @@ -66,7 +63,6 @@ static int testCompareXMLToArgvFiles(const char *xml, =20 actualargv =3D virBufferContentAndReset(&buf); virTestClearCommandPath(actualargv); - virCommandSetDryRun(NULL, NULL, NULL); =20 if (virTestCompareToFile(actualargv, cmdline) < 0) goto cleanup; @@ -74,6 +70,7 @@ static int testCompareXMLToArgvFiles(const char *xml, ret =3D 0; =20 cleanup: + virTestSetDryRun(NULL, NULL, NULL); virBufferFreeAndReset(&buf); VIR_FREE(expectargv); VIR_FREE(actualargv); diff --git a/tests/nwfilterebiptablestest.c b/tests/nwfilterebiptablestest.c index 6073423..186349c 100644 --- a/tests/nwfilterebiptablestest.c +++ b/tests/nwfilterebiptablestest.c @@ -29,12 +29,8 @@ #define __VIR_FIREWALL_PRIV_H_ALLOW__ #include "virfirewallpriv.h" =20 -#define __VIR_COMMAND_PRIV_H_ALLOW__ -#include "vircommandpriv.h" - #define VIR_FROM_THIS VIR_FROM_NONE =20 - #define VIR_NWFILTER_NEW_RULES_TEARDOWN \ "iptables -D libvirt-out -m physdev --physdev-is-bridged --physdev-out= vnet0 -g FP-vnet0\n" \ "iptables -D libvirt-out -m physdev --physdev-out vnet0 -g FP-vnet0\n"= \ @@ -104,7 +100,7 @@ testNWFilterEBIPTablesAllTeardown(const void *opaque AT= TRIBUTE_UNUSED) char *actual =3D NULL; int ret =3D -1; =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 if (ebiptables_driver.allTeardown("vnet0") < 0) goto cleanup; @@ -122,7 +118,7 @@ testNWFilterEBIPTablesAllTeardown(const void *opaque AT= TRIBUTE_UNUSED) =20 ret =3D 0; cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virBufferFreeAndReset(&buf); VIR_FREE(actual); return ret; @@ -175,7 +171,7 @@ testNWFilterEBIPTablesTearOldRules(const void *opaque A= TTRIBUTE_UNUSED) char *actual =3D NULL; int ret =3D -1; =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 if (ebiptables_driver.tearOldRules("vnet0") < 0) goto cleanup; @@ -193,7 +189,7 @@ testNWFilterEBIPTablesTearOldRules(const void *opaque A= TTRIBUTE_UNUSED) =20 ret =3D 0; cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virBufferFreeAndReset(&buf); VIR_FREE(actual); return ret; @@ -224,7 +220,7 @@ testNWFilterEBIPTablesRemoveBasicRules(const void *opaq= ue ATTRIBUTE_UNUSED) char *actual =3D NULL; int ret =3D -1; =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 if (ebiptables_driver.removeBasicRules("vnet0") < 0) goto cleanup; @@ -242,7 +238,7 @@ testNWFilterEBIPTablesRemoveBasicRules(const void *opaq= ue ATTRIBUTE_UNUSED) =20 ret =3D 0; cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virBufferFreeAndReset(&buf); VIR_FREE(actual); return ret; @@ -258,7 +254,7 @@ testNWFilterEBIPTablesTearNewRules(const void *opaque A= TTRIBUTE_UNUSED) char *actual =3D NULL; int ret =3D -1; =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 if (ebiptables_driver.tearNewRules("vnet0") < 0) goto cleanup; @@ -276,7 +272,7 @@ testNWFilterEBIPTablesTearNewRules(const void *opaque A= TTRIBUTE_UNUSED) =20 ret =3D 0; cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virBufferFreeAndReset(&buf); VIR_FREE(actual); return ret; @@ -330,7 +326,7 @@ testNWFilterEBIPTablesApplyBasicRules(const void *opaqu= e ATTRIBUTE_UNUSED) int ret =3D -1; virMacAddr mac =3D { .addr =3D { 0x10, 0x20, 0x30, 0x40, 0x50, 0x60 } = }; =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 if (ebiptables_driver.applyBasicRules("vnet0", &mac) < 0) goto cleanup; @@ -348,7 +344,7 @@ testNWFilterEBIPTablesApplyBasicRules(const void *opaqu= e ATTRIBUTE_UNUSED) =20 ret =3D 0; cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virBufferFreeAndReset(&buf); VIR_FREE(actual); return ret; @@ -420,7 +416,7 @@ testNWFilterEBIPTablesApplyDHCPOnlyRules(const void *op= aque ATTRIBUTE_UNUSED) } }; =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 if (ebiptables_driver.applyDHCPOnlyRules("vnet0", &mac, &val, false) <= 0) goto cleanup; @@ -438,7 +434,7 @@ testNWFilterEBIPTablesApplyDHCPOnlyRules(const void *op= aque ATTRIBUTE_UNUSED) =20 ret =3D 0; cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virBufferFreeAndReset(&buf); VIR_FREE(actual); return ret; @@ -493,7 +489,7 @@ testNWFilterEBIPTablesApplyDropAllRules(const void *opa= que ATTRIBUTE_UNUSED) char *actual =3D NULL; int ret =3D -1; =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 if (ebiptables_driver.applyDropAllRules("vnet0") < 0) goto cleanup; @@ -511,7 +507,7 @@ testNWFilterEBIPTablesApplyDropAllRules(const void *opa= que ATTRIBUTE_UNUSED) =20 ret =3D 0; cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virBufferFreeAndReset(&buf); VIR_FREE(actual); return ret; diff --git a/tests/nwfilterxml2firewalltest.c b/tests/nwfilterxml2firewallt= est.c index 043b7d1..6ae0ef7 100644 --- a/tests/nwfilterxml2firewalltest.c +++ b/tests/nwfilterxml2firewalltest.c @@ -30,8 +30,6 @@ # define __VIR_FIREWALL_PRIV_H_ALLOW__ # include "virfirewallpriv.h" =20 -# define __VIR_COMMAND_PRIV_H_ALLOW__ -# include "vircommandpriv.h" =20 # define VIR_FROM_THIS VIR_FROM_NONE =20 @@ -380,7 +378,7 @@ static int testCompareXMLToArgvFiles(const char *xml, =20 memset(&inst, 0, sizeof(inst)); =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 if (!vars) goto cleanup; @@ -401,7 +399,6 @@ static int testCompareXMLToArgvFiles(const char *xml, =20 actualargv =3D virBufferContentAndReset(&buf); virTestClearCommandPath(actualargv); - virCommandSetDryRun(NULL, NULL, NULL); =20 testRemoveCommonRules(actualargv); =20 @@ -411,6 +408,7 @@ static int testCompareXMLToArgvFiles(const char *xml, ret =3D 0; =20 cleanup: + virTestSetDryRun(NULL, NULL, NULL); virBufferFreeAndReset(&buf); VIR_FREE(actualargv); virNWFilterInstReset(&inst); diff --git a/tests/testutils.c b/tests/testutils.c index ab938c1..01d9edc 100644 --- a/tests/testutils.c +++ b/tests/testutils.c @@ -48,6 +48,9 @@ #include "virprocess.h" #include "virstring.h" =20 +#define __VIR_COMMAND_PRIV_H_ALLOW__ +#include "vircommandpriv.h" + #ifdef TEST_OOM # ifdef TEST_OOM_TRACE # include @@ -1414,3 +1417,210 @@ const char =20 return virtTestCounterStr; } + + +#define VIR_TEST_DRYRUN_PIPE "/tmp/vir_test_pipe" + +/* According to old virCommandDryRunCallback */ +typedef int (*dryRunCallback)(const char *const*args, + const char *const*env, + const char *input, + const void *opaque); + +typedef struct _dryRunHookData dryRunHookData; +typedef dryRunHookData *dryRunHookDataPtr; + +struct _dryRunHookData +{ + dryRunCallback callback; + void *opaque; + virBufferPtr buffer; + virThreadPtr thread; + int readfd; +}; + +static dryRunHookData hookdata =3D { NULL, NULL, NULL, NULL, -1 }; + + +/* of virExecHook type */ +static int +dryRunHookForTest(void *opaque, virCommandPtr cmd, int *status) +{ + dryRunHookDataPtr data =3D opaque; + + virThreadCancel(data->thread); + virThreadJoin(data->thread); + VIR_FREE(data->thread); + if (data->readfd !=3D -1) + VIR_FORCE_CLOSE(data->readfd); + + if (!status) + return -1; + + *status =3D 0; + + if (data->buffer) { + int fd; + int len =3D 0; + int pos =3D 0; + VIR_AUTOFREE(char *) str =3D NULL; + str =3D virCommandToString(cmd); + if (!str) + return -1; + + len =3D strlen(str); + if (len =3D=3D 0) + return -1; + + if ((fd =3D open(VIR_TEST_DRYRUN_PIPE, O_WRONLY)) < 0) + return -1; + + while (len > 0) { + int size =3D len > PIPE_BUF ? PIPE_BUF : len; + if (safewrite(fd, str + pos, size) !=3D size) { + VIR_FORCE_CLOSE(fd); + return -1; + } + pos +=3D size; + len -=3D size; + } + + if (safewrite(fd, "\n", 1) !=3D 1) { + VIR_FORCE_CLOSE(fd); + return -1; + } + + VIR_FORCE_CLOSE(fd); + } + + if (data->callback) { + *status =3D data->callback(virCommandGetArgs(cmd), + virCommandGetEnv(cmd), + virCommandGetInputBuffer(cmd), + data->opaque); + } + + /* For dry-run: + * It returns 1 to exit from child in advance */ + return 1; +} + + +static void +dryRunWaitHelper(void *opaque) +{ + int *fd =3D (int *) opaque; + while (true) { + if ((*fd =3D open(VIR_TEST_DRYRUN_PIPE, O_RDONLY)) < 0) { + fprintf(stderr, "cannot open dryrun pipe for read\n"); + return; + } + + while (true) { + int ret; + char str[PIPE_BUF]; + memset(str, 0, sizeof(str)); + ret =3D read(*fd, str, PIPE_BUF); + if (ret < 0) { + fprintf(stderr, "read dryrun pipe error: %d\n", errno); + VIR_FORCE_CLOSE(*fd); + return; + } + + if (ret =3D=3D 0) + break; + + virBufferAdd(hookdata.buffer, str, ret); + } + + VIR_FORCE_CLOSE(*fd); + } + + /* Never reach here */ +} + + +/** + * virTestSetDryRun: (substitute for old virCommandSetDryRun) + * @buf: buffer to store stringified commands + * @callback: callback to process input/output/args + * @opaque: argument passed to callback + * + * In unit testing, it's desired to not actually run given command, + * but see its string representation without having to change the + * callee. The callee constructs the command and calls it via + * virCommandRun* API. The virTestSetDryRun allows you to + * modify this behavior: once called, every call to + * virCommandRun* results in command string representation being + * appended to @buf instead of being executed. If @callback is + * provided, then it is invoked with the argv, env and stdin + * data string for the command. It is expected to fill the stdout + * and stderr data strings and exit status variables. + * + * The strings stored in @buf are escaped for a shell and + * separated by a newline. For example: + * + * virBuffer buffer =3D VIR_BUFFER_INITIALIZER; + * virTestSetDryRun(&buffer, NULL, NULL); + * + * virCommandPtr echocmd =3D virCommandNewArgList("/bin/echo", "Hello worl= d", NULL); + * virCommandRun(echocmd, NULL); + * + * After this, the @buffer should contain: + * + * /bin/echo 'Hello world'\n + * + * To cancel this effect pass NULL for @buf, @callback and @opaque. + * virTestSetDryRun(NULL, NULL, NULL); + * + */ +void +virTestSetDryRun(virBufferPtr buf, void *callback, void *opaque) +{ + if (!buf && !callback && !opaque) { + /* Passing NULL for @buf, @callback and @opaque to cancel dry-run = */ + if (hookdata.thread) { + virThreadCancel(hookdata.thread); + virThreadJoin(hookdata.thread); + VIR_FREE(hookdata.thread); + } + + hookdata.buffer =3D NULL; + hookdata.callback =3D NULL; + hookdata.opaque =3D NULL; + if (hookdata.readfd !=3D -1) + VIR_FORCE_CLOSE(hookdata.readfd); + + virCommandSetPreExecHook(NULL, NULL, NULL); + unlink(VIR_TEST_DRYRUN_PIPE); + return; + } + + if (hookdata.buffer || hookdata.callback || hookdata.opaque || hookdat= a.thread) { + fprintf(stderr, "cannot set dryrun twice buf(%p) cb(%p) opaque(%p)= thread(%p)\n", + hookdata.buffer, hookdata.callback, hookdata.opaque, hookd= ata.thread); + return; + } + + if (hookdata.readfd !=3D -1) + VIR_FORCE_CLOSE(hookdata.readfd); + + if (!virFileExists(VIR_TEST_DRYRUN_PIPE)) { + if (mkfifo(VIR_TEST_DRYRUN_PIPE, 0600) < 0) { + fprintf(stderr, "cannot create dryrun pipe. err: %d\n", errno); + return; + } + } + + if (VIR_ALLOC(hookdata.thread) < 0 || + virThreadCreate(hookdata.thread, true, dryRunWaitHelper, &hookdata= .readfd) < 0) { + fprintf(stderr, "cannot create thread for dryrun. err: %d\n", errn= o); + VIR_FREE(hookdata.thread); + return; + } + + hookdata.buffer =3D buf; + hookdata.callback =3D callback; + hookdata.opaque =3D opaque; + virCommandSetPreExecHook(NULL, dryRunHookForTest, &hookdata); +} diff --git a/tests/testutils.h b/tests/testutils.h index 3bd7bf1..82bfa0a 100644 --- a/tests/testutils.h +++ b/tests/testutils.h @@ -167,4 +167,6 @@ int testCompareDomXML2XMLFiles(virCapsPtr caps, unsigned int parseFlags, testCompareDomXML2XMLResult expectResult); =20 +void virTestSetDryRun(virBufferPtr buf, void *callback, void *opaque); + #endif /* __VIR_TEST_UTILS_H__ */ diff --git a/tests/virfirewalltest.c b/tests/virfirewalltest.c index e6d6874..1bf41c7 100644 --- a/tests/virfirewalltest.c +++ b/tests/virfirewalltest.c @@ -21,14 +21,12 @@ #include =20 #define __VIR_FIREWALL_PRIV_H_ALLOW__ -#define __VIR_COMMAND_PRIV_H_ALLOW__ =20 #include "testutils.h" =20 #if defined(__linux__) =20 # include "virbuffer.h" -# include "vircommandpriv.h" # include "virfirewallpriv.h" # include "virmock.h" # include "virdbuspriv.h" @@ -213,7 +211,7 @@ testFirewallSingleGroup(const void *opaque) goto cleanup; =20 if (data->expectBackend =3D=3D VIR_FIREWALL_BACKEND_DIRECT) - virCommandSetDryRun(&cmdbuf, NULL, NULL); + virTestSetDryRun(&cmdbuf, NULL, NULL); else fwBuf =3D &cmdbuf; =20 @@ -249,7 +247,7 @@ testFirewallSingleGroup(const void *opaque) cleanup: virBufferFreeAndReset(&cmdbuf); fwBuf =3D NULL; - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virFirewallFree(fw); return ret; } @@ -273,7 +271,7 @@ testFirewallRemoveRule(const void *opaque) goto cleanup; =20 if (data->expectBackend =3D=3D VIR_FIREWALL_BACKEND_DIRECT) - virCommandSetDryRun(&cmdbuf, NULL, NULL); + virTestSetDryRun(&cmdbuf, NULL, NULL); else fwBuf =3D &cmdbuf; =20 @@ -315,7 +313,7 @@ testFirewallRemoveRule(const void *opaque) cleanup: virBufferFreeAndReset(&cmdbuf); fwBuf =3D NULL; - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virFirewallFree(fw); return ret; } @@ -340,7 +338,7 @@ testFirewallManyGroups(const void *opaque ATTRIBUTE_UNU= SED) goto cleanup; =20 if (data->expectBackend =3D=3D VIR_FIREWALL_BACKEND_DIRECT) - virCommandSetDryRun(&cmdbuf, NULL, NULL); + virTestSetDryRun(&cmdbuf, NULL, NULL); else fwBuf =3D &cmdbuf; =20 @@ -388,19 +386,16 @@ testFirewallManyGroups(const void *opaque ATTRIBUTE_U= NUSED) cleanup: virBufferFreeAndReset(&cmdbuf); fwBuf =3D NULL; - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virFirewallFree(fw); return ret; } =20 -static void +static int testFirewallRollbackHook(const char *const*args, const char *const*env ATTRIBUTE_UNUSED, const char *input ATTRIBUTE_UNUSED, - char **output ATTRIBUTE_UNUSED, - char **error ATTRIBUTE_UNUSED, - int *status, - void *opaque ATTRIBUTE_UNUSED) + const void *opaque ATTRIBUTE_UNUSED) { bool isAdd =3D false; while (*args) { @@ -408,11 +403,11 @@ testFirewallRollbackHook(const char *const*args, if (STREQ(*args, "-A")) { isAdd =3D true; } else if (isAdd && STREQ(*args, "192.168.122.255")) { - *status =3D 127; - break; + return 127; } args++; } + return 0; } =20 static int @@ -434,7 +429,7 @@ testFirewallIgnoreFailGroup(const void *opaque ATTRIBUT= E_UNUSED) goto cleanup; =20 if (data->expectBackend =3D=3D VIR_FIREWALL_BACKEND_DIRECT) { - virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); + virTestSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); } else { fwBuf =3D &cmdbuf; fwError =3D true; @@ -484,7 +479,7 @@ testFirewallIgnoreFailGroup(const void *opaque ATTRIBUT= E_UNUSED) cleanup: virBufferFreeAndReset(&cmdbuf); fwBuf =3D NULL; - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virFirewallFree(fw); return ret; } @@ -509,7 +504,7 @@ testFirewallIgnoreFailRule(const void *opaque ATTRIBUTE= _UNUSED) goto cleanup; =20 if (data->expectBackend =3D=3D VIR_FIREWALL_BACKEND_DIRECT) { - virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); + virTestSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); } else { fwBuf =3D &cmdbuf; fwError =3D true; @@ -558,7 +553,7 @@ testFirewallIgnoreFailRule(const void *opaque ATTRIBUTE= _UNUSED) cleanup: virBufferFreeAndReset(&cmdbuf); fwBuf =3D NULL; - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virFirewallFree(fw); return ret; } @@ -581,7 +576,7 @@ testFirewallNoRollback(const void *opaque ATTRIBUTE_UNU= SED) goto cleanup; =20 if (data->expectBackend =3D=3D VIR_FIREWALL_BACKEND_DIRECT) { - virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); + virTestSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); } else { fwBuf =3D &cmdbuf; fwError =3D true; @@ -629,7 +624,7 @@ testFirewallNoRollback(const void *opaque ATTRIBUTE_UNU= SED) cleanup: virBufferFreeAndReset(&cmdbuf); fwBuf =3D NULL; - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virFirewallFree(fw); return ret; } @@ -654,7 +649,7 @@ testFirewallSingleRollback(const void *opaque ATTRIBUTE= _UNUSED) goto cleanup; =20 if (data->expectBackend =3D=3D VIR_FIREWALL_BACKEND_DIRECT) { - virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); + virTestSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); } else { fwError =3D true; fwBuf =3D &cmdbuf; @@ -719,7 +714,7 @@ testFirewallSingleRollback(const void *opaque ATTRIBUTE= _UNUSED) cleanup: virBufferFreeAndReset(&cmdbuf); fwBuf =3D NULL; - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virFirewallFree(fw); return ret; } @@ -743,7 +738,7 @@ testFirewallManyRollback(const void *opaque ATTRIBUTE_U= NUSED) goto cleanup; =20 if (data->expectBackend =3D=3D VIR_FIREWALL_BACKEND_DIRECT) { - virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); + virTestSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); } else { fwBuf =3D &cmdbuf; fwError =3D true; @@ -812,7 +807,7 @@ testFirewallManyRollback(const void *opaque ATTRIBUTE_U= NUSED) cleanup: virBufferFreeAndReset(&cmdbuf); fwBuf =3D NULL; - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virFirewallFree(fw); return ret; } @@ -840,7 +835,7 @@ testFirewallChainedRollback(const void *opaque ATTRIBUT= E_UNUSED) goto cleanup; =20 if (data->expectBackend =3D=3D VIR_FIREWALL_BACKEND_DIRECT) { - virCommandSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); + virTestSetDryRun(&cmdbuf, testFirewallRollbackHook, NULL); } else { fwBuf =3D &cmdbuf; fwError =3D true; @@ -935,7 +930,7 @@ testFirewallChainedRollback(const void *opaque ATTRIBUT= E_UNUSED) cleanup: virBufferFreeAndReset(&cmdbuf); fwBuf =3D NULL; - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virFirewallFree(fw); return ret; } @@ -967,26 +962,26 @@ static const char *expectedLines[] =3D { static size_t expectedLineNum; static bool expectedLineError; =20 -static void +static int testFirewallQueryHook(const char *const*args, const char *const*env ATTRIBUTE_UNUSED, const char *input ATTRIBUTE_UNUSED, - char **output, - char **error ATTRIBUTE_UNUSED, - int *status, - void *opaque ATTRIBUTE_UNUSED) + const void *opaque ATTRIBUTE_UNUSED) { if (STREQ(args[0], IPTABLES_PATH) && STREQ(args[1], "-L")) { - if (VIR_STRDUP(*output, TEST_FILTER_TABLE_LIST) < 0) - *status =3D 127; + if (safewrite(STDOUT_FILENO, TEST_FILTER_TABLE_LIST, + strlen(TEST_FILTER_TABLE_LIST)) < 0) + return 127; } else if (STREQ(args[0], IPTABLES_PATH) && STREQ(args[1], "-t") && STREQ(args[2], "nat") && STREQ(args[3], "-L")) { - if (VIR_STRDUP(*output, TEST_NAT_TABLE_LIST) < 0) - *status =3D 127; + if (safewrite(STDOUT_FILENO, TEST_NAT_TABLE_LIST, + strlen(TEST_NAT_TABLE_LIST)) < 0) + return 127; } + return 0; } =20 =20 @@ -1044,7 +1039,7 @@ testFirewallQuery(const void *opaque ATTRIBUTE_UNUSED) goto cleanup; =20 if (data->expectBackend =3D=3D VIR_FIREWALL_BACKEND_DIRECT) { - virCommandSetDryRun(&cmdbuf, testFirewallQueryHook, NULL); + virTestSetDryRun(&cmdbuf, testFirewallQueryHook, NULL); } else { fwBuf =3D &cmdbuf; fwError =3D true; @@ -1118,7 +1113,7 @@ testFirewallQuery(const void *opaque ATTRIBUTE_UNUSED) cleanup: virBufferFreeAndReset(&cmdbuf); fwBuf =3D NULL; - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virFirewallFree(fw); return ret; } diff --git a/tests/viriscsitest.c b/tests/viriscsitest.c index 4fd7ff6..11a2a54 100644 --- a/tests/viriscsitest.c +++ b/tests/viriscsitest.c @@ -19,6 +19,7 @@ */ =20 #include +#include =20 #include "testutils.h" =20 @@ -29,9 +30,6 @@ main(void) return EXIT_AM_SKIP; } #else -# define __VIR_COMMAND_PRIV_H_ALLOW__ - -# include "vircommandpriv.h" # include "viriscsi.h" =20 # define VIR_FROM_THIS VIR_FROM_NONE @@ -72,27 +70,40 @@ const char *iscsiadmIfaceIfaceOutput =3D =20 struct testIscsiadmCbData { bool output_version; - bool iface_created; + char *result_path; }; =20 -static void testIscsiadmCb(const char *const*args, - const char *const*env ATTRIBUTE_UNUSED, - const char *input ATTRIBUTE_UNUSED, - char **output, - char **error ATTRIBUTE_UNUSED, - int *status, - void *opaque) +static int testIscsiadmCb(const char *const*args, + const char *const*env ATTRIBUTE_UNUSED, + const char *input ATTRIBUTE_UNUSED, + const void *opaque) { - struct testIscsiadmCbData *data =3D opaque; + int fd; + int iface_created =3D 0; + const struct testIscsiadmCbData *data =3D opaque; + + if (data) { + fd =3D open(data->result_path, O_RDONLY); + if (fd < 0) + return -1; + + if (read(fd, &iface_created, sizeof(int)) !=3D sizeof(int)) { + VIR_FORCE_CLOSE(fd); + return -1; + } + VIR_FORCE_CLOSE(fd); + } =20 if (args[0] && STREQ(args[0], ISCSIADM) && args[1] && STREQ(args[1], "--mode") && args[2] && STREQ(args[2], "session") && args[3] =3D=3D NULL) { if (data->output_version) - ignore_value(VIR_STRDUP(*output, iscsiadmSessionOutputNonFlash= )); + ignore_value(safewrite(STDOUT_FILENO, iscsiadmSessionOutputNon= Flash, + strlen(iscsiadmSessionOutputNonFlash))); else - ignore_value(VIR_STRDUP(*output, iscsiadmSessionOutput)); + ignore_value(safewrite(STDOUT_FILENO, iscsiadmSessionOutput, + strlen(iscsiadmSessionOutput))); } else if (args[0] && STREQ(args[0], ISCSIADM) && args[1] && STREQ(args[1], "--mode") && args[2] && STREQ(args[2], "discovery") && @@ -103,7 +114,8 @@ static void testIscsiadmCb(const char *const*args, args[7] && STREQ(args[7], "--op") && args[8] && STREQ(args[8], "nonpersistent") && args[9] =3D=3D NULL) { - ignore_value(VIR_STRDUP(*output, iscsiadmSendtargetsOutput)); + ignore_value(safewrite(STDOUT_FILENO, iscsiadmSendtargetsOutput, + strlen(iscsiadmSendtargetsOutput))); } else if (args[0] && STREQ(args[0], ISCSIADM) && args[1] && STREQ(args[1], "--mode") && args[2] && STREQ(args[2], "node") && @@ -127,10 +139,12 @@ static void testIscsiadmCb(const char *const*args, args[1] && STREQ(args[1], "--mode") && args[2] && STREQ(args[2], "iface") && args[3] =3D=3D NULL) { - if (data->iface_created) - ignore_value(VIR_STRDUP(*output, iscsiadmIfaceIfaceOutput)); + if (iface_created) + ignore_value(safewrite(STDOUT_FILENO, iscsiadmIfaceIfaceOutput, + strlen(iscsiadmIfaceIfaceOutput))); else - ignore_value(VIR_STRDUP(*output, iscsiadmIfaceDefaultOutput)); + ignore_value(safewrite(STDOUT_FILENO, iscsiadmIfaceDefaultOutp= ut, + strlen(iscsiadmIfaceDefaultOutput))); } else if (args[0] && STREQ(args[0], ISCSIADM) && args[1] && STREQ(args[1], "--mode") && args[2] && STREQ(args[2], "iface") && @@ -144,7 +158,18 @@ static void testIscsiadmCb(const char *const*args, * * New interface libvirt-iface-03020100 added */ - data->iface_created =3D true; + if (data) { + iface_created =3D 1; + fd =3D open(data->result_path, O_WRONLY); + if (fd < 0) + return -1; + + if (safewrite(fd, &iface_created, sizeof(int)) !=3D sizeof(int= )) { + VIR_FORCE_CLOSE(fd); + return -1; + } + VIR_FORCE_CLOSE(fd); + } } else if (args[0] && STREQ(args[0], ISCSIADM) && args[1] && STREQ(args[1], "--mode") && args[2] && STREQ(args[2], "iface") && @@ -157,7 +182,7 @@ static void testIscsiadmCb(const char *const*args, args[9] && STREQ(args[9], "--value") && args[10] && STREQ(args[10], "iqn.2004-06.example:example1:i= nitiator") && args[11] =3D=3D NULL && - data->iface_created) { + iface_created) { /* Mocking real environment output is not needed for now. * Example output from real environment: * @@ -173,8 +198,9 @@ static void testIscsiadmCb(const char *const*args, args[7] && STREQ(args[7], "--interface") && args[8] && STREQ(args[8], "libvirt-iface-03020100") && args[9] =3D=3D NULL && - data->iface_created) { - ignore_value(VIR_STRDUP(*output, iscsiadmSendtargetsOutput)); + iface_created) { + ignore_value(safewrite(STDOUT_FILENO, iscsiadmSendtargetsOutput, + strlen(iscsiadmSendtargetsOutput))); } else if (args[0] && STREQ(args[0], ISCSIADM) && args[1] && STREQ(args[1], "--mode") && args[2] && STREQ(args[2], "node") && @@ -186,7 +212,7 @@ static void testIscsiadmCb(const char *const*args, args[8] && STREQ(args[8], "--interface") && args[9] && STREQ(args[9], "libvirt-iface-03020100") && args[10] =3D=3D NULL && - data->iface_created) { + iface_created) { /* Mocking real environment output is not needed for now. * Example output from real environment: * @@ -198,10 +224,31 @@ static void testIscsiadmCb(const char *const*args, * portal: 10.20.30.40:3260,1] successful. */ } else { - *status =3D -1; + return -1; } + return 0; } =20 + +static int +testCreateTempFile(char *path) +{ + int iface_created =3D 0; + int fd =3D -1; + if ((fd =3D mkostemp(path, O_RDWR)) < 0) + return -1; + + if (safewrite(fd, &iface_created, sizeof(int)) !=3D sizeof(int)) { + VIR_FORCE_CLOSE(fd); + unlink(path); + return -1; + } + + VIR_FORCE_CLOSE(fd); + return 0; +} + + struct testSessionInfo { const char *device_path; bool output_version; @@ -215,10 +262,15 @@ testISCSIGetSession(const void *data) struct testIscsiadmCbData cbData =3D { 0 }; char *actual_session =3D NULL; int ret =3D -1; + char path[] =3D "/dev/shm/testiscsi.XXXXXX"; =20 + if (testCreateTempFile(path) < 0) + return -1; + + cbData.result_path =3D path; cbData.output_version =3D info->output_version; =20 - virCommandSetDryRun(NULL, testIscsiadmCb, &cbData); + virTestSetDryRun(NULL, testIscsiadmCb, &cbData); =20 actual_session =3D virISCSIGetSession(info->device_path, true); =20 @@ -233,7 +285,8 @@ testISCSIGetSession(const void *data) ret =3D 0; =20 cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); + unlink(path); VIR_FREE(actual_session); return ret; } @@ -254,7 +307,7 @@ testISCSIScanTargets(const void *data) int ret =3D -1; size_t i; =20 - virCommandSetDryRun(NULL, testIscsiadmCb, NULL); + virTestSetDryRun(NULL, testIscsiadmCb, NULL); =20 if (virISCSIScanTargets(info->portal, NULL, false, &ntargets, &targets) < 0) @@ -279,7 +332,7 @@ testISCSIScanTargets(const void *data) ret =3D 0; =20 cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); for (i =3D 0; i < ntargets; i++) VIR_FREE(targets[i]); VIR_FREE(targets); @@ -300,15 +353,21 @@ testISCSIConnectionLogin(const void *data) const struct testConnectionInfoLogin *info =3D data; struct testIscsiadmCbData cbData =3D { 0 }; int ret =3D -1; + char path[] =3D "/dev/shm/testiscsi.XXXXXX"; + + if (testCreateTempFile(path) < 0) + return -1; =20 - virCommandSetDryRun(NULL, testIscsiadmCb, &cbData); + cbData.result_path =3D path; + virTestSetDryRun(NULL, testIscsiadmCb, &cbData); =20 if (virISCSIConnectionLogin(info->portal, info->initiatoriqn, info->ta= rget) < 0) goto cleanup; =20 ret =3D 0; cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); + unlink(path); return ret; } =20 @@ -362,7 +421,6 @@ mymain(void) DO_LOGIN_TEST("10.20.30.40:3260,1", NULL, "iqn.2004-06.example:example= 1:iscsi.test"); DO_LOGIN_TEST("10.20.30.40:3260,1", "iqn.2004-06.example:example1:init= iator", "iqn.2004-06.example:example1:iscsi.test"); - if (rv < 0) return EXIT_FAILURE; return EXIT_SUCCESS; diff --git a/tests/virkmodtest.c b/tests/virkmodtest.c index b153e07..408e338 100644 --- a/tests/virkmodtest.c +++ b/tests/virkmodtest.c @@ -23,8 +23,6 @@ #ifdef __linux__ =20 # include -# define __VIR_COMMAND_PRIV_H_ALLOW__ -# include "vircommandpriv.h" # include "virkmod.h" # include "virstring.h" =20 @@ -96,7 +94,7 @@ testKModLoad(const void *args) bool useBlacklist =3D info->useBlacklist; virBuffer buf =3D VIR_BUFFER_INITIALIZER; =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 errbuf =3D virKModLoad(module, useBlacklist); if (errbuf) { @@ -110,7 +108,7 @@ testKModLoad(const void *args) ret =3D 0; =20 cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); VIR_FREE(errbuf); return ret; } @@ -125,7 +123,7 @@ testKModUnload(const void *args) const char *module =3D info->module; virBuffer buf =3D VIR_BUFFER_INITIALIZER; =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 errbuf =3D virKModUnload(module); if (errbuf) { @@ -139,7 +137,7 @@ testKModUnload(const void *args) ret =3D 0; =20 cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); VIR_FREE(errbuf); return ret; } diff --git a/tests/virnetdevbandwidthtest.c b/tests/virnetdevbandwidthtest.c index 72bfeff..62cb044 100644 --- a/tests/virnetdevbandwidthtest.c +++ b/tests/virnetdevbandwidthtest.c @@ -21,8 +21,6 @@ #include =20 #include "testutils.h" -#define __VIR_COMMAND_PRIV_H_ALLOW__ -#include "vircommandpriv.h" #include "virnetdevbandwidth.h" #include "netdev_bandwidth_conf.c" =20 @@ -79,7 +77,7 @@ testVirNetDevBandwidthSet(const void *data) if (!iface) iface =3D "eth0"; =20 - virCommandSetDryRun(&buf, NULL, NULL); + virTestSetDryRun(&buf, NULL, NULL); =20 if (virNetDevBandwidthSet(iface, band, info->hierarchical_class, true)= < 0) goto cleanup; @@ -103,7 +101,7 @@ testVirNetDevBandwidthSet(const void *data) =20 ret =3D 0; cleanup: - virCommandSetDryRun(NULL, NULL, NULL); + virTestSetDryRun(NULL, NULL, NULL); virNetDevBandwidthFree(band); virBufferFreeAndReset(&buf); VIR_FREE(actual_cmd); --=20 2.7.4 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list