[libvirt] PATCH: 5/5: Make all code use virExec
Jim Meyering
jim at meyering.net
Wed Aug 20 16:40:37 UTC 2008
"Daniel P. Berrange" <berrange at 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!
> diff -r 2591ebc40bd7 src/bridge.c
...
> @@ -680,7 +645,10 @@
>
> argv[n++] = NULL;
>
> - retval = brctlSpawn(argv);
> + if (virRun(NULL, argv, NULL) < 0)
> + retval = errno;
Using errno here isn't always kosher, since _virExec doesn't always
preserve it when things go wrong (the ReportError call and close
calls after "cleanup:" can clobber errno).
But one can argue that it doesn't matter too much, since virExec
does diagnose each failure. However, that would suggest not
using errno upon virRun failure.
...
> - retval = brctlSpawn(argv);
> + if (virRun(NULL, argv, NULL) < 0)
> + retval = errno;
Likewise.
...
> diff -r 2591ebc40bd7 src/qemu_conf.c
> --- a/src/qemu_conf.c Tue Aug 12 15:29:29 2008 +0100
> +++ b/src/qemu_conf.c Tue Aug 12 15:33:42 2008 +0100
> @@ -397,116 +397,88 @@
>
>
> int qemudExtractVersionInfo(const char *qemu, int *version, int *flags) {
> + const char *const qemuarg[] = { qemu, "-help", NULL };
> + const char *const qemuenv[] = { "LANG=C", NULL };
If you have to use just one environment variable, use LC_ALL=C.
It trumps all others, when it comes to locale-related things.
> 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;
> + int major, minor, micro;
> + int ver;
If you make the above 4 variables unsigned
and adjust the %d formats accordingly, the version
parsing will be a little tighter.
> if (flags)
> *flags = 0;
> if (version)
> *version = 0;
>
> - if (pipe(newstdout) < 0) {
> + if (virExec(NULL, qemuarg, qemuenv, &child,
> + -1, &newstdout, NULL, VIR_EXEC_NONE) < 0)
> return -1;
> +
> +
> + while (got < (sizeof(help)-1)) {
> + int len;
> + if ((len = read(newstdout, help+got, sizeof(help)-got-1)) <= 0) {
> + if (!len)
> + break;
> + if (errno == EINTR)
> + continue;
> + goto cleanup2;
> + }
> + got += len;
> + }
Any reason not to use saferead in place of this while-loop?
> + help[got] = '\0';
> +
> + if (sscanf(help, "QEMU PC emulator version %d.%d.%d", &major,&minor, µ) != 3) {
> + goto cleanup2;
> }
>
> - if ((child = fork()) < 0) {
> - close(newstdout[0]);
> - close(newstdout[1]);
> - return -1;
> + 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",
If version can really be NULL, as the above "if (version)" tests
suggest, then you'll want to change "*version" here, to e.g.,
version ? *version : "NA"
Same for *flags.
> + 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"),
> + status, (unsigned long)child);
You've probably already fixed this, but "status" here is a
combination of exit status and signal number.
> + 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"),
> + status);
> }
...
> int qemudExtractVersion(virConnectPtr conn,
> diff -r 2591ebc40bd7 src/remote_internal.c
> --- a/src/remote_internal.c Tue Aug 12 15:29:29 2008 +0100
> +++ b/src/remote_internal.c Tue Aug 12 15:33:42 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,61 +222,21 @@
> remoteForkDaemon(virConnectPtr conn)
> {
> const char *daemonPath = remoteFindDaemonPath();
> + const char *daemonargs[4];
> int ret, pid, status;
> +
> + daemonargs[0] = daemonPath;
> + daemonargs[1] = "--timeout";
> + daemonargs[2] = "30";
Save an arg slot and use "--timeout=30"?
That's slightly more readable, too.
> + daemonargs[3] = NULL;
>
...
> + if (virExec(NULL, daemonargs, NULL, &pid, -1, NULL, NULL, VIR_EXEC_DAEMON) < 0)
> + error(conn, VIR_ERR_INTERNAL_ERROR, _("failed to fork libvirtd binary"));
s/ binary//, in case someday it's not a binary.
...
> + if (virExec(conn, (const char**)cmd_argv, NULL,
> + &pid, sv[1], &(sv[1]), NULL, VIR_EXEC_NONE) < 0) {
> + error (conn, VIR_ERR_SYSTEM_ERROR, strerror (errno));
Similar to the issue with virRun, whenever virExec returns nonzero,
it has already diagnosed the error and errno may be clobbered.
More information about the libvir-list
mailing list