提交 07c9d660 编写于 作者: D Daniel P. Berrangé

qemu: use line breaks in command line args written to log

The QEMU command line arguments are very long and currently all written
on a single line to /var/log/libvirt/qemu/$GUEST.log. This introduces
logic to add line breaks after every env variable and "-" optional
argument, and every positional argument. This will create a clearer log
file, which will in turn present better in bug reports when people cut +
paste from the log into a bug comment.

An example log file entry now looks like this:

  2018-12-14 12:57:03.677+0000: starting up libvirt version: 5.0.0, qemu version: 3.0.0qemu-3.0.0-1.fc29, kernel: 4.19.5-300.fc29.x86_64, hostname: localhost.localdomain
  LC_ALL=C \
  PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin \
  HOME=/home/berrange \
  USER=berrange \
  LOGNAME=berrange \
  QEMU_AUDIO_DRV=none \
  /usr/bin/qemu-system-ppc64 \
  -name guest=guest,debug-threads=on \
  -S \
  -object secret,id=masterKey0,format=raw,file=/home/berrange/.config/libvirt/qemu/lib/domain-33-guest/master-key.aes \
  -machine pseries-2.10,accel=tcg,usb=off,dump-guest-core=off \
  -m 1024 \
  -realtime mlock=off \
  -smp 1,sockets=1,cores=1,threads=1 \
  -uuid c8a74977-ab18-41d0-ae3b-4041c7fffbcd \
  -display none \
  -no-user-config \
  -nodefaults \
  -chardev socket,id=charmonitor,fd=23,server,nowait \
  -mon chardev=charmonitor,id=monitor,mode=control \
  -rtc base=utc \
  -no-shutdown \
  -boot strict=on \
  -device qemu-xhci,id=usb,bus=pci.0,addr=0x1 \
  -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x2 \
  -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny \
  -msg timestamp=on
  2018-12-14 12:57:03.730+0000: shutting down, reason=failed
