libvirt/src/util/vircommand.h

225 lines
7.4 KiB
C
Raw Normal View History

/*
* vircommand.h: Child command execution
*
* Copyright (C) 2010-2014 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, see
* <http://www.gnu.org/licenses/>.
*
*/
#pragma once
#include "internal.h"
#include "virbuffer.h"
typedef struct _virCommand virCommand;
/* This will execute in the context of the first child
* after fork() but before execve(). As such, it is unsafe to
* call any function that is not async-signal-safe. */
typedef int (*virExecHook)(void *data);
pid_t virFork(void) G_GNUC_WARN_UNUSED_RESULT;
virCommand *virCommandNew(const char *binary) ATTRIBUTE_NONNULL(1);
virCommand *virCommandNewArgs(const char *const*args) ATTRIBUTE_NONNULL(1);
virCommand *virCommandNewArgList(const char *binary, ...)
ATTRIBUTE_NONNULL(1) G_GNUC_NULL_TERMINATED;
virCommand *virCommandNewVAList(const char *binary, va_list list)
ATTRIBUTE_NONNULL(1);
/* All error report from these setup APIs is
* delayed until the Run/RunAsync methods
*/
typedef enum {
/* Close the FD in the parent */
VIR_COMMAND_PASS_FD_CLOSE_PARENT = (1 << 0),
} virCommandPassFDFlags;
void virCommandPassFD(virCommand *cmd,
int fd,
unsigned int flags) G_GNUC_NO_INLINE;
void virCommandPassFDIndex(virCommand *cmd,
int fd,
unsigned int flags,
size_t *idx) G_GNUC_NO_INLINE;
int virCommandPassFDGetFDIndex(virCommand *cmd,
int fd);
void virCommandSetPidFile(virCommand *cmd,
const char *pidfile) ATTRIBUTE_NONNULL(2);
gid_t virCommandGetGID(virCommand *cmd) ATTRIBUTE_NONNULL(1);
uid_t virCommandGetUID(virCommand *cmd) ATTRIBUTE_NONNULL(1);
void virCommandSetGID(virCommand *cmd, gid_t gid);
void virCommandSetUID(virCommand *cmd, uid_t uid);
void virCommandSetMaxMemLock(virCommand *cmd, unsigned long long bytes);
void virCommandSetMaxProcesses(virCommand *cmd, unsigned int procs);
void virCommandSetMaxFiles(virCommand *cmd, unsigned int files);
void virCommandSetMaxCoreSize(virCommand *cmd, unsigned long long bytes);
void virCommandSetUmask(virCommand *cmd, int umask);
void virCommandClearCaps(virCommand *cmd);
void virCommandAllowCap(virCommand *cmd,
int capability);
void virCommandSetSELinuxLabel(virCommand *cmd,
const char *label);
void virCommandSetAppArmorProfile(virCommand *cmd,
const char *profile);
void virCommandDaemonize(virCommand *cmd);
void virCommandNonblockingFDs(virCommand *cmd);
void virCommandRawStatus(virCommand *cmd);
util: make it easier to grab only regular command exit Auditing all callers of virCommandRun and virCommandWait that passed a non-NULL pointer for exit status turned up some interesting observations. Many callers were merely passing a pointer to avoid the overall command dying, but without caring what the exit status was - but these callers would be better off treating a child death by signal as an abnormal exit. Other callers were actually acting on the status, but not all of them remembered to filter by WIFEXITED and convert with WEXITSTATUS; depending on the platform, this can result in a status being reported as 256 times too big. And among those that correctly parse the output, it gets rather verbose. Finally, there were the callers that explicitly checked that the status was 0, and gave their own message, but with fewer details than what virCommand gives for free. So the best idea is to move the complexity out of callers and into virCommand - by default, we return the actual exit status already cleaned through WEXITSTATUS and treat signals as a failed command; but the few callers that care can ask for raw status and act on it themselves. * src/util/vircommand.h (virCommandRawStatus): New prototype. * src/libvirt_private.syms (util/command.h): Export it. * docs/internals/command.html.in: Document it. * src/util/vircommand.c (virCommandRawStatus): New function. (virCommandWait): Adjust semantics. * tests/commandtest.c (test1): Test it. * daemon/remote.c (remoteDispatchAuthPolkit): Adjust callers. * src/access/viraccessdriverpolkit.c (virAccessDriverPolkitCheck): Likewise. * src/fdstream.c (virFDStreamCloseInt): Likewise. * src/lxc/lxc_process.c (virLXCProcessStart): Likewise. * src/qemu/qemu_command.c (qemuCreateInBridgePortWithHelper): Likewise. * src/xen/xen_driver.c (xenUnifiedXendProbe): Simplify. * tests/reconnect.c (mymain): Likewise. * tests/statstest.c (mymain): Likewise. * src/bhyve/bhyve_process.c (virBhyveProcessStart) (virBhyveProcessStop): Don't overwrite virCommand error. * src/libvirt.c (virConnectAuthGainPolkit): Likewise. * src/openvz/openvz_driver.c (openvzDomainGetBarrierLimit) (openvzDomainSetBarrierLimit): Likewise. * src/util/virebtables.c (virEbTablesOnceInit): Likewise. * src/util/viriptables.c (virIpTablesOnceInit): Likewise. * src/util/virnetdevveth.c (virNetDevVethCreate): Fix debug message. * src/qemu/qemu_capabilities.c (virQEMUCapsInitQMP): Add comment. * src/storage/storage_backend_iscsi.c (virStorageBackendISCSINodeUpdate): Likewise. Signed-off-by: Eric Blake <eblake@redhat.com>
2014-02-20 00:32:19 +00:00
void virCommandAddEnvFormat(virCommand *cmd, const char *format, ...)
ATTRIBUTE_NONNULL(2) G_GNUC_PRINTF(2, 3);
void virCommandAddEnvPair(virCommand *cmd,
const char *name,
const char *value) ATTRIBUTE_NONNULL(2);
void virCommandAddEnvString(virCommand *cmd,
const char *str) ATTRIBUTE_NONNULL(2);
void virCommandAddEnvPass(virCommand *cmd,
const char *name) ATTRIBUTE_NONNULL(2);
void virCommandAddEnvPassCommon(virCommand *cmd);
void virCommandAddEnvXDG(virCommand *cmd, const char *baseDir);
void virCommandAddArg(virCommand *cmd,
const char *val) ATTRIBUTE_NONNULL(2);
void virCommandAddArgBuffer(virCommand *cmd,
virBuffer *buf);
void virCommandAddArgFormat(virCommand *cmd,
const char *format, ...)
ATTRIBUTE_NONNULL(2) G_GNUC_PRINTF(2, 3);
void virCommandAddArgPair(virCommand *cmd,
const char *name,
const char *val);
void virCommandAddArgSet(virCommand *cmd,
const char *const*vals) ATTRIBUTE_NONNULL(2);
void virCommandAddArgList(virCommand *cmd,
... /* const char *arg, ..., NULL */)
G_GNUC_NULL_TERMINATED;
void virCommandSetWorkingDirectory(virCommand *cmd,
const char *pwd) ATTRIBUTE_NONNULL(2);
int virCommandSetSendBuffer(virCommand *cmd,
unsigned char *buffer,
size_t buflen)
ATTRIBUTE_NONNULL(2);
void virCommandSetInputBuffer(virCommand *cmd,
const char *inbuf) ATTRIBUTE_NONNULL(2);
void virCommandSetOutputBuffer(virCommand *cmd,
char **outbuf) ATTRIBUTE_NONNULL(2);
void virCommandSetErrorBuffer(virCommand *cmd,
char **errbuf) ATTRIBUTE_NONNULL(2);
void virCommandSetInputFD(virCommand *cmd,
int infd);
void virCommandSetOutputFD(virCommand *cmd,
int *outfd) ATTRIBUTE_NONNULL(2);
void virCommandSetErrorFD(virCommand *cmd,
int *errfd) ATTRIBUTE_NONNULL(2);
void virCommandSetPreExecHook(virCommand *cmd,
virExecHook hook,
void *opaque) ATTRIBUTE_NONNULL(2);
void virCommandWriteArgLog(virCommand *cmd,
int logfd);
char *virCommandToString(virCommand *cmd, bool linebreaks) G_GNUC_WARN_UNUSED_RESULT;
char *virCommandToStringFull(virCommand *cmd,
bool linebreaks,
bool stripCommandPath);
int virCommandGetArgList(virCommand *cmd, char ***args, size_t *nargs);
int virCommandExec(virCommand *cmd, gid_t *groups, int ngroups) G_GNUC_WARN_UNUSED_RESULT;
int virCommandRun(virCommand *cmd,
int *exitstatus) G_GNUC_WARN_UNUSED_RESULT;
int virCommandRunAsync(virCommand *cmd,
pid_t *pid) G_GNUC_WARN_UNUSED_RESULT;
int virCommandWait(virCommand *cmd,
int *exitstatus) G_GNUC_WARN_UNUSED_RESULT;
void virCommandRequireHandshake(virCommand *cmd);
int virCommandHandshakeWait(virCommand *cmd)
G_GNUC_WARN_UNUSED_RESULT;
int virCommandHandshakeNotify(virCommand *cmd)
G_GNUC_WARN_UNUSED_RESULT;
void virCommandAbort(virCommand *cmd);
void virCommandFree(virCommand *cmd);
void virCommandDoAsyncIO(virCommand *cmd);
typedef int (*virCommandRunRegexFunc)(char **const groups,
void *data);
typedef int (*virCommandRunNulFunc)(size_t n_tokens,
char **const groups,
void *data);
int virCommandRunRegex(virCommand *cmd,
int nregex,
const char **regex,
int *nvars,
virCommandRunRegexFunc func,
void *data,
const char *cmd_to_ignore,
int *exitstatus);
int virCommandRunNul(virCommand *cmd,
size_t n_columns,
virCommandRunNulFunc func,
void *data);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(virCommand, virCommandFree);