2010-05-25 11:14:06 +00:00
|
|
|
/*
|
|
|
|
* commandtest.c: Test the libCommand API
|
|
|
|
*
|
2014-02-19 01:06:50 +00:00
|
|
|
* Copyright (C) 2010-2014 Red Hat, Inc.
|
2010-05-25 11:14:06 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-07-21 10:06:23 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
2010-05-25 11:14:06 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/stat.h>
|
2020-01-16 11:38:18 +00:00
|
|
|
#ifndef WIN32
|
|
|
|
# include <sys/wait.h>
|
|
|
|
#endif
|
2010-05-25 11:14:06 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
|
|
|
|
#include "testutils.h"
|
|
|
|
#include "internal.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-12 16:27:01 +00:00
|
|
|
#include "vircommand.h"
|
2011-07-19 18:32:58 +00:00
|
|
|
#include "virfile.h"
|
2011-08-12 21:54:49 +00:00
|
|
|
#include "virpidfile.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2013-01-16 10:58:00 +00:00
|
|
|
#include "virthread.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2014-02-20 03:04:40 +00:00
|
|
|
#include "virprocess.h"
|
2020-02-16 21:59:28 +00:00
|
|
|
#include "virutil.h"
|
2012-05-31 21:50:07 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
2010-05-25 11:14:06 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
|
2011-07-28 15:48:12 +00:00
|
|
|
int
|
|
|
|
main(void)
|
2010-05-25 11:14:06 +00:00
|
|
|
{
|
2011-07-28 15:48:12 +00:00
|
|
|
return EXIT_AM_SKIP;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
2020-01-07 16:16:19 +00:00
|
|
|
/* Some UNIX lack it in headers & it doesn't hurt to redeclare */
|
|
|
|
extern char **environ;
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
static int checkoutput(const char *testname,
|
|
|
|
char *prefix)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
int ret = -1;
|
|
|
|
char *expectname = NULL;
|
|
|
|
char *expectlog = NULL;
|
|
|
|
char *actualname = NULL;
|
|
|
|
char *actuallog = NULL;
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
expectname = g_strdup_printf("%s/commanddata/%s.log", abs_srcdir, testname);
|
|
|
|
actualname = g_strdup_printf("%s/commandhelper.log", abs_builddir);
|
2010-05-25 11:14:06 +00:00
|
|
|
|
|
|
|
if (virFileReadAll(expectname, 1024*64, &expectlog) < 0) {
|
|
|
|
fprintf(stderr, "cannot read %s\n", expectname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virFileReadAll(actualname, 1024*64, &actuallog) < 0) {
|
|
|
|
fprintf(stderr, "cannot read %s\n", actualname);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
if (prefix) {
|
|
|
|
char *tmp = NULL;
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
tmp = g_strdup_printf("%s%s", prefix, expectlog);
|
2014-07-16 14:19:28 +00:00
|
|
|
|
|
|
|
VIR_FREE(expectlog);
|
|
|
|
expectlog = tmp;
|
|
|
|
}
|
|
|
|
|
2010-05-25 11:14:06 +00:00
|
|
|
if (STRNEQ(expectlog, actuallog)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, expectlog, actuallog);
|
2010-05-25 11:14:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2011-05-03 16:37:13 +00:00
|
|
|
if (actualname)
|
|
|
|
unlink(actualname);
|
2010-05-25 11:14:06 +00:00
|
|
|
VIR_FREE(actuallog);
|
|
|
|
VIR_FREE(actualname);
|
|
|
|
VIR_FREE(expectlog);
|
|
|
|
VIR_FREE(expectname);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit all ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open
|
|
|
|
* No slot for return status must log error.
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test0(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
cmd = virCommandNew(abs_builddir "/commandhelper-doesnotexist");
|
|
|
|
if (virCommandRun(cmd, NULL) == 0)
|
|
|
|
goto cleanup;
|
2010-12-06 11:58:56 +00:00
|
|
|
|
2018-05-05 12:04:21 +00:00
|
|
|
if (virGetLastErrorCode() == VIR_ERR_OK)
|
2010-05-25 11:14:06 +00:00
|
|
|
goto cleanup;
|
2010-12-06 11:58:56 +00:00
|
|
|
|
2010-05-25 11:14:06 +00:00
|
|
|
virResetLastError();
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit all ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open
|
|
|
|
* Capturing return status must not log error.
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test1(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd;
|
|
|
|
int ret = -1;
|
|
|
|
int status;
|
|
|
|
|
|
|
|
cmd = virCommandNew(abs_builddir "/commandhelper-doesnotexist");
|
2014-02-20 00:32:19 +00:00
|
|
|
if (virCommandRun(cmd, &status) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
if (status != EXIT_ENOENT)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virCommandRawStatus(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
if (virCommandRun(cmd, &status) < 0)
|
|
|
|
goto cleanup;
|
2014-02-19 01:06:50 +00:00
|
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != EXIT_ENOENT)
|
2010-05-25 11:14:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program (twice), no args, inherit all ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test2(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
if ((ret = checkoutput("test2", NULL)) != 0) {
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
return checkoutput("test2", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit all ENV, keep CWD.
|
|
|
|
* stdin/out/err + two extra FD open
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test3(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
int newfd1 = dup(STDERR_FILENO);
|
|
|
|
int newfd2 = dup(STDERR_FILENO);
|
|
|
|
int newfd3 = dup(STDERR_FILENO);
|
2020-01-17 10:52:46 +00:00
|
|
|
struct stat before, after;
|
2010-12-06 21:48:11 +00:00
|
|
|
int ret = -1;
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2020-01-17 10:52:46 +00:00
|
|
|
if (fstat(newfd3, &before) < 0) {
|
|
|
|
perror("fstat");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2013-07-11 10:31:56 +00:00
|
|
|
virCommandPassFD(cmd, newfd1, 0);
|
|
|
|
virCommandPassFD(cmd, newfd3,
|
|
|
|
VIR_COMMAND_PASS_FD_CLOSE_PARENT);
|
2010-05-25 11:14:06 +00:00
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fcntl(newfd1, F_GETFL) < 0 ||
|
2020-01-17 10:52:46 +00:00
|
|
|
fcntl(newfd2, F_GETFL) < 0) {
|
|
|
|
puts("fds 1/2 were not open");
|
2010-12-06 21:48:11 +00:00
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
2020-01-17 10:52:46 +00:00
|
|
|
/* We expect newfd3 to be closed, but the
|
|
|
|
* fd might have already been reused by
|
|
|
|
* the event loop. So if it is open, we
|
|
|
|
* check if it matches the stat info we
|
|
|
|
* got earlier
|
|
|
|
*/
|
|
|
|
if (fcntl(newfd3, F_GETFL) >= 0 &&
|
|
|
|
fstat(newfd3, &after) >= 0) {
|
|
|
|
|
|
|
|
if (before.st_ino == after.st_ino &&
|
|
|
|
before.st_dev == after.st_dev &&
|
|
|
|
before.st_mode == after.st_mode) {
|
|
|
|
puts("fd 3 should not be open");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
ret = checkoutput("test3", NULL);
|
2010-12-06 21:48:11 +00:00
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandFree(cmd);
|
2014-01-13 15:50:00 +00:00
|
|
|
/* coverity[double_close] */
|
2010-05-25 11:14:06 +00:00
|
|
|
VIR_FORCE_CLOSE(newfd1);
|
|
|
|
VIR_FORCE_CLOSE(newfd2);
|
2010-12-06 21:48:11 +00:00
|
|
|
return ret;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit all ENV, CWD is /
|
|
|
|
* Only stdin/out/err open.
|
|
|
|
* Daemonized
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test4(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
2011-08-12 21:54:49 +00:00
|
|
|
char *pidfile = virPidFileBuildPath(abs_builddir, "commandhelper");
|
2010-12-06 21:48:11 +00:00
|
|
|
pid_t pid;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!pidfile)
|
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
|
|
|
|
virCommandSetPidFile(cmd, pidfile);
|
|
|
|
virCommandDaemonize(cmd);
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
2011-08-12 21:54:49 +00:00
|
|
|
if (virPidFileRead(abs_builddir, "commandhelper", &pid) < 0) {
|
2010-05-25 11:14:06 +00:00
|
|
|
printf("cannot read pidfile\n");
|
2010-12-06 21:48:11 +00:00
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
while (kill(pid, 0) != -1)
|
2019-10-02 17:01:11 +00:00
|
|
|
g_usleep(100*1000);
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
ret = checkoutput("test4", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2011-05-03 16:37:13 +00:00
|
|
|
if (pidfile)
|
|
|
|
unlink(pidfile);
|
2010-05-25 11:14:06 +00:00
|
|
|
VIR_FREE(pidfile);
|
2010-12-06 21:48:11 +00:00
|
|
|
return ret;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit filtered ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test5(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
|
|
|
|
virCommandAddEnvPassCommon(cmd);
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
return checkoutput("test5", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit filtered ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test6(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
|
2019-08-01 12:52:00 +00:00
|
|
|
virCommandAddEnvPass(cmd, "DISPLAY");
|
|
|
|
virCommandAddEnvPass(cmd, "DOESNOTEXIST");
|
2010-05-25 11:14:06 +00:00
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
return checkoutput("test6", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit filtered ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test7(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
|
|
|
|
virCommandAddEnvPassCommon(cmd);
|
2019-08-01 12:52:00 +00:00
|
|
|
virCommandAddEnvPass(cmd, "DISPLAY");
|
|
|
|
virCommandAddEnvPass(cmd, "DOESNOTEXIST");
|
2010-05-25 11:14:06 +00:00
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
return checkoutput("test7", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit filtered ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test8(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
|
2012-09-24 23:04:46 +00:00
|
|
|
virCommandAddEnvString(cmd, "USER=bogus");
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandAddEnvString(cmd, "LANG=C");
|
2012-09-24 23:04:46 +00:00
|
|
|
virCommandAddEnvPair(cmd, "USER", "also bogus");
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandAddEnvPair(cmd, "USER", "test");
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
return checkoutput("test8", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, some args, inherit all ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test9(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
const char* const args[] = { "arg1", "arg2", NULL };
|
2011-11-10 00:19:33 +00:00
|
|
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
2010-05-25 11:14:06 +00:00
|
|
|
|
|
|
|
virCommandAddArg(cmd, "-version");
|
|
|
|
virCommandAddArgPair(cmd, "-log", "bar.log");
|
|
|
|
virCommandAddArgSet(cmd, args);
|
2011-11-10 00:19:33 +00:00
|
|
|
virCommandAddArgBuffer(cmd, &buf);
|
|
|
|
virBufferAddLit(&buf, "arg4");
|
|
|
|
virCommandAddArgBuffer(cmd, &buf);
|
|
|
|
virCommandAddArgList(cmd, "arg5", "arg6", NULL);
|
|
|
|
|
|
|
|
if (virBufferUse(&buf)) {
|
|
|
|
printf("Buffer not transferred\n");
|
|
|
|
virBufferFreeAndReset(&buf);
|
|
|
|
virCommandFree(cmd);
|
|
|
|
return -1;
|
|
|
|
}
|
2010-05-25 11:14:06 +00:00
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
return checkoutput("test9", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, some args, inherit all ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test10(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
const char *const args[] = {
|
|
|
|
"-version", "-log=bar.log", NULL,
|
|
|
|
};
|
|
|
|
|
|
|
|
virCommandAddArgSet(cmd, args);
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
return checkoutput("test10", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, some args, inherit all ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test11(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
const char *args[] = {
|
|
|
|
abs_builddir "/commandhelper",
|
|
|
|
"-version", "-log=bar.log", NULL,
|
|
|
|
};
|
|
|
|
virCommandPtr cmd = virCommandNewArgs(args);
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
return checkoutput("test11", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit all ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open. Set stdin data
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test12(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
|
|
|
|
virCommandSetInputBuffer(cmd, "Hello World\n");
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
return checkoutput("test12", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit all ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open. Set stdin data
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test13(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
char *outactual = NULL;
|
|
|
|
const char *outexpect = "BEGIN STDOUT\n"
|
|
|
|
"Hello World\n"
|
|
|
|
"END STDOUT\n";
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
virCommandSetInputBuffer(cmd, "Hello World\n");
|
|
|
|
virCommandSetOutputBuffer(cmd, &outactual);
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
2010-12-06 21:48:11 +00:00
|
|
|
if (!outactual)
|
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
|
|
|
|
virCommandFree(cmd);
|
2010-12-06 21:48:11 +00:00
|
|
|
cmd = NULL;
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2015-10-20 16:15:12 +00:00
|
|
|
if (STRNEQ(outactual, outexpect)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, outexpect, outactual);
|
2010-05-25 11:14:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
ret = checkoutput("test13", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
VIR_FREE(outactual);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit all ENV, keep CWD.
|
|
|
|
* Only stdin/out/err open. Set stdin data
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test14(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
char *outactual = NULL;
|
|
|
|
const char *outexpect = "BEGIN STDOUT\n"
|
|
|
|
"Hello World\n"
|
|
|
|
"END STDOUT\n";
|
|
|
|
char *erractual = NULL;
|
|
|
|
const char *errexpect = "BEGIN STDERR\n"
|
|
|
|
"Hello World\n"
|
|
|
|
"END STDERR\n";
|
2012-01-27 22:40:20 +00:00
|
|
|
|
|
|
|
char *jointactual = NULL;
|
|
|
|
const char *jointexpect = "BEGIN STDOUT\n"
|
|
|
|
"BEGIN STDERR\n"
|
|
|
|
"Hello World\n"
|
|
|
|
"Hello World\n"
|
|
|
|
"END STDOUT\n"
|
|
|
|
"END STDERR\n";
|
2010-05-25 11:14:06 +00:00
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
virCommandSetInputBuffer(cmd, "Hello World\n");
|
|
|
|
virCommandSetOutputBuffer(cmd, &outactual);
|
|
|
|
virCommandSetErrorBuffer(cmd, &erractual);
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
2010-12-06 21:48:11 +00:00
|
|
|
if (!outactual || !erractual)
|
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
|
|
|
|
virCommandFree(cmd);
|
2012-01-27 22:40:20 +00:00
|
|
|
|
|
|
|
cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
virCommandSetInputBuffer(cmd, "Hello World\n");
|
|
|
|
virCommandSetOutputBuffer(cmd, &jointactual);
|
|
|
|
virCommandSetErrorBuffer(cmd, &jointactual);
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2012-01-27 22:40:20 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (!jointactual)
|
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2015-10-20 16:15:12 +00:00
|
|
|
if (STRNEQ(outactual, outexpect)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, outexpect, outactual);
|
2010-05-25 11:14:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2015-10-20 16:15:12 +00:00
|
|
|
if (STRNEQ(erractual, errexpect)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, errexpect, erractual);
|
2010-05-25 11:14:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2015-10-20 16:15:12 +00:00
|
|
|
if (STRNEQ(jointactual, jointexpect)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, jointexpect, jointactual);
|
2012-01-27 22:40:20 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
ret = checkoutput("test14", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
VIR_FREE(outactual);
|
|
|
|
VIR_FREE(erractual);
|
2012-01-27 22:40:20 +00:00
|
|
|
VIR_FREE(jointactual);
|
2010-05-25 11:14:06 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Run program, no args, inherit all ENV, change CWD.
|
|
|
|
* Only stdin/out/err open
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test15(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
2010-12-06 12:03:26 +00:00
|
|
|
char *cwd = NULL;
|
|
|
|
int ret = -1;
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
cwd = g_strdup_printf("%s/commanddata", abs_srcdir);
|
2010-12-06 12:03:26 +00:00
|
|
|
virCommandSetWorkingDirectory(cmd, cwd);
|
2014-09-03 15:13:21 +00:00
|
|
|
virCommandSetUmask(cmd, 002);
|
2010-05-25 11:14:06 +00:00
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-06 12:03:26 +00:00
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
ret = checkoutput("test15", NULL);
|
2010-12-06 12:03:26 +00:00
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-12-06 12:03:26 +00:00
|
|
|
VIR_FREE(cwd);
|
2010-05-25 11:14:06 +00:00
|
|
|
virCommandFree(cmd);
|
|
|
|
|
2010-12-06 12:03:26 +00:00
|
|
|
return ret;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Don't run program; rather, log what would be run.
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test16(const void *unused G_GNUC_UNUSED)
|
2010-12-06 10:51:41 +00:00
|
|
|
{
|
2011-07-28 15:51:26 +00:00
|
|
|
virCommandPtr cmd = virCommandNew("true");
|
2010-05-25 11:14:06 +00:00
|
|
|
char *outactual = NULL;
|
2012-08-28 18:11:45 +00:00
|
|
|
const char *outexpect = "A=B C='D E' true F 'G H'";
|
2010-05-25 11:14:06 +00:00
|
|
|
int ret = -1;
|
|
|
|
int fd = -1;
|
|
|
|
|
|
|
|
virCommandAddEnvPair(cmd, "A", "B");
|
2012-08-28 18:11:45 +00:00
|
|
|
virCommandAddEnvPair(cmd, "C", "D E");
|
|
|
|
virCommandAddArg(cmd, "F");
|
|
|
|
virCommandAddArg(cmd, "G H");
|
2010-05-25 11:14:06 +00:00
|
|
|
|
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: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 12:07:08 +00:00
|
|
|
if ((outactual = virCommandToString(cmd, false)) == NULL) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot convert to string: %s\n", virGetLastErrorMessage());
|
2010-12-06 21:48:11 +00:00
|
|
|
goto cleanup;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
if ((fd = open(abs_builddir "/commandhelper.log",
|
|
|
|
O_CREAT | O_TRUNC | O_WRONLY, 0600)) < 0) {
|
2019-10-02 15:30:36 +00:00
|
|
|
printf("Cannot open log file: %s\n", g_strerror(errno));
|
2010-05-25 11:14:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virCommandWriteArgLog(cmd, fd);
|
|
|
|
if (VIR_CLOSE(fd) < 0) {
|
2019-10-02 15:30:36 +00:00
|
|
|
printf("Cannot close log file: %s\n", g_strerror(errno));
|
2010-05-25 11:14:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2015-10-20 16:15:12 +00:00
|
|
|
if (STRNEQ(outactual, outexpect)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, outexpect, outactual);
|
2010-05-25 11:14:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
2010-12-06 21:48:11 +00:00
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
ret = checkoutput("test16", NULL);
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-12-06 21:48:11 +00:00
|
|
|
virCommandFree(cmd);
|
2010-05-25 11:14:06 +00:00
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
VIR_FREE(outactual);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-12-03 21:14:16 +00:00
|
|
|
/*
|
|
|
|
* Test string handling when no output is present.
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test17(const void *unused G_GNUC_UNUSED)
|
2010-12-03 21:14:16 +00:00
|
|
|
{
|
2011-07-28 15:51:26 +00:00
|
|
|
virCommandPtr cmd = virCommandNew("true");
|
2010-12-03 21:14:16 +00:00
|
|
|
int ret = -1;
|
|
|
|
char *outbuf;
|
2013-01-22 14:15:42 +00:00
|
|
|
char *errbuf = NULL;
|
2010-12-03 21:14:16 +00:00
|
|
|
|
|
|
|
virCommandSetOutputBuffer(cmd, &outbuf);
|
|
|
|
if (outbuf != NULL) {
|
|
|
|
puts("buffer not sanitized at registration");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-03 21:14:16 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-03-25 17:03:19 +00:00
|
|
|
sa_assert(outbuf);
|
2013-01-14 15:35:45 +00:00
|
|
|
if (*outbuf) {
|
2010-12-03 21:14:16 +00:00
|
|
|
puts("output buffer is not an allocated empty string");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
VIR_FREE(outbuf);
|
2019-10-20 11:49:46 +00:00
|
|
|
outbuf = g_strdup("should not be leaked");
|
2010-12-03 21:14:16 +00:00
|
|
|
|
|
|
|
virCommandSetErrorBuffer(cmd, &errbuf);
|
|
|
|
if (errbuf != NULL) {
|
|
|
|
puts("buffer not sanitized at registration");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-03 21:14:16 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2013-01-14 15:35:45 +00:00
|
|
|
if (*outbuf || *errbuf) {
|
2010-12-03 21:14:16 +00:00
|
|
|
puts("output buffers are not allocated empty strings");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-12-03 21:14:16 +00:00
|
|
|
virCommandFree(cmd);
|
|
|
|
VIR_FREE(outbuf);
|
|
|
|
VIR_FREE(errbuf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2010-12-21 18:49:49 +00:00
|
|
|
/*
|
|
|
|
* Run long-running daemon, to ensure no hang.
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test18(const void *unused G_GNUC_UNUSED)
|
2010-12-21 18:49:49 +00:00
|
|
|
{
|
|
|
|
virCommandPtr cmd = virCommandNewArgList("sleep", "100", NULL);
|
2011-08-12 21:54:49 +00:00
|
|
|
char *pidfile = virPidFileBuildPath(abs_builddir, "commandhelper");
|
2010-12-21 18:49:49 +00:00
|
|
|
pid_t pid;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (!pidfile)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
virCommandSetPidFile(cmd, pidfile);
|
|
|
|
virCommandDaemonize(cmd);
|
|
|
|
|
|
|
|
alarm(5);
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2010-12-21 18:49:49 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
alarm(0);
|
|
|
|
|
2011-08-12 21:54:49 +00:00
|
|
|
if (virPidFileRead(abs_builddir, "commandhelper", &pid) < 0) {
|
2010-12-21 18:49:49 +00:00
|
|
|
printf("cannot read pidfile\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
2011-03-22 22:22:37 +00:00
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
cmd = NULL;
|
|
|
|
if (kill(pid, 0) != 0) {
|
|
|
|
printf("daemon should still be running\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2010-12-21 18:49:49 +00:00
|
|
|
while (kill(pid, SIGINT) != -1)
|
2019-10-02 17:01:11 +00:00
|
|
|
g_usleep(100*1000);
|
2010-12-21 18:49:49 +00:00
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2010-12-21 18:49:49 +00:00
|
|
|
virCommandFree(cmd);
|
2011-05-03 16:37:13 +00:00
|
|
|
if (pidfile)
|
|
|
|
unlink(pidfile);
|
2010-12-21 18:49:49 +00:00
|
|
|
VIR_FREE(pidfile);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-03-22 22:22:37 +00:00
|
|
|
/*
|
|
|
|
* Asynchronously run long-running daemon, to ensure no hang.
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test19(const void *unused G_GNUC_UNUSED)
|
2011-03-22 22:22:37 +00:00
|
|
|
{
|
|
|
|
virCommandPtr cmd = virCommandNewArgList("sleep", "100", NULL);
|
|
|
|
pid_t pid;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
alarm(5);
|
|
|
|
if (virCommandRunAsync(cmd, &pid) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2011-03-22 22:22:37 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (kill(pid, 0) != 0) {
|
|
|
|
printf("Child should still be running");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandAbort(cmd);
|
|
|
|
|
|
|
|
if (kill(pid, 0) == 0) {
|
|
|
|
printf("Child should be aborted");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
alarm(0);
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2011-03-22 22:22:37 +00:00
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
2010-12-21 18:49:49 +00:00
|
|
|
|
2012-05-31 21:50:07 +00:00
|
|
|
/*
|
|
|
|
* Run program, no args, inherit all ENV, keep CWD.
|
|
|
|
* Ignore huge stdin data, to provoke SIGPIPE or EPIPE in parent.
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test20(const void *unused G_GNUC_UNUSED)
|
2012-05-31 21:50:07 +00:00
|
|
|
{
|
|
|
|
virCommandPtr cmd = virCommandNewArgList(abs_builddir "/commandhelper",
|
|
|
|
"--close-stdin", NULL);
|
|
|
|
char *buf;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
struct sigaction sig_action;
|
|
|
|
|
|
|
|
sig_action.sa_handler = SIG_IGN;
|
|
|
|
sig_action.sa_flags = 0;
|
|
|
|
sigemptyset(&sig_action.sa_mask);
|
|
|
|
|
|
|
|
sigaction(SIGPIPE, &sig_action, NULL);
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
buf = g_strdup_printf("1\n%100000d\n", 2);
|
2012-05-31 21:50:07 +00:00
|
|
|
virCommandSetInputBuffer(cmd, buf);
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2012-05-31 21:50:07 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
ret = checkoutput("test20", NULL);
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2012-05-31 21:50:07 +00:00
|
|
|
virCommandFree(cmd);
|
|
|
|
VIR_FREE(buf);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-05-11 15:51:30 +00:00
|
|
|
static const char *const newenv[] = {
|
|
|
|
"PATH=/usr/bin:/bin",
|
|
|
|
"HOSTNAME=test",
|
|
|
|
"LANG=C",
|
|
|
|
"HOME=/home/test",
|
|
|
|
"USER=test",
|
2017-11-17 13:17:38 +00:00
|
|
|
"LOGNAME=test",
|
2011-05-11 15:51:30 +00:00
|
|
|
"TMPDIR=/tmp",
|
|
|
|
"DISPLAY=:0.0",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test21(const void *unused G_GNUC_UNUSED)
|
2013-01-16 17:55:06 +00:00
|
|
|
{
|
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
int ret = -1;
|
|
|
|
const char *wrbuf = "Hello world\n";
|
|
|
|
char *outbuf = NULL, *errbuf = NULL;
|
2014-01-20 11:27:29 +00:00
|
|
|
const char *outbufExpected = "BEGIN STDOUT\n"
|
2013-01-16 17:55:06 +00:00
|
|
|
"Hello world\n"
|
|
|
|
"END STDOUT\n";
|
2014-01-20 11:27:29 +00:00
|
|
|
const char *errbufExpected = "BEGIN STDERR\n"
|
2013-01-16 17:55:06 +00:00
|
|
|
"Hello world\n"
|
|
|
|
"END STDERR\n";
|
|
|
|
|
|
|
|
virCommandSetInputBuffer(cmd, wrbuf);
|
|
|
|
virCommandSetOutputBuffer(cmd, &outbuf);
|
|
|
|
virCommandSetErrorBuffer(cmd, &errbuf);
|
|
|
|
virCommandDoAsyncIO(cmd);
|
|
|
|
|
|
|
|
if (virCommandRunAsync(cmd, NULL) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2013-01-16 17:55:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virCommandWait(cmd, NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (virTestGetVerbose())
|
|
|
|
printf("STDOUT:%s\nSTDERR:%s\n", NULLSTR(outbuf), NULLSTR(errbuf));
|
|
|
|
|
2018-09-27 23:54:05 +00:00
|
|
|
if (STRNEQ_NULLABLE(outbuf, outbufExpected)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, outbufExpected, outbuf);
|
2013-01-16 17:55:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2018-09-27 23:54:05 +00:00
|
|
|
if (STRNEQ_NULLABLE(errbuf, errbufExpected)) {
|
2016-05-26 15:01:51 +00:00
|
|
|
virTestDifference(stderr, errbufExpected, errbuf);
|
2013-01-16 17:55:06 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2014-07-16 14:19:28 +00:00
|
|
|
ret = checkoutput("test21", NULL);
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2013-01-16 17:55:06 +00:00
|
|
|
VIR_FREE(outbuf);
|
|
|
|
VIR_FREE(errbuf);
|
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-02-19 01:06:50 +00:00
|
|
|
static int
|
2019-10-14 12:45:03 +00:00
|
|
|
test22(const void *unused G_GNUC_UNUSED)
|
2014-02-19 01:06:50 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
virCommandPtr cmd;
|
|
|
|
int status = -1;
|
|
|
|
|
|
|
|
cmd = virCommandNewArgList("/bin/sh", "-c", "exit 3", NULL);
|
|
|
|
|
2014-02-20 00:32:19 +00:00
|
|
|
if (virCommandRun(cmd, &status) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2014-02-20 00:32:19 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (status != 3) {
|
|
|
|
printf("Unexpected status %d\n", status);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandRawStatus(cmd);
|
2014-02-19 01:06:50 +00:00
|
|
|
if (virCommandRun(cmd, &status) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2014-02-19 01:06:50 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 3) {
|
|
|
|
printf("Unexpected status %d\n", status);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandFree(cmd);
|
|
|
|
cmd = virCommandNewArgList("/bin/sh", "-c", "kill -9 $$", NULL);
|
|
|
|
|
2014-02-20 00:32:19 +00:00
|
|
|
if (virCommandRun(cmd, &status) == 0) {
|
|
|
|
printf("Death by signal not detected, status %d\n", status);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
virCommandRawStatus(cmd);
|
2014-02-19 01:06:50 +00:00
|
|
|
if (virCommandRun(cmd, &status) < 0) {
|
2016-05-19 19:10:18 +00:00
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
2014-02-19 01:06:50 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL) {
|
|
|
|
printf("Unexpected status %d\n", status);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
2014-03-25 06:53:44 +00:00
|
|
|
cleanup:
|
2014-02-19 01:06:50 +00:00
|
|
|
virCommandFree(cmd);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-02-20 03:04:40 +00:00
|
|
|
|
|
|
|
static int
|
2019-10-14 12:45:03 +00:00
|
|
|
test23(const void *unused G_GNUC_UNUSED)
|
2014-02-20 03:04:40 +00:00
|
|
|
{
|
|
|
|
/* Not strictly a virCommand test, but this is the easiest place
|
|
|
|
* to test this lower-level interface. It takes a double fork to
|
|
|
|
* test virProcessExitWithStatus. */
|
|
|
|
int status = -1;
|
|
|
|
pid_t pid;
|
|
|
|
|
virFork: simplify semantics
The old semantics of virFork() violates the priciple of good
usability: it requires the caller to check the pid argument
after use, *even when virFork returned -1*, in order to properly
abort a child process that failed setup done immediately after
fork() - that is, the caller must call _exit() in the child.
While uses in virfile.c did this correctly, uses in 'virsh
lxc-enter-namespace' and 'virt-login-shell' would happily return
from the calling function in both the child and the parent,
leading to very confusing results. [Thankfully, I found the
problem by inspection, and can't actually trigger the double
return on error without an LD_PRELOAD library.]
It is much better if the semantics of virFork are impossible
to abuse. Looking at virFork(), the parent could only ever
return -1 with a non-negative pid if it misused pthread_sigmask,
but this never happens. Up until this patch series, the child
could return -1 with non-negative pid if it fails to set up
signals correctly, but we recently fixed that to make the child
call _exit() at that point instead of forcing the caller to do
it. Thus, the return value and contents of the pid argument are
now redundant (a -1 return now happens only for failure to fork,
a child 0 return only happens for a successful 0 pid, and a
parent 0 return only happens for a successful non-zero pid),
so we might as well return the pid directly rather than an
integer of whether it succeeded or failed; this is also good
from the interface design perspective as users are already
familiar with fork() semantics.
One last change in this patch: before returning the pid directly,
I found cases where using virProcessWait unconditionally on a
cleanup path of a virFork's -1 pid return would be nicer if there
were a way to avoid it overwriting an earlier message. While
such paths are a bit harder to come by with my change to a direct
pid return, I decided to keep the virProcessWait change in this
patch.
* src/util/vircommand.h (virFork): Change signature.
* src/util/vircommand.c (virFork): Guarantee that child will only
return on success, to simplify callers. Return pid rather than
status, now that the situations are always the same.
(virExec): Adjust caller, also avoid open-coding process death.
* src/util/virprocess.c (virProcessWait): Tweak semantics when pid
is -1.
(virProcessRunInMountNamespace): Adjust caller.
* src/util/virfile.c (virFileAccessibleAs, virFileOpenForked)
(virDirCreate): Likewise.
* tools/virt-login-shell.c (main): Likewise.
* tools/virsh-domain.c (cmdLxcEnterNamespace): Likewise.
* tests/commandtest.c (test23): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-12-22 00:54:33 +00:00
|
|
|
if ((pid = virFork()) < 0)
|
2019-11-12 20:46:29 +00:00
|
|
|
return -1;
|
2014-02-20 03:04:40 +00:00
|
|
|
if (pid == 0) {
|
virFork: simplify semantics
The old semantics of virFork() violates the priciple of good
usability: it requires the caller to check the pid argument
after use, *even when virFork returned -1*, in order to properly
abort a child process that failed setup done immediately after
fork() - that is, the caller must call _exit() in the child.
While uses in virfile.c did this correctly, uses in 'virsh
lxc-enter-namespace' and 'virt-login-shell' would happily return
from the calling function in both the child and the parent,
leading to very confusing results. [Thankfully, I found the
problem by inspection, and can't actually trigger the double
return on error without an LD_PRELOAD library.]
It is much better if the semantics of virFork are impossible
to abuse. Looking at virFork(), the parent could only ever
return -1 with a non-negative pid if it misused pthread_sigmask,
but this never happens. Up until this patch series, the child
could return -1 with non-negative pid if it fails to set up
signals correctly, but we recently fixed that to make the child
call _exit() at that point instead of forcing the caller to do
it. Thus, the return value and contents of the pid argument are
now redundant (a -1 return now happens only for failure to fork,
a child 0 return only happens for a successful 0 pid, and a
parent 0 return only happens for a successful non-zero pid),
so we might as well return the pid directly rather than an
integer of whether it succeeded or failed; this is also good
from the interface design perspective as users are already
familiar with fork() semantics.
One last change in this patch: before returning the pid directly,
I found cases where using virProcessWait unconditionally on a
cleanup path of a virFork's -1 pid return would be nicer if there
were a way to avoid it overwriting an earlier message. While
such paths are a bit harder to come by with my change to a direct
pid return, I decided to keep the virProcessWait change in this
patch.
* src/util/vircommand.h (virFork): Change signature.
* src/util/vircommand.c (virFork): Guarantee that child will only
return on success, to simplify callers. Return pid rather than
status, now that the situations are always the same.
(virExec): Adjust caller, also avoid open-coding process death.
* src/util/virprocess.c (virProcessWait): Tweak semantics when pid
is -1.
(virProcessRunInMountNamespace): Adjust caller.
* src/util/virfile.c (virFileAccessibleAs, virFileOpenForked)
(virDirCreate): Likewise.
* tools/virt-login-shell.c (main): Likewise.
* tools/virsh-domain.c (cmdLxcEnterNamespace): Likewise.
* tests/commandtest.c (test23): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-12-22 00:54:33 +00:00
|
|
|
if ((pid = virFork()) < 0)
|
2014-02-20 03:04:40 +00:00
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
if (pid == 0)
|
|
|
|
_exit(42);
|
2014-02-20 03:23:44 +00:00
|
|
|
if (virProcessWait(pid, &status, true) < 0)
|
2014-02-20 03:04:40 +00:00
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
virProcessExitWithStatus(status);
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2014-02-20 03:23:44 +00:00
|
|
|
if (virProcessWait(pid, &status, true) < 0)
|
2019-11-12 20:46:29 +00:00
|
|
|
return -1;
|
2014-02-20 03:04:40 +00:00
|
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 42) {
|
|
|
|
printf("Unexpected status %d\n", status);
|
2019-11-12 20:46:29 +00:00
|
|
|
return -1;
|
2014-02-20 03:04:40 +00:00
|
|
|
}
|
|
|
|
|
virFork: simplify semantics
The old semantics of virFork() violates the priciple of good
usability: it requires the caller to check the pid argument
after use, *even when virFork returned -1*, in order to properly
abort a child process that failed setup done immediately after
fork() - that is, the caller must call _exit() in the child.
While uses in virfile.c did this correctly, uses in 'virsh
lxc-enter-namespace' and 'virt-login-shell' would happily return
from the calling function in both the child and the parent,
leading to very confusing results. [Thankfully, I found the
problem by inspection, and can't actually trigger the double
return on error without an LD_PRELOAD library.]
It is much better if the semantics of virFork are impossible
to abuse. Looking at virFork(), the parent could only ever
return -1 with a non-negative pid if it misused pthread_sigmask,
but this never happens. Up until this patch series, the child
could return -1 with non-negative pid if it fails to set up
signals correctly, but we recently fixed that to make the child
call _exit() at that point instead of forcing the caller to do
it. Thus, the return value and contents of the pid argument are
now redundant (a -1 return now happens only for failure to fork,
a child 0 return only happens for a successful 0 pid, and a
parent 0 return only happens for a successful non-zero pid),
so we might as well return the pid directly rather than an
integer of whether it succeeded or failed; this is also good
from the interface design perspective as users are already
familiar with fork() semantics.
One last change in this patch: before returning the pid directly,
I found cases where using virProcessWait unconditionally on a
cleanup path of a virFork's -1 pid return would be nicer if there
were a way to avoid it overwriting an earlier message. While
such paths are a bit harder to come by with my change to a direct
pid return, I decided to keep the virProcessWait change in this
patch.
* src/util/vircommand.h (virFork): Change signature.
* src/util/vircommand.c (virFork): Guarantee that child will only
return on success, to simplify callers. Return pid rather than
status, now that the situations are always the same.
(virExec): Adjust caller, also avoid open-coding process death.
* src/util/virprocess.c (virProcessWait): Tweak semantics when pid
is -1.
(virProcessRunInMountNamespace): Adjust caller.
* src/util/virfile.c (virFileAccessibleAs, virFileOpenForked)
(virDirCreate): Likewise.
* tools/virt-login-shell.c (main): Likewise.
* tools/virsh-domain.c (cmdLxcEnterNamespace): Likewise.
* tests/commandtest.c (test23): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-12-22 00:54:33 +00:00
|
|
|
if ((pid = virFork()) < 0)
|
2019-11-12 20:46:29 +00:00
|
|
|
return -1;
|
2014-02-20 03:04:40 +00:00
|
|
|
if (pid == 0) {
|
virFork: simplify semantics
The old semantics of virFork() violates the priciple of good
usability: it requires the caller to check the pid argument
after use, *even when virFork returned -1*, in order to properly
abort a child process that failed setup done immediately after
fork() - that is, the caller must call _exit() in the child.
While uses in virfile.c did this correctly, uses in 'virsh
lxc-enter-namespace' and 'virt-login-shell' would happily return
from the calling function in both the child and the parent,
leading to very confusing results. [Thankfully, I found the
problem by inspection, and can't actually trigger the double
return on error without an LD_PRELOAD library.]
It is much better if the semantics of virFork are impossible
to abuse. Looking at virFork(), the parent could only ever
return -1 with a non-negative pid if it misused pthread_sigmask,
but this never happens. Up until this patch series, the child
could return -1 with non-negative pid if it fails to set up
signals correctly, but we recently fixed that to make the child
call _exit() at that point instead of forcing the caller to do
it. Thus, the return value and contents of the pid argument are
now redundant (a -1 return now happens only for failure to fork,
a child 0 return only happens for a successful 0 pid, and a
parent 0 return only happens for a successful non-zero pid),
so we might as well return the pid directly rather than an
integer of whether it succeeded or failed; this is also good
from the interface design perspective as users are already
familiar with fork() semantics.
One last change in this patch: before returning the pid directly,
I found cases where using virProcessWait unconditionally on a
cleanup path of a virFork's -1 pid return would be nicer if there
were a way to avoid it overwriting an earlier message. While
such paths are a bit harder to come by with my change to a direct
pid return, I decided to keep the virProcessWait change in this
patch.
* src/util/vircommand.h (virFork): Change signature.
* src/util/vircommand.c (virFork): Guarantee that child will only
return on success, to simplify callers. Return pid rather than
status, now that the situations are always the same.
(virExec): Adjust caller, also avoid open-coding process death.
* src/util/virprocess.c (virProcessWait): Tweak semantics when pid
is -1.
(virProcessRunInMountNamespace): Adjust caller.
* src/util/virfile.c (virFileAccessibleAs, virFileOpenForked)
(virDirCreate): Likewise.
* tools/virt-login-shell.c (main): Likewise.
* tools/virsh-domain.c (cmdLxcEnterNamespace): Likewise.
* tests/commandtest.c (test23): Likewise.
Signed-off-by: Eric Blake <eblake@redhat.com>
2013-12-22 00:54:33 +00:00
|
|
|
if ((pid = virFork()) < 0)
|
2014-02-20 03:04:40 +00:00
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
if (pid == 0) {
|
|
|
|
raise(SIGKILL);
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
2014-02-20 03:23:44 +00:00
|
|
|
if (virProcessWait(pid, &status, true) < 0)
|
2014-02-20 03:04:40 +00:00
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
virProcessExitWithStatus(status);
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
2014-02-20 03:23:44 +00:00
|
|
|
if (virProcessWait(pid, &status, true) < 0)
|
2019-11-12 20:46:29 +00:00
|
|
|
return -1;
|
2014-02-20 03:04:40 +00:00
|
|
|
if (!WIFSIGNALED(status) || WTERMSIG(status) != SIGKILL) {
|
|
|
|
printf("Unexpected status %d\n", status);
|
2019-11-12 20:46:29 +00:00
|
|
|
return -1;
|
2014-02-20 03:04:40 +00:00
|
|
|
}
|
|
|
|
|
2019-11-12 20:46:29 +00:00
|
|
|
return 0;
|
2014-02-20 03:04:40 +00:00
|
|
|
}
|
|
|
|
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test25(const void *unused G_GNUC_UNUSED)
|
2016-07-11 14:03:34 +00:00
|
|
|
{
|
|
|
|
int ret = -1;
|
|
|
|
int pipeFD[2] = { -1, -1};
|
2016-07-13 16:53:22 +00:00
|
|
|
int rv = 0;
|
2016-07-11 14:03:34 +00:00
|
|
|
ssize_t tries = 100;
|
|
|
|
pid_t pid;
|
2017-10-09 19:14:56 +00:00
|
|
|
gid_t *groups = NULL;
|
|
|
|
int ngroups;
|
|
|
|
virCommandPtr cmd = virCommandNew("some/nonexistent/binary");
|
2016-07-11 14:03:34 +00:00
|
|
|
|
2020-01-24 15:22:12 +00:00
|
|
|
if (virPipeQuiet(pipeFD) < 0) {
|
2016-07-11 14:03:34 +00:00
|
|
|
fprintf(stderr, "Unable to create pipe\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virSetNonBlock(pipeFD[0]) < 0) {
|
|
|
|
fprintf(stderr, "Unable to make read end of pipe nonblocking\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2017-10-09 19:14:56 +00:00
|
|
|
if ((ngroups = virGetGroupList(virCommandGetUID(cmd), virCommandGetGID(cmd),
|
|
|
|
&groups)) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2016-07-11 14:03:34 +00:00
|
|
|
/* Now, fork and try to exec a nonexistent binary. */
|
|
|
|
pid = virFork();
|
|
|
|
if (pid < 0) {
|
|
|
|
fprintf(stderr, "Unable to spawn child\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pid == 0) {
|
|
|
|
/* Child */
|
2017-10-09 19:14:56 +00:00
|
|
|
rv = virCommandExec(cmd, groups, ngroups);
|
2017-04-09 11:28:07 +00:00
|
|
|
|
2016-07-11 14:03:34 +00:00
|
|
|
if (safewrite(pipeFD[1], &rv, sizeof(rv)) < 0)
|
|
|
|
fprintf(stderr, "Unable to write to pipe\n");
|
|
|
|
_exit(EXIT_FAILURE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Parent */
|
|
|
|
while (--tries) {
|
|
|
|
if (saferead(pipeFD[0], &rv, sizeof(rv)) < 0) {
|
|
|
|
if (errno != EWOULDBLOCK) {
|
|
|
|
fprintf(stderr, "Unable to read from pipe\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2019-10-02 17:01:11 +00:00
|
|
|
g_usleep(10 * 1000);
|
2016-07-11 14:03:34 +00:00
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!tries) {
|
|
|
|
fprintf(stderr, "Child hasn't returned anything\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rv >= 0) {
|
|
|
|
fprintf(stderr, "Child should have returned an error\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
cleanup:
|
|
|
|
VIR_FORCE_CLOSE(pipeFD[0]);
|
|
|
|
VIR_FORCE_CLOSE(pipeFD[1]);
|
2017-10-09 19:14:56 +00:00
|
|
|
VIR_FREE(groups);
|
|
|
|
virCommandFree(cmd);
|
2016-07-11 14:03:34 +00:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 12:07:08 +00:00
|
|
|
/*
|
|
|
|
* Don't run program; rather, log what would be run.
|
|
|
|
*/
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test26(const void *unused G_GNUC_UNUSED)
|
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: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 12:07:08 +00:00
|
|
|
{
|
|
|
|
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) {
|
2019-10-02 15:30:36 +00:00
|
|
|
printf("Cannot open log file: %s\n", g_strerror(errno));
|
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: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 12:07:08 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
virCommandWriteArgLog(cmd, fd);
|
|
|
|
if (VIR_CLOSE(fd) < 0) {
|
2019-10-02 15:30:36 +00:00
|
|
|
printf("Cannot close log file: %s\n", g_strerror(errno));
|
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: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 12:07:08 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-10-14 12:45:03 +00:00
|
|
|
static int test27(const void *unused G_GNUC_UNUSED)
|
2019-07-25 18:22:10 +00:00
|
|
|
{
|
|
|
|
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
|
|
|
int pipe1[2];
|
|
|
|
int pipe2[2];
|
|
|
|
int ret = -1;
|
|
|
|
size_t buflen = 1024 * 128;
|
|
|
|
char *buffer0 = NULL;
|
|
|
|
char *buffer1 = NULL;
|
|
|
|
char *buffer2 = NULL;
|
|
|
|
char *outactual = NULL;
|
|
|
|
char *erractual = NULL;
|
|
|
|
char *outexpect = NULL;
|
|
|
|
# define TEST27_OUTEXPECT_TEMP "BEGIN STDOUT\n" \
|
|
|
|
"%s%s%s" \
|
|
|
|
"END STDOUT\n"
|
|
|
|
char *errexpect = NULL;
|
|
|
|
# define TEST27_ERREXPECT_TEMP "BEGIN STDERR\n" \
|
|
|
|
"%s%s%s" \
|
|
|
|
"END STDERR\n"
|
|
|
|
|
|
|
|
if (VIR_ALLOC_N(buffer0, buflen) < 0 ||
|
|
|
|
VIR_ALLOC_N(buffer1, buflen) < 0 ||
|
|
|
|
VIR_ALLOC_N(buffer2, buflen) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
memset(buffer0, 'H', buflen - 2);
|
|
|
|
buffer0[buflen - 2] = '\n';
|
|
|
|
buffer0[buflen - 1] = 0;
|
|
|
|
|
|
|
|
memset(buffer1, '1', buflen - 2);
|
|
|
|
buffer1[buflen - 2] = '\n';
|
|
|
|
buffer1[buflen - 1] = 0;
|
|
|
|
|
|
|
|
memset(buffer2, '2', buflen - 2);
|
|
|
|
buffer2[buflen - 2] = '\n';
|
|
|
|
buffer2[buflen - 1] = 0;
|
|
|
|
|
2019-10-22 13:26:14 +00:00
|
|
|
outexpect = g_strdup_printf(TEST27_OUTEXPECT_TEMP,
|
|
|
|
buffer0, buffer1, buffer2);
|
|
|
|
errexpect = g_strdup_printf(TEST27_ERREXPECT_TEMP,
|
|
|
|
buffer0, buffer1, buffer2);
|
2019-07-25 18:22:10 +00:00
|
|
|
|
2020-01-24 15:22:12 +00:00
|
|
|
if (virPipeQuiet(pipe1) < 0 || virPipeQuiet(pipe2) < 0) {
|
2019-10-02 15:30:36 +00:00
|
|
|
printf("Could not create pipe: %s\n", g_strerror(errno));
|
2019-07-25 18:22:10 +00:00
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (virCommandSetSendBuffer(cmd, pipe1[1],
|
|
|
|
(unsigned char *)buffer1, buflen - 1) < 0 ||
|
|
|
|
virCommandSetSendBuffer(cmd, pipe2[1],
|
|
|
|
(unsigned char *)buffer2, buflen - 1) < 0) {
|
|
|
|
printf("Could not set send buffers\n");
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
pipe1[1] = 0;
|
|
|
|
pipe2[1] = 0;
|
|
|
|
buffer1 = NULL;
|
|
|
|
buffer2 = NULL;
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "--readfd");
|
|
|
|
virCommandAddArgFormat(cmd, "%d", pipe1[0]);
|
|
|
|
virCommandPassFD(cmd, pipe1[0], 0);
|
|
|
|
|
|
|
|
virCommandAddArg(cmd, "--readfd");
|
|
|
|
virCommandAddArgFormat(cmd, "%d", pipe2[0]);
|
|
|
|
virCommandPassFD(cmd, pipe2[0], 0);
|
|
|
|
|
|
|
|
virCommandSetInputBuffer(cmd, buffer0);
|
|
|
|
virCommandSetOutputBuffer(cmd, &outactual);
|
|
|
|
virCommandSetErrorBuffer(cmd, &erractual);
|
|
|
|
|
|
|
|
if (virCommandRun(cmd, NULL) < 0) {
|
|
|
|
printf("Cannot run child %s\n", virGetLastErrorMessage());
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!outactual || !erractual)
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
if (STRNEQ(outactual, outexpect)) {
|
|
|
|
virTestDifference(stderr, outexpect, outactual);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
if (STRNEQ(erractual, errexpect)) {
|
|
|
|
virTestDifference(stderr, errexpect, erractual);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
2019-07-29 14:11:29 +00:00
|
|
|
if (checkoutput("test27", NULL) < 0)
|
|
|
|
goto cleanup;
|
|
|
|
|
2019-07-25 18:22:10 +00:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
cleanup:
|
2019-07-26 20:56:31 +00:00
|
|
|
virCommandFree(cmd);
|
2019-07-25 18:22:10 +00:00
|
|
|
VIR_FORCE_CLOSE(pipe1[0]);
|
|
|
|
VIR_FORCE_CLOSE(pipe2[0]);
|
|
|
|
VIR_FORCE_CLOSE(pipe1[1]);
|
|
|
|
VIR_FORCE_CLOSE(pipe2[1]);
|
|
|
|
VIR_FREE(buffer0);
|
|
|
|
VIR_FREE(buffer1);
|
|
|
|
VIR_FREE(buffer2);
|
|
|
|
VIR_FREE(outactual);
|
|
|
|
VIR_FREE(erractual);
|
|
|
|
VIR_FREE(outexpect);
|
|
|
|
VIR_FREE(errexpect);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-01-16 10:58:00 +00:00
|
|
|
|
2010-05-25 11:14:06 +00:00
|
|
|
static int
|
2011-04-29 16:21:20 +00:00
|
|
|
mymain(void)
|
2010-05-25 11:14:06 +00:00
|
|
|
{
|
|
|
|
int ret = 0;
|
2011-01-28 21:22:39 +00:00
|
|
|
int fd;
|
2013-01-14 15:35:45 +00:00
|
|
|
int virinitret;
|
2013-01-16 10:58:00 +00:00
|
|
|
|
2010-05-25 11:14:06 +00:00
|
|
|
if (chdir("/tmp") < 0)
|
2012-03-22 11:33:35 +00:00
|
|
|
return EXIT_FAILURE;
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2014-09-03 15:13:21 +00:00
|
|
|
umask(022);
|
|
|
|
|
2011-02-24 12:12:27 +00:00
|
|
|
setpgid(0, 0);
|
2012-04-27 21:25:35 +00:00
|
|
|
ignore_value(setsid());
|
2011-02-24 12:12:27 +00:00
|
|
|
|
2012-01-06 21:07:23 +00:00
|
|
|
/* Our test expects particular fd values; to get that, we must not
|
|
|
|
* leak fds that we inherited from a lazy parent. At the same
|
|
|
|
* time, virInitialize may open some fds (perhaps via third-party
|
|
|
|
* libraries that it uses), and we must not kill off an fd that
|
|
|
|
* this process opens as it might break expectations of a
|
|
|
|
* pthread_atfork handler, as well as interfering with our tests
|
|
|
|
* trying to ensure we aren't leaking to our children. The
|
|
|
|
* solution is to do things in two phases - reserve the fds we
|
|
|
|
* want by overwriting any externally inherited fds, then
|
|
|
|
* initialize, then clear the slots for testing. */
|
|
|
|
if ((fd = open("/dev/null", O_RDONLY)) < 0 ||
|
|
|
|
dup2(fd, 3) < 0 ||
|
|
|
|
dup2(fd, 4) < 0 ||
|
|
|
|
dup2(fd, 5) < 0 ||
|
2013-02-05 16:15:20 +00:00
|
|
|
dup2(fd, 6) < 0 ||
|
|
|
|
dup2(fd, 7) < 0 ||
|
|
|
|
dup2(fd, 8) < 0 ||
|
2013-01-14 15:35:45 +00:00
|
|
|
(fd > 8 && VIR_CLOSE(fd) < 0)) {
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
2012-01-06 21:07:23 +00:00
|
|
|
return EXIT_FAILURE;
|
2013-01-14 15:35:45 +00:00
|
|
|
}
|
2011-08-25 11:05:54 +00:00
|
|
|
|
|
|
|
/* Prime the debug/verbose settings from the env vars,
|
|
|
|
* since we're about to reset 'environ' */
|
2012-04-27 21:25:35 +00:00
|
|
|
ignore_value(virTestGetDebug());
|
|
|
|
ignore_value(virTestGetVerbose());
|
2011-08-25 11:05:54 +00:00
|
|
|
|
2013-01-14 15:35:45 +00:00
|
|
|
/* Make sure to not leak fd's */
|
|
|
|
virinitret = virInitialize();
|
2012-01-06 21:07:23 +00:00
|
|
|
|
|
|
|
/* Phase two of killing interfering fds; see above. */
|
2013-01-14 15:35:45 +00:00
|
|
|
/* coverity[overwrite_var] - silence the obvious */
|
2011-01-28 21:22:39 +00:00
|
|
|
fd = 3;
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
fd = 4;
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
fd = 5;
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
2013-02-05 16:15:20 +00:00
|
|
|
fd = 6;
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
fd = 7;
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
|
|
|
fd = 8;
|
|
|
|
VIR_FORCE_CLOSE(fd);
|
2010-12-10 22:30:56 +00:00
|
|
|
|
2013-01-14 15:35:45 +00:00
|
|
|
if (virinitret < 0)
|
|
|
|
return EXIT_FAILURE;
|
|
|
|
|
2010-05-25 11:14:06 +00:00
|
|
|
environ = (char **)newenv;
|
|
|
|
|
2017-11-03 12:09:47 +00:00
|
|
|
# define DO_TEST(NAME) \
|
|
|
|
if (virTestRun("Command Exec " #NAME " test", \
|
|
|
|
NAME, NULL) < 0) \
|
2010-05-25 11:14:06 +00:00
|
|
|
ret = -1
|
|
|
|
|
|
|
|
DO_TEST(test0);
|
|
|
|
DO_TEST(test1);
|
|
|
|
DO_TEST(test2);
|
|
|
|
DO_TEST(test3);
|
|
|
|
DO_TEST(test4);
|
|
|
|
DO_TEST(test5);
|
|
|
|
DO_TEST(test6);
|
|
|
|
DO_TEST(test7);
|
|
|
|
DO_TEST(test8);
|
|
|
|
DO_TEST(test9);
|
|
|
|
DO_TEST(test10);
|
|
|
|
DO_TEST(test11);
|
|
|
|
DO_TEST(test12);
|
|
|
|
DO_TEST(test13);
|
|
|
|
DO_TEST(test14);
|
|
|
|
DO_TEST(test15);
|
|
|
|
DO_TEST(test16);
|
2010-12-03 21:14:16 +00:00
|
|
|
DO_TEST(test17);
|
2010-12-21 18:49:49 +00:00
|
|
|
DO_TEST(test18);
|
2011-03-22 22:22:37 +00:00
|
|
|
DO_TEST(test19);
|
2012-05-31 21:50:07 +00:00
|
|
|
DO_TEST(test20);
|
2013-01-16 17:55:06 +00:00
|
|
|
DO_TEST(test21);
|
2014-02-19 01:06:50 +00:00
|
|
|
DO_TEST(test22);
|
2014-02-20 03:04:40 +00:00
|
|
|
DO_TEST(test23);
|
2016-07-11 14:03:34 +00:00
|
|
|
DO_TEST(test25);
|
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: Daniel P. Berrangé <berrange@redhat.com>
2018-12-14 12:07:08 +00:00
|
|
|
DO_TEST(test26);
|
2019-07-25 18:22:10 +00:00
|
|
|
DO_TEST(test27);
|
2010-05-25 11:14:06 +00:00
|
|
|
|
2014-03-17 09:38:38 +00:00
|
|
|
return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
|
2010-05-25 11:14:06 +00:00
|
|
|
}
|
|
|
|
|
2017-03-29 14:45:42 +00:00
|
|
|
VIR_TEST_MAIN(mymain)
|
2011-07-28 15:48:12 +00:00
|
|
|
|
|
|
|
#endif /* !WIN32 */
|