Signed-off-by: NDaniel P. Berrangé <berrange@redhat.com>
上级 912c6b22
...@@ -426,7 +426,7 @@ dprintf(logfd, "%s: ", timestamp); ...@@ -426,7 +426,7 @@ dprintf(logfd, "%s: ", timestamp);
VIR_FREE(timestamp); VIR_FREE(timestamp);
virCommandWriteArgLog(cmd, logfd); virCommandWriteArgLog(cmd, logfd);
string = virCommandToString(cmd); string = virCommandToString(cmd, false);
if (string) if (string)
VIR_DEBUG("about to run %s", string); VIR_DEBUG("about to run %s", string);
VIR_FREE(string); VIR_FREE(string);
......
...@@ -733,14 +733,14 @@ bhyveConnectDomainXMLToNative(virConnectPtr conn, ...@@ -733,14 +733,14 @@ bhyveConnectDomainXMLToNative(virConnectPtr conn,
NULL))) NULL)))
goto cleanup; goto cleanup;
virBufferAdd(&buf, virCommandToString(loadcmd), -1); virBufferAdd(&buf, virCommandToString(loadcmd, false), -1);
virBufferAddChar(&buf, '\n'); virBufferAddChar(&buf, '\n');
} }
if (!(cmd = virBhyveProcessBuildBhyveCmd(conn, def, true))) if (!(cmd = virBhyveProcessBuildBhyveCmd(conn, def, true)))
goto cleanup; goto cleanup;
virBufferAdd(&buf, virCommandToString(cmd), -1); virBufferAdd(&buf, virCommandToString(cmd, false), -1);
if (virBufferCheckError(&buf) < 0) if (virBufferCheckError(&buf) < 0)
goto cleanup; goto cleanup;
......
...@@ -7425,7 +7425,7 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn, ...@@ -7425,7 +7425,7 @@ static char *qemuConnectDomainXMLToNative(virConnectPtr conn,
VIR_QEMU_PROCESS_START_COLD))) VIR_QEMU_PROCESS_START_COLD)))
goto cleanup; goto cleanup;
ret = virCommandToString(cmd); ret = virCommandToString(cmd, false);
cleanup: cleanup:
virCommandFree(cmd); virCommandFree(cmd);
......
...@@ -360,7 +360,7 @@ qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg, ...@@ -360,7 +360,7 @@ qemuCreateInBridgePortWithHelper(virQEMUDriverConfigPtr cfg,
char ebuf[1024]; char ebuf[1024];
char *errstr = NULL; char *errstr = NULL;
if (!(cmdstr = virCommandToString(cmd))) if (!(cmdstr = virCommandToString(cmd, false)))
goto cleanup; goto cleanup;
virCommandAbort(cmd); virCommandAbort(cmd);
......
...@@ -4353,7 +4353,7 @@ qemuLogOperation(virDomainObjPtr vm, ...@@ -4353,7 +4353,7 @@ qemuLogOperation(virDomainObjPtr vm,
goto cleanup; goto cleanup;
if (cmd) { if (cmd) {
char *args = virCommandToString(cmd); char *args = virCommandToString(cmd, true);
qemuDomainLogContextWrite(logCtxt, "%s\n", args); qemuDomainLogContextWrite(logCtxt, "%s\n", args);
VIR_FREE(args); VIR_FREE(args);
} }
......
...@@ -654,7 +654,7 @@ AppArmorSetSecurityChildProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED, ...@@ -654,7 +654,7 @@ AppArmorSetSecurityChildProcessLabel(virSecurityManagerPtr mgr ATTRIBUTE_UNUSED,
if ((profile_name = get_profile_name(def)) == NULL) if ((profile_name = get_profile_name(def)) == NULL)
goto cleanup; goto cleanup;
cmd_str = virCommandToString(cmd); cmd_str = virCommandToString(cmd, false);
VIR_DEBUG("Changing AppArmor profile to %s on %s", profile_name, cmd_str); VIR_DEBUG("Changing AppArmor profile to %s on %s", profile_name, cmd_str);
virCommandSetAppArmorProfile(cmd, profile_name); virCommandSetAppArmorProfile(cmd, profile_name);
rc = 0; rc = 0;
......
...@@ -1960,6 +1960,7 @@ virCommandWriteArgLog(virCommandPtr cmd, int logfd) ...@@ -1960,6 +1960,7 @@ virCommandWriteArgLog(virCommandPtr cmd, int logfd)
/** /**
* virCommandToString: * virCommandToString:
* @cmd: the command to convert * @cmd: the command to convert
* @linebreaks: true to break line after each env var or option
* *
* Call after adding all arguments and environment settings, but * Call after adding all arguments and environment settings, but
* before Run/RunAsync, to return a string representation of the * before Run/RunAsync, to return a string representation of the
...@@ -1969,10 +1970,11 @@ virCommandWriteArgLog(virCommandPtr cmd, int logfd) ...@@ -1969,10 +1970,11 @@ virCommandWriteArgLog(virCommandPtr cmd, int logfd)
* Caller is responsible for freeing the resulting string. * Caller is responsible for freeing the resulting string.
*/ */
char * char *
virCommandToString(virCommandPtr cmd) virCommandToString(virCommandPtr cmd, bool linebreaks)
{ {
size_t i; size_t i;
virBuffer buf = VIR_BUFFER_INITIALIZER; virBuffer buf = VIR_BUFFER_INITIALIZER;
bool prevopt = false;
/* Cannot assume virCommandRun will be called; so report the error /* Cannot assume virCommandRun will be called; so report the error
* now. If virCommandRun is called, it will report the same error. */ * now. If virCommandRun is called, it will report the same error. */
...@@ -2001,11 +2003,22 @@ virCommandToString(virCommandPtr cmd) ...@@ -2001,11 +2003,22 @@ virCommandToString(virCommandPtr cmd)
virBufferAdd(&buf, cmd->env[i], eq - cmd->env[i]); virBufferAdd(&buf, cmd->env[i], eq - cmd->env[i]);
virBufferEscapeShell(&buf, eq); virBufferEscapeShell(&buf, eq);
virBufferAddChar(&buf, ' '); virBufferAddChar(&buf, ' ');
if (linebreaks)
virBufferAddLit(&buf, "\\\n");
} }
virBufferEscapeShell(&buf, cmd->args[0]); virBufferEscapeShell(&buf, cmd->args[0]);
for (i = 1; i < cmd->nargs; i++) { for (i = 1; i < cmd->nargs; i++) {
virBufferAddChar(&buf, ' '); virBufferAddChar(&buf, ' ');
if (linebreaks) {
/* Line break if this is a --arg or if
* the previous arg was a positional option
*/
if (cmd->args[i][0] == '-' ||
!prevopt)
virBufferAddLit(&buf, "\\\n");
}
virBufferEscapeShell(&buf, cmd->args[i]); virBufferEscapeShell(&buf, cmd->args[i]);
prevopt = (cmd->args[i][0] == '-');
} }
if (virBufferCheckError(&buf) < 0) if (virBufferCheckError(&buf) < 0)
...@@ -2448,7 +2461,7 @@ virCommandRunAsync(virCommandPtr cmd, pid_t *pid) ...@@ -2448,7 +2461,7 @@ virCommandRunAsync(virCommandPtr cmd, pid_t *pid)
goto cleanup; goto cleanup;
} }
str = virCommandToString(cmd); str = virCommandToString(cmd, false);
if (dryRunBuffer || dryRunCallback) { if (dryRunBuffer || dryRunCallback) {
dryRunStatus = 0; dryRunStatus = 0;
if (!str) { if (!str) {
...@@ -2589,7 +2602,7 @@ virCommandWait(virCommandPtr cmd, int *exitstatus) ...@@ -2589,7 +2602,7 @@ virCommandWait(virCommandPtr cmd, int *exitstatus)
if (exitstatus && (cmd->rawStatus || WIFEXITED(status))) { if (exitstatus && (cmd->rawStatus || WIFEXITED(status))) {
*exitstatus = cmd->rawStatus ? status : WEXITSTATUS(status); *exitstatus = cmd->rawStatus ? status : WEXITSTATUS(status);
} else if (status) { } else if (status) {
VIR_AUTOFREE(char *) str = virCommandToString(cmd); VIR_AUTOFREE(char *) str = virCommandToString(cmd, false);
VIR_AUTOFREE(char *) st = virProcessTranslateStatus(status); VIR_AUTOFREE(char *) st = virProcessTranslateStatus(status);
bool haveErrMsg = cmd->errbuf && *cmd->errbuf && (*cmd->errbuf)[0]; bool haveErrMsg = cmd->errbuf && *cmd->errbuf && (*cmd->errbuf)[0];
......
...@@ -172,7 +172,7 @@ void virCommandSetPreExecHook(virCommandPtr cmd, ...@@ -172,7 +172,7 @@ void virCommandSetPreExecHook(virCommandPtr cmd,
void virCommandWriteArgLog(virCommandPtr cmd, void virCommandWriteArgLog(virCommandPtr cmd,
int logfd); int logfd);
char *virCommandToString(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK; char *virCommandToString(virCommandPtr cmd, bool linebreaks) ATTRIBUTE_RETURN_CHECK;
int virCommandExec(virCommandPtr cmd, gid_t *groups, int ngroups) ATTRIBUTE_RETURN_CHECK; int virCommandExec(virCommandPtr cmd, gid_t *groups, int ngroups) ATTRIBUTE_RETURN_CHECK;
......
...@@ -694,7 +694,7 @@ virFirewallApplyRuleDirect(virFirewallRulePtr rule, ...@@ -694,7 +694,7 @@ virFirewallApplyRuleDirect(virFirewallRulePtr rule,
if (ignoreErrors) { if (ignoreErrors) {
VIR_DEBUG("Ignoring error running command"); VIR_DEBUG("Ignoring error running command");
} else { } else {
VIR_AUTOFREE(char *) args = virCommandToString(cmd); VIR_AUTOFREE(char *) args = virCommandToString(cmd, false);
virReportError(VIR_ERR_INTERNAL_ERROR, virReportError(VIR_ERR_INTERNAL_ERROR,
_("Failed to apply firewall rules %s: %s"), _("Failed to apply firewall rules %s: %s"),
NULLSTR(args), NULLSTR(error)); NULLSTR(args), NULLSTR(error));
......
...@@ -68,13 +68,13 @@ static int testCompareXMLToArgvFiles(const char *xml, ...@@ -68,13 +68,13 @@ static int testCompareXMLToArgvFiles(const char *xml,
goto out; goto out;
} }
if (!(actualargv = virCommandToString(cmd))) if (!(actualargv = virCommandToString(cmd, false)))
goto out; goto out;
if (actualdm != NULL) if (actualdm != NULL)
virTrimSpaces(actualdm, NULL); virTrimSpaces(actualdm, NULL);
if (!(actualld = virCommandToString(ldcmd))) if (!(actualld = virCommandToString(ldcmd, false)))
goto out; goto out;
if (virTestCompareToFile(actualargv, cmdline) < 0) if (virTestCompareToFile(actualargv, cmdline) < 0)
......
A=B C=D E true --foo bar --oooh -f --wizz eek eek -w -z -l --mmm flash bang wallop
...@@ -630,7 +630,7 @@ static int test16(const void *unused ATTRIBUTE_UNUSED) ...@@ -630,7 +630,7 @@ static int test16(const void *unused ATTRIBUTE_UNUSED)
virCommandAddArg(cmd, "F"); virCommandAddArg(cmd, "F");
virCommandAddArg(cmd, "G H"); virCommandAddArg(cmd, "G H");
if ((outactual = virCommandToString(cmd)) == NULL) { if ((outactual = virCommandToString(cmd, false)) == NULL) {
printf("Cannot convert to string: %s\n", virGetLastErrorMessage()); printf("Cannot convert to string: %s\n", virGetLastErrorMessage());
goto cleanup; goto cleanup;
} }
...@@ -1135,6 +1135,67 @@ static int test25(const void *unused ATTRIBUTE_UNUSED) ...@@ -1135,6 +1135,67 @@ static int test25(const void *unused ATTRIBUTE_UNUSED)
} }
/*
* Don't run program; rather, log what would be run.
*/
static int test26(const void *unused ATTRIBUTE_UNUSED)
{
virCommandPtr cmd = virCommandNew("true");
char *outactual = NULL;
const char *outexpect =
"A=B \\\n"
"C='D E' \\\n"
"true \\\n"
"--foo bar \\\n"
"--oooh \\\n"
"-f \\\n"
"--wizz 'eek eek' \\\n"
"-w \\\n"
"-z \\\n"
"-l \\\n"
"--mmm flash \\\n"
"bang \\\n"
"wallop";
int ret = -1;
int fd = -1;
virCommandAddEnvPair(cmd, "A", "B");
virCommandAddEnvPair(cmd, "C", "D E");
virCommandAddArgList(cmd, "--foo", "bar", "--oooh", "-f",
"--wizz", "eek eek", "-w", "-z", "-l",
"--mmm", "flash", "bang", "wallop",
NULL);
if ((outactual = virCommandToString(cmd, true)) == NULL) {
printf("Cannot convert to string: %s\n", virGetLastErrorMessage());
goto cleanup;
}
if ((fd = open(abs_builddir "/commandhelper.log",
O_CREAT | O_TRUNC | O_WRONLY, 0600)) < 0) {
printf("Cannot open log file: %s\n", strerror(errno));
goto cleanup;
}
virCommandWriteArgLog(cmd, fd);
if (VIR_CLOSE(fd) < 0) {
printf("Cannot close log file: %s\n", strerror(errno));
goto cleanup;
}
if (STRNEQ(outactual, outexpect)) {
virTestDifference(stderr, outexpect, outactual);
goto cleanup;
}
ret = checkoutput("test26", NULL);
cleanup:
virCommandFree(cmd);
VIR_FORCE_CLOSE(fd);
VIR_FREE(outactual);
return ret;
}
static void virCommandThreadWorker(void *opaque) static void virCommandThreadWorker(void *opaque)
{ {
virCommandTestDataPtr test = opaque; virCommandTestDataPtr test = opaque;
...@@ -1288,6 +1349,7 @@ mymain(void) ...@@ -1288,6 +1349,7 @@ mymain(void)
DO_TEST(test23); DO_TEST(test23);
DO_TEST(test24); DO_TEST(test24);
DO_TEST(test25); DO_TEST(test25);
DO_TEST(test26);
virMutexLock(&test->lock); virMutexLock(&test->lock);
if (test->running) { if (test->running) {
......
...@@ -620,7 +620,7 @@ testCompareXMLToArgv(const void *data) ...@@ -620,7 +620,7 @@ testCompareXMLToArgv(const void *data)
goto cleanup; goto cleanup;
} }
if (!(actualargv = virCommandToString(cmd))) if (!(actualargv = virCommandToString(cmd, false)))
goto cleanup; goto cleanup;
if (virTestCompareToFile(actualargv, args) < 0) if (virTestCompareToFile(actualargv, args) < 0)
......
...@@ -71,7 +71,7 @@ testCompareXMLToArgvFiles(bool shouldFail, ...@@ -71,7 +71,7 @@ testCompareXMLToArgvFiles(bool shouldFail,
goto cleanup; goto cleanup;
}; };
if (!(actualCmdline = virCommandToString(cmd))) { if (!(actualCmdline = virCommandToString(cmd, false))) {
VIR_TEST_DEBUG("pool type %d failed to get commandline\n", def->type); VIR_TEST_DEBUG("pool type %d failed to get commandline\n", def->type);
goto cleanup; goto cleanup;
} }
......
...@@ -104,14 +104,14 @@ testCompareXMLToArgvFiles(bool shouldFail, ...@@ -104,14 +104,14 @@ testCompareXMLToArgvFiles(bool shouldFail,
} }
if (convertStep != VIR_STORAGE_VOL_ENCRYPT_CONVERT) { if (convertStep != VIR_STORAGE_VOL_ENCRYPT_CONVERT) {
if (!(actualCmdline = virCommandToString(cmd))) if (!(actualCmdline = virCommandToString(cmd, false)))
goto cleanup; goto cleanup;
} else { } else {
char *createCmdline = actualCmdline; char *createCmdline = actualCmdline;
char *cvtCmdline; char *cvtCmdline;
int rc; int rc;
if (!(cvtCmdline = virCommandToString(cmd))) if (!(cvtCmdline = virCommandToString(cmd, false)))
goto cleanup; goto cleanup;
rc = virAsprintf(&actualCmdline, "%s\n%s", rc = virAsprintf(&actualCmdline, "%s\n%s",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册