static gboolean
sysroot_setup_stdout_redirect (RpmostreedSysroot *self,
                               GError **error)
{
  g_autoptr(GInputStream) stream = NULL;
  g_autoptr(GSource) source = NULL;
  StdoutClosure *closure;
  gint pipefd[2];
  gboolean ret = FALSE;

  /* XXX libostree logs messages to systemd's journal and also to stdout.
   *     Redirect our own stdout back to ourselves so we can capture those
   *     messages and pass them on to clients.  Admittedly hokey but avoids
   *     hacking libostree directly (for now). */

  closure = g_slice_new0 (StdoutClosure);
  g_weak_ref_set (&closure->sysroot, self);

  /* Save the real stdout before overwriting its file descriptor. */
  closure->real_stdout = g_unix_output_stream_new (dup (STDOUT_FILENO), FALSE);

  if (pipe (pipefd) < 0)
    {
      glnx_set_prefix_error_from_errno (error, "%s", "pipe() failed");
      goto out;
    }

  if (dup2 (pipefd[1], STDOUT_FILENO) < 0)
    {
      glnx_set_prefix_error_from_errno (error, "%s", "dup2() failed");
      goto out;
    }

  stream = g_memory_input_stream_new ();
  closure->data_stream = g_data_input_stream_new (stream);
  g_clear_object (&stream);

  stream = g_unix_input_stream_new (pipefd[0], FALSE);

  source = g_pollable_input_stream_create_source (G_POLLABLE_INPUT_STREAM (stream),
                                                  NULL);
  /* Transfer ownership of the StdoutClosure. */
  g_source_set_callback (source,
                         (GSourceFunc) sysroot_stdout_ready_cb,
                         closure,
                         (GDestroyNotify) stdout_closure_free);
  closure = NULL;

  self->stdout_source_id = g_source_attach (source, NULL);

  ret = TRUE;

out:
  if (closure != NULL)
    stdout_closure_free (closure);

  return ret;
}
Example #2
0
/**
 * glnx_dirfd_iterator_next_dent:
 * @dfd_iter: A directory iterator
 * @out_dent: (out) (transfer none): Pointer to dirent; do not free
 * @cancellable: Cancellable
 * @error: Error
 *
 * Read the next value from @dfd_iter, causing @out_dent to be
 * updated.  If end of stream is reached, @out_dent will be set
 * to %NULL, and %TRUE will be returned.
 */
gboolean
glnx_dirfd_iterator_next_dent (GLnxDirFdIterator  *dfd_iter,
                               struct dirent     **out_dent,
                               GCancellable       *cancellable,
                               GError             **error)
{
  gboolean ret = FALSE;
  GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter;

  g_return_val_if_fail (out_dent, FALSE);

  if (g_cancellable_set_error_if_cancelled (cancellable, error))
    goto out;

  do
    {
      errno = 0;
      *out_dent = readdir (real_dfd_iter->d);
      if (*out_dent == NULL && errno != 0)
        {
          glnx_set_prefix_error_from_errno (error, "%s", "fdopendir");
          goto out;
        }
    } while (*out_dent &&
             (strcmp ((*out_dent)->d_name, ".") == 0 ||
              strcmp ((*out_dent)->d_name, "..") == 0));

  ret = TRUE;
 out:
  return ret;
}
Example #3
0
/**
 * glnx_mkdtempat:
 * @dfd: Directory fd
 * @tmpl: (type filename): template directory name, last 6 characters will be replaced
 * @mode: permissions to create the temporary directory with
 * @error: Error
 *
 * Similar to g_mkdtemp_full, but using openat.
 */
gboolean
glnx_mkdtempat (int dfd,
                gchar *tmpl,
                int mode,
                GError **error)
{
  int count;

  g_return_val_if_fail (tmpl != NULL, -1);

  for (count = 0; count < 100; count++)
    {
      glnx_gen_temp_name (tmpl);

      if (mkdirat (dfd, tmpl, mode) == -1)
        {
          if (errno == EEXIST)
            continue;

          /* Any other error will apply also to other names we might
           *  try, and there are 2^32 or so of them, so give up now.
           */
          glnx_set_prefix_error_from_errno (error, "%s", "mkdirat");
          return FALSE;
        }

      return TRUE;
    }

  g_set_error (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
               "mkstempat ran out of combinations to try.");
  return FALSE;
}
Example #4
0
/**
 * glnx_opendirat:
 * @dfd: File descriptor for origin directory
 * @path: Pathname, relative to @dfd
 * @follow: Whether or not to follow symbolic links
 * @error: Error
 *
 * Use openat() to open a directory, using a standard set of flags.
 */
gboolean
glnx_opendirat (int             dfd,
                const char     *path,
                gboolean        follow,
                int            *out_fd,
                GError        **error)
{
  int ret = glnx_opendirat_with_errno (dfd, path, follow);
  if (ret == -1)
    {
      glnx_set_prefix_error_from_errno (error, "%s", "openat");
      return FALSE;
    }
  *out_fd = ret;
  return TRUE;
}
Example #5
0
/**
 * glnx_dirfd_iterator_init_take_fd:
 * @dfd: File descriptor - ownership is taken
 * @dfd_iter: A directory iterator
 * @error: Error
 *
 * Steal ownership of @dfd, using it to initialize @dfd_iter for
 * iteration.
 */
gboolean
glnx_dirfd_iterator_init_take_fd (int                dfd,
                                  GLnxDirFdIterator *dfd_iter,
                                  GError           **error)
{
  gboolean ret = FALSE;
  GLnxRealDirfdIterator *real_dfd_iter = (GLnxRealDirfdIterator*) dfd_iter;
  DIR *d = NULL;

  d = fdopendir (dfd);
  if (!d)
    {
      glnx_set_prefix_error_from_errno (error, "%s", "fdopendir");
      goto out;
    }

  real_dfd_iter->fd = dfd;
  real_dfd_iter->d = d;

  ret = TRUE;
 out:
  return ret;
}