Blame support/support_capture_subprocess.c

Packit 6c4009
/* Capture output from a subprocess.
Packit 6c4009
   Copyright (C) 2017-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit Service e7925c
#include <support/subprocess.h>
Packit 6c4009
#include <support/capture_subprocess.h>
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <support/check.h>
Packit 6c4009
#include <support/xunistd.h>
Packit 6c4009
#include <support/xsocket.h>
Packit Service e7925c
#include <support/xspawn.h>
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream)
Packit 6c4009
{
Packit 6c4009
  if (pfd->revents != 0)
Packit 6c4009
    {
Packit 6c4009
      char buf[1024];
Packit 6c4009
      ssize_t ret = TEMP_FAILURE_RETRY (read (pfd->fd, buf, sizeof (buf)));
Packit 6c4009
      if (ret < 0)
Packit 6c4009
        {
Packit 6c4009
          support_record_failure ();
Packit 6c4009
          printf ("error: reading from subprocess %s: %m", what);
Packit 6c4009
          pfd->events = 0;
Packit 6c4009
          pfd->revents = 0;
Packit 6c4009
        }
Packit 6c4009
      else if (ret == 0)
Packit 6c4009
        {
Packit 6c4009
          /* EOF reached.  Stop listening.  */
Packit 6c4009
          pfd->events = 0;
Packit 6c4009
          pfd->revents = 0;
Packit 6c4009
        }
Packit 6c4009
      else
Packit 6c4009
        /* Store the data just read.   */
Packit 6c4009
        TEST_VERIFY (fwrite (buf, ret, 1, stream->out) == 1);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit Service e7925c
static void
Packit Service e7925c
support_capture_poll (struct support_capture_subprocess *result,
Packit Service e7925c
                     struct support_subprocess *proc)
Packit Service d2291c
{
Packit Service 6de65a
  struct pollfd fds[2] =
Packit Service 6de65a
    {
Packit Service e7925c
      { .fd = proc->stdout_pipe[0], .events = POLLIN },
Packit Service e7925c
      { .fd = proc->stderr_pipe[0], .events = POLLIN },
Packit Service 6de65a
    };
Packit Service d2291c
Packit Service 6de65a
  do
Packit Service 6de65a
    {
Packit Service 6de65a
      xpoll (fds, 2, -1);
Packit Service e7925c
      transfer ("stdout", &fds[0], &result->out);
Packit Service e7925c
      transfer ("stderr", &fds[1], &result->err);
Packit Service 6de65a
    }
Packit Service 6de65a
  while (fds[0].events != 0 || fds[1].events != 0);
Packit Service e7925c
  xfclose_memstream (&result->out);
Packit Service e7925c
  xfclose_memstream (&result->err);
Packit Service e7925c
Packit Service e7925c
  result->status = support_process_wait (proc);
Packit Service e7925c
}
Packit Service e7925c
Packit Service e7925c
struct support_capture_subprocess
Packit Service e7925c
support_capture_subprocess (void (*callback) (void *), void *closure)
Packit Service e7925c
{
Packit Service e7925c
  struct support_capture_subprocess result;
Packit Service e7925c
  xopen_memstream (&result.out);
Packit Service e7925c
  xopen_memstream (&result.err);
Packit Service e7925c
Packit Service e7925c
  struct support_subprocess proc = support_subprocess (callback, closure);
Packit Service e7925c
Packit Service e7925c
  support_capture_poll (&result, &proc;;
Packit Service e7925c
  return result;
Packit Service e7925c
}
Packit Service e7925c
Packit Service e7925c
struct support_capture_subprocess
Packit Service e7925c
support_capture_subprogram (const char *file, char *const argv[])
Packit Service e7925c
{
Packit Service e7925c
  struct support_capture_subprocess result;
Packit Service e7925c
  xopen_memstream (&result.out);
Packit Service e7925c
  xopen_memstream (&result.err);
Packit Service e7925c
Packit Service e7925c
  struct support_subprocess proc = support_subprogram (file, argv);
Packit 6c4009
Packit Service e7925c
  support_capture_poll (&result, &proc;;
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
support_capture_subprocess_free (struct support_capture_subprocess *p)
Packit 6c4009
{
Packit 6c4009
  free (p->out.buffer);
Packit 6c4009
  free (p->err.buffer);
Packit 6c4009
}