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; }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }