[libvirt] [PATCH 0/3 RFC] Demonstrating a new API for spawning processes

Daniel P. Berrange berrange at redhat.com
Wed May 26 14:44:56 UTC 2010


On Tue, May 25, 2010 at 11:56:15AM -0600, Eric Blake wrote:
> On 05/25/2010 07:24 AM, Daniel P. Berrange wrote:
> > We have had great success with our APIs for memory allocation and
> > string buffer management, removing most of the potential for incorrect
> > API usage, thus avoiding many common errors. It is time todo the same
> > for command execution.
> 
> Yes, this makes a good addition.
> 
> > 
> >   Defining commands in libvirt
> > 
> >    The first step is to declare what command is to be executed. The command
> >    name can be either a fully qualified path, or a bare command name. In the
> >    latter case it will be resolved wrt the $PATH environment variable.
> 
> The $PATH of the parent process, or the $PATH of the environment passed
> to the child process?  That can make a subtle difference, if one uses
> virCommandAddEnvString(cmd, "PATH=...").

I was going to say 'the same rules as execvp' but I now realize there
is no execvp variant that also accepts a  char * argv + char *env[]. 
Only a va_args variant. And execve doesn't do path resolution.

It doesn't hugely matter which semantics we have - which do you
suggest.

> >    If an argument takes an attached value of the form -arg=val, then this can
> >    be done using
> > 
> >        virCommandAddArgPair(cmd, "--conf-file", "/etc/dnsmasq.conf");
> 
> Does this create the two arguments "--conf-file /etc/dnsmasq.conf" or
> the one argument "--conf-file=/etc/dnsmasq.conf"?

One arg. The two arg case is dealt with by just calling AddArg() twice.

> >    This has now set up a clean environment for the child, passing through
> >    PATH, LD_PRELOAD, LD_LIBRARY_PATH, HOME, USER, LOGNAME and TMPDIR.
> >    Furthermore it will explicitly set LC_ALL=C to avoid unexpected
> >    localization of command output. Further variables can be passed through
> >    from parent explicitly:
> > 
> >        virCommandAddEnvPass(cmd, "DISPLAY");
> >        virCommandAddEnvPass(cmd, "XAUTHORITY");
> 
> If the same env-var is added more than once, are we guaranteeing that
> the last one wins?  In other words, it should be easy to call
> virCommandAddEnvPassCommon(cmd) && virCommandAddEnvString(cmd,
> "PATH=...") to override just PATH.

What does execve() do if env[] has the same name twice ? We'll just
be delegating to that 

> Should there be an easy way to specify that a particular child process
> should keep the localization settings of the parent, rather than the
> LC_ALL=C of virCommandAddEnvPassCommon?

AFAIK, none of our current usage requires it, but if the conversion
of existing code requires it, we can adapt.

> >    When daemonizing a command, the PID visible from the caller will be that
> >    of the intermediate process, not the actual damonized command. If the PID
> >    of the real command is required then a pidfile can be requested
> > 
> >        virCommandSetPidFile(cmd, "/var/run/dnsmasq.pid");
> 
> Is this worth a printf-style varargs call, to make it easier to cobble
> together components?  Perhaps like:
> virCommandSetPidFile(cmd, "%s/%s.pid", LOCAL_STATE_DIR, "dnsmasq")
> 
> On the other hand, it's relatively easy to build up a string using
> virBuffer APIs, so we might as well keep the virCommand API simple.

We already have a convenient   virPidFile(path, name) function,
so probably isn't required here.

> >   Managing file handles
> > 
> >    To prevent unintended resource leaks to child processes, all open file
> >    handles will be closed in the child, and its stdin/out/err all connected
> >    to /dev/null. It is possible to allow an open file handle to be passed
> >    into the child:
> > 
> >        virCommandPreserveFD(cmd, 5);
> > 
> > 
> >    With this file descriptor 5 in the current process remains open as file
> >    descriptor 5 in the child. For stdin/out/err it is usually neccessary to
> >    map a file handle. To attach file descriptor 7 in the current process to
> >    stdin in the child:
> > 
> >        virCommandSetInputFD(cmd, 7);
> 
> Does the child see fd 7 closed in this case?

Correct, FD 7 in the parent will appear as FD 0 in the child. No FD 7
will be visible in the child.

> >        virCommandSetOutputFD(cmd, &outfd);
> >        virCommandSetErrorFD(cmd, &errfd);
> > 
> > 
> >    Once the command is running, outfd and errfd will be initialized with
> >    valid file handles that can be read from.
> 
> Any restrictions on when (or even if) the parent process may/must call
> close(outfd)?  In other words, must the parent's side of the output fd
> remain open until the exit status of the child has been collected, and
> does collecting the child's status automatically close the parent's side?

I'm intending to declare that the caller must close these FDs when
it decides best.

> >   Feeding & capturing strings to/from the child
> > 
> >    Often dealing with file handles for stdin/out/err is unneccessarily
> >    complex. It is possible to specify a string buffer to act as the data
> >    source for the child's stdin
> > 
> >        const char *input = "Hello World\n";
> >        virCommandSetInputBuffer(cmd, input);
> 
> Any limitations to be aware of to avoid I/O deadlock when set up as a
> bi-directional pipe to the child?

The impl of virCommandRun() calls out to virProcessIO which uses
select() to wait on the stdin+out+err, so we can avoid blocking.
But this reminds me that I should set the FDs O_NONBLOCK


Daniel
-- 
|: Red Hat, Engineering, London    -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org -o- http://virt-manager.org -o- http://deltacloud.org :|
|: http://autobuild.org        -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-   F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list