[libvirt] [PATCHv2 3/8] Introduce new APIs for spawning processes
Daniel P. Berrange
berrange at redhat.com
Thu Dec 2 14:24:28 UTC 2010
On Wed, Dec 01, 2010 at 10:42:40PM +0100, Matthias Bolte wrote:
> 2010/11/24 Eric Blake <eblake at redhat.com>:
> > +/*
> > + * Manage input and output to the child process.
> > + */
> > +static int
> > +virCommandProcessIO(virCommandPtr cmd)
> > +{
> > + int infd = -1, outfd = -1, errfd = -1;
> > + size_t inlen = 0, outlen = 0, errlen = 0;
> > + size_t inoff = 0;
> > +
> > + /* With an input buffer, feed data to child
> > + * via pipe */
> > + if (cmd->inbuf) {
> > + inlen = strlen(cmd->inbuf);
> > + infd = cmd->inpipe;
> > + }
> > +
> > + /* With out/err buffer, the outfd/errfd
> > + * have been filled with an FD for us */
> > + if (cmd->outbuf)
> > + outfd = cmd->outfd;
> > + if (cmd->errbuf)
> > + errfd = cmd->errfd;
> > +
>
> > +/*
> > + * Run the command and wait for completion.
> > + * Returns -1 on any error executing the
> > + * command. Returns 0 if the command executed,
> > + * with the exit status set
> > + */
> > +int
> > +virCommandRun(virCommandPtr cmd, int *exitstatus)
> > +{
> > + int ret = 0;
> > + char *outbuf = NULL;
> > + char *errbuf = NULL;
> > + int infd[2];
> > +
> > + if (!cmd || cmd->has_error == -1) {
> > + virCommandError(VIR_ERR_INTERNAL_ERROR, "%s",
> > + _("invalid use of command API"));
> > + return -1;
> > + }
> > + if (cmd->has_error == ENOMEM) {
> > + virReportOOMError();
> > + return -1;
> > + }
> > +
> > + /* If we have an input buffer, we need
> > + * a pipe to feed the data to the child */
> > + if (cmd->inbuf) {
> > + if (pipe(infd) < 0) {
> > + virReportSystemError(errno, "%s",
> > + _("unable to open pipe"));
> > + return -1;
> > + }
> > + cmd->infd = infd[0];
> > + cmd->inpipe = infd[1];
> > + }
> > +
> > + if (virCommandRunAsync(cmd, NULL) < 0) {
> > + if (cmd->inbuf) {
> > + int tmpfd = infd[0];
> > + if (VIR_CLOSE(infd[0]) < 0)
> > + VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
> > + tmpfd = infd[1];
> > + if (VIR_CLOSE(infd[1]) < 0)
> > + VIR_DEBUG("ignoring failed close on fd %d", tmpfd);
> > + }
> > + return -1;
> > + }
> > +
> > + /* If caller hasn't requested capture of
> > + * stdout/err, then capture it ourselves
> > + * so we can log it
> > + */
> > + if (!cmd->outbuf &&
> > + !cmd->outfdptr) {
> > + cmd->outfd = -1;
> > + cmd->outfdptr = &cmd->outfd;
> > + cmd->outbuf = &outbuf;
> > + }
> > + if (!cmd->errbuf &&
> > + !cmd->errfdptr) {
> > + cmd->errfd = -1;
> > + cmd->errfdptr = &cmd->errfd;
> > + cmd->errbuf = &errbuf;
> > + }
> > +
> > + if (cmd->inbuf || cmd->outbuf || cmd->errbuf)
> > + ret = virCommandProcessIO(cmd);
>
> In virCommandProcessIO you say that cmd->{out|err}fd is a valid FD
> (created in virExecWithHook called by virCommandRunAsync) when
> cmd->{out|err}buf is not NULL. As far as I can tell from the code that
> is true when the caller had requested to capture stdout and stderr.
> But in case that caller didn't do this then you setup buffers to
> capture stdout and stderr for logging. In that case
> virCommandProcessIO will be called with cmd->{out|err}buf being
> non-NULL but cmd->{out|err}fd being invalid as you explicitly set them
> to -1 in the two if blocks before the call to virCommandProcessIO.
Those two blocks setting errfd/outfd to -1 are not executed
when outbuf/errbuf are non-NULL, so errfd/outfd are still
pointing to the pipe() FDs when virCommandProcesIO is run.
> > diff --git a/tests/commandtest.c b/tests/commandtest.c
> > new file mode 100644
> > index 0000000..46d6ae5
> > --- /dev/null
> > +++ b/tests/commandtest.c
>
> > +
> > +#ifndef __linux__
>
> What's Linux specific in this test? Shouldn't the command API and this
> test be working on all systems that support fork/exec?
It should have been #ifndef WIN32 actually.
Daniel
More information about the libvir-list
mailing list