mirror of https://gitee.com/openkylin/libvirt.git
Introduce new APIs for spawning processes
This introduces a new set of APIs in src/util/command.h to use for invoking commands. This is intended to replace all current usage of virRun and virExec variants, with a more flexible and less error prone API. * src/util/command.c: New file. * src/util/command.h: New header. * src/Makefile.am (UTIL_SOURCES): Build it. * src/libvirt_private.syms: Export symbols internally. * tests/commandtest.c: New test. * tests/Makefile.am (check_PROGRAMS): Run it. * tests/commandhelper.c: Auxiliary program. * tests/commanddata/test2.log - test15.log: New expected outputs. * cfg.mk (useless_free_options): Add virCommandFree. (msg_gen_function): Add virCommandError. * po/POTFILES.in: New translation. * .x-sc_avoid_write: Add exemption. * tests/.gitignore: Ignore new built file.
This commit is contained in:
parent
fce3baee26
commit
f16ad06fb2
|
@ -1,6 +1,7 @@
|
|||
^src/libvirt\.c$
|
||||
^src/fdstream\.c$
|
||||
^src/qemu/qemu_monitor\.c$
|
||||
^src/util/command\.c$
|
||||
^src/util/util\.c$
|
||||
^src/xen/xend_internal\.c$
|
||||
^daemon/libvirtd.c$
|
||||
|
|
4
cfg.mk
4
cfg.mk
|
@ -81,6 +81,7 @@ useless_free_options = \
|
|||
--name=virCapabilitiesFreeHostNUMACell \
|
||||
--name=virCapabilitiesFreeMachines \
|
||||
--name=virCgroupFree \
|
||||
--name=virCommandFree \
|
||||
--name=virConfFreeList \
|
||||
--name=virConfFreeValue \
|
||||
--name=virDomainChrDefFree \
|
||||
|
@ -368,9 +369,9 @@ msg_gen_function += umlReportError
|
|||
msg_gen_function += vah_error
|
||||
msg_gen_function += vah_warning
|
||||
msg_gen_function += vboxError
|
||||
msg_gen_function += virCommandError
|
||||
msg_gen_function += virConfError
|
||||
msg_gen_function += virDomainReportError
|
||||
msg_gen_function += virSecurityReportError
|
||||
msg_gen_function += virHashError
|
||||
msg_gen_function += virLibConnError
|
||||
msg_gen_function += virLibDomainError
|
||||
|
@ -379,6 +380,7 @@ msg_gen_function += virNodeDeviceReportError
|
|||
msg_gen_function += virRaiseError
|
||||
msg_gen_function += virReportErrorHelper
|
||||
msg_gen_function += virReportSystemError
|
||||
msg_gen_function += virSecurityReportError
|
||||
msg_gen_function += virSexprError
|
||||
msg_gen_function += virStorageReportError
|
||||
msg_gen_function += virXMLError
|
||||
|
|
|
@ -78,6 +78,7 @@ src/uml/uml_driver.c
|
|||
src/util/authhelper.c
|
||||
src/util/bridge.c
|
||||
src/util/cgroup.c
|
||||
src/util/command.c
|
||||
src/util/conf.c
|
||||
src/util/dnsmasq.c
|
||||
src/util/hooks.c
|
||||
|
|
|
@ -48,6 +48,7 @@ UTIL_SOURCES = \
|
|||
util/bitmap.c util/bitmap.h \
|
||||
util/bridge.c util/bridge.h \
|
||||
util/buf.c util/buf.h \
|
||||
util/command.c util/command.h \
|
||||
util/conf.c util/conf.h \
|
||||
util/cgroup.c util/cgroup.h \
|
||||
util/event.c util/event.h \
|
||||
|
|
|
@ -83,6 +83,41 @@ virCgroupSetMemorySoftLimit;
|
|||
virCgroupSetSwapHardLimit;
|
||||
|
||||
|
||||
# command.h
|
||||
virCommandAddArg;
|
||||
virCommandAddArgFormat;
|
||||
virCommandAddArgList;
|
||||
virCommandAddArgPair;
|
||||
virCommandAddArgSet;
|
||||
virCommandAddEnvPair;
|
||||
virCommandAddEnvPass;
|
||||
virCommandAddEnvPassCommon;
|
||||
virCommandAddEnvString;
|
||||
virCommandClearCaps;
|
||||
virCommandDaemonize;
|
||||
virCommandFree;
|
||||
virCommandNew;
|
||||
virCommandNewArgList;
|
||||
virCommandNewArgs;
|
||||
virCommandNonblockingFDs;
|
||||
virCommandPreserveFD;
|
||||
virCommandRun;
|
||||
virCommandRunAsync;
|
||||
virCommandSetErrorBuffer;
|
||||
virCommandSetErrorFD;
|
||||
virCommandSetInputBuffer;
|
||||
virCommandSetInputFD;
|
||||
virCommandSetOutputBuffer;
|
||||
virCommandSetOutputFD;
|
||||
virCommandSetPidFile;
|
||||
virCommandSetPreExecHook;
|
||||
virCommandSetWorkingDirectory;
|
||||
virCommandToString;
|
||||
virCommandTransferFD;
|
||||
virCommandWait;
|
||||
virCommandWriteArgLog;
|
||||
|
||||
|
||||
# conf.h
|
||||
virConfFree;
|
||||
virConfFreeValue;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,260 @@
|
|||
/*
|
||||
* command.h: Child command execution
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* 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
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __VIR_COMMAND_H__
|
||||
# define __VIR_COMMAND_H__
|
||||
|
||||
# include "internal.h"
|
||||
# include "util.h"
|
||||
|
||||
typedef struct _virCommand virCommand;
|
||||
typedef virCommand *virCommandPtr;
|
||||
|
||||
/*
|
||||
* Create a new command for named binary
|
||||
*/
|
||||
virCommandPtr virCommandNew(const char *binary) ATTRIBUTE_NONNULL(1);
|
||||
|
||||
/*
|
||||
* Create a new command with a NULL terminated
|
||||
* set of args, taking binary from argv[0]
|
||||
*/
|
||||
virCommandPtr virCommandNewArgs(const char *const*args) ATTRIBUTE_NONNULL(1);
|
||||
|
||||
/*
|
||||
* Create a new command with a NULL terminated
|
||||
* list of args, starting with the binary to run
|
||||
*/
|
||||
virCommandPtr virCommandNewArgList(const char *binary, ...)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL;
|
||||
|
||||
/* All error report from these setup APIs is
|
||||
* delayed until the Run/RunAsync methods
|
||||
*/
|
||||
|
||||
/*
|
||||
* Preserve the specified file descriptor
|
||||
* in the child, instead of closing it.
|
||||
* The parent is still responsible for managing fd.
|
||||
*/
|
||||
void virCommandPreserveFD(virCommandPtr cmd,
|
||||
int fd);
|
||||
|
||||
/*
|
||||
* Transfer the specified file descriptor
|
||||
* to the child, instead of closing it.
|
||||
* Close the fd in the parent during Run/RunAsync/Free.
|
||||
*/
|
||||
void virCommandTransferFD(virCommandPtr cmd,
|
||||
int fd);
|
||||
|
||||
/*
|
||||
* Save the child PID in a pidfile
|
||||
*/
|
||||
void virCommandSetPidFile(virCommandPtr cmd,
|
||||
const char *pidfile) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
/*
|
||||
* Remove all capabilities from the child
|
||||
*/
|
||||
void virCommandClearCaps(virCommandPtr cmd);
|
||||
|
||||
# if 0
|
||||
/*
|
||||
* Re-allow a specific capability
|
||||
*/
|
||||
void virCommandAllowCap(virCommandPtr cmd,
|
||||
int capability);
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Daemonize the child process
|
||||
*/
|
||||
void virCommandDaemonize(virCommandPtr cmd);
|
||||
|
||||
/*
|
||||
* Set FDs created by virCommandSetOutputFD and virCommandSetErrorFD
|
||||
* as non-blocking in the parent.
|
||||
*/
|
||||
void virCommandNonblockingFDs(virCommandPtr cmd);
|
||||
|
||||
/*
|
||||
* Add an environment variable to the child
|
||||
* using separate name & value strings
|
||||
*/
|
||||
void virCommandAddEnvPair(virCommandPtr cmd,
|
||||
const char *name,
|
||||
const char *value) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
/*
|
||||
* Add an environemnt variable to the child
|
||||
* using a preformated env string FOO=BAR
|
||||
*/
|
||||
void virCommandAddEnvString(virCommandPtr cmd,
|
||||
const char *str) ATTRIBUTE_NONNULL(2);
|
||||
/*
|
||||
* Pass an environment variable to the child
|
||||
* using current process' value
|
||||
*/
|
||||
void virCommandAddEnvPass(virCommandPtr cmd,
|
||||
const char *name) ATTRIBUTE_NONNULL(2);
|
||||
/*
|
||||
* Pass a common set of environment variables
|
||||
* to the child using current process' values
|
||||
*/
|
||||
void virCommandAddEnvPassCommon(virCommandPtr cmd);
|
||||
|
||||
/*
|
||||
* Add a command line argument to the child
|
||||
*/
|
||||
void virCommandAddArg(virCommandPtr cmd,
|
||||
const char *val) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
/*
|
||||
* Add a command line argument created by a printf-style format
|
||||
*/
|
||||
void virCommandAddArgFormat(virCommandPtr cmd,
|
||||
const char *format, ...)
|
||||
ATTRIBUTE_NONNULL(2) ATTRIBUTE_FMT_PRINTF(2, 3);
|
||||
|
||||
/*
|
||||
* Add a command line argument to the child
|
||||
*/
|
||||
void virCommandAddArgPair(virCommandPtr cmd,
|
||||
const char *name,
|
||||
const char *val)
|
||||
ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(3);
|
||||
/*
|
||||
* Add a NULL terminated array of args
|
||||
*/
|
||||
void virCommandAddArgSet(virCommandPtr cmd,
|
||||
const char *const*vals) ATTRIBUTE_NONNULL(2);
|
||||
/*
|
||||
* Add a NULL terminated list of args
|
||||
*/
|
||||
void virCommandAddArgList(virCommandPtr cmd,
|
||||
... /* const char *arg, ..., NULL */)
|
||||
ATTRIBUTE_SENTINEL;
|
||||
|
||||
/*
|
||||
* Set the working directory of a non-daemon child process, rather
|
||||
* than the parent's working directory. Daemons automatically get /
|
||||
* without using this call.
|
||||
*/
|
||||
void virCommandSetWorkingDirectory(virCommandPtr cmd,
|
||||
const char *pwd) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
/*
|
||||
* Feed the child's stdin from a string buffer.
|
||||
*
|
||||
* NB: Only works with virCommandRun()
|
||||
*/
|
||||
void virCommandSetInputBuffer(virCommandPtr cmd,
|
||||
const char *inbuf) ATTRIBUTE_NONNULL(2);
|
||||
/*
|
||||
* Capture the child's stdout to a string buffer
|
||||
*
|
||||
* NB: Only works with virCommandRun()
|
||||
*/
|
||||
void virCommandSetOutputBuffer(virCommandPtr cmd,
|
||||
char **outbuf) ATTRIBUTE_NONNULL(2);
|
||||
/*
|
||||
* Capture the child's stderr to a string buffer
|
||||
*
|
||||
* NB: Only works with virCommandRun()
|
||||
*/
|
||||
void virCommandSetErrorBuffer(virCommandPtr cmd,
|
||||
char **errbuf) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
/*
|
||||
* Set a file descriptor as the child's stdin
|
||||
*/
|
||||
void virCommandSetInputFD(virCommandPtr cmd,
|
||||
int infd);
|
||||
/*
|
||||
* Set a file descriptor as the child's stdout
|
||||
*/
|
||||
void virCommandSetOutputFD(virCommandPtr cmd,
|
||||
int *outfd) ATTRIBUTE_NONNULL(2);
|
||||
/*
|
||||
* Set a file descriptor as the child's stderr
|
||||
*/
|
||||
void virCommandSetErrorFD(virCommandPtr cmd,
|
||||
int *errfd) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
/*
|
||||
* A hook function to run between fork + exec
|
||||
*/
|
||||
void virCommandSetPreExecHook(virCommandPtr cmd,
|
||||
virExecHook hook,
|
||||
void *opaque) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
/*
|
||||
* Call after adding all arguments and environment settings, but before
|
||||
* Run/RunAsync, to immediately output the environment and arguments of
|
||||
* cmd to logfd. If virCommandRun cannot succeed (because of an
|
||||
* out-of-memory condition while building cmd), nothing will be logged.
|
||||
*/
|
||||
void virCommandWriteArgLog(virCommandPtr cmd,
|
||||
int logfd);
|
||||
|
||||
/*
|
||||
* Call after adding all arguments and environment settings, but before
|
||||
* Run/RunAsync, to return a string representation of the environment and
|
||||
* arguments of cmd. If virCommandRun cannot succeed (because of an
|
||||
* out-of-memory condition while building cmd), NULL will be returned.
|
||||
* Caller is responsible for freeing the resulting string.
|
||||
*/
|
||||
char *virCommandToString(virCommandPtr cmd) ATTRIBUTE_RETURN_CHECK;
|
||||
|
||||
/*
|
||||
* Run the command and wait for completion.
|
||||
* Returns -1 on any error executing the
|
||||
* command. Returns 0 if the command executed,
|
||||
* with the exit status set
|
||||
*/
|
||||
int virCommandRun(virCommandPtr cmd,
|
||||
int *exitstatus) ATTRIBUTE_RETURN_CHECK;
|
||||
|
||||
/*
|
||||
* Run the command asynchronously
|
||||
* Returns -1 on any error executing the
|
||||
* command. Returns 0 if the command executed.
|
||||
*/
|
||||
int virCommandRunAsync(virCommandPtr cmd,
|
||||
pid_t *pid) ATTRIBUTE_RETURN_CHECK;
|
||||
|
||||
/*
|
||||
* Wait for the async command to complete.
|
||||
* Return -1 on any error waiting for
|
||||
* completion. Returns 0 if the command
|
||||
* finished with the exit status set
|
||||
*/
|
||||
int virCommandWait(virCommandPtr cmd,
|
||||
int *exitstatus) ATTRIBUTE_RETURN_CHECK;
|
||||
|
||||
/*
|
||||
* Release all resources
|
||||
*/
|
||||
void virCommandFree(virCommandPtr cmd);
|
||||
|
||||
|
||||
#endif /* __VIR_COMMAND_H__ */
|
|
@ -1,6 +1,10 @@
|
|||
*.exe
|
||||
.deps
|
||||
.libs
|
||||
commandhelper
|
||||
commandhelper.log
|
||||
commandhelper.pid
|
||||
commandtest
|
||||
conftest
|
||||
esxutilstest
|
||||
eventtest
|
||||
|
|
|
@ -73,7 +73,8 @@ EXTRA_DIST = \
|
|||
cputestdata
|
||||
|
||||
check_PROGRAMS = virshtest conftest sockettest \
|
||||
nodeinfotest qparamtest virbuftest
|
||||
nodeinfotest qparamtest virbuftest \
|
||||
commandtest commandhelper
|
||||
|
||||
if WITH_XEN
|
||||
check_PROGRAMS += xml2sexprtest sexpr2xmltest \
|
||||
|
@ -157,6 +158,7 @@ TESTS = virshtest \
|
|||
qparamtest \
|
||||
virbuftest \
|
||||
sockettest \
|
||||
commandtest \
|
||||
$(test_scripts)
|
||||
|
||||
if WITH_XEN
|
||||
|
@ -349,6 +351,16 @@ nodeinfotest_SOURCES = \
|
|||
nodeinfotest.c testutils.h testutils.c
|
||||
nodeinfotest_LDADD = $(LDADDS)
|
||||
|
||||
commandtest_SOURCES = \
|
||||
commandtest.c testutils.h testutils.c
|
||||
commandtest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\""
|
||||
commandtest_LDADD = $(LDADDS)
|
||||
|
||||
commandhelper_SOURCES = \
|
||||
commandhelper.c
|
||||
commandhelper_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\""
|
||||
commandhelper_LDADD = $(LDADDS)
|
||||
|
||||
if WITH_SECDRIVER_SELINUX
|
||||
seclabeltest_SOURCES = \
|
||||
seclabeltest.c
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
ARG:-version
|
||||
ARG:-log=bar.log
|
||||
ENV:DISPLAY=:0.0
|
||||
ENV:HOME=/home/test
|
||||
ENV:HOSTNAME=test
|
||||
ENV:LANG=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,14 @@
|
|||
ARG:-version
|
||||
ARG:-log=bar.log
|
||||
ENV:DISPLAY=:0.0
|
||||
ENV:HOME=/home/test
|
||||
ENV:HOSTNAME=test
|
||||
ENV:LANG=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,12 @@
|
|||
ENV:DISPLAY=:0.0
|
||||
ENV:HOME=/home/test
|
||||
ENV:HOSTNAME=test
|
||||
ENV:LANG=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,12 @@
|
|||
ENV:DISPLAY=:0.0
|
||||
ENV:HOME=/home/test
|
||||
ENV:HOSTNAME=test
|
||||
ENV:LANG=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,12 @@
|
|||
ENV:DISPLAY=:0.0
|
||||
ENV:HOME=/home/test
|
||||
ENV:HOSTNAME=test
|
||||
ENV:LANG=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,12 @@
|
|||
ENV:DISPLAY=:0.0
|
||||
ENV:HOME=/home/test
|
||||
ENV:HOSTNAME=test
|
||||
ENV:LANG=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:.../commanddata
|
|
@ -0,0 +1 @@
|
|||
A=B /bin/true C
|
|
@ -0,0 +1,12 @@
|
|||
ENV:DISPLAY=:0.0
|
||||
ENV:HOME=/home/test
|
||||
ENV:HOSTNAME=test
|
||||
ENV:LANG=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,14 @@
|
|||
ENV:DISPLAY=:0.0
|
||||
ENV:HOME=/home/test
|
||||
ENV:HOSTNAME=test
|
||||
ENV:LANG=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
FD:3
|
||||
FD:5
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,12 @@
|
|||
ENV:DISPLAY=:0.0
|
||||
ENV:HOME=/home/test
|
||||
ENV:HOSTNAME=test
|
||||
ENV:LANG=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:yes
|
||||
CWD:/
|
|
@ -0,0 +1,10 @@
|
|||
ENV:HOME=/home/test
|
||||
ENV:LC_ALL=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,6 @@
|
|||
ENV:DISPLAY=:0.0
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,11 @@
|
|||
ENV:DISPLAY=:0.0
|
||||
ENV:HOME=/home/test
|
||||
ENV:LC_ALL=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,7 @@
|
|||
ENV:LANG=C
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,18 @@
|
|||
ARG:-version
|
||||
ARG:-log=bar.log
|
||||
ARG:arg1
|
||||
ARG:arg2
|
||||
ARG:arg3
|
||||
ARG:arg4
|
||||
ENV:DISPLAY=:0.0
|
||||
ENV:HOME=/home/test
|
||||
ENV:HOSTNAME=test
|
||||
ENV:LANG=C
|
||||
ENV:LOGNAME=testTMPDIR=/tmp
|
||||
ENV:PATH=/usr/bin:/bin
|
||||
ENV:USER=test
|
||||
FD:0
|
||||
FD:1
|
||||
FD:2
|
||||
DAEMON:no
|
||||
CWD:/tmp
|
|
@ -0,0 +1,137 @@
|
|||
/*
|
||||
* commandhelper.c: Auxiliary program for commandtest
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* 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
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "files.h"
|
||||
|
||||
|
||||
static int envsort(const void *a, const void *b) {
|
||||
const char *const*astrptr = a;
|
||||
const char *const*bstrptr = b;
|
||||
const char *astr = *astrptr;
|
||||
const char *bstr = *bstrptr;
|
||||
char *aeq = strchr(astr, '=');
|
||||
char *beq = strchr(bstr, '=');
|
||||
char *akey = strndup(astr, aeq - astr);
|
||||
char *bkey = strndup(bstr, beq - bstr);
|
||||
int ret = strcmp(akey, bkey);
|
||||
free(akey);
|
||||
free(bkey);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i, n;
|
||||
char **origenv;
|
||||
char **newenv;
|
||||
FILE *log = fopen(abs_builddir "/commandhelper.log", "w");
|
||||
|
||||
if (!log)
|
||||
goto error;
|
||||
|
||||
for (i = 1 ; i < argc ; i++) {
|
||||
fprintf(log, "ARG:%s\n", argv[i]);
|
||||
}
|
||||
|
||||
origenv = environ;
|
||||
n = 0;
|
||||
while (*origenv != NULL) {
|
||||
n++;
|
||||
origenv++;
|
||||
}
|
||||
|
||||
if (VIR_ALLOC_N(newenv, n) < 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
origenv = environ;
|
||||
n = i = 0;
|
||||
while (*origenv != NULL) {
|
||||
newenv[i++] = *origenv;
|
||||
n++;
|
||||
origenv++;
|
||||
}
|
||||
qsort(newenv, n, sizeof(newenv[0]), envsort);
|
||||
|
||||
for (i = 0 ; i < n ; i++) {
|
||||
fprintf(log, "ENV:%s\n", newenv[i]);
|
||||
}
|
||||
|
||||
for (i = 0 ; i < sysconf(_SC_OPEN_MAX) ; i++) {
|
||||
int f;
|
||||
int closed;
|
||||
if (i == fileno(log))
|
||||
continue;
|
||||
closed = fcntl(i, F_GETFD, &f) == -1 &&
|
||||
errno == EBADF;
|
||||
if (!closed)
|
||||
fprintf(log, "FD:%d\n", i);
|
||||
}
|
||||
|
||||
fprintf(log, "DAEMON:%s\n", getppid() == 1 ? "yes" : "no");
|
||||
char cwd[1024];
|
||||
getcwd(cwd, sizeof(cwd));
|
||||
if (strlen(cwd) > strlen("/commanddata") &&
|
||||
STREQ(cwd + strlen(cwd) - strlen("/commanddata"), "/commanddata"))
|
||||
strcpy(cwd, ".../commanddata");
|
||||
fprintf(log, "CWD:%s\n", cwd);
|
||||
|
||||
VIR_FORCE_FCLOSE(log);
|
||||
|
||||
char buf[1024];
|
||||
ssize_t got;
|
||||
|
||||
fprintf(stdout, "BEGIN STDOUT\n");
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "BEGIN STDERR\n");
|
||||
fflush(stderr);
|
||||
|
||||
for (;;) {
|
||||
got = read(STDIN_FILENO, buf, sizeof(buf));
|
||||
if (got < 0)
|
||||
goto error;
|
||||
if (got == 0)
|
||||
break;
|
||||
if (safewrite(STDOUT_FILENO, buf, got) != got)
|
||||
goto error;
|
||||
if (safewrite(STDERR_FILENO, buf, got) != got)
|
||||
goto error;
|
||||
}
|
||||
|
||||
fprintf(stdout, "END STDOUT\n");
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "END STDERR\n");
|
||||
fflush(stderr);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
error:
|
||||
return EXIT_FAILURE;
|
||||
}
|
|
@ -0,0 +1,642 @@
|
|||
/*
|
||||
* commandtest.c: Test the libCommand API
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* 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
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "testutils.h"
|
||||
#include "internal.h"
|
||||
#include "nodeinfo.h"
|
||||
#include "util.h"
|
||||
#include "memory.h"
|
||||
#include "command.h"
|
||||
#include "files.h"
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
static int
|
||||
mymain(int argc ATTRIBUTE_UNUSED, char **argv ATTRIBUTE_UNUSED)
|
||||
{
|
||||
exit (EXIT_AM_SKIP);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static char *progname;
|
||||
static char *abs_srcdir;
|
||||
|
||||
|
||||
static int checkoutput(const char *testname) {
|
||||
int ret = -1;
|
||||
char cwd[1024];
|
||||
char *expectname = NULL;
|
||||
char *expectlog = NULL;
|
||||
char *actualname = NULL;
|
||||
char *actuallog = NULL;
|
||||
|
||||
if (!getcwd(cwd, sizeof(cwd)))
|
||||
return -1;
|
||||
|
||||
if (virAsprintf(&expectname, "%s/commanddata/%s.log", abs_srcdir,
|
||||
testname) < 0)
|
||||
goto cleanup;
|
||||
if (virAsprintf(&actualname, "%s/commandhelper.log", abs_builddir) < 0)
|
||||
goto cleanup;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (STRNEQ(expectlog, actuallog)) {
|
||||
virtTestDifference(stderr, expectlog, actuallog);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
unlink(actuallog);
|
||||
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.
|
||||
*/
|
||||
static int test0(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd;
|
||||
char *log;
|
||||
int ret = -1;
|
||||
|
||||
free(virtTestLogContentAndReset());
|
||||
cmd = virCommandNew(abs_builddir "/commandhelper-doesnotexist");
|
||||
if (virCommandRun(cmd, NULL) == 0)
|
||||
goto cleanup;
|
||||
if ((log = virtTestLogContentAndReset()) == NULL)
|
||||
goto cleanup;
|
||||
if (strstr(log, ": error :") == NULL)
|
||||
goto cleanup;
|
||||
virResetLastError();
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
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.
|
||||
*/
|
||||
static int test1(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd;
|
||||
int ret = -1;
|
||||
int status;
|
||||
|
||||
cmd = virCommandNew(abs_builddir "/commandhelper-doesnotexist");
|
||||
if (virCommandRun(cmd, &status) < 0)
|
||||
goto cleanup;
|
||||
if (status == 0)
|
||||
goto cleanup;
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
virCommandFree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run program (twice), no args, inherit all ENV, keep CWD.
|
||||
* Only stdin/out/err open
|
||||
*/
|
||||
static int test2(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
||||
int ret;
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((ret = checkoutput("test2")) != 0) {
|
||||
virCommandFree(cmd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
return checkoutput("test2");
|
||||
}
|
||||
|
||||
/*
|
||||
* Run program, no args, inherit all ENV, keep CWD.
|
||||
* stdin/out/err + two extra FD open
|
||||
*/
|
||||
static int test3(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
||||
int newfd1 = dup(STDERR_FILENO);
|
||||
int newfd2 = dup(STDERR_FILENO);
|
||||
int newfd3 = dup(STDERR_FILENO);
|
||||
|
||||
virCommandPreserveFD(cmd, newfd1);
|
||||
virCommandTransferFD(cmd, newfd3);
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (fcntl(newfd1, F_GETFL) < 0 ||
|
||||
fcntl(newfd2, F_GETFL) < 0 ||
|
||||
fcntl(newfd3, F_GETFL) >= 0) {
|
||||
puts("fds in wrong state");
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
VIR_FORCE_CLOSE(newfd1);
|
||||
VIR_FORCE_CLOSE(newfd2);
|
||||
|
||||
return checkoutput("test3");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Run program, no args, inherit all ENV, CWD is /
|
||||
* Only stdin/out/err open.
|
||||
* Daemonized
|
||||
*/
|
||||
static int test4(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
||||
pid_t pid;
|
||||
char *pidfile = virFilePid(abs_builddir, "commandhelper");
|
||||
|
||||
virCommandSetPidFile(cmd, pidfile);
|
||||
virCommandDaemonize(cmd);
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (virFileReadPid(abs_builddir, "commandhelper", &pid) != 0) {
|
||||
printf("cannot read pidfile\n");
|
||||
return -1;
|
||||
}
|
||||
while (kill(pid, 0) != -1)
|
||||
usleep(100*1000);
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
VIR_FREE(pidfile);
|
||||
|
||||
return checkoutput("test4");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Run program, no args, inherit filtered ENV, keep CWD.
|
||||
* Only stdin/out/err open
|
||||
*/
|
||||
static int test5(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
||||
|
||||
virCommandAddEnvPassCommon(cmd);
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
return checkoutput("test5");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Run program, no args, inherit filtered ENV, keep CWD.
|
||||
* Only stdin/out/err open
|
||||
*/
|
||||
static int test6(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
||||
|
||||
virCommandAddEnvPass(cmd, "DISPLAY");
|
||||
virCommandAddEnvPass(cmd, "DOESNOTEXIST");
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
return checkoutput("test6");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Run program, no args, inherit filtered ENV, keep CWD.
|
||||
* Only stdin/out/err open
|
||||
*/
|
||||
static int test7(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
||||
|
||||
virCommandAddEnvPassCommon(cmd);
|
||||
virCommandAddEnvPass(cmd, "DISPLAY");
|
||||
virCommandAddEnvPass(cmd, "DOESNOTEXIST");
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
return checkoutput("test7");
|
||||
}
|
||||
|
||||
/*
|
||||
* Run program, no args, inherit filtered ENV, keep CWD.
|
||||
* Only stdin/out/err open
|
||||
*/
|
||||
static int test8(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
||||
|
||||
virCommandAddEnvString(cmd, "LANG=C");
|
||||
virCommandAddEnvPair(cmd, "USER", "test");
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
return checkoutput("test8");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Run program, some args, inherit all ENV, keep CWD.
|
||||
* Only stdin/out/err open
|
||||
*/
|
||||
static int test9(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
||||
const char* const args[] = { "arg1", "arg2", NULL };
|
||||
|
||||
virCommandAddArg(cmd, "-version");
|
||||
virCommandAddArgPair(cmd, "-log", "bar.log");
|
||||
virCommandAddArgSet(cmd, args);
|
||||
virCommandAddArgList(cmd, "arg3", "arg4", NULL);
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
return checkoutput("test9");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Run program, some args, inherit all ENV, keep CWD.
|
||||
* Only stdin/out/err open
|
||||
*/
|
||||
static int test10(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
||||
const char *const args[] = {
|
||||
"-version", "-log=bar.log", NULL,
|
||||
};
|
||||
|
||||
virCommandAddArgSet(cmd, args);
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
return checkoutput("test10");
|
||||
}
|
||||
|
||||
/*
|
||||
* Run program, some args, inherit all ENV, keep CWD.
|
||||
* Only stdin/out/err open
|
||||
*/
|
||||
static int test11(const void *unused ATTRIBUTE_UNUSED) {
|
||||
const char *args[] = {
|
||||
abs_builddir "/commandhelper",
|
||||
"-version", "-log=bar.log", NULL,
|
||||
};
|
||||
virCommandPtr cmd = virCommandNewArgs(args);
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
return checkoutput("test11");
|
||||
}
|
||||
|
||||
/*
|
||||
* Run program, no args, inherit all ENV, keep CWD.
|
||||
* Only stdin/out/err open. Set stdin data
|
||||
*/
|
||||
static int test12(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
||||
|
||||
virCommandSetInputBuffer(cmd, "Hello World\n");
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
return checkoutput("test12");
|
||||
}
|
||||
|
||||
/*
|
||||
* Run program, no args, inherit all ENV, keep CWD.
|
||||
* Only stdin/out/err open. Set stdin data
|
||||
*/
|
||||
static int test13(const void *unused ATTRIBUTE_UNUSED) {
|
||||
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) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
if (!STREQ(outactual, outexpect)) {
|
||||
virtTestDifference(stderr, outactual, outexpect);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (checkoutput("test13") < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(outactual);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run program, no args, inherit all ENV, keep CWD.
|
||||
* Only stdin/out/err open. Set stdin data
|
||||
*/
|
||||
static int test14(const void *unused ATTRIBUTE_UNUSED) {
|
||||
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";
|
||||
int ret = -1;
|
||||
|
||||
virCommandSetInputBuffer(cmd, "Hello World\n");
|
||||
virCommandSetOutputBuffer(cmd, &outactual);
|
||||
virCommandSetErrorBuffer(cmd, &erractual);
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
if (!STREQ(outactual, outexpect)) {
|
||||
virtTestDifference(stderr, outactual, outexpect);
|
||||
goto cleanup;
|
||||
}
|
||||
if (!STREQ(erractual, errexpect)) {
|
||||
virtTestDifference(stderr, erractual, errexpect);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (checkoutput("test14") < 0)
|
||||
goto cleanup;
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
VIR_FREE(outactual);
|
||||
VIR_FREE(erractual);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Run program, no args, inherit all ENV, change CWD.
|
||||
* Only stdin/out/err open
|
||||
*/
|
||||
static int test15(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew(abs_builddir "/commandhelper");
|
||||
|
||||
virCommandSetWorkingDirectory(cmd, abs_builddir "/commanddata");
|
||||
|
||||
if (virCommandRun(cmd, NULL) < 0) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot run child %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
return checkoutput("test15");
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't run program; rather, log what would be run.
|
||||
*/
|
||||
static int test16(const void *unused ATTRIBUTE_UNUSED) {
|
||||
virCommandPtr cmd = virCommandNew("/bin/true");
|
||||
char *outactual = NULL;
|
||||
const char *outexpect = "A=B /bin/true C";
|
||||
int ret = -1;
|
||||
int fd = -1;
|
||||
|
||||
virCommandAddEnvPair(cmd, "A", "B");
|
||||
virCommandAddArg(cmd, "C");
|
||||
|
||||
if ((outactual = virCommandToString(cmd)) == NULL) {
|
||||
virErrorPtr err = virGetLastError();
|
||||
printf("Cannot convert to string: %s\n", err->message);
|
||||
return -1;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
virCommandFree(cmd);
|
||||
|
||||
if (checkoutput("test16") < 0)
|
||||
goto cleanup;
|
||||
|
||||
if (!STREQ(outactual, outexpect)) {
|
||||
virtTestDifference(stderr, outactual, outexpect);
|
||||
goto cleanup;
|
||||
}
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
VIR_FORCE_CLOSE(fd);
|
||||
VIR_FREE(outactual);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
mymain(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
char cwd[PATH_MAX];
|
||||
|
||||
abs_srcdir = getenv("abs_srcdir");
|
||||
if (!abs_srcdir)
|
||||
abs_srcdir = getcwd(cwd, sizeof(cwd));
|
||||
|
||||
progname = argv[0];
|
||||
|
||||
if (argc > 1) {
|
||||
fprintf(stderr, "Usage: %s\n", progname);
|
||||
return(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (chdir("/tmp") < 0)
|
||||
return(EXIT_FAILURE);
|
||||
|
||||
virInitialize();
|
||||
|
||||
const char *const newenv[] = {
|
||||
"PATH=/usr/bin:/bin",
|
||||
"HOSTNAME=test",
|
||||
"LANG=C",
|
||||
"HOME=/home/test",
|
||||
"USER=test",
|
||||
"LOGNAME=test"
|
||||
"TMPDIR=/tmp",
|
||||
"DISPLAY=:0.0",
|
||||
NULL
|
||||
};
|
||||
environ = (char **)newenv;
|
||||
|
||||
# define DO_TEST(NAME) \
|
||||
if (virtTestRun("Command Exec " #NAME " test", \
|
||||
1, NAME, NULL) < 0) \
|
||||
ret = -1
|
||||
|
||||
char *actualname;
|
||||
if (virAsprintf(&actualname, "%s/commandhelper.log", abs_builddir) < 0)
|
||||
return EXIT_FAILURE;
|
||||
unlink(actualname);
|
||||
VIR_FREE(actualname);
|
||||
|
||||
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);
|
||||
|
||||
return(ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
#endif /* !WIN32 */
|
||||
|
||||
VIRT_TEST_MAIN(mymain)
|
Loading…
Reference in New Issue