Daniel P. Berrange wrote:
The attached patch fixes two issues
- It explicitly checks to see if the requested /usr/bin/qemu* binary
actually exists before fork()/exec()'ing it. While its technically
possible to catch the execve() failure of ENOENT, its a real pain to
feed this error back to the qemu daemon because we're in a sub-process
at that point. The obvious & easy solution is to thus check to see if
the binary exists before trying to fork.
This is quite a hard problem to fix properly, as I'm sure you know.
If we were to change to use execvp, so making libvirt less dependent on
the precise location of qemu binaries[1] then a complete test would also
need to parse $PATH.
With SELinux an exec can fail for a lot more reasons than just lack of
the binary or lack of execute bit.
And additionally, just because we manage to execvp the qemu-* binary,
that doesn't mean that it initialises fully. In Real Life rpm ensures
that we can't install libvirt without having qemu, so qemu
initialisation failures are likely to be far more common than
cannot-exec-qemu failures.
Olwm (the old OpenLook window manager) solved both problems in this way.
From the olwm man page[2]:
-syncpid process-id
When olwm has completed its initialization, it will
send a signal (SIGALRM by default) to process-id. The
signal will be sent only if this option is present.
This is useful for running olwm from shell scripts
(such as .xinitrc) in such a way that the script waits
for olwm to finish its initialization, while leaving
olwm as a child process of the shell script. This can
be done using the following sh(1) construct:
sleep 15 & pid=$!
olwm -syncpid $pid &
wait $pid
-syncsignal signal
Specifies the signal to send instead of SIGALRM. The
signal is specified as a number, not symbolically.
(In the shell-script example shown there is no way to catch errors, but
you can easily extend this by sending SIGALRM to the parent --
indicating correct exec + initialisation -- or timing out).
OK, so this requires an upstream patch to qemu. Worth getting this in
now with the view that a few years down the line it'll be useful?
In the present, qemu has two features which seem to allow us to detect
partial or full initialisation.
The -daemonize flag in qemu explicitly allows you to do this. They use
a pipe from the child back to the parent which sends a signal back to
the parent after full initialisation has happened. Unfortunately this
means that qemu is not only not a child of libvirt, but also we no
longer have access to stdin/stdout (ie. console). We would need to make
another (good) change to allow qemu to write console sockets into a
well-known directory using qemu -monitor unix:/var/...
The -pidfile flag is a more immediate, partial solution. The pidfile is
written part way through initialisation -- the qemu process has been
exec'd and has done some work, and then works its way through the
command line arguments until it reaches this one, whereupon it creates
the file immediately. After parsing command line arguments, some
further initialisation is done, so this is not a full solution.
What do people think? Worth me working on fixing this problem properly?
Rich.
[1] It's arguable whether we should do that, or rely on configure-time
detection of the binaries. Perhaps configure-time configuration is more
secure.
[2]
http://www.umanitoba.ca/cgi-bin/man.cgi?section=1&topic=olwm