[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, &micro) != 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