Moving files, first attempt at gcrypt compatibility, more interface
[oweals/tinc.git] / src / pokey / process.c
1 /*
2     process.c -- process management functions
3     Copyright (C) 1999-2002 Ivo Timmermans <itimmermans@bigfoot.com>,
4                   2000-2002 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 2002/04/28 12:46:26 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 <pidfile.h>
39 #include <utils.h>
40 #include <xalloc.h>
41
42 #include "conf.h"
43 #include "interface.h"
44 #include "process.h"
45 #include "subnet.h"
46 #include "connection.h"
47 #include "logging.h"
48
49 #include "system.h"
50
51 /* If zero, don't detach from the terminal. */
52 int do_detach = 1;
53
54 extern char *identname;
55 extern char *pidfilename;
56 extern char **g_argv;
57
58 sigset_t emptysigset;
59
60 static int saved_debug_lvl = 0;
61
62 extern int sighup;
63 extern int sigalrm;
64 extern int do_purge;
65
66 void memory_full(int size)
67 {
68   log(0, TLOG_ERROR,
69       _("Memory exhausted (couldn't allocate %d bytes), exitting."),
70       size);
71   cp_trace();
72   exit(1);
73 }
74
75 /* Some functions the less gifted operating systems might lack... */
76
77 #ifndef HAVE_FCLOSEALL
78 int fcloseall(void)
79 {
80   fflush(stdin);
81   fflush(stdout);
82   fflush(stderr);
83   fclose(stdin);
84   fclose(stdout);
85   fclose(stderr);
86   return 0;
87 }
88 #endif
89
90 /*
91   Close network connections, and terminate neatly
92 */
93 void cleanup_and_exit(int c)
94 {
95 cp
96   close_network_connections();
97
98   syslog(LOG_NOTICE, _("Terminating"));
99
100   closelog();
101   exit(c);
102 }
103
104 /*
105   check for an existing tinc for this net, and write pid to pidfile
106 */
107 int write_pidfile(void)
108 {
109   int pid;
110 cp
111   if((pid = check_pid(pidfilename)))
112     {
113       if(netname)
114         fprintf(stderr, _("A tincd is already running for net `%s' with pid %d.\n"),
115                 netname, pid);
116       else
117         fprintf(stderr, _("A tincd is already running with pid %d.\n"), pid);
118       return 1;
119     }
120
121   /* if it's locked, write-protected, or whatever */
122   if(!write_pid(pidfilename))
123     return 1;
124 cp
125   return 0;
126 }
127
128 /*
129   kill older tincd for this net
130 */
131 int kill_other(int signal)
132 {
133   int pid;
134 cp
135   if(!(pid = read_pid(pidfilename)))
136     {
137       if(netname)
138         fprintf(stderr, _("No other tincd is running for net `%s'.\n"), netname);
139       else
140         fprintf(stderr, _("No other tincd is running.\n"));
141       return 1;
142     }
143
144   errno = 0;    /* No error, sometimes errno is only changed on error */
145   /* ESRCH is returned when no process with that pid is found */
146   if(kill(pid, signal) && errno == ESRCH)
147     {
148       if(netname)
149         fprintf(stderr, _("The tincd for net `%s' is no longer running. "), netname);
150       else
151         fprintf(stderr, _("The tincd is no longer running. "));
152
153       fprintf(stderr, _("Removing stale lock file.\n"));
154       remove_pid(pidfilename);
155     }
156 cp
157   return 0;
158 }
159
160 /*
161   Detach from current terminal, write pidfile, kill parent
162 */
163 int detach(void)
164 {
165 cp
166   setup_signals();
167
168   /* First check if we can open a fresh new pidfile */
169   
170   if(write_pidfile())
171     return -1;
172
173   /* If we succeeded in doing that, detach */
174
175   closelog();
176
177   if(do_detach)
178     {
179       if(daemon(0, 0) < 0)
180         {
181           fprintf(stderr, _("Couldn't detach from terminal: %s"), strerror(errno));
182           return -1;
183         }
184
185       /* Now UPDATE the pid in the pidfile, because we changed it... */
186       
187       if(!write_pid(pidfilename))
188         return -1;
189     }
190   
191   openlog(identname, LOG_CONS | LOG_PID, LOG_DAEMON);
192
193   if(debug_lvl > DEBUG_NOTHING)
194     log(0, TLOG_NOTICE,
195         _("tincd %s (%s %s) starting, debug level %d"),
196         VERSION, __DATE__, __TIME__, debug_lvl);
197   else
198     log(DEBUG_NOTHING, TLOG_NOTICE,
199         _("tincd %s starting"),
200         VERSION);
201
202   xalloc_fail_func = memory_full;
203 cp
204   return 0;
205 }
206
207 /*
208   Execute the program name, with sane environment.  All output will be
209   redirected to syslog.
210 */
211 void _execute_script(const char *name)  __attribute__ ((noreturn));
212 void _execute_script(const char *name)
213 {
214   char *scriptname;
215   char *s;
216 cp
217 #ifdef HAVE_UNSETENV
218   unsetenv("NETNAME");
219   unsetenv("INTERFACE");
220 #endif
221
222   if(netname)
223     {
224       asprintf(&s, "NETNAME=%s", netname);
225       putenv(s);        /* Don't free s! see man 3 putenv */
226     }
227
228   chdir("/");
229   
230   asprintf(&scriptname, "%s/%s", confbase, name);
231
232   /* Close all file descriptors */
233   closelog();           /* <- this means we cannot use syslog() here anymore! */
234   fcloseall();
235
236   execl(scriptname, NULL);
237   /* No return on success */
238   
239   if(errno != ENOENT)   /* Ignore if the file does not exist */
240     exit(1);            /* Some error while trying execl(). */
241   else
242     exit(0);
243 }
244
245 /*
246   Fork and execute the program pointed to by name.
247 */
248 int execute_script(const char *name)
249 {
250   pid_t pid;
251   int status;
252 cp
253   if((pid = fork()) < 0)
254     {
255       syslog(LOG_ERR, _("System call `%s' failed: %s"), "fork", strerror(errno));
256       return -1;
257     }
258
259   if(pid)
260     {
261       log(DEBUG_STATUS, TLOG_INFO,
262           _("Executing script %s"),
263           name);
264
265       if(waitpid(pid, &status, 0) == pid)
266         {
267           if(WIFEXITED(status))         /* Child exited by itself */
268             {
269               if(WEXITSTATUS(status))
270                 {
271                   syslog(LOG_ERR, _("Process %d (%s) exited with non-zero status %d"), pid, name, WEXITSTATUS(status));
272                   return -1;
273                 }
274               else
275                 return 0;
276             }
277           else if(WIFSIGNALED(status))  /* Child was killed by a signal */
278             {
279               syslog(LOG_ERR, _("Process %d (%s) was killed by signal %d (%s)"),
280                      pid, name, WTERMSIG(status), strsignal(WTERMSIG(status)));
281               return -1;
282             }
283           else                          /* Something strange happened */
284             {
285               syslog(LOG_ERR, _("Process %d (%s) terminated abnormally"), pid, name);
286               return -1;
287             }
288         }
289       else
290         {
291           syslog(LOG_ERR, _("System call `%s' failed: %s"), "waitpid", strerror(errno));
292           return -1;
293         }
294     }
295 cp
296   /* Child here */
297
298   _execute_script(name);
299 }
300
301
302 /*
303   Signal handlers.
304 */
305
306 RETSIGTYPE
307 sigterm_handler(int a)
308 {
309   log(DEBUG_NOTHING, TLOG_NOTICE,
310       _("Got TERM signal"));
311
312   cleanup_and_exit(0);
313 }
314
315 RETSIGTYPE
316 sigquit_handler(int a)
317 {
318   log(DEBUG_NOTHING, TLOG_NOTICE,
319       _("Got QUIT signal"));
320   cleanup_and_exit(0);
321 }
322
323 RETSIGTYPE
324 fatal_signal_square(int a)
325 {
326   syslog(LOG_ERR, _("Got another fatal signal %d (%s): not restarting."), a, strsignal(a));
327   cp_trace();
328   exit(1);
329 }
330
331 RETSIGTYPE
332 fatal_signal_handler(int a)
333 {
334   syslog(LOG_ERR, _("Got fatal signal %d (%s)"), a, strsignal(a));
335   cp_trace();
336
337   syslog(LOG_NOTICE, _("Not restarting."));
338   exit(1);
339 }
340
341 RETSIGTYPE
342 sighup_handler(int a)
343 {
344   if(debug_lvl > DEBUG_NOTHING)
345     syslog(LOG_NOTICE, _("Got HUP signal"));
346   sighup = 1;
347 }
348
349 RETSIGTYPE
350 sigint_handler(int a)
351 {
352   if(saved_debug_lvl)
353     {
354       syslog(LOG_NOTICE, _("Reverting to old debug level (%d)"),
355              saved_debug_lvl);
356       debug_lvl = saved_debug_lvl;
357       saved_debug_lvl = 0;
358     }
359   else
360     {
361       syslog(LOG_NOTICE, _("Temporarily setting debug level to 5.  Kill me with SIGINT again to go back to level %d."),
362              debug_lvl);
363       saved_debug_lvl = debug_lvl;
364       debug_lvl = 5;
365     }
366 }
367
368 RETSIGTYPE
369 sigalrm_handler(int a)
370 {
371   if(debug_lvl > DEBUG_NOTHING)
372     syslog(LOG_NOTICE, _("Got ALRM signal"));
373   sigalrm = 1;
374 }
375
376 RETSIGTYPE
377 sigusr1_handler(int a)
378 {
379   dump_connections();
380 }
381
382 RETSIGTYPE
383 sigusr2_handler(int a)
384 {
385   dump_nodes();
386   dump_edges();
387   dump_subnets();
388 }
389
390 RETSIGTYPE
391 sigwinch_handler(int a)
392 {
393   extern int do_purge;
394   do_purge = 1;
395 }
396
397 RETSIGTYPE
398 unexpected_signal_handler(int a)
399 {
400   syslog(LOG_WARNING, _("Got unexpected signal %d (%s)"), a, strsignal(a));
401   cp_trace();
402 }
403
404 RETSIGTYPE
405 ignore_signal_handler(int a)
406 {
407   if(debug_lvl >= DEBUG_SCARY_THINGS)
408   {
409     syslog(LOG_DEBUG, _("Ignored signal %d (%s)"), a, strsignal(a));
410     cp_trace();
411   }
412 }
413
414 struct {
415   int signal;
416   void (*handler)(int);
417 } sighandlers[] = {
418   { SIGHUP, sighup_handler },
419   { SIGTERM, sigterm_handler },
420   { SIGQUIT, sigquit_handler },
421   { SIGSEGV, fatal_signal_handler },
422   { SIGBUS, fatal_signal_handler },
423   { SIGILL, fatal_signal_handler },
424   { SIGPIPE, ignore_signal_handler },
425   { SIGINT, sigint_handler },
426   { SIGUSR1, sigusr1_handler },
427   { SIGUSR2, sigusr2_handler },
428   { SIGCHLD, ignore_signal_handler },
429   { SIGALRM, sigalrm_handler },
430   { SIGWINCH, sigwinch_handler },
431   { 0, NULL }
432 };
433
434 void
435 setup_signals(void)
436 {
437   int i;
438   struct sigaction act;
439
440   sigemptyset(&emptysigset);
441   act.sa_handler = NULL;
442   act.sa_mask = emptysigset;
443   act.sa_flags = 0;
444
445   /* Set a default signal handler for every signal, errors will be
446      ignored. */
447   for(i = 0; i < NSIG; i++) 
448     {
449       if(!do_detach)
450         act.sa_handler = SIG_DFL;
451       else
452         act.sa_handler = unexpected_signal_handler;
453       sigaction(i, &act, NULL);
454     }
455
456   /* If we didn't detach, allow coredumps */
457   if(!do_detach)
458     sighandlers[3].handler = SIG_DFL;
459
460   /* Then, for each known signal that we want to catch, assign a
461      handler to the signal, with error checking this time. */
462   for(i = 0; sighandlers[i].signal; i++)
463     {
464       act.sa_handler = sighandlers[i].handler;
465       if(sigaction(sighandlers[i].signal, &act, NULL) < 0)
466         fprintf(stderr, _("Installing signal handler for signal %d (%s) failed: %s\n"),
467                 sighandlers[i].signal, strsignal(sighandlers[i].signal), strerror(errno));
468     }
469 }