~gagern/lightdm/preferred-users

352 by robert.ancell at canonical
Split child process code out from session/xserver
1
/*
494 by Robert Ancell
Update copyright year
2
 * Copyright (C) 2010-2011 Robert Ancell.
352 by robert.ancell at canonical
Split child process code out from session/xserver
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 <glib/gstdio.h>
1517 by Robert Ancell
Handle clearenv() not being defined
21
#include <config.h>
352 by robert.ancell at canonical
Split child process code out from session/xserver
22
849 by Robert Ancell
Rename ChildProcess to Process
23
#include "process.h"
352 by robert.ancell at canonical
Split child process code out from session/xserver
24
25
enum {
1128 by Robert Ancell
Add VNC server support
26
    RUN,
353 by robert.ancell at canonical
Use a private pipe for greeter<->server communication instead of D-Bus (needs to be fixed in liblightdm-qt)
27
    GOT_DATA,
352 by robert.ancell at canonical
Split child process code out from session/xserver
28
    GOT_SIGNAL,  
652 by Robert Ancell
Shut down display manager more carefully
29
    STOPPED,
352 by robert.ancell at canonical
Split child process code out from session/xserver
30
    LAST_SIGNAL
31
};
32
static guint signals[LAST_SIGNAL] = { 0 };
33
849 by Robert Ancell
Rename ChildProcess to Process
34
struct ProcessPrivate
352 by robert.ancell at canonical
Split child process code out from session/xserver
35
{  
1128 by Robert Ancell
Add VNC server support
36
    /* Command to run */
37
    gchar *command;
1211 by Robert Ancell
Move user/log file code outside of process.c, get PAM environment after pam_setcred() is used, remove some unused started signals
38
  
39
    /* TRUE to clear the environment in this process */
40
    gboolean clear_environment;
41
42
    /* Environment variables to set */
43
    GHashTable *env;
44
1128 by Robert Ancell
Add VNC server support
45
    /* Process ID */
46
    GPid pid;
1156 by Robert Ancell
Tidy up blocking process code
47
  
48
    /* Exit status of process */
49
    int exit_status;
1128 by Robert Ancell
Add VNC server support
50
652 by Robert Ancell
Shut down display manager more carefully
51
    /* Timeout waiting for process to quit */
52
    guint quit_timeout;
1601 by Robert Ancell
Fix script hooks no longer working with latest glib
53
54
    /* Watch on process */
55
    guint watch;
352 by robert.ancell at canonical
Split child process code out from session/xserver
56
};
57
849 by Robert Ancell
Rename ChildProcess to Process
58
G_DEFINE_TYPE (Process, process, G_TYPE_OBJECT);
352 by robert.ancell at canonical
Split child process code out from session/xserver
59
849 by Robert Ancell
Rename ChildProcess to Process
60
static Process *current_process = NULL;
352 by robert.ancell at canonical
Split child process code out from session/xserver
61
static GHashTable *processes = NULL;
62
static int signal_pipe[2];
63
849 by Robert Ancell
Rename ChildProcess to Process
64
Process *
65
process_get_current (void)
352 by robert.ancell at canonical
Split child process code out from session/xserver
66
{
849 by Robert Ancell
Rename ChildProcess to Process
67
    if (current_process)
68
        return current_process;
69
70
    current_process = process_new ();
71
    current_process->priv->pid = getpid ();
72
73
    return current_process;
352 by robert.ancell at canonical
Split child process code out from session/xserver
74
}
75
849 by Robert Ancell
Rename ChildProcess to Process
76
Process *
77
process_new (void)
352 by robert.ancell at canonical
Split child process code out from session/xserver
78
{
849 by Robert Ancell
Rename ChildProcess to Process
79
    return g_object_new (PROCESS_TYPE, NULL);
352 by robert.ancell at canonical
Split child process code out from session/xserver
80
}
81
82
void
1211 by Robert Ancell
Move user/log file code outside of process.c, get PAM environment after pam_setcred() is used, remove some unused started signals
83
process_set_clear_environment (Process *process, gboolean clear_environment)
84
{
85
    g_return_if_fail (process != NULL);
86
    process->priv->clear_environment = clear_environment;
87
}
88
89
gboolean
90
process_get_clear_environment (Process *process)
91
{
92
    g_return_val_if_fail (process != NULL, FALSE);
93
    return process->priv->clear_environment;
94
}
95
96
void
97
process_set_env (Process *process, const gchar *name, const gchar *value)
98
{
99
    g_return_if_fail (process != NULL);
100
    g_return_if_fail (name != NULL);
101
    g_hash_table_insert (process->priv->env, g_strdup (name), g_strdup (value));  
102
}
103
104
const gchar *
105
process_get_env (Process *process, const gchar *name)
106
{
107
    g_return_val_if_fail (process != NULL, NULL);
108
    g_return_val_if_fail (name != NULL, NULL);
109
    return g_hash_table_lookup (process->priv->env, name);
110
}
111
112
void
1128 by Robert Ancell
Add VNC server support
113
process_set_command (Process *process, const gchar *command)
114
{
115
    g_return_if_fail (process != NULL);
116
117
    g_free (process->priv->command);
118
    process->priv->command = g_strdup (command);
119
}
120
121
const gchar *
122
process_get_command (Process *process)
123
{
124
    g_return_val_if_fail (process != NULL, NULL);
125
    return process->priv->command;
126
}
127
352 by robert.ancell at canonical
Split child process code out from session/xserver
128
static void
849 by Robert Ancell
Rename ChildProcess to Process
129
process_watch_cb (GPid pid, gint status, gpointer data)
352 by robert.ancell at canonical
Split child process code out from session/xserver
130
{
849 by Robert Ancell
Rename ChildProcess to Process
131
    Process *process = data;
352 by robert.ancell at canonical
Split child process code out from session/xserver
132
1156 by Robert Ancell
Tidy up blocking process code
133
    process->priv->exit_status = status;
134
352 by robert.ancell at canonical
Split child process code out from session/xserver
135
    if (WIFEXITED (status))
136
        g_debug ("Process %d exited with return value %d", pid, WEXITSTATUS (status));
137
    else if (WIFSIGNALED (status))
138
        g_debug ("Process %d terminated with signal %d", pid, WTERMSIG (status));
139
1601 by Robert Ancell
Fix script hooks no longer working with latest glib
140
    if (process->priv->watch)
141
        g_source_remove (process->priv->watch);
142
    process->priv->watch = 0;
143
652 by Robert Ancell
Shut down display manager more carefully
144
    if (process->priv->quit_timeout)
145
        g_source_remove (process->priv->quit_timeout);
146
    process->priv->quit_timeout = 0;  
589 by Robert Ancell
Fix reference counting with child processes
147
    process->priv->pid = 0;
597 by Robert Ancell
Stop all child processes before quitting main process
148
    g_hash_table_remove (processes, GINT_TO_POINTER (pid));
149
652 by Robert Ancell
Shut down display manager more carefully
150
    g_signal_emit (process, signals[STOPPED], 0);
352 by robert.ancell at canonical
Split child process code out from session/xserver
151
}
152
153
static void
1202 by Robert Ancell
Run pam_setcred inside the session process so pam_group works
154
process_run (Process *process)
155
{
156
    gint argc;
157
    gchar **argv;
1211 by Robert Ancell
Move user/log file code outside of process.c, get PAM environment after pam_setcred() is used, remove some unused started signals
158
    GHashTableIter iter;
159
    gpointer key, value;
1202 by Robert Ancell
Run pam_setcred inside the session process so pam_group works
160
    GError *error = NULL;
161
162
    if (!g_shell_parse_argv (process->priv->command, &argc, &argv, &error))
163
    {
164
        g_warning ("Error parsing command %s: %s", process->priv->command, error->message);
165
        _exit (EXIT_FAILURE);
166
    }
167
1211 by Robert Ancell
Move user/log file code outside of process.c, get PAM environment after pam_setcred() is used, remove some unused started signals
168
    if (process->priv->clear_environment)
1517 by Robert Ancell
Handle clearenv() not being defined
169
#ifdef HAVE_CLEARENV
1211 by Robert Ancell
Move user/log file code outside of process.c, get PAM environment after pam_setcred() is used, remove some unused started signals
170
        clearenv ();
1517 by Robert Ancell
Handle clearenv() not being defined
171
#else
172
        environ = NULL;
173
#endif
1202 by Robert Ancell
Run pam_setcred inside the session process so pam_group works
174
1211 by Robert Ancell
Move user/log file code outside of process.c, get PAM environment after pam_setcred() is used, remove some unused started signals
175
    g_hash_table_iter_init (&iter, process->priv->env);
176
    while (g_hash_table_iter_next (&iter, &key, &value))
177
        g_setenv ((gchar *)key, (gchar *)value, TRUE);
1202 by Robert Ancell
Run pam_setcred inside the session process so pam_group works
178
  
179
    execvp (argv[0], argv);
180
181
    g_warning ("Error executing child process %s: %s", argv[0], g_strerror (errno));
182
    _exit (EXIT_FAILURE);
183
}
184
352 by robert.ancell at canonical
Split child process code out from session/xserver
185
gboolean
1601 by Robert Ancell
Fix script hooks no longer working with latest glib
186
process_start (Process *process, gboolean block)
352 by robert.ancell at canonical
Split child process code out from session/xserver
187
{
353 by robert.ancell at canonical
Use a private pipe for greeter<->server communication instead of D-Bus (needs to be fixed in liblightdm-qt)
188
    pid_t pid;
352 by robert.ancell at canonical
Split child process code out from session/xserver
189
601 by Robert Ancell
Add g_return_if_fail lines to more modules
190
    g_return_val_if_fail (process != NULL, FALSE);
1128 by Robert Ancell
Add VNC server support
191
    g_return_val_if_fail (process->priv->command != NULL, FALSE);  
352 by robert.ancell at canonical
Split child process code out from session/xserver
192
    g_return_val_if_fail (process->priv->pid == 0, FALSE);
193
353 by robert.ancell at canonical
Use a private pipe for greeter<->server communication instead of D-Bus (needs to be fixed in liblightdm-qt)
194
    pid = fork ();
195
    if (pid < 0)
196
    {
197
        g_warning ("Failed to fork: %s", strerror (errno));
198
        return FALSE;
199
    }
200
201
    if (pid == 0)
1211 by Robert Ancell
Move user/log file code outside of process.c, get PAM environment after pam_setcred() is used, remove some unused started signals
202
        g_signal_emit (process, signals[RUN], 0);
352 by robert.ancell at canonical
Split child process code out from session/xserver
203
1211 by Robert Ancell
Move user/log file code outside of process.c, get PAM environment after pam_setcred() is used, remove some unused started signals
204
    g_debug ("Launching process %d: %s", pid, process->priv->command);
352 by robert.ancell at canonical
Split child process code out from session/xserver
205
353 by robert.ancell at canonical
Use a private pipe for greeter<->server communication instead of D-Bus (needs to be fixed in liblightdm-qt)
206
    process->priv->pid = pid;
352 by robert.ancell at canonical
Split child process code out from session/xserver
207
1601 by Robert Ancell
Fix script hooks no longer working with latest glib
208
    if (block)
209
    {
210
        int exit_status;
211
        waitpid (process->priv->pid, &exit_status, 0);
212
        process_watch_cb (process->priv->pid, exit_status, process);
213
    }  
214
    else
215
    {
216
        g_hash_table_insert (processes, GINT_TO_POINTER (process->priv->pid), g_object_ref (process));
217
        process->priv->watch = g_child_watch_add (process->priv->pid, process_watch_cb, process);
218
    }
352 by robert.ancell at canonical
Split child process code out from session/xserver
219
220
    return TRUE;
221
}
222
664 by Robert Ancell
Restart X server if it crashes during a session
223
gboolean
849 by Robert Ancell
Rename ChildProcess to Process
224
process_get_is_running (Process *process)
664 by Robert Ancell
Restart X server if it crashes during a session
225
{
226
    g_return_val_if_fail (process != NULL, FALSE);
227
    return process->priv->pid != 0;
228
}
229
352 by robert.ancell at canonical
Split child process code out from session/xserver
230
GPid
849 by Robert Ancell
Rename ChildProcess to Process
231
process_get_pid (Process *process)
352 by robert.ancell at canonical
Split child process code out from session/xserver
232
{
664 by Robert Ancell
Restart X server if it crashes during a session
233
    g_return_val_if_fail (process != NULL, 0);
352 by robert.ancell at canonical
Split child process code out from session/xserver
234
    return process->priv->pid;
235
}
236
237
void
849 by Robert Ancell
Rename ChildProcess to Process
238
process_signal (Process *process, int signum)
352 by robert.ancell at canonical
Split child process code out from session/xserver
239
{
601 by Robert Ancell
Add g_return_if_fail lines to more modules
240
    g_return_if_fail (process != NULL);
241
597 by Robert Ancell
Stop all child processes before quitting main process
242
    if (process->priv->pid == 0)
243
        return;
244
245
    g_debug ("Sending signal %d to process %d", signum, process->priv->pid);
246
247
    if (kill (process->priv->pid, signum) < 0)
248
        g_warning ("Error sending signal %d to process %d: %s", signum, process->priv->pid, strerror (errno));
352 by robert.ancell at canonical
Split child process code out from session/xserver
249
}
250
652 by Robert Ancell
Shut down display manager more carefully
251
static gboolean
849 by Robert Ancell
Rename ChildProcess to Process
252
quit_timeout_cb (Process *process)
652 by Robert Ancell
Shut down display manager more carefully
253
{
254
    process->priv->quit_timeout = 0;
849 by Robert Ancell
Rename ChildProcess to Process
255
    process_signal (process, SIGKILL);
652 by Robert Ancell
Shut down display manager more carefully
256
    return FALSE;
257
}
258
597 by Robert Ancell
Stop all child processes before quitting main process
259
void
849 by Robert Ancell
Rename ChildProcess to Process
260
process_stop (Process *process)
597 by Robert Ancell
Stop all child processes before quitting main process
261
{
1156 by Robert Ancell
Tidy up blocking process code
262
    g_return_if_fail (process != NULL);
263
652 by Robert Ancell
Shut down display manager more carefully
264
    /* Send SIGTERM, and then SIGKILL if no response */
265
    process->priv->quit_timeout = g_timeout_add (5000, (GSourceFunc) quit_timeout_cb, process);
849 by Robert Ancell
Rename ChildProcess to Process
266
    process_signal (process, SIGTERM);
597 by Robert Ancell
Stop all child processes before quitting main process
267
}
268
1156 by Robert Ancell
Tidy up blocking process code
269
int
270
process_get_exit_status (Process *process)
271
{
272
    g_return_val_if_fail (process != NULL, -1);
273
    return process->priv->exit_status;
274
}
275
352 by robert.ancell at canonical
Split child process code out from session/xserver
276
static void
849 by Robert Ancell
Rename ChildProcess to Process
277
process_init (Process *process)
352 by robert.ancell at canonical
Split child process code out from session/xserver
278
{
849 by Robert Ancell
Rename ChildProcess to Process
279
    process->priv = G_TYPE_INSTANCE_GET_PRIVATE (process, PROCESS_TYPE, ProcessPrivate);
352 by robert.ancell at canonical
Split child process code out from session/xserver
280
    process->priv->env = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
281
}
282
283
static void
1006 by Robert Ancell
Moving authentication from Display to Session
284
process_stopped (Process *process)
285
{
286
}
287
288
static void
849 by Robert Ancell
Rename ChildProcess to Process
289
process_finalize (GObject *object)
352 by robert.ancell at canonical
Split child process code out from session/xserver
290
{
849 by Robert Ancell
Rename ChildProcess to Process
291
    Process *self;
352 by robert.ancell at canonical
Split child process code out from session/xserver
292
849 by Robert Ancell
Rename ChildProcess to Process
293
    self = PROCESS (object);
972 by Robert Ancell
Fix whitespace
294
1128 by Robert Ancell
Add VNC server support
295
    if (self->priv->pid > 0)
296
        g_hash_table_remove (processes, GINT_TO_POINTER (self->priv->pid));
297
298
    g_free (self->priv->command);
1211 by Robert Ancell
Move user/log file code outside of process.c, get PAM environment after pam_setcred() is used, remove some unused started signals
299
    g_hash_table_unref (self->priv->env);
1812.1.1 by Robert Ancell
Destroy quit timeout when a process object is destroyed - fixes a crash where a deleted Process object might be accessed after a timeout
300
    if (self->priv->quit_timeout)
301
        g_source_remove (self->priv->quit_timeout);
1601 by Robert Ancell
Fix script hooks no longer working with latest glib
302
    if (self->priv->watch)
303
        g_source_remove (self->priv->watch);
352 by robert.ancell at canonical
Split child process code out from session/xserver
304
305
    if (self->priv->pid)
306
        kill (self->priv->pid, SIGTERM);
307
849 by Robert Ancell
Rename ChildProcess to Process
308
    G_OBJECT_CLASS (process_parent_class)->finalize (object);
352 by robert.ancell at canonical
Split child process code out from session/xserver
309
}
310
311
static void
312
signal_cb (int signum, siginfo_t *info, void *data)
313
{
590 by Robert Ancell
Fix crash when catching signals
314
    /* NOTE: Using g_printerr as can't call g_warning from a signal callback */
352 by robert.ancell at canonical
Split child process code out from session/xserver
315
    if (write (signal_pipe[1], &info->si_signo, sizeof (int)) < 0 ||
316
        write (signal_pipe[1], &info->si_pid, sizeof (pid_t)) < 0)
590 by Robert Ancell
Fix crash when catching signals
317
        g_printerr ("Failed to write to signal pipe: %s", strerror (errno));
352 by robert.ancell at canonical
Split child process code out from session/xserver
318
}
319
320
static gboolean
321
handle_signal (GIOChannel *source, GIOCondition condition, gpointer data)
322
{
323
    int signo;
324
    pid_t pid;
849 by Robert Ancell
Rename ChildProcess to Process
325
    Process *process;
352 by robert.ancell at canonical
Split child process code out from session/xserver
326
1774.3.7 by Robert Ancell
Check return value reading from signal pipe
327
    errno = 0;
328
    if (read (signal_pipe[0], &signo, sizeof (int)) != sizeof (int) || 
329
        read (signal_pipe[0], &pid, sizeof (pid_t)) != sizeof (pid_t))
552 by Robert Ancell
Log failures to read signal pipe
330
    {
331
        g_warning ("Error reading from signal pipe: %s", strerror (errno));
352 by robert.ancell at canonical
Split child process code out from session/xserver
332
        return TRUE;
552 by Robert Ancell
Log failures to read signal pipe
333
    }
352 by robert.ancell at canonical
Split child process code out from session/xserver
334
590 by Robert Ancell
Fix crash when catching signals
335
    g_debug ("Got signal %d from process %d", signo, pid);
336
478.1.1 by Jason Conti
child-process/handle_signal: Try to lookup the process in the hash table before falling back to the parent process, so signals are properly emitted on shutdown.
337
    process = g_hash_table_lookup (processes, GINT_TO_POINTER (pid));
589 by Robert Ancell
Fix reference counting with child processes
338
    if (process == NULL)
849 by Robert Ancell
Rename ChildProcess to Process
339
        process = process_get_current ();
589 by Robert Ancell
Fix reference counting with child processes
340
    if (process)
352 by robert.ancell at canonical
Split child process code out from session/xserver
341
        g_signal_emit (process, signals[GOT_SIGNAL], 0, signo);
342
343
    return TRUE;
344
}
345
346
static void
849 by Robert Ancell
Rename ChildProcess to Process
347
process_class_init (ProcessClass *klass)
352 by robert.ancell at canonical
Split child process code out from session/xserver
348
{
349
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
350
    struct sigaction action;
351
1128 by Robert Ancell
Add VNC server support
352
    klass->run = process_run;
1006 by Robert Ancell
Moving authentication from Display to Session
353
    klass->stopped = process_stopped;
849 by Robert Ancell
Rename ChildProcess to Process
354
    object_class->finalize = process_finalize;  
352 by robert.ancell at canonical
Split child process code out from session/xserver
355
849 by Robert Ancell
Rename ChildProcess to Process
356
    g_type_class_add_private (klass, sizeof (ProcessPrivate));
352 by robert.ancell at canonical
Split child process code out from session/xserver
357
1128 by Robert Ancell
Add VNC server support
358
    signals[RUN] =
359
        g_signal_new ("run",
360
                      G_TYPE_FROM_CLASS (klass),
361
                      G_SIGNAL_RUN_LAST,
362
                      G_STRUCT_OFFSET (ProcessClass, run),
363
                      NULL, NULL,
1710.1.1 by Robert Ancell
Stop generating glib marshals by using glib >= 2.30
364
                      NULL,
1128 by Robert Ancell
Add VNC server support
365
                      G_TYPE_NONE, 0); 
353 by robert.ancell at canonical
Use a private pipe for greeter<->server communication instead of D-Bus (needs to be fixed in liblightdm-qt)
366
    signals[GOT_DATA] =
367
        g_signal_new ("got-data",
368
                      G_TYPE_FROM_CLASS (klass),
369
                      G_SIGNAL_RUN_LAST,
849 by Robert Ancell
Rename ChildProcess to Process
370
                      G_STRUCT_OFFSET (ProcessClass, got_data),
353 by robert.ancell at canonical
Use a private pipe for greeter<->server communication instead of D-Bus (needs to be fixed in liblightdm-qt)
371
                      NULL, NULL,
1710.1.1 by Robert Ancell
Stop generating glib marshals by using glib >= 2.30
372
                      NULL,
353 by robert.ancell at canonical
Use a private pipe for greeter<->server communication instead of D-Bus (needs to be fixed in liblightdm-qt)
373
                      G_TYPE_NONE, 0); 
352 by robert.ancell at canonical
Split child process code out from session/xserver
374
    signals[GOT_SIGNAL] =
375
        g_signal_new ("got-signal",
376
                      G_TYPE_FROM_CLASS (klass),
377
                      G_SIGNAL_RUN_LAST,
849 by Robert Ancell
Rename ChildProcess to Process
378
                      G_STRUCT_OFFSET (ProcessClass, got_signal),
352 by robert.ancell at canonical
Split child process code out from session/xserver
379
                      NULL, NULL,
1710.1.1 by Robert Ancell
Stop generating glib marshals by using glib >= 2.30
380
                      NULL,
352 by robert.ancell at canonical
Split child process code out from session/xserver
381
                      G_TYPE_NONE, 1, G_TYPE_INT);
652 by Robert Ancell
Shut down display manager more carefully
382
    signals[STOPPED] =
383
        g_signal_new ("stopped",
384
                      G_TYPE_FROM_CLASS (klass),
385
                      G_SIGNAL_RUN_LAST,
849 by Robert Ancell
Rename ChildProcess to Process
386
                      G_STRUCT_OFFSET (ProcessClass, stopped),
652 by Robert Ancell
Shut down display manager more carefully
387
                      NULL, NULL,
1710.1.1 by Robert Ancell
Stop generating glib marshals by using glib >= 2.30
388
                      NULL,
652 by Robert Ancell
Shut down display manager more carefully
389
                      G_TYPE_NONE, 0);
352 by robert.ancell at canonical
Split child process code out from session/xserver
390
391
    /* Catch signals and feed them to the main loop via a pipe */
589 by Robert Ancell
Fix reference counting with child processes
392
    processes = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
352 by robert.ancell at canonical
Split child process code out from session/xserver
393
    if (pipe (signal_pipe) != 0)
394
        g_critical ("Failed to create signal pipe");
1445 by Robert Ancell
Stop file descriptors leaking into the session processes
395
    fcntl (signal_pipe[0], F_SETFD, FD_CLOEXEC);
396
    fcntl (signal_pipe[1], F_SETFD, FD_CLOEXEC);
352 by robert.ancell at canonical
Split child process code out from session/xserver
397
    g_io_add_watch (g_io_channel_unix_new (signal_pipe[0]), G_IO_IN, handle_signal, NULL);
398
    action.sa_sigaction = signal_cb;
399
    sigemptyset (&action.sa_mask);
400
    action.sa_flags = SA_SIGINFO;
401
    sigaction (SIGTERM, &action, NULL);
402
    sigaction (SIGINT, &action, NULL);
403
    sigaction (SIGHUP, &action, NULL);
404
    sigaction (SIGUSR1, &action, NULL);
405
    sigaction (SIGUSR2, &action, NULL);
406
}