diff options
-rw-r--r-- | shell/Makefile.am | 18 | ||||
-rw-r--r-- | shell/killev.c | 158 | ||||
-rw-r--r-- | shell/main.c | 22 |
3 files changed, 178 insertions, 20 deletions
diff --git a/shell/Makefile.am b/shell/Makefile.am index 541f941e58..6ff40baab7 100644 --- a/shell/Makefile.am +++ b/shell/Makefile.am @@ -114,12 +114,12 @@ evolution_CPPFLAGS = \ -DEVOLUTION_ICONDIR=\""$(icondir)"\" \ -DEVOLUTION_MODULEDIR=\""$(moduledir)"\" \ -DEVOLUTION_RULEDIR=\""$(privdatadir)"\" \ + -DEVOLUTION_TOOLSDIR=\""$(privlibexecdir)"\" \ -DEVOLUTION_UIDIR=\""$(uidir)"\" \ -DPREFIX=\""$(prefix)"\" \ -DSYSCONFDIR=\""$(sysconfdir)"\" \ -DDATADIR=\""$(datadir)"\" \ -DLIBDIR=\""$(datadir)"\" \ - -DG_LOG_DOMAIN=\"evolution-shell\" \ $(TZDIALOG_CFLAGS) \ $(SHELL_CFLAGS) @@ -142,6 +142,22 @@ if OS_WIN32 evolution_LDFLAGS = -mwindows endif +# Killev utility + +if OS_WIN32 +else +privlibexec_PROGRAMS = killev +endif + +killev_CPPFLAGS = \ + $(AM_CPPFLAGS) \ + -DEVOLUTION_LOCALEDIR=\""$(localedir)"\" \ + $(GNOME_PLATFORM_CFLAGS) + +killev_SOURCES = killev.c + +killev_LDADD = $(GNOME_PLATFORM_LIBS) + # Misc stuff error_DATA = shell.error diff --git a/shell/killev.c b/shell/killev.c new file mode 100644 index 0000000000..d1eb523495 --- /dev/null +++ b/shell/killev.c @@ -0,0 +1,158 @@ +/* + * killev.c + * + * 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 of the License, or (at your option) version 3. + * + * 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 the program; if not, see <http://www.gnu.org/licenses/> + * + * + * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) + * + */ + +#include <config.h> + +#include <signal.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/wait.h> + +#include <gio/gio.h> +#include <glib/gi18n.h> + +/* Seconds to wait after asking Evolution to terminate gracefully. + * If the process has not terminated before the timeout expires, + * then we get violent. */ +#define EVOLUTION_SHUTDOWN_TIMEOUT 5 + +static GPid evolution_pid; +static GMainLoop *main_loop; + +static void +file_monitor_changed_cb (GFileMonitor *monitor, + GFile *file, + GFile *not_used, + GFileMonitorEvent event_type) +{ + if (event_type != G_FILE_MONITOR_EVENT_DELETED) + return; + + g_print ("Evolution process exited normally\n"); + + g_main_loop_quit (main_loop); +} + +static gboolean +evolution_not_responding_cb (void) +{ + g_print ("No response from Evolution -- killing the process\n"); + + /* Kill the process. */ + kill ((pid_t) evolution_pid, SIGTERM); + + g_main_loop_quit (main_loop); + + return FALSE; +} + +static gboolean +get_evolution_pid (GFile *file) +{ + gint64 v_int64; + gchar *contents = NULL; + gboolean success = FALSE; + + /* Try to read Evolution's PID from its .running file. */ + + if (!g_file_load_contents (file, NULL, &contents, NULL, NULL, NULL)) + goto exit; + + /* Try to extract an integer value from the string. */ + v_int64 = g_ascii_strtoll (contents, NULL, 10); + if (!(v_int64 > 0 && v_int64 < G_MAXINT64)) + goto exit; + + /* XXX Probably not portable. */ + evolution_pid = (GPid) v_int64; + + success = TRUE; + +exit: + g_free (contents); + + return success; +} + +gint +main (gint argc, gchar **argv) +{ + GFile *pid_file; + GFileMonitor *monitor; + gchar *filename; + GError *error = NULL; + + bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + g_type_init (); + + /* XXX If e_get_user_data_dir() ever gets moved to libedataserver, + * use that instead of hard-coding the directory path here. */ + filename = g_build_filename ( + g_get_home_dir (), ".evolution", ".running", NULL); + pid_file = g_file_new_for_path (filename); + g_free (filename); + + if (!get_evolution_pid (pid_file)) { + g_printerr ("Could not find Evolution's process ID\n"); + exit (EXIT_FAILURE); + } + + /* Play it safe here and bail if something goes wrong. We don't + * want to just skip to the killing if we can't ask Evolution to + * terminate gracefully. Despite our name we actually want to + * -avoid- killing Evolution if at all possible. */ + if (!g_spawn_command_line_async ("evolution --quit", &error)) { + g_printerr ("%s", error->message); + g_error_free (error); + exit (EXIT_FAILURE); + } + + /* Now we set up a monitor on Evolution's .running file. + * If Evolution is still responsive it will delete this + * file just before terminating and we'll be notified. */ + monitor = g_file_monitor_file (pid_file, 0, NULL, &error); + if (error != NULL) { + g_printerr ("%s", error->message); + g_error_free (error); + exit (EXIT_FAILURE); + } + + g_signal_connect ( + monitor, "changed", + G_CALLBACK (file_monitor_changed_cb), NULL); + + g_timeout_add_seconds ( + EVOLUTION_SHUTDOWN_TIMEOUT, (GSourceFunc) + evolution_not_responding_cb, NULL); + + /* Start the clock. */ + + main_loop = g_main_loop_new (NULL, TRUE); + g_main_loop_run (main_loop); + g_main_loop_unref (main_loop); + + g_object_unref (monitor); + + return EXIT_SUCCESS; +} diff --git a/shell/main.c b/shell/main.c index 396cd690fa..c37ccc4d6c 100644 --- a/shell/main.c +++ b/shell/main.c @@ -390,26 +390,10 @@ set_paths (void) static void G_GNUC_NORETURN shell_force_shutdown (void) { - gchar *program; + gchar *filename; - /* This is not as destructive as it was in the Bonobo era. - * The Evolution-Data-Server D-Bus services should not be killed - * because other programs may be using them. The alarm daemon is - * an autostart program now and Evolution no longer spawns it, so - * that should not be killed either. The only thing left to do - * really is shoot ourselves. */ - - /* XXX Maybe --force-shutdown should be deprecated. */ - - program = g_find_program_in_path ("pkill"); - - if (program == NULL) { - g_printerr ("Could not find `pkill' program in path.\n"); - exit (1); - } - - /* This does not return. */ - execl (program, "pkill", "evolution", NULL); + filename = g_build_filename (EVOLUTION_TOOLSDIR, "killev", NULL); + execl (filename, "killev", NULL); g_assert_not_reached (); } |