1 /*
2 * killev.c
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with the program; if not, see <http://www.gnu.org/licenses/>
16 *
17 *
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
19 *
20 */
21
22 #include <config.h>
23
24 #include <signal.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <sys/wait.h>
28
29 #include <gio/gio.h>
30 #include <glib/gi18n.h>
31
32 #include <libedataserver/libedataserver.h>
33
34 /* Seconds to wait after asking Evolution to terminate gracefully.
35 * If the process has not terminated before the timeout expires,
36 * then we get violent. */
37 #define EVOLUTION_SHUTDOWN_TIMEOUT 5
38
39 static GPid evolution_pid;
40 static GMainLoop *main_loop;
41
42 static void
43 file_monitor_changed_cb (GFileMonitor *monitor,
44 GFile *file,
45 GFile *not_used,
46 GFileMonitorEvent event_type)
47 {
48 if (event_type != G_FILE_MONITOR_EVENT_DELETED)
49 return;
50
51 g_print ("Evolution process exited normally\n");
52
53 g_main_loop_quit (main_loop);
54 }
55
56 static gboolean
57 evolution_not_responding_cb (void)
58 {
59 g_print ("No response from Evolution -- killing the process\n");
60
61 /* Kill the process. */
62 kill ((pid_t) evolution_pid, SIGTERM);
63
64 g_main_loop_quit (main_loop);
65
66 return FALSE;
67 }
68
69 static gboolean
70 get_evolution_pid (GFile *file)
71 {
72 gint64 v_int64;
73 gchar *contents = NULL;
74 gboolean success = FALSE;
75
76 /* Try to read Evolution's PID from its .running file. */
77
78 if (!g_file_load_contents (file, NULL, &contents, NULL, NULL, NULL))
79 goto exit;
80
81 /* Try to extract an integer value from the string. */
82 v_int64 = g_ascii_strtoll (contents, NULL, 10);
83 if (!(v_int64 > 0 && v_int64 < G_MAXINT64))
84 goto exit;
85
86 /* XXX Probably not portable. */
87 evolution_pid = (GPid) v_int64;
88
89 success = TRUE;
90
91 exit:
92 g_free (contents);
93
94 return success;
95 }
96
97 gint
98 main (gint argc,
99 gchar **argv)
100 {
101 GFile *pid_file;
102 GFileMonitor *monitor;
103 const gchar *user_config_dir;
104 gchar *filename;
105 gint retval = EXIT_SUCCESS;
106 GError *error = NULL;
107
108 bindtextdomain (GETTEXT_PACKAGE, EVOLUTION_LOCALEDIR);
109 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
110 textdomain (GETTEXT_PACKAGE);
111
112 g_type_init ();
113
114 user_config_dir = e_get_user_config_dir ();
115 filename = g_build_filename (user_config_dir, ".running", NULL);
116 pid_file = g_file_new_for_path (filename);
117 g_free (filename);
118
119 if (!get_evolution_pid (pid_file)) {
120 g_printerr ("Could not find Evolution's process ID\n");
121 retval = EXIT_FAILURE;
122 goto kill;
123 }
124
125 if (g_getenv ("DISPLAY") == NULL)
126 goto kill;
127
128 /* Play it safe here and bail if something goes wrong. We don't
129 * want to just skip to the killing if we can't ask Evolution to
130 * terminate gracefully. Despite our name we actually want to
131 * -avoid- killing Evolution if at all possible. */
132 if (!g_spawn_command_line_async ("evolution --quit", &error)) {
133 g_printerr ("%s\n", error->message);
134 g_error_free (error);
135 retval = EXIT_FAILURE;
136 goto kill;
137 }
138
139 /* Now we set up a monitor on Evolution's .running file.
140 * If Evolution is still responsive it will delete this
141 * file just before terminating and we'll be notified. */
142 monitor = g_file_monitor_file (pid_file, 0, NULL, &error);
143 if (error != NULL) {
144 g_printerr ("%s\n", error->message);
145 g_error_free (error);
146 retval = EXIT_FAILURE;
147 goto kill;
148 }
149
150 g_signal_connect (
151 monitor, "changed",
152 G_CALLBACK (file_monitor_changed_cb), NULL);
153
154 g_timeout_add_seconds (
155 EVOLUTION_SHUTDOWN_TIMEOUT, (GSourceFunc)
156 evolution_not_responding_cb, NULL);
157
158 /* Start the clock. */
159
160 main_loop = g_main_loop_new (NULL, TRUE);
161 g_main_loop_run (main_loop);
162 g_main_loop_unref (main_loop);
163
164 g_object_unref (monitor);
165
166 kill:
167 #ifdef KILL_PROCESS_CMD
168 system (KILL_PROCESS_CMD " -QUIT evolution 2> /dev/null");
ignoring return value of 'system', declared with attribute warn_unused_result
(emitted by gcc)
169 #else
170 g_printerr ("No \"kill\" command available.\n");
171 #endif
172
173 return retval;
174 }