On Wed, Aug 20, 2008 at 06:40:37PM +0200, Jim Meyering wrote:
"Daniel P. Berrange" <berrange(a)redhat.com> wrote:
> This final patch switches over all places which do fork()/exec() to use the
> new enhanced virExec() code. A fair amount of code is deleted, but that's
> not the whole story - the new impl is more robust that most of the existing
> code we're deleting here.
Nice clean-up!
I believe I've addressed all the comments you had - its quite a significant
change from the previous patch. I was in fact able to simplify the bridge.c
file even more than I did before.
bridge.c | 128 ++++--------------------------------
proxy_internal.c | 26 +------
qemu_conf.c | 188 +++++++++++++++++++++++-------------------------------
qemu_conf.h | 8 +-
qemu_driver.c | 15 +---
remote_internal.c | 101 +++--------------------------
6 files changed, 125 insertions(+), 341 deletions(-)
Daniel
diff -r c3d345142e1b src/bridge.c
--- a/src/bridge.c Wed Aug 27 12:45:11 2008 +0100
+++ b/src/bridge.c Wed Aug 27 14:09:26 2008 +0100
@@ -46,6 +46,7 @@
#include "internal.h"
#include "memory.h"
+#include "util.h"
#define MAX_BRIDGE_ID 256
@@ -596,42 +597,6 @@
return brGetInetAddr(ctl, ifname, SIOCGIFNETMASK, addr, maxlen);
}
-static int
-brctlSpawn(char * const *argv)
-{
- pid_t pid, ret;
- int status;
- int null = -1;
-
- if ((null = open(_PATH_DEVNULL, O_RDONLY)) < 0)
- return errno;
-
- pid = fork();
- if (pid == -1) {
- int saved_errno = errno;
- close(null);
- return saved_errno;
- }
-
- if (pid == 0) { /* child */
- dup2(null, STDIN_FILENO);
- dup2(null, STDOUT_FILENO);
- dup2(null, STDERR_FILENO);
- close(null);
-
- execvp(argv[0], argv);
-
- _exit (1);
- }
-
- close(null);
-
- while ((ret = waitpid(pid, &status, 0) == -1) && errno == EINTR);
- if (ret == -1)
- return errno;
-
- return (WIFEXITED(status) && WEXITSTATUS(status) == 0) ? 0 : EINVAL;
-}
/**
* brSetForwardDelay:
@@ -641,7 +606,7 @@
*
* Set the bridge forward delay
*
- * Returns 0 in case of success or an errno code in case of failure.
+ * Returns 0 in case of success or -1 on failure
*/
int
@@ -649,48 +614,17 @@
const char *bridge,
int delay)
{
- char **argv;
- int retval = ENOMEM;
- int n;
char delayStr[30];
-
- n = 1 + /* brctl */
- 1 + /* setfd */
- 1 + /* brige name */
- 1; /* value */
+ const char *const progargv[] = {
+ BRCTL, "setfd", bridge, delayStr, NULL
+ };
snprintf(delayStr, sizeof(delayStr), "%d", delay);
- if (VIR_ALLOC_N(argv, n + 1) < 0)
- goto error;
+ if (virRun(NULL, progargv, NULL) < 0)
+ return -1;
- n = 0;
-
- if (!(argv[n++] = strdup(BRCTL)))
- goto error;
-
- if (!(argv[n++] = strdup("setfd")))
- goto error;
-
- if (!(argv[n++] = strdup(bridge)))
- goto error;
-
- if (!(argv[n++] = strdup(delayStr)))
- goto error;
-
- argv[n++] = NULL;
-
- retval = brctlSpawn(argv);
-
- error:
- if (argv) {
- n = 0;
- while (argv[n])
- VIR_FREE(argv[n++]);
- VIR_FREE(argv);
- }
-
- return retval;
+ return 0;
}
/**
@@ -702,52 +636,22 @@
* Control whether the bridge participates in the spanning tree protocol,
* in general don't disable it without good reasons.
*
- * Returns 0 in case of success or an errno code in case of failure.
+ * Returns 0 in case of success or -1 on failure
*/
int
brSetEnableSTP(brControl *ctl ATTRIBUTE_UNUSED,
const char *bridge,
int enable)
{
- char **argv;
- int retval = ENOMEM;
- int n;
+ const char *setting = enable ? "on" : "off";
+ const char *const progargv[] = {
+ BRCTL, "stp", bridge, setting, NULL
+ };
- n = 1 + /* brctl */
- 1 + /* stp */
- 1 + /* brige name */
- 1; /* value */
+ if (virRun(NULL, progargv, NULL) < 0)
+ return -1;
- if (VIR_ALLOC_N(argv, n + 1) < 0)
- goto error;
-
- n = 0;
-
- if (!(argv[n++] = strdup(BRCTL)))
- goto error;
-
- if (!(argv[n++] = strdup("stp")))
- goto error;
-
- if (!(argv[n++] = strdup(bridge)))
- goto error;
-
- if (!(argv[n++] = strdup(enable ? "on" : "off")))
- goto error;
-
- argv[n++] = NULL;
-
- retval = brctlSpawn(argv);
-
- error:
- if (argv) {
- n = 0;
- while (argv[n])
- VIR_FREE(argv[n++]);
- VIR_FREE(argv);
- }
-
- return retval;
+ return 0;
}
#endif /* WITH_QEMU || WITH_LXC */
diff -r c3d345142e1b src/proxy_internal.c
--- a/src/proxy_internal.c Wed Aug 27 12:45:11 2008 +0100
+++ b/src/proxy_internal.c Wed Aug 27 14:09:26 2008 +0100
@@ -160,6 +160,7 @@
{
const char *proxyPath = virProxyFindServerPath();
int ret, pid, status;
+ const char *proxyarg[2];
if (!proxyPath) {
fprintf(stderr, "failed to find libvirt_proxy\n");
@@ -169,27 +170,12 @@
if (debug)
fprintf(stderr, "Asking to launch %s\n", proxyPath);
- /* Become a daemon */
- pid = fork();
- if (pid == 0) {
- long open_max;
- long i;
+ proxyarg[0] = proxyPath;
+ proxyarg[1] = NULL;
- /* don't hold open fd opened from the client of the library */
- open_max = sysconf (_SC_OPEN_MAX);
- for (i = 0; i < open_max; i++)
- fcntl (i, F_SETFD, FD_CLOEXEC);
-
- setsid();
- if (fork() == 0) {
- execl(proxyPath, proxyPath, NULL);
- fprintf(stderr, _("failed to exec %s\n"), proxyPath);
- }
- /*
- * calling exit() generate troubles for termination handlers
- */
- _exit(0);
- }
+ if (virExec(NULL, proxyarg, NULL, NULL,
+ &pid, -1, NULL, NULL, VIR_EXEC_DAEMON) < 0)
+ fprintf(stderr, "Failed to fork libvirt_proxy\n");
/*
* do a waitpid on the intermediate process to avoid zombies.
diff -r c3d345142e1b src/qemu_conf.c
--- a/src/qemu_conf.c Wed Aug 27 12:45:11 2008 +0100
+++ b/src/qemu_conf.c Wed Aug 27 14:09:26 2008 +0100
@@ -394,124 +394,100 @@
}
-int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) {
+int qemudExtractVersionInfo(const char *qemu,
+ unsigned int *retversion,
+ unsigned int *retflags) {
+ const char *const qemuarg[] = { qemu, "-help", NULL };
+ const char *const qemuenv[] = { "LC_ALL=C", NULL };
pid_t child;
- int newstdout[2];
+ int newstdout = -1;
+ char help[8192]; /* Ought to be enough to hold QEMU help screen */
+ int got = 0, ret = -1, status;
+ unsigned int major, minor, micro;
+ unsigned int version;
+ unsigned int flags = 0;
- if (flags)
- *flags = 0;
- if (version)
- *version = 0;
+ if (retflags)
+ *retflags = 0;
+ if (retversion)
+ *retversion = 0;
- if (pipe(newstdout) < 0) {
+ if (virExec(NULL, qemuarg, qemuenv, NULL,
+ &child, -1, &newstdout, NULL, VIR_EXEC_NONE) < 0)
return -1;
+
+
+ while (got < (sizeof(help)-1)) {
+ int len;
+ if ((len = saferead(newstdout, help+got, sizeof(help)-got-1)) < 0)
+ goto cleanup2;
+ if (!len)
+ break;
+ got += len;
+ }
+ help[got] = '\0';
+
+ if (sscanf(help, "QEMU PC emulator version %u.%u.%u",
+ &major, &minor, µ) != 3) {
+ goto cleanup2;
}
- if ((child = fork()) < 0) {
- close(newstdout[0]);
- close(newstdout[1]);
- return -1;
+ version = (major * 1000 * 1000) + (minor * 1000) + micro;
+
+ if (strstr(help, "-no-kqemu"))
+ flags |= QEMUD_CMD_FLAG_KQEMU;
+ if (strstr(help, "-no-reboot"))
+ flags |= QEMUD_CMD_FLAG_NO_REBOOT;
+ if (strstr(help, "-name"))
+ flags |= QEMUD_CMD_FLAG_NAME;
+ if (strstr(help, "-drive"))
+ flags |= QEMUD_CMD_FLAG_DRIVE;
+ if (strstr(help, "boot=on"))
+ flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
+ if (version >= 9000)
+ flags |= QEMUD_CMD_FLAG_VNC_COLON;
+
+
+ if (retversion)
+ *retversion = version;
+ if (retflags)
+ *retflags = flags;
+
+ ret = 0;
+
+ qemudDebug("Version %d %d %d Cooked version: %d, with flags ? %d",
+ major, minor, micro, version, flags);
+
+cleanup2:
+ if (close(newstdout) < 0)
+ ret = -1;
+
+rewait:
+ if (waitpid(child, &status, 0) != child) {
+ if (errno == EINTR)
+ goto rewait;
+
+ qemudLog(QEMUD_ERR,
+ _("Unexpected exit status from qemu %d pid %lu"),
+ WEXITSTATUS(status), (unsigned long)child);
+ ret = -1;
+ }
+ /* Check & log unexpected exit status, but don't fail,
+ * as there's really no need to throw an error if we did
+ * actually read a valid version number above */
+ if (WEXITSTATUS(status) != 0) {
+ qemudLog(QEMUD_WARN,
+ _("Unexpected exit status '%d', qemu probably
failed"),
+ WEXITSTATUS(status));
}
- if (child == 0) { /* Kid */
- /* Just in case QEMU is translated someday we force to C locale.. */
- const char *const qemuenv[] = { "LANG=C", NULL };
-
- if (close(STDIN_FILENO) < 0)
- goto cleanup1;
- if (close(STDERR_FILENO) < 0)
- goto cleanup1;
- if (close(newstdout[0]) < 0)
- goto cleanup1;
- if (dup2(newstdout[1], STDOUT_FILENO) < 0)
- goto cleanup1;
-
- /* Passing -help, rather than relying on no-args which doesn't
- always work */
- execle(qemu, qemu, "-help", (char*)NULL, qemuenv);
-
- cleanup1:
- _exit(-1); /* Just in case */
- } else { /* Parent */
- char help[8192]; /* Ought to be enough to hold QEMU help screen */
- int got = 0, ret = -1;
- int major, minor, micro;
- int ver;
-
- if (close(newstdout[1]) < 0)
- goto cleanup2;
-
- while (got < (sizeof(help)-1)) {
- int len;
- if ((len = read(newstdout[0], help+got, sizeof(help)-got-1)) <= 0) {
- if (!len)
- break;
- if (errno == EINTR)
- continue;
- goto cleanup2;
- }
- got += len;
- }
- help[got] = '\0';
-
- if (sscanf(help, "QEMU PC emulator version %d.%d.%d",
&major,&minor, µ) != 3) {
- goto cleanup2;
- }
-
- ver = (major * 1000 * 1000) + (minor * 1000) + micro;
- if (version)
- *version = ver;
- if (flags) {
- if (strstr(help, "-no-kqemu"))
- *flags |= QEMUD_CMD_FLAG_KQEMU;
- if (strstr(help, "-no-reboot"))
- *flags |= QEMUD_CMD_FLAG_NO_REBOOT;
- if (strstr(help, "-name"))
- *flags |= QEMUD_CMD_FLAG_NAME;
- if (strstr(help, "-drive"))
- *flags |= QEMUD_CMD_FLAG_DRIVE;
- if (strstr(help, "boot=on"))
- *flags |= QEMUD_CMD_FLAG_DRIVE_BOOT;
- if (ver >= 9000)
- *flags |= QEMUD_CMD_FLAG_VNC_COLON;
- }
- ret = 0;
-
- qemudDebug("Version %d %d %d Cooked version: %d, with flags ? %d",
- major, minor, micro, *version, *flags);
-
- cleanup2:
- if (close(newstdout[0]) < 0)
- ret = -1;
-
- rewait:
- if (waitpid(child, &got, 0) != child) {
- if (errno == EINTR) {
- goto rewait;
- }
- qemudLog(QEMUD_ERR,
- _("Unexpected exit status from qemu %d pid %lu"),
- got, (unsigned long)child);
- ret = -1;
- }
- /* Check & log unexpected exit status, but don't fail,
- * as there's really no need to throw an error if we did
- * actually read a valid version number above */
- if (WEXITSTATUS(got) != 0) {
- qemudLog(QEMUD_WARN,
- _("Unexpected exit status '%d', qemu probably
failed"),
- got);
- }
-
- return ret;
- }
+ return ret;
}
int qemudExtractVersion(virConnectPtr conn,
struct qemud_driver *driver) {
const char *binary;
struct stat sb;
- int ignored;
if (driver->qemuVersion > 0)
return 0;
@@ -529,7 +505,7 @@
return -1;
}
- if (qemudExtractVersionInfo(binary, &driver->qemuVersion, &ignored) <
0) {
+ if (qemudExtractVersionInfo(binary, &driver->qemuVersion, NULL) < 0) {
return -1;
}
@@ -716,7 +692,7 @@
int qemudBuildCommandLine(virConnectPtr conn,
struct qemud_driver *driver,
virDomainObjPtr vm,
- int qemuCmdFlags,
+ unsigned int qemuCmdFlags,
const char ***retargv,
int **tapfds,
int *ntapfds,
diff -r c3d345142e1b src/qemu_conf.h
--- a/src/qemu_conf.h Wed Aug 27 12:45:11 2008 +0100
+++ b/src/qemu_conf.h Wed Aug 27 14:09:26 2008 +0100
@@ -49,7 +49,7 @@
/* Main driver state */
struct qemud_driver {
- int qemuVersion;
+ unsigned int qemuVersion;
int nextvmid;
virDomainObjPtr domains;
@@ -86,13 +86,13 @@
int qemudExtractVersion (virConnectPtr conn,
struct qemud_driver *driver);
int qemudExtractVersionInfo (const char *qemu,
- int *version,
- int *flags);
+ unsigned int *version,
+ unsigned int *flags);
int qemudBuildCommandLine (virConnectPtr conn,
struct qemud_driver *driver,
virDomainObjPtr dom,
- int qemuCmdFlags,
+ unsigned int qemuCmdFlags,
const char ***argv,
int **tapfds,
int *ntapfds,
diff -r c3d345142e1b src/qemu_driver.c
--- a/src/qemu_driver.c Wed Aug 27 12:45:11 2008 +0100
+++ b/src/qemu_driver.c Wed Aug 27 14:09:26 2008 +0100
@@ -312,6 +312,7 @@
qemudActive(void) {
virDomainObjPtr dom = qemu_driver->domains;
virNetworkObjPtr net = qemu_driver->networks;
+
while (dom) {
if (virDomainIsActive(dom))
return 1;
@@ -846,7 +847,7 @@
struct stat sb;
int *tapfds = NULL;
int ntapfds = 0;
- int qemuCmdFlags;
+ unsigned int qemuCmdFlags;
fd_set keepfd;
FD_ZERO(&keepfd);
@@ -1509,19 +1510,11 @@
}
- if ((err = brSetForwardDelay(driver->brctl, network->def->bridge,
network->def->delay))) {
- qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- _("failed to set bridge forward delay to %ld"),
- network->def->delay);
+ if (brSetForwardDelay(driver->brctl, network->def->bridge,
network->def->delay) < 0)
goto err_delbr;
- }
- if ((err = brSetEnableSTP(driver->brctl, network->def->bridge,
network->def->stp ? 1 : 0))) {
- qemudReportError(conn, NULL, NULL, VIR_ERR_INTERNAL_ERROR,
- _("failed to set bridge STP to %s"),
- network->def->stp ? "on" : "off");
+ if (brSetEnableSTP(driver->brctl, network->def->bridge,
network->def->stp ? 1 : 0) < 0)
goto err_delbr;
- }
if (network->def->ipAddress &&
(err = brSetInetAddress(driver->brctl, network->def->bridge,
network->def->ipAddress))) {
diff -r c3d345142e1b src/remote_internal.c
--- a/src/remote_internal.c Wed Aug 27 12:45:11 2008 +0100
+++ b/src/remote_internal.c Wed Aug 27 14:09:26 2008 +0100
@@ -72,6 +72,7 @@
#include "remote_internal.h"
#include "remote_protocol.h"
#include "memory.h"
+#include "util.h"
#define DEBUG(fmt,...) VIR_DEBUG(__FILE__, fmt,__VA_ARGS__)
#define DEBUG0(msg) VIR_DEBUG(__FILE__, "%s", msg)
@@ -221,62 +222,17 @@
remoteForkDaemon(virConnectPtr conn)
{
const char *daemonPath = remoteFindDaemonPath();
+ const char *const daemonargs[] = { daemonPath, "--timeout=30", NULL };
int ret, pid, status;
if (!daemonPath) {
error(conn, VIR_ERR_INTERNAL_ERROR, _("failed to find libvirtd
binary"));
- return(-1);
- }
-
- /* Become a daemon */
- pid = fork();
- if (pid == 0) {
- int stdinfd = -1;
- int stdoutfd = -1;
- int i, open_max;
- if ((stdinfd = open(_PATH_DEVNULL, O_RDONLY)) < 0)
- goto cleanup;
- if ((stdoutfd = open(_PATH_DEVNULL, O_WRONLY)) < 0)
- goto cleanup;
- if (dup2(stdinfd, STDIN_FILENO) != STDIN_FILENO)
- goto cleanup;
- if (dup2(stdoutfd, STDOUT_FILENO) != STDOUT_FILENO)
- goto cleanup;
- if (dup2(stdoutfd, STDERR_FILENO) != STDERR_FILENO)
- goto cleanup;
- if (close(stdinfd) < 0)
- goto cleanup;
- stdinfd = -1;
- if (close(stdoutfd) < 0)
- goto cleanup;
- stdoutfd = -1;
-
- open_max = sysconf (_SC_OPEN_MAX);
- for (i = 0; i < open_max; i++)
- if (i != STDIN_FILENO &&
- i != STDOUT_FILENO &&
- i != STDERR_FILENO)
- close(i);
-
- setsid();
- if (fork() == 0) {
- /* Run daemon in auto-shutdown mode, so it goes away when
- no longer needed by an active guest, or client */
- execl(daemonPath, daemonPath, "--timeout", "30", NULL);
- }
- /*
- * calling exit() generate troubles for termination handlers
- */
- _exit(0);
-
- cleanup:
- if (stdoutfd != -1)
- close(stdoutfd);
- if (stdinfd != -1)
- close(stdinfd);
- _exit(-1);
- }
-
+ return -1;
+ }
+
+ if (virExec(NULL, daemonargs, NULL, NULL,
+ &pid, -1, NULL, NULL, VIR_EXEC_DAEMON) < 0)
+ return -1;
/*
* do a waitpid on the intermediate process to avoid zombies.
*/
@@ -287,7 +243,7 @@
goto retry_wait;
}
- return (0);
+ return 0;
}
#endif
@@ -349,7 +305,7 @@
char *name = 0, *command = 0, *sockname = 0, *netcat = 0, *username = 0;
char *port = 0, *authtype = 0;
int no_verify = 0, no_tty = 0;
- char **cmd_argv = 0;
+ char **cmd_argv = NULL;
/* Return code from this function, and the private data. */
int retcode = VIR_DRV_OPEN_ERROR;
@@ -693,40 +649,9 @@
goto failed;
}
- pid = fork ();
- if (pid == -1) {
- errorf (conn, VIR_ERR_SYSTEM_ERROR,
- _("unable to fork external network transport: %s"),
- strerror (errno));
- goto failed;
- } else if (pid == 0) { /* Child. */
- close (sv[0]);
- // Connect socket (sv[1]) to stdin/stdout.
- close (0);
- if (dup (sv[1]) == -1) {
- perror ("dup");
- _exit(1);
- }
- close (1);
- if (dup (sv[1]) == -1) {
- perror ("dup");
- _exit(1);
- }
- close (sv[1]);
-
- // Run the external process.
- if (!cmd_argv) {
- if (VIR_ALLOC_N(cmd_argv, 2) < 0) {
- perror("malloc");
- _exit(1);
- }
- cmd_argv[0] = command;
- cmd_argv[1] = 0;
- }
- execvp (command, cmd_argv);
- perror (command);
- _exit (1);
- }
+ if (virExec(conn, (const char**)cmd_argv, NULL, NULL,
+ &pid, sv[1], &(sv[1]), NULL, VIR_EXEC_NONE) < 0)
+ goto failed;
/* Parent continues here. */
close (sv[1]);
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|