diff options
Diffstat (limited to 'src/udisksspawnedjob.c')
-rw-r--r-- | src/udisksspawnedjob.c | 988 |
1 files changed, 0 insertions, 988 deletions
diff --git a/src/udisksspawnedjob.c b/src/udisksspawnedjob.c deleted file mode 100644 index 124c221..0000000 --- a/src/udisksspawnedjob.c +++ /dev/null @@ -1,988 +0,0 @@ -/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- - * - * Copyright (C) 2007-2010 David Zeuthen <zeuthen@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 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 General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - * - */ - -#include "config.h" -#include <glib/gi18n-lib.h> - -#include <stdio.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <string.h> -#include <unistd.h> -#include <pwd.h> -#include <grp.h> -#include <stdlib.h> - -#include "udisksbasejob.h" -#include "udisksspawnedjob.h" -#include "udisks-daemon-marshal.h" -#include "udisksdaemon.h" - -/** - * SECTION:udisksspawnedjob - * @title: UDisksSpawnedJob - * @short_description: Job that spawns a command - * - * This type provides an implementation of the #UDisksJob interface - * for jobs that are implemented by spawning a command line. - */ - -typedef struct _UDisksSpawnedJobClass UDisksSpawnedJobClass; - -/** - * UDisksSpawnedJob: - * - * The #UDisksSpawnedJob structure contains only private data and should - * only be accessed using the provided API. - */ -struct _UDisksSpawnedJob -{ - UDisksBaseJob parent_instance; - - gchar *command_line; - gulong cancellable_handler_id; - - GMainContext *main_context; - - gchar *input_string; - uid_t run_as_uid; - uid_t run_as_euid; - gid_t real_egid; - gid_t real_gid; - uid_t real_uid; - char *real_pwname; - const gchar *input_string_cursor; - - GPid child_pid; - gint child_stdin_fd; - gint child_stdout_fd; - gint child_stderr_fd; - - GIOChannel *child_stdin_channel; - GIOChannel *child_stdout_channel; - GIOChannel *child_stderr_channel; - - GSource *child_watch_source; - GSource *child_stdin_source; - GSource *child_stdout_source; - GSource *child_stderr_source; - - GString *child_stdout; - GString *child_stderr; -}; - -struct _UDisksSpawnedJobClass -{ - UDisksBaseJobClass parent_class; - - gboolean (*spawned_job_completed) (UDisksSpawnedJob *job, - GError *error, - gint status, - GString *standard_output, - GString *standard_error); -}; - -static void job_iface_init (UDisksJobIface *iface); - -enum -{ - PROP_0, - PROP_COMMAND_LINE, - PROP_INPUT_STRING, - PROP_RUN_AS_UID, - PROP_RUN_AS_EUID -}; - -enum -{ - SPAWNED_JOB_COMPLETED_SIGNAL, - LAST_SIGNAL -}; - -static guint signals[LAST_SIGNAL] = { 0 }; - -static gboolean udisks_spawned_job_spawned_job_completed_default (UDisksSpawnedJob *job, - GError *error, - gint status, - GString *standard_output, - GString *standard_error); - -static void udisks_spawned_job_release_resources (UDisksSpawnedJob *job); - -G_DEFINE_TYPE_WITH_CODE (UDisksSpawnedJob, udisks_spawned_job, UDISKS_TYPE_BASE_JOB, - G_IMPLEMENT_INTERFACE (UDISKS_TYPE_JOB, job_iface_init)); - -static void -udisks_spawned_job_finalize (GObject *object) -{ - UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (object); - - udisks_spawned_job_release_resources (job); - - if (job->main_context != NULL) - g_main_context_unref (job->main_context); - - g_free (job->command_line); - - /* input string may contain key material - nuke contents */ - if (job->input_string != NULL) - { - memset (job->input_string, '\0', strlen (job->input_string)); - g_free (job->input_string); - } - - if (G_OBJECT_CLASS (udisks_spawned_job_parent_class)->finalize != NULL) - G_OBJECT_CLASS (udisks_spawned_job_parent_class)->finalize (object); -} - -static void -udisks_spawned_job_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (object); - - switch (prop_id) - { - case PROP_COMMAND_LINE: - g_value_set_string (value, udisks_spawned_job_get_command_line (job)); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -udisks_spawned_job_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (object); - - switch (prop_id) - { - case PROP_COMMAND_LINE: - g_assert (job->command_line == NULL); - job->command_line = g_value_dup_string (value); - break; - - case PROP_INPUT_STRING: - g_assert (job->input_string == NULL); - job->input_string = g_value_dup_string (value); - break; - - case PROP_RUN_AS_UID: - job->run_as_uid = g_value_get_uint (value); - break; - - case PROP_RUN_AS_EUID: - job->run_as_euid = g_value_get_uint (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/* ---------------------------------------------------------------------------------------------------- */ - -typedef struct -{ - UDisksSpawnedJob *job; - GError *error; -} EmitCompletedData; - -static gboolean -emit_completed_with_error_in_idle_cb (gpointer user_data) -{ - EmitCompletedData *data = user_data; - gboolean ret; - - g_signal_emit (data->job, - signals[SPAWNED_JOB_COMPLETED_SIGNAL], - 0, - data->error, - 0, /* status */ - data->job->child_stdout, /* standard_output */ - data->job->child_stderr, /* standard_error */ - &ret); - g_object_unref (data->job); - g_error_free (data->error); - g_free (data); - return FALSE; -} - -static void -emit_completed_with_error_in_idle (UDisksSpawnedJob *job, - GError *error) -{ - EmitCompletedData *data; - GSource *idle_source; - - g_return_if_fail (UDISKS_IS_SPAWNED_JOB (job)); - g_return_if_fail (error != NULL); - - data = g_new0 (EmitCompletedData, 1); - data->job = g_object_ref (job); - data->error = g_error_copy (error); - idle_source = g_idle_source_new (); - g_source_set_priority (idle_source, G_PRIORITY_DEFAULT); - g_source_set_callback (idle_source, - emit_completed_with_error_in_idle_cb, - data, - NULL); - g_source_attach (idle_source, job->main_context); - g_source_unref (idle_source); -} - -/* called in the thread where @cancellable was cancelled */ -static void -on_cancelled (GCancellable *cancellable, - gpointer user_data) -{ - UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (user_data); - GError *error; - - error = NULL; - g_warn_if_fail (g_cancellable_set_error_if_cancelled (cancellable, &error)); - emit_completed_with_error_in_idle (job, error); - g_error_free (error); -} - -static gboolean -read_child_stderr (GIOChannel *channel, - GIOCondition condition, - gpointer user_data) -{ - UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (user_data); - gchar buf[1024]; - gsize bytes_read; - - g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL); - g_string_append_len (job->child_stderr, buf, bytes_read); - return TRUE; -} - -static gboolean -read_child_stdout (GIOChannel *channel, - GIOCondition condition, - gpointer user_data) -{ - UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (user_data); - gchar buf[1024]; - gsize bytes_read; - - g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL); - g_string_append_len (job->child_stdout, buf, bytes_read); - return TRUE; -} - -static gboolean -write_child_stdin (GIOChannel *channel, - GIOCondition condition, - gpointer user_data) -{ - UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (user_data); - gsize bytes_written; - - if (job->input_string_cursor == NULL || *job->input_string_cursor == '\0') - { - /* nothing left to write; close our end so the child will get EOF */ - g_io_channel_unref (job->child_stdin_channel); - g_source_destroy (job->child_stdin_source); - g_warn_if_fail (close (job->child_stdin_fd) == 0); - job->child_stdin_channel = NULL; - job->child_stdin_source = NULL; - job->child_stdin_fd = -1; - return FALSE; - } - - g_io_channel_write_chars (channel, - job->input_string_cursor, - strlen (job->input_string_cursor), - &bytes_written, - NULL); - g_io_channel_flush (channel, NULL); - job->input_string_cursor += bytes_written; - - /* keep writing */ - return TRUE; -} - -static void -child_watch_cb (GPid pid, - gint status, - gpointer user_data) -{ - UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (user_data); - gchar *buf; - gsize buf_size; - gboolean ret; - - if (g_io_channel_read_to_end (job->child_stdout_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL) - { - g_string_append_len (job->child_stdout, buf, buf_size); - g_free (buf); - } - if (g_io_channel_read_to_end (job->child_stderr_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL) - { - g_string_append_len (job->child_stderr, buf, buf_size); - g_free (buf); - } - - //g_debug ("helper(pid %5d): completed with exit code %d\n", job->child_pid, WEXITSTATUS (status)); - - /* take a reference so it's safe for a signal-handler to release the last one */ - g_object_ref (job); - g_signal_emit (job, - signals[SPAWNED_JOB_COMPLETED_SIGNAL], - 0, - NULL, /* GError */ - status, - job->child_stdout, - job->child_stderr, - &ret); - job->child_pid = 0; - job->child_watch_source = NULL; - udisks_spawned_job_release_resources (job); - g_object_unref (job); -} - -/* careful, this is in the fork()'ed child so all utility threads etc are not available */ -static void -child_setup (gpointer user_data) -{ - UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (user_data); - - if (job->run_as_uid == getuid () && job->run_as_euid == geteuid ()) - goto out; - - /* become the user... - * - * TODO: this might need to involve running the whole PAM 'session' - * stack as done by e.g. pkexec(1) and various login managers - * otherwise things like the SELinux context might not be entirely - * right. What we really need is some library function to - * impersonate a pid or uid. What a mess. - */ - if (setgroups (0, NULL) != 0) - { - g_printerr ("Error resetting groups: %m\n"); - abort (); - } - if (initgroups (job->real_pwname, job->real_gid) != 0) - { - g_printerr ("Error initializing groups for user %s and group %d: %m\n", - job->real_pwname, (gint) job->real_gid); - abort (); - } - if (setregid (job->real_gid, job->real_egid) != 0) - { - g_printerr ("Error setting real+effective gid %d and %d: %m\n", - (gint) job->real_gid, (gint) job->real_egid); - abort (); - } - if (setreuid (job->real_uid, job->run_as_euid) != 0) - { - g_printerr ("Error setting real+effective uid %d and %d: %m\n", - (gint) job->real_uid, (gint) job->run_as_euid); - abort (); - } - - out: - ; -} - -static void -udisks_spawned_job_constructed (GObject *object) -{ - UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (object); - GError *error; - gint child_argc; - gchar **child_argv; - struct passwd pwstruct; - gchar pwbuf[8192]; - struct passwd *pw = NULL; - int rc; - - if (G_OBJECT_CLASS (udisks_spawned_job_parent_class)->constructed != NULL) - G_OBJECT_CLASS (udisks_spawned_job_parent_class)->constructed (object); - - job->main_context = g_main_context_get_thread_default (); - if (job->main_context != NULL) - g_main_context_ref (job->main_context); - - /* could already be cancelled */ - error = NULL; - if (g_cancellable_set_error_if_cancelled (udisks_base_job_get_cancellable (UDISKS_BASE_JOB (job)), &error)) - { - emit_completed_with_error_in_idle (job, error); - g_error_free (error); - goto out; - } - - job->cancellable_handler_id = g_cancellable_connect (udisks_base_job_get_cancellable (UDISKS_BASE_JOB (job)), - G_CALLBACK (on_cancelled), - job, - NULL); - - error = NULL; - if (!g_shell_parse_argv (job->command_line, - &child_argc, - &child_argv, - &error)) - { - g_prefix_error (&error, - "Error parsing command-line `%s': ", - job->command_line); - emit_completed_with_error_in_idle (job, error); - g_error_free (error); - goto out; - } - - /* Save real egid and gid info for the child process */ - if (job->run_as_uid != getuid () || job->run_as_euid != geteuid ()) - { - rc = getpwuid_r (job->run_as_euid, &pwstruct, pwbuf, sizeof pwbuf, &pw); - if (rc != 0 || pw == NULL) - { - g_set_error(&error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No password record for uid %d: %m\n", (gint) job->run_as_euid); - emit_completed_with_error_in_idle (job, error); - g_error_free (error); - goto out; - } - job->real_egid = pw->pw_gid; - - rc = getpwuid_r (job->run_as_uid, &pwstruct, pwbuf, sizeof pwbuf, &pw); - if (rc != 0 || pw == NULL) - { - g_set_error(&error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No password record for uid %d: %m\n", (gint) job->run_as_uid); - emit_completed_with_error_in_idle (job, error); - g_error_free (error); - goto out; - } - job->real_gid = pw->pw_gid; - job->real_uid = pw->pw_uid; - job->real_pwname = strdup (pw->pw_name); - } - - error = NULL; - if (!g_spawn_async_with_pipes (NULL, /* working directory */ - child_argv, - NULL, /* envp */ - G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, - child_setup, /* child_setup */ - job, /* child_setup's user_data */ - &(job->child_pid), - job->input_string != NULL ? &(job->child_stdin_fd) : NULL, - &(job->child_stdout_fd), - &(job->child_stderr_fd), - &error)) - { - g_prefix_error (&error, - "Error spawning command-line `%s': ", - job->command_line); - emit_completed_with_error_in_idle (job, error); - g_error_free (error); - goto out; - } - - job->child_watch_source = g_child_watch_source_new (job->child_pid); - g_source_set_callback (job->child_watch_source, (GSourceFunc) child_watch_cb, job, NULL); - g_source_attach (job->child_watch_source, job->main_context); - g_source_unref (job->child_watch_source); - - if (job->child_stdin_fd != -1) - { - job->input_string_cursor = job->input_string; - - job->child_stdin_channel = g_io_channel_unix_new (job->child_stdin_fd); - g_io_channel_set_flags (job->child_stdin_channel, G_IO_FLAG_NONBLOCK, NULL); - job->child_stdin_source = g_io_create_watch (job->child_stdin_channel, G_IO_OUT); - g_source_set_callback (job->child_stdin_source, (GSourceFunc) write_child_stdin, job, NULL); - g_source_attach (job->child_stdin_source, job->main_context); - g_source_unref (job->child_stdin_source); - } - - job->child_stdout_channel = g_io_channel_unix_new (job->child_stdout_fd); - g_io_channel_set_flags (job->child_stdout_channel, G_IO_FLAG_NONBLOCK, NULL); - job->child_stdout_source = g_io_create_watch (job->child_stdout_channel, G_IO_IN); - g_source_set_callback (job->child_stdout_source, (GSourceFunc) read_child_stdout, job, NULL); - g_source_attach (job->child_stdout_source, job->main_context); - g_source_unref (job->child_stdout_source); - - job->child_stderr_channel = g_io_channel_unix_new (job->child_stderr_fd); - g_io_channel_set_flags (job->child_stderr_channel, G_IO_FLAG_NONBLOCK, NULL); - job->child_stderr_source = g_io_create_watch (job->child_stderr_channel, G_IO_IN); - g_source_set_callback (job->child_stderr_source, (GSourceFunc) read_child_stderr, job, NULL); - g_source_attach (job->child_stderr_source, job->main_context); - g_source_unref (job->child_stderr_source); - - out: - ; -} - -static void -udisks_spawned_job_init (UDisksSpawnedJob *job) -{ - job->child_stdout = g_string_new (NULL); - job->child_stderr = g_string_new (NULL); - job->child_stdin_fd = -1; - job->child_stdout_fd = -1; - job->child_stderr_fd = -1; -} - -static void -udisks_spawned_job_class_init (UDisksSpawnedJobClass *klass) -{ - GObjectClass *gobject_class; - - klass->spawned_job_completed = udisks_spawned_job_spawned_job_completed_default; - - gobject_class = G_OBJECT_CLASS (klass); - gobject_class->finalize = udisks_spawned_job_finalize; - gobject_class->constructed = udisks_spawned_job_constructed; - gobject_class->set_property = udisks_spawned_job_set_property; - gobject_class->get_property = udisks_spawned_job_get_property; - - /** - * UDisksSpawnedJob:command-line: - * - * The command-line to run. - */ - g_object_class_install_property (gobject_class, - PROP_COMMAND_LINE, - g_param_spec_string ("command-line", - "Command Line", - "The command-line to run", - NULL, - G_PARAM_READABLE | - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - /** - * UDisksSpawnedJob:input-string: - * - * String that will be written to stdin of the spawned program or - * %NULL to not write anything. - */ - g_object_class_install_property (gobject_class, - PROP_INPUT_STRING, - g_param_spec_string ("input-string", - "Input String", - "String to write to stdin of the spawned program", - NULL, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - /** - * UDisksSpawnedJob:run-as-uid: - * - * The #uid_t to run the program as. - */ - g_object_class_install_property (gobject_class, - PROP_RUN_AS_UID, - g_param_spec_uint ("run-as-uid", - "Run As", - "The uid_t to run the program as", - 0, G_MAXUINT, 0, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - /** - * UDisksSpawnedJob:run-as-euid: - * - * The effective #uid_t to run the program as. - */ - g_object_class_install_property (gobject_class, - PROP_RUN_AS_EUID, - g_param_spec_uint ("run-as-euid", - "Run As (effective)", - "The effective uid_t to run the program as", - 0, G_MAXUINT, 0, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS)); - - /** - * UDisksSpawnedJob::spawned-job-completed: - * @job: The #UDisksSpawnedJob emitting the signal. - * @error: %NULL if running the whole command line succeeded, otherwise a #GError that is set. - * @status: The exit status of the command line that was run. - * @standard_output: Standard output from the command line that was run. - * @standard_error: Standard error output from the command line that was run. - * - * Emitted when the spawned job is complete. If spawning the command - * failed or if the job was cancelled, @error will - * non-%NULL. Otherwise you can use macros such as WIFEXITED() and - * WEXITSTATUS() on the @status integer to obtain more information. - * - * The default implementation simply emits the #UDisksJob::completed - * signal with @success set to %TRUE if, and only if, @error is - * %NULL, WIFEXITED() evaluates to %TRUE and WEXITSTATUS() is - * zero. Additionally, @message on that signal is set to - * @standard_error regards of whether @success is %TRUE or %FALSE. - * - * You can avoid the default implementation by returning %TRUE from - * your signal handler. - * - * This signal is emitted in the - * <link linkend="g-main-context-push-thread-default">thread-default main loop</link> - * of the thread that @job was created in. - * - * Returns: %TRUE if the signal was handled, %FALSE to let other - * handlers run. - */ - signals[SPAWNED_JOB_COMPLETED_SIGNAL] = - g_signal_new ("spawned-job-completed", - UDISKS_TYPE_SPAWNED_JOB, - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UDisksSpawnedJobClass, spawned_job_completed), - g_signal_accumulator_true_handled, - NULL, - udisks_daemon_marshal_BOOLEAN__BOXED_INT_BOXED_BOXED, - G_TYPE_BOOLEAN, - 4, - G_TYPE_ERROR, - G_TYPE_INT, - G_TYPE_GSTRING, - G_TYPE_GSTRING); -} - -/** - * udisks_spawned_job_new: - * @command_line: The command line to run. - * @input_string: A string to write to stdin of the spawned program or %NULL. - * @run_as_uid: The #uid_t to run the program as. - * @run_as_euid: The effective #uid_t to run the program as. - * @daemon: A #UDisksDaemon. - * @cancellable: A #GCancellable or %NULL. - * - * Creates a new #UDisksSpawnedJob instance. - * - * The job is started immediately - connect to the - * #UDisksSpawnedJob::spawned-job-completed or #UDisksJob::completed - * signals to get notified when the job is done. - * - * Returns: A new #UDisksSpawnedJob. Free with g_object_unref(). - */ -UDisksSpawnedJob * -udisks_spawned_job_new (const gchar *command_line, - const gchar *input_string, - uid_t run_as_uid, - uid_t run_as_euid, - UDisksDaemon *daemon, - GCancellable *cancellable) -{ - g_return_val_if_fail (command_line != NULL, NULL); - /* g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), NULL); */ - g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); - return UDISKS_SPAWNED_JOB (g_object_new (UDISKS_TYPE_SPAWNED_JOB, - "command-line", command_line, - "input-string", input_string, - "run-as-uid", run_as_uid, - "run-as-euid", run_as_euid, - "daemon", daemon, - "cancellable", cancellable, - NULL)); -} - -/** - * udisks_spawned_job_get_command_line: - * @job: A #UDisksSpawnedJob. - * - * Gets the command line that @job was constructed with. - * - * Returns: A string owned by @job. Do not free. - */ -const gchar * -udisks_spawned_job_get_command_line (UDisksSpawnedJob *job) -{ - g_return_val_if_fail (UDISKS_IS_SPAWNED_JOB (job), NULL); - return job->command_line; -} - -/* ---------------------------------------------------------------------------------------------------- */ - -static void -job_iface_init (UDisksJobIface *iface) -{ - /* For Cancel(), just use the implementation from our super class (UDisksBaseJob) */ - /* iface->handle_cancel = handle_cancel; */ -} - -/* ---------------------------------------------------------------------------------------------------- */ - -static const gchar * -get_signal_name (gint signal_number) -{ - switch (signal_number) - { -#define _HANDLE_SIG(sig) case sig: return #sig; - _HANDLE_SIG (SIGHUP); - _HANDLE_SIG (SIGINT); - _HANDLE_SIG (SIGQUIT); - _HANDLE_SIG (SIGILL); - _HANDLE_SIG (SIGABRT); - _HANDLE_SIG (SIGFPE); - _HANDLE_SIG (SIGKILL); - _HANDLE_SIG (SIGSEGV); - _HANDLE_SIG (SIGPIPE); - _HANDLE_SIG (SIGALRM); - _HANDLE_SIG (SIGTERM); - _HANDLE_SIG (SIGUSR1); - _HANDLE_SIG (SIGUSR2); - _HANDLE_SIG (SIGCHLD); - _HANDLE_SIG (SIGCONT); - _HANDLE_SIG (SIGSTOP); - _HANDLE_SIG (SIGTSTP); - _HANDLE_SIG (SIGTTIN); - _HANDLE_SIG (SIGTTOU); - _HANDLE_SIG (SIGBUS); - _HANDLE_SIG (SIGPOLL); - _HANDLE_SIG (SIGPROF); - _HANDLE_SIG (SIGSYS); - _HANDLE_SIG (SIGTRAP); - _HANDLE_SIG (SIGURG); - _HANDLE_SIG (SIGVTALRM); - _HANDLE_SIG (SIGXCPU); - _HANDLE_SIG (SIGXFSZ); -#undef _HANDLE_SIG - default: - break; - } - return "UNKNOWN_SIGNAL"; -} - -static gboolean -udisks_spawned_job_spawned_job_completed_default (UDisksSpawnedJob *job, - GError *error, - gint status, - GString *standard_output, - GString *standard_error) -{ -#if 0 - g_debug ("in udisks_spawned_job_spawned_job_completed_default()\n" - " command_line `%s'\n" - " error->message=`%s'\n" - " status=%d (WIFEXITED=%d WEXITSTATUS=%d)\n" - " standard_output=`%s' (%d bytes)\n" - " standard_error=`%s' (%d bytes)\n", - job->command_line, - error != NULL ? error->message : "(error not set)", - status, - WIFEXITED (status), WEXITSTATUS (status), - standard_output->str, (gint) standard_output->len, - standard_error->str, (gint) standard_error->len); -#endif - - if (error != NULL) - { - gchar *message; - message = g_strdup_printf ("%s (%s, %d)", - error->message, - g_quark_to_string (error->domain), - error->code); - udisks_job_emit_completed (UDISKS_JOB (job), - FALSE, - message); - g_free (message); - } - else if (WIFEXITED (status) && WEXITSTATUS (status) == 0) - { - udisks_job_emit_completed (UDISKS_JOB (job), - TRUE, - standard_error->str); - } - else - { - GString *message; - message = g_string_new (NULL); - if (WIFEXITED (status)) - { - g_string_append_printf (message, - "Command-line `%s' exited with non-zero exit status %d:", - job->command_line, - WEXITSTATUS (status)); - } - else if (WIFSIGNALED (status)) - { - g_string_append_printf (message, - "Command-line `%s' was signaled with signal %s (%d):", - job->command_line, - get_signal_name (WTERMSIG (status)), - WTERMSIG (status)); - } - if (standard_output->len > 0 && standard_error->len) - { - g_string_append_printf (message, - "\n" - "stdout: `%s'\n" - "stderr: `%s'", - standard_output->str, - standard_error->str); - } - else if (standard_output->len > 0) - { - g_string_append_printf (message, " %s", standard_output->str); - } - else - { - g_string_append_printf (message, " %s", standard_error->str); - } - - udisks_job_emit_completed (UDISKS_JOB (job), - FALSE, - message->str); - g_string_free (message, TRUE); - } - return TRUE; -} - -static void -child_watch_from_release_cb (GPid pid, - gint status, - gpointer user_data) -{ -} - -/* called when we're done running the command line */ -static void -udisks_spawned_job_release_resources (UDisksSpawnedJob *job) -{ - /* Nuke the child, if necessary */ - if (job->child_watch_source != NULL) - { - g_source_destroy (job->child_watch_source); - job->child_watch_source = NULL; - } - - if (job->child_pid != 0) - { - GSource *source; - - //g_debug ("ugh, need to kill %d", (gint) job->child_pid); - kill (job->child_pid, SIGTERM); - - /* OK, we need to reap for the child ourselves - we don't want - * to use waitpid() because that might block the calling - * thread (the child might handle SIGTERM and use several - * seconds for cleanup/rollback). - * - * So we use GChildWatch instead. - * - * Note that we might be called from the finalizer so avoid - * taking references to ourselves. We do need to pass the - * GSource so we can nuke it once handled. - */ - source = g_child_watch_source_new (job->child_pid); - g_source_set_callback (source, - (GSourceFunc) child_watch_from_release_cb, - source, - (GDestroyNotify) g_source_destroy); - g_source_attach (source, job->main_context); - g_source_unref (source); - - job->child_pid = 0; - } - - if (job->child_stdout != NULL) - { - g_string_free (job->child_stdout, TRUE); - job->child_stdout = NULL; - } - - if (job->child_stderr != NULL) - { - g_string_free (job->child_stderr, TRUE); - job->child_stderr = NULL; - } - - if (job->child_stdin_channel != NULL) - { - g_io_channel_unref (job->child_stdin_channel); - job->child_stdin_channel = NULL; - } - if (job->child_stdout_channel != NULL) - { - g_io_channel_unref (job->child_stdout_channel); - job->child_stdout_channel = NULL; - } - if (job->child_stderr_channel != NULL) - { - g_io_channel_unref (job->child_stderr_channel); - job->child_stderr_channel = NULL; - } - - if (job->child_stdin_source != NULL) - { - g_source_destroy (job->child_stdin_source); - job->child_stdin_source = NULL; - } - if (job->child_stdout_source != NULL) - { - g_source_destroy (job->child_stdout_source); - job->child_stdout_source = NULL; - } - if (job->child_stderr_source != NULL) - { - g_source_destroy (job->child_stderr_source); - job->child_stderr_source = NULL; - } - - if (job->child_stdin_fd != -1) - { - g_warn_if_fail (close (job->child_stdin_fd) == 0); - job->child_stdin_fd = -1; - } - if (job->child_stdout_fd != -1) - { - g_warn_if_fail (close (job->child_stdout_fd) == 0); - job->child_stdout_fd = -1; - } - if (job->child_stderr_fd != -1) - { - g_warn_if_fail (close (job->child_stderr_fd) == 0); - job->child_stderr_fd = -1; - } - - if (job->cancellable_handler_id > 0) - { - g_cancellable_disconnect (udisks_base_job_get_cancellable (UDISKS_BASE_JOB (job)), job->cancellable_handler_id); - job->cancellable_handler_id = 0; - } - - if (job->real_pwname != NULL) - { - free (job->real_pwname); - job->real_pwname = NULL; - } -} - |