Use sigaction to set signal handlers, the previous commit (1.1.2.16)
[tinc] / src / process.c
1 /*
2     process.c -- process management functions
3     Copyright (C) 1999,2000 Ivo Timmermans <itimmermans@bigfoot.com>,
4                        2000 Guus Sliepen <guus@sliepen.warande.net>
5
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id: process.c,v 1.1.2.17 2000/11/28 08:59:27 zarq Exp $
21 */
22
23 #include "config.h"
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <syslog.h>
31 #include <sys/ioctl.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <termios.h>
37
38 #include <list.h>
39 #include <pidfile.h>
40 #include <utils.h>
41 #include <xalloc.h>
42
43 #include "conf.h"
44 #include "process.h"
45 #include "subnet.h"
46 #include "connection.h"
47
48 #include "system.h"
49
50 /* If zero, don't detach from the terminal. */
51 int do_detach = 1;
52
53 extern char *identname;
54 extern char *pidfilename;
55 extern char **g_argv;
56
57 sigset_t emptysigset;
58
59 void memory_full(int size)
60 {
61   syslog(LOG_ERR, _("Memory exhausted (couldn't allocate %d bytes), exiting."), size);
62   cp_trace();
63   exit(1);
64 }
65
66 /* Some functions the less gifted operating systems might lack... */
67
68 #ifndef HAVE_FCLOSEALL
69 int fcloseall(void)
70 {
71   fflush(stdin);
72   fflush(stdout);
73   fflush(stderr);
74   fclose(stdin);
75   fclose(stdout);
76   fclose(stderr);
77 }
78 #endif
79
80 /*
81   Close network connections, and terminate neatly
82 */
83 void cleanup_and_exit(int c)
84 {
85 cp
86   close_network_connections();
87
88   if(debug_lvl > DEBUG_NOTHING)
89     syslog(LOG_INFO, _("Total bytes written: tap %d, socket %d; bytes read: tap %d, socket %d"),
90            total_tap_out, total_socket_out, total_tap_in, total_socket_in);
91
92   syslog(LOG_NOTICE, _("Terminating"));
93
94   closelog();
95   exit(c);
96 }
97
98 /*
99   check for an existing tinc for this net, and write pid to pidfile
100 */
101 int write_pidfile(void)
102 {
103   int pid;
104 cp
105   if((pid = check_pid(pidfilename)))
106     {
107       if(netname)
108         fprintf(stderr, _("A tincd is already running for net `%s' with pid %d.\n"),
109                 netname, pid);
110       else
111         fprintf(stderr, _("A tincd is already running with pid %d.\n"), pid);
112       return 1;
113     }
114
115   /* if it's locked, write-protected, or whatever */
116   if(!write_pid(pidfilename))
117     return 1;
118 cp
119   return 0;
120 }
121
122 /*
123   kill older tincd for this net
124 */
125 int kill_other(void)
126 {
127   int pid;
128 cp
129   if(!(pid = read_pid(pidfilename)))
130     {
131       if(netname)
132         fprintf(stderr, _("No other tincd is running for net `%s'.\n"), netname);
133       else
134         fprintf(stderr, _("No other tincd is running.\n"));
135       return 1;
136     }
137
138   errno = 0;    /* No error, sometimes errno is only changed on error */
139   /* ESRCH is returned when no process with that pid is found */
140   if(kill(pid, SIGTERM) && errno == ESRCH)
141     fprintf(stderr, _("Removing stale lock file.\n"));
142   remove_pid(pidfilename);
143 cp
144   return 0;
145 }
146
147 /*
148   Detach from current terminal, write pidfile, kill parent
149 */
150 int detach(void)
151 {
152 cp
153   setup_signals();
154
155   /* First check if we can open a fresh new pidfile */
156   
157   if(write_pidfile())
158     return -1;
159
160   /* If we succeeded in doing that, detach */
161
162   if(do_detach)
163     {
164       if(daemon(0, 0) < 0)
165         {
166           fprintf(stderr, _("Couldn't detach from terminal: %m"));
167           return -1;
168         }
169
170       /* Now UPDATE the pid in the pidfile, because we changed it... */
171       
172       if(!write_pid(pidfilename))
173         return -1;
174     }
175   
176   openlog(identname, LOG_CONS | LOG_PID, LOG_DAEMON);
177
178   if(debug_lvl > DEBUG_NOTHING)
179     syslog(LOG_NOTICE, _("tincd %s (%s %s) starting, debug level %d"),
180            VERSION, __DATE__, __TIME__, debug_lvl);
181   else
182     syslog(LOG_NOTICE, _("tincd %s starting"), VERSION);
183
184   xalloc_fail_func = memory_full;
185 cp
186   return 0;
187 }
188
189 /*
190   Execute the program name, with sane environment.  All output will be
191   redirected to syslog.
192 */
193 void _execute_script(const char *name)  __attribute__ ((noreturn));
194 void _execute_script(const char *name)
195 {
196   char *scriptname;
197   char *s;
198 cp
199   if(netname)
200     {
201       asprintf(&s, "NETNAME=%s", netname);
202       putenv(s);        /* Don't free s! see man 3 putenv */
203     }
204 #ifdef HAVE_UNSETENV
205   else
206     {
207       unsetenv("NETNAME");
208     }
209 #endif
210
211   chdir("/");
212   
213   asprintf(&scriptname, "%s/%s", confbase, name);
214
215   /* Close all file descriptors */
216   closelog();           /* <- this means we cannot use syslog() here anymore! */
217   fcloseall();
218
219   execl(scriptname, NULL);
220   /* No return on success */
221   
222   if(errno != ENOENT)   /* Ignore if the file does not exist */
223     exit(-1);           /* Some error while trying execl(). */
224   else
225     exit(0);
226 }
227
228 /*
229   Fork and execute the program pointed to by name.
230 */
231 int execute_script(const char *name)
232 {
233   pid_t pid;
234   int status;
235 cp
236   if((pid = fork()) < 0)
237     {
238       syslog(LOG_ERR, _("System call `%s' failed: %m"),
239              "fork");
240       return -1;
241     }
242
243   if(pid)
244     {
245       if(debug_lvl >= DEBUG_STATUS)
246         syslog(LOG_INFO, _("Executing script %s"), name);
247
248       if(waitpid(pid, &status, 0) == pid)
249         {
250           if(WIFEXITED(status))         /* Child exited by itself */
251             {
252               if(WEXITSTATUS(status))
253                 {
254                   syslog(LOG_ERR, _("Process %d (%s) exited with non-zero status %d"), pid, name, WEXITSTATUS(status));
255                   return -1;
256                 }
257               else
258                 return 0;
259             }
260           else if(WIFSIGNALED(status))  /* Child was killed by a signal */
261             {
262               syslog(LOG_ERR, _("Process %d (%s) was killed by signal %d (%s)"),
263                      pid, name, WTERMSIG(status), strsignal(WTERMSIG(status)));
264               return -1;
265             }
266           else                          /* Something strange happened */
267             {
268               syslog(LOG_ERR, _("Process %d (%s) terminated abnormally"), pid, name);
269               return -1;
270             }
271         }
272       else
273         {
274           syslog(LOG_ERR, _("System call `%s' failed: %m"), "waitpid");
275           return -1;
276         }
277     }
278 cp
279   /* Child here */
280
281   _execute_script(name);
282 }
283
284
285 /*
286   Signal handlers.
287 */
288
289 RETSIGTYPE
290 sigterm_handler(int a, siginfo_t *info, void *b)
291 {
292   if(debug_lvl > DEBUG_NOTHING)
293     syslog(LOG_NOTICE, _("Got TERM signal"));
294
295   cleanup_and_exit(0);
296 }
297
298 RETSIGTYPE
299 sigquit_handler(int a, siginfo_t *info, void *b)
300 {
301   if(debug_lvl > DEBUG_NOTHING)
302     syslog(LOG_NOTICE, _("Got QUIT signal"));
303   cleanup_and_exit(0);
304 }
305
306 RETSIGTYPE
307 sigsegv_square(int a, siginfo_t *info, void *b)
308 {
309   syslog(LOG_ERR, _("Got another SEGV signal: not restarting"));
310   cp_trace();
311   exit(0);
312 }
313
314 RETSIGTYPE
315 sigsegv_handler(int a, siginfo_t *info, void *b)
316 {
317   struct sigaction act;
318   syslog(LOG_ERR, _("Got SEGV signal"));
319   cp_trace();
320
321   if(do_detach)
322     {
323       syslog(LOG_NOTICE, _("Trying to re-execute in 5 seconds..."));
324
325       act.sa_handler = NULL;
326       act.sa_mask = emptysigset;
327       act.sa_flags = SA_SIGINFO;
328       act.sa_sigaction = sigsegv_square;
329
330       close_network_connections();
331       sleep(5);
332       remove_pid(pidfilename);
333       execvp(g_argv[0], g_argv);
334     }
335   else
336     {
337       syslog(LOG_NOTICE, _("Not restarting."));
338       exit(0);
339     }
340 }
341
342 RETSIGTYPE
343 sighup_handler(int a, siginfo_t *info, void *b)
344 {
345   if(debug_lvl > DEBUG_NOTHING)
346     syslog(LOG_NOTICE, _("Got HUP signal"));
347   sighup = 1;
348 }
349
350 RETSIGTYPE
351 sigint_handler(int a, siginfo_t *info, void *b)
352 {
353   if(debug_lvl > DEBUG_NOTHING)
354     syslog(LOG_NOTICE, _("Got INT signal, exiting"));
355   cleanup_and_exit(0);
356 }
357
358 RETSIGTYPE
359 sigusr1_handler(int a, siginfo_t *info, void *b)
360 {
361   dump_connection_list();
362 }
363
364 RETSIGTYPE
365 sigusr2_handler(int a, siginfo_t *info, void *b)
366 {
367   dump_subnet_list();
368 }
369
370 RETSIGTYPE
371 unexpected_signal_handler(int a, siginfo_t *info, void *b)
372 {
373   syslog(LOG_WARNING, _("Got unexpected signal %d (%s)"), a, strsignal(a));
374   cp_trace();
375 }
376
377 struct {
378   int signal;
379   void (*handler)(int, siginfo_t *, void *);
380 } sighandlers[] = {
381   { SIGHUP, sighup_handler },
382   { SIGTERM, sigterm_handler },
383   { SIGQUIT, sigquit_handler },
384   { SIGSEGV, sigsegv_handler },
385   { SIGPIPE, NULL },
386   { SIGINT, sigint_handler },
387   { SIGUSR1, sigusr1_handler },
388   { SIGUSR2, sigusr2_handler },
389   { SIGCHLD, NULL },
390   { 0, NULL }
391 };
392
393 void
394 setup_signals(void)
395 {
396   int i;
397   struct sigaction act;
398
399   sigemptyset(&emptysigset);
400   act.sa_handler = NULL;
401   act.sa_mask = emptysigset;
402   act.sa_flags = SA_SIGINFO;
403
404   /* Set a default signal handler for every signal, errors will be
405      ignored. */
406   for(i = 0; i < NSIG; i++) 
407     {
408       act.sa_sigaction = unexpected_signal_handler;
409       sigaction(sighandlers[i].signal, &act, NULL);
410     }
411
412   /* Then, for each known signal that we want to catch, assign a
413      handler to the signal, with error checking this time. */
414   for(i = 0; sighandlers[i].signal; i++)
415     {
416       act.sa_sigaction = sighandlers[i].handler;
417       if(sigaction(sighandlers[i].signal, &act, NULL) < 0)
418         fprintf(stderr, _("Installing signal handler for signal %d (%s) failed: %m\n"),
419                 sighandlers[i].signal, strsignal(sighandlers[i].signal));
420     }
421 }