diff options
Diffstat (limited to 'egg/egg-spawn.c')
-rw-r--r-- | egg/egg-spawn.c | 377 |
1 files changed, 0 insertions, 377 deletions
diff --git a/egg/egg-spawn.c b/egg/egg-spawn.c deleted file mode 100644 index 46f409ba..00000000 --- a/egg/egg-spawn.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * gnome-keyring - * - * Copyright (C) 2009 Stefan Walter - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation; either version 2.1 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this program; if not, see - * <http://www.gnu.org/licenses/>. - */ - -#include "config.h" - -#include "egg-spawn.h" - -#include <glib/gi18n-lib.h> - -#include <errno.h> -#include <string.h> -#include <unistd.h> - -#include <sys/select.h> -#include <sys/wait.h> - -typedef struct _CallbackSource { - GSource source; - EggSpawnCallbacks callbacks; - GPollFD polls[3]; -} CallbackSource; - -static void -close_fd (int *fd) -{ - g_assert (fd); - if (*fd >= 0) - close (*fd); - *fd = -1; -} - -static void -close_poll (GSource *source, GPollFD *poll) -{ - g_source_remove_poll (source, poll); - close_fd (&poll->fd); - poll->revents = 0; -} - -static gboolean -unused_callback (gpointer data) -{ - /* Never called */ - g_assert_not_reached (); - return FALSE; -} - -static gboolean -cb_source_prepare (GSource *source, gint *timeout_) -{ - CallbackSource *cb_source = (CallbackSource*)source; - gint i; - - for (i = 0; i < 3; ++i) { - if (cb_source->polls[i].fd >= 0) - return FALSE; - } - - /* If none of the FDs are valid, then process immediately */ - return TRUE; -} - -static gboolean -cb_source_check (GSource *source) -{ - CallbackSource *cb_source = (CallbackSource*)source; - gint i; - - for (i = 0; i < 3; ++i) { - if (cb_source->polls[i].fd >= 0 && cb_source->polls[i].revents != 0) - return TRUE; - } - return FALSE; -} - -static void -cb_source_finalize (GSource *source) -{ - CallbackSource *cb_source = (CallbackSource*)source; - gint i; - - for (i = 0; i < 3; ++i) - close_fd (&cb_source->polls[i].fd); -} - -static gboolean -cb_source_dispatch (GSource *source, GSourceFunc unused, gpointer user_data) -{ - CallbackSource *cb_source = (CallbackSource*)source; - GPollFD *poll; - gint i; - - /* Standard input */ - poll = &cb_source->polls[0]; - if (poll->fd >= 0 && poll->revents != 0) { - g_assert (cb_source->callbacks.standard_input); - if (!(cb_source->callbacks.standard_input) (poll->fd, user_data)) - close_poll (source, poll); - } - - /* Standard output */ - poll = &cb_source->polls[1]; - if (poll->fd >= 0 && poll->revents != 0) { - g_assert (cb_source->callbacks.standard_output); - if (!(cb_source->callbacks.standard_output) (poll->fd, user_data)) - close_poll (source, poll); - } - - /* Standard error */ - poll = &cb_source->polls[2]; - if (poll->fd >= 0 && poll->revents != 0) { - g_assert (cb_source->callbacks.standard_error); - if (!(cb_source->callbacks.standard_error) (poll->fd, user_data)) - close_poll (source, poll); - } - - for (i = 0; i < 3; ++i) { - if (cb_source->polls[i].fd >= 0) - return TRUE; - } - - /* All input and output is done */ - if (cb_source->callbacks.completed) - (cb_source->callbacks.completed) (user_data); - return FALSE; -} - -static GSourceFuncs cb_source_funcs = { - cb_source_prepare, - cb_source_check, - cb_source_dispatch, - cb_source_finalize, -}; - -guint -egg_spawn_async_with_callbacks (const gchar *working_directory, gchar **argv, - gchar **envp, GSpawnFlags flags, GPid *child_pid, - EggSpawnCallbacks *cbs, gpointer user_data, - GMainContext *context, GError **error) -{ - gint in_fd, out_fd, err_fd; - CallbackSource *cb_source; - GSource *source; - guint tag; - - g_return_val_if_fail (argv != NULL, FALSE); - g_return_val_if_fail ((cbs && cbs->standard_input == NULL) || - !(flags & G_SPAWN_CHILD_INHERITS_STDIN), 0); - g_return_val_if_fail ((cbs && cbs->standard_output == NULL) || - !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), 0); - g_return_val_if_fail ((cbs && cbs->standard_error == NULL) || - !(flags & G_SPAWN_STDERR_TO_DEV_NULL), 0); - - in_fd = out_fd = err_fd = -1; - - if (!g_spawn_async_with_pipes (working_directory, argv, envp, flags, - cbs ? cbs->child_setup : NULL, - user_data, child_pid, - cbs && cbs->standard_input ? &in_fd : NULL, - cbs && cbs->standard_output ? &out_fd : NULL, - cbs && cbs->standard_error ? &err_fd : NULL, - error)) - return 0; - - source = g_source_new (&cb_source_funcs, sizeof (CallbackSource)); - - cb_source = (CallbackSource*)source; - if (cbs != NULL) - memcpy (&cb_source->callbacks, cbs, sizeof (EggSpawnCallbacks)); - - cb_source->polls[0].fd = in_fd; - if (in_fd >= 0) { - g_assert (cb_source->callbacks.standard_input); - cb_source->polls[0].events = G_IO_ERR | G_IO_OUT; - g_source_add_poll (source, &cb_source->polls[0]); - } - cb_source->polls[1].fd = out_fd; - if (out_fd >= 0) { - g_assert (cb_source->callbacks.standard_output); - cb_source->polls[1].events = G_IO_ERR | G_IO_HUP | G_IO_IN; - g_source_add_poll (source, &cb_source->polls[1]); - } - cb_source->polls[2].fd = err_fd; - if (err_fd >= 0) { - g_assert (cb_source->callbacks.standard_error); - cb_source->polls[2].events = G_IO_ERR | G_IO_HUP | G_IO_IN; - g_source_add_poll (source, &cb_source->polls[2]); - } - - if (context == NULL) - context = g_main_context_default (); - g_source_set_callback (source, unused_callback, user_data, - cbs ? cbs->finalize_func : NULL); - tag = g_source_attach (source, context); - g_source_unref (source); - - return tag; -} - -gboolean -egg_spawn_sync_with_callbacks (const gchar *working_directory, gchar **argv, - gchar **envp, GSpawnFlags flags, GPid *child_pid, - EggSpawnCallbacks *cbs, gpointer user_data, - gint *exit_status, GError **error) -{ - gint in_fd, out_fd, err_fd, max_fd; - fd_set read_fds, write_fds; - gboolean failed = FALSE; - gint status; - GPid pid; - gint ret; - - g_return_val_if_fail (argv != NULL, FALSE); - g_return_val_if_fail ((cbs && cbs->standard_input == NULL) || - !(flags & G_SPAWN_CHILD_INHERITS_STDIN), 0); - g_return_val_if_fail ((cbs && cbs->standard_output == NULL) || - !(flags & G_SPAWN_STDOUT_TO_DEV_NULL), 0); - g_return_val_if_fail ((cbs && cbs->standard_error == NULL) || - !(flags & G_SPAWN_STDERR_TO_DEV_NULL), 0); - - in_fd = out_fd = err_fd = -1; - - if (exit_status) - flags |= G_SPAWN_DO_NOT_REAP_CHILD; - - if (!g_spawn_async_with_pipes (working_directory, argv, envp, flags, - cbs ? cbs->child_setup : NULL, - user_data, &pid, - cbs && cbs->standard_input ? &in_fd : NULL, - cbs && cbs->standard_output ? &out_fd : NULL, - cbs && cbs->standard_error ? &err_fd : NULL, - error)) - return FALSE; - - if (child_pid) - *child_pid = pid; - - max_fd = MAX (in_fd, MAX (out_fd, err_fd)) + 1; - - while (in_fd >= 0 || out_fd >= 0 || err_fd >= 0) { - - FD_ZERO (&write_fds); - if (in_fd >= 0) - FD_SET (in_fd, &write_fds); - FD_ZERO (&read_fds); - if (out_fd >= 0) - FD_SET (out_fd, &read_fds); - if (err_fd >= 0) - FD_SET (err_fd, &read_fds); - - ret = select (max_fd, &read_fds, &write_fds, NULL, NULL); - if (ret < 0 && errno != EINTR) { - failed = TRUE; - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ, - _("Unexpected error in select() reading data from a child process (%s)"), - g_strerror (errno)); - break; - } - - if (in_fd >= 0 && FD_ISSET (in_fd, &write_fds)) { - g_assert (cbs && cbs->standard_input); - if (!(cbs->standard_input) (in_fd, user_data)) - close_fd (&in_fd); - } - if (out_fd >= 0 && FD_ISSET (out_fd, &read_fds)) { - g_assert (cbs && cbs->standard_output); - if (!(cbs->standard_output) (out_fd, user_data)) - close_fd (&out_fd); - } - if (err_fd >= 0 && FD_ISSET (err_fd, &read_fds)) { - g_assert (cbs && cbs->standard_error); - if (!(cbs->standard_error) (err_fd, user_data)) - close_fd (&err_fd); - } - } - - if (in_fd >= 0) - close_fd (&in_fd); - if (out_fd >= 0) - close_fd (&out_fd); - if (err_fd >= 0) - close_fd (&err_fd); - - if (!failed) { - if (cbs && cbs->completed) - (cbs->completed) (user_data); - } - -again: - ret = waitpid (pid, &status, 0); - if (ret < 0) { - if (errno == EINTR) - goto again; - else if (errno == ECHILD) { - if (exit_status) - g_warning ("In call to g_spawn_sync(), exit status of a child process was requested but SIGCHLD action was set to SIG_IGN and ECHILD was received by waitpid(), so exit status can't be returned. This is a bug in the program calling g_spawn_sync(); either don't request the exit status, or don't set the SIGCHLD action."); - else - ; /* We don't need the exit status. */ - } else if (!failed) { /* avoid error pileups */ - failed = TRUE; - g_set_error (error, G_SPAWN_ERROR, G_SPAWN_ERROR_READ, - _("Unexpected error in waitpid() (%s)"), - g_strerror (errno)); - } - } else { - if (exit_status) - *exit_status = status; - } - - if (!child_pid) - g_spawn_close_pid (pid); - - if (cbs && cbs->finalize_func) - (cbs->finalize_func) (user_data); - - return !failed; -} - -gssize -egg_spawn_write_input (int fd, gconstpointer data, gsize n_data) -{ - gssize result; - - g_return_val_if_fail (fd >= 0, -1); - - for (;;) { - result = write (fd, data, n_data); - if (result < 0) { - if (errno == EINTR) - continue; - else if (errno == EAGAIN) - result = 0; - } - break; - } - - return result; -} - -gssize -egg_spawn_read_output (int fd, gpointer data, gsize n_data) -{ - gssize result; - - g_return_val_if_fail (fd >= 0, -1); - - for (;;) { - result = read (fd, data, n_data); - if (result < 0) { - if (errno == EINTR) - continue; - else if (errno == EAGAIN) - result = 0; - } - break; - } - - return result; -} - |