1 /*
2 * Copyright (C) 2010-2011 Robert Ancell.
3 * Author: Robert Ancell <robert.ancell@canonical.com>
4 *
5 * This program is free software: you can redistribute it and/or modify it under
6 * the terms of the GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option) any later
8 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9 * license.
10 */
11
12 #include <stdlib.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <errno.h>
16 #include <sys/wait.h>
17 #include <fcntl.h>
18 #include <signal.h>
19 #include <grp.h>
20 #include <config.h>
21
22 #include "log-file.h"
23 #include "process.h"
24
25 enum {
26 GOT_DATA,
27 GOT_SIGNAL,
28 STOPPED,
29 LAST_SIGNAL
30 };
31 static guint signals[LAST_SIGNAL] = { 0 };
32
33 typedef struct
34 {
35 /* Function to run inside subprocess before exec */
36 ProcessRunFunc run_func;
37 gpointer run_func_data;
38
39 /* File to log to */
40 gchar *log_file;
41 gboolean log_stdout;
42 LogMode log_mode;
43
44 /* Command to run */
45 gchar *command;
46
47 /* TRUE to clear the environment in this process */
48 gboolean clear_environment;
49
50 /* Environment variables to set */
51 GHashTable *env;
52
53 /* Process ID */
54 GPid pid;
55
56 /* Exit status of process */
57 int exit_status;
58
59 /* TRUE if stopping this process (waiting for child process to stop) */
60 gboolean stopping;
61
62 /* Timeout waiting for process to quit */
63 guint quit_timeout;
64
65 /* Watch on process */
66 guint watch;
67 } ProcessPrivate;
68
69 G_DEFINE_TYPE_WITH_PRIVATE (Process, process, G_TYPE_OBJECT)
70
71 static Process *current_process = NULL;
72 static GHashTable *processes = NULL;
73 static pid_t signal_pid;
74 static int signal_pipe[2];
75
76 extern char **environ;
77
78 Process *
process_get_current(void)79 process_get_current (void)
80 {
81 if (current_process)
82 return current_process;
83
84 current_process = process_new (NULL, NULL);
85 ProcessPrivate *priv = process_get_instance_private (current_process);
86 priv->pid = getpid ();
87
88 return current_process;
89 }
90
91 Process *
process_new(ProcessRunFunc run_func,gpointer run_func_data)92 process_new (ProcessRunFunc run_func, gpointer run_func_data)
93 {
94 Process *process = g_object_new (PROCESS_TYPE, NULL);
95 ProcessPrivate *priv = process_get_instance_private (process);
96
97 priv->run_func = run_func;
98 priv->run_func_data = run_func_data;
99 priv->log_mode = LOG_MODE_INVALID;
100 return process;
101 }
102
103 void
process_set_log_file(Process * process,const gchar * path,gboolean log_stdout,LogMode log_mode)104 process_set_log_file (Process *process, const gchar *path, gboolean log_stdout, LogMode log_mode)
105 {
106 ProcessPrivate *priv = process_get_instance_private (process);
107
108 g_return_if_fail (process != NULL);
109
110 g_free (priv->log_file);
111 priv->log_file = g_strdup (path);
112 priv->log_stdout = log_stdout;
113 priv->log_mode = log_mode;
114 }
115
116 void
process_set_clear_environment(Process * process,gboolean clear_environment)117 process_set_clear_environment (Process *process, gboolean clear_environment)
118 {
119 ProcessPrivate *priv = process_get_instance_private (process);
120 g_return_if_fail (process != NULL);
121 priv->clear_environment = clear_environment;
122 }
123
124 gboolean
process_get_clear_environment(Process * process)125 process_get_clear_environment (Process *process)
126 {
127 ProcessPrivate *priv = process_get_instance_private (process);
128 g_return_val_if_fail (process != NULL, FALSE);
129 return priv->clear_environment;
130 }
131
132 void
process_set_env(Process * process,const gchar * name,const gchar * value)133 process_set_env (Process *process, const gchar *name, const gchar *value)
134 {
135 ProcessPrivate *priv = process_get_instance_private (process);
136 g_return_if_fail (process != NULL);
137 g_return_if_fail (name != NULL);
138 g_hash_table_insert (priv->env, g_strdup (name), g_strdup (value));
139 }
140
141 const gchar *
process_get_env(Process * process,const gchar * name)142 process_get_env (Process *process, const gchar *name)
143 {
144 ProcessPrivate *priv = process_get_instance_private (process);
145 g_return_val_if_fail (process != NULL, NULL);
146 g_return_val_if_fail (name != NULL, NULL);
147 return g_hash_table_lookup (priv->env, name);
148 }
149
150 void
process_set_command(Process * process,const gchar * command)151 process_set_command (Process *process, const gchar *command)
152 {
153 ProcessPrivate *priv = process_get_instance_private (process);
154 g_return_if_fail (process != NULL);
155 g_free (priv->command);
156 priv->command = g_strdup (command);
157 }
158
159 const gchar *
process_get_command(Process * process)160 process_get_command (Process *process)
161 {
162 ProcessPrivate *priv = process_get_instance_private (process);
163 g_return_val_if_fail (process != NULL, NULL);
164 return priv->command;
165 }
166
167 static void
process_watch_cb(GPid pid,gint status,gpointer data)168 process_watch_cb (GPid pid, gint status, gpointer data)
169 {
170 Process *process = data;
171 ProcessPrivate *priv = process_get_instance_private (process);
172
173 priv->watch = 0;
174 priv->exit_status = status;
175
176 if (WIFEXITED (status))
177 g_debug ("Process %d exited with return value %d", pid, WEXITSTATUS (status));
178 else if (WIFSIGNALED (status))
179 g_debug ("Process %d terminated with signal %d", pid, WTERMSIG (status));
180
181 if (priv->quit_timeout)
182 g_source_remove (priv->quit_timeout);
183 priv->quit_timeout = 0;
184 priv->pid = 0;
185 g_hash_table_remove (processes, GINT_TO_POINTER (pid));
186
187 g_signal_emit (process, signals[STOPPED], 0);
188 }
189
190 gboolean
process_start(Process * process,gboolean block)191 process_start (Process *process, gboolean block)
192 {
193 ProcessPrivate *priv = process_get_instance_private (process);
194
195 g_return_val_if_fail (process != NULL, FALSE);
196 g_return_val_if_fail (priv->command != NULL, FALSE);
197 g_return_val_if_fail (priv->pid == 0, FALSE);
198
199 gint argc;
200 g_auto(GStrv) argv = NULL;
201 g_autoptr(GError) error = NULL;
202 if (!g_shell_parse_argv (priv->command, &argc, &argv, &error))
203 {
204 g_warning ("Error parsing command %s: %s", priv->command, error->message);
205 return FALSE;
206 }
207
208 int log_fd = -1;
209 if (priv->log_file)
210 log_fd = log_file_open (priv->log_file, priv->log_mode);
211
212 /* Work out variables to set */
213 guint env_length = g_hash_table_size (priv->env);
214 g_autofree gchar **env_keys = g_malloc (sizeof (gchar *) * env_length);
215 g_autofree gchar **env_values = g_malloc (sizeof (gchar *) * env_length);
216 GList *keys = g_hash_table_get_keys (priv->env);
217 guint i = 0;
218 for (GList *link = keys; i < env_length; i++, link = link->next)
219 {
220 env_keys[i] = link->data;
221 env_values[i] = g_hash_table_lookup (priv->env, env_keys[i]);
222 }
223 g_list_free (keys);
224
225 pid_t pid = fork ();
226 if (pid == 0)
227 {
228 /* Do custom setup */
229 if (priv->run_func)
230 priv->run_func (process, priv->run_func_data);
231
232 /* Redirect output to logfile */
233 if (log_fd >= 0)
234 {
235 if (priv->log_stdout)
236 dup2 (log_fd, STDOUT_FILENO);
237 dup2 (log_fd, STDERR_FILENO);
238 close (log_fd);
239 }
240
241 /* Set environment */
242 if (priv->clear_environment)
243 #ifdef HAVE_CLEARENV
244 clearenv ();
245 #else
246 environ = NULL;
247 #endif
248 for (guint i = 0; i < env_length; i++)
249 setenv (env_keys[i], env_values[i], TRUE);
250
251 /* Reset SIGPIPE handler so the child has default behaviour (we disabled it at LightDM start) */
252 signal (SIGPIPE, SIG_DFL);
253
254 execvp (argv[0], argv);
255 _exit (EXIT_FAILURE);
256 }
257
258 close (log_fd);
259
260 if (pid < 0)
261 {
262 g_warning ("Failed to fork: %s", strerror (errno));
263 return FALSE;
264 }
265
266 g_debug ("Launching process %d: %s", pid, priv->command);
267
268 priv->pid = pid;
269
270 if (block)
271 {
272 int exit_status;
273 waitpid (priv->pid, &exit_status, 0);
274 process_watch_cb (priv->pid, exit_status, process);
275 }
276 else
277 {
278 g_hash_table_insert (processes, GINT_TO_POINTER (priv->pid), g_object_ref (process));
279 priv->watch = g_child_watch_add (priv->pid, process_watch_cb, process);
280 }
281
282 return TRUE;
283 }
284
285 gboolean
process_get_is_running(Process * process)286 process_get_is_running (Process *process)
287 {
288 ProcessPrivate *priv = process_get_instance_private (process);
289 g_return_val_if_fail (process != NULL, FALSE);
290 return priv->pid != 0;
291 }
292
293 GPid
process_get_pid(Process * process)294 process_get_pid (Process *process)
295 {
296 ProcessPrivate *priv = process_get_instance_private (process);
297 g_return_val_if_fail (process != NULL, 0);
298 return priv->pid;
299 }
300
301 void
process_signal(Process * process,int signum)302 process_signal (Process *process, int signum)
303 {
304 ProcessPrivate *priv = process_get_instance_private (process);
305
306 g_return_if_fail (process != NULL);
307
308 if (priv->pid == 0)
309 return;
310
311 g_debug ("Sending signal %d to process %d", signum, priv->pid);
312
313 if (kill (priv->pid, signum) < 0)
314 {
315 /* Ignore ESRCH, we will pick that up in our wait */
316 if (errno != ESRCH)
317 g_warning ("Error sending signal %d to process %d: %s", signum, priv->pid, strerror (errno));
318 }
319 }
320
321 static gboolean
quit_timeout_cb(Process * process)322 quit_timeout_cb (Process *process)
323 {
324 ProcessPrivate *priv = process_get_instance_private (process);
325
326 priv->quit_timeout = 0;
327 process_signal (process, SIGKILL);
328
329 return FALSE;
330 }
331
332 void
process_stop(Process * process)333 process_stop (Process *process)
334 {
335 ProcessPrivate *priv = process_get_instance_private (process);
336
337 g_return_if_fail (process != NULL);
338
339 if (priv->stopping)
340 return;
341 priv->stopping = TRUE;
342
343 /* If already stopped then we're done! */
344 if (priv->pid == 0)
345 return;
346
347 /* Send SIGTERM, and then SIGKILL if no response */
348 priv->quit_timeout = g_timeout_add (5000, (GSourceFunc) quit_timeout_cb, process);
349 process_signal (process, SIGTERM);
350 }
351
352 int
process_get_exit_status(Process * process)353 process_get_exit_status (Process *process)
354 {
355 ProcessPrivate *priv = process_get_instance_private (process);
356 g_return_val_if_fail (process != NULL, -1);
357 return priv->exit_status;
358 }
359
360 static void
process_init(Process * process)361 process_init (Process *process)
362 {
363 ProcessPrivate *priv = process_get_instance_private (process);
364 priv->env = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
365 }
366
367 static void
process_stopped(Process * process)368 process_stopped (Process *process)
369 {
370 }
371
372 static void
process_finalize(GObject * object)373 process_finalize (GObject *object)
374 {
375 Process *self = PROCESS (object);
376 ProcessPrivate *priv = process_get_instance_private (self);
377
378 if (priv->pid > 0)
379 g_hash_table_remove (processes, GINT_TO_POINTER (priv->pid));
380
381 g_clear_pointer (&priv->log_file, g_free);
382 g_clear_pointer (&priv->command, g_free);
383 g_hash_table_unref (priv->env);
384 if (priv->quit_timeout)
385 g_source_remove (priv->quit_timeout);
386 if (priv->watch)
387 g_source_remove (priv->watch);
388
389 if (priv->pid)
390 kill (priv->pid, SIGTERM);
391
392 G_OBJECT_CLASS (process_parent_class)->finalize (object);
393 }
394
395 static void
signal_cb(int signum,siginfo_t * info,void * data)396 signal_cb (int signum, siginfo_t *info, void *data)
397 {
398 /* Check if we are from a forked process that hasn't updated the signal handlers or execed.
399 If so, then we should just quit */
400 if (getpid () != signal_pid)
401 _exit (EXIT_SUCCESS);
402
403 /* Write signal to main thread, if something goes wrong just close the pipe so it is detected on the other end */
404 if (write (signal_pipe[1], &info->si_signo, sizeof (int)) < 0 ||
405 write (signal_pipe[1], &info->si_pid, sizeof (pid_t)) < 0)
406 close (signal_pipe[1]);
407 }
408
409 static gboolean
handle_signal(GIOChannel * source,GIOCondition condition,gpointer data)410 handle_signal (GIOChannel *source, GIOCondition condition, gpointer data)
411 {
412 errno = 0;
413 int signo;
414 pid_t pid;
415 if (read (signal_pipe[0], &signo, sizeof (int)) != sizeof (int) ||
416 read (signal_pipe[0], &pid, sizeof (pid_t)) != sizeof (pid_t))
417 {
418 g_warning ("Error reading from signal pipe: %s", strerror (errno));
419 return FALSE;
420 }
421
422 g_debug ("Got signal %d from process %d", signo, pid);
423
424 Process *process = g_hash_table_lookup (processes, GINT_TO_POINTER (pid));
425 if (process == NULL)
426 process = process_get_current ();
427 if (process)
428 g_signal_emit (process, signals[GOT_SIGNAL], 0, signo);
429
430 return TRUE;
431 }
432
433 static void
process_class_init(ProcessClass * klass)434 process_class_init (ProcessClass *klass)
435 {
436 GObjectClass *object_class = G_OBJECT_CLASS (klass);
437 struct sigaction action;
438
439 klass->stopped = process_stopped;
440 object_class->finalize = process_finalize;
441
442 signals[GOT_DATA] =
443 g_signal_new (PROCESS_SIGNAL_GOT_DATA,
444 G_TYPE_FROM_CLASS (klass),
445 G_SIGNAL_RUN_LAST,
446 G_STRUCT_OFFSET (ProcessClass, got_data),
447 NULL, NULL,
448 NULL,
449 G_TYPE_NONE, 0);
450 signals[GOT_SIGNAL] =
451 g_signal_new (PROCESS_SIGNAL_GOT_SIGNAL,
452 G_TYPE_FROM_CLASS (klass),
453 G_SIGNAL_RUN_LAST,
454 G_STRUCT_OFFSET (ProcessClass, got_signal),
455 NULL, NULL,
456 NULL,
457 G_TYPE_NONE, 1, G_TYPE_INT);
458 signals[STOPPED] =
459 g_signal_new (PROCESS_SIGNAL_STOPPED,
460 G_TYPE_FROM_CLASS (klass),
461 G_SIGNAL_RUN_LAST,
462 G_STRUCT_OFFSET (ProcessClass, stopped),
463 NULL, NULL,
464 NULL,
465 G_TYPE_NONE, 0);
466
467 /* Catch signals and feed them to the main loop via a pipe */
468 processes = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
469 signal_pid = getpid ();
470 if (pipe (signal_pipe) != 0)
471 g_critical ("Failed to create signal pipe");
472 fcntl (signal_pipe[0], F_SETFD, FD_CLOEXEC);
473 fcntl (signal_pipe[1], F_SETFD, FD_CLOEXEC);
474 g_io_add_watch (g_io_channel_unix_new (signal_pipe[0]), G_IO_IN, handle_signal, NULL);
475 action.sa_sigaction = signal_cb;
476 sigemptyset (&action.sa_mask);
477 action.sa_flags = SA_SIGINFO | SA_RESTART;
478 sigaction (SIGTERM, &action, NULL);
479 sigaction (SIGINT, &action, NULL);
480 sigaction (SIGUSR1, &action, NULL);
481 sigaction (SIGUSR2, &action, NULL);
482 }
483