f221a9aa1c17537c67504fd7bfde9859ebb11dcc
[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.1 2000/11/16 17:54:28 zarq Exp $
21 */
22
23 #include "config.h"
24
25 #include <list.h>
26
27 /* A list containing all our children */
28 list_t *child_pids;
29
30 /* If zero, don't detach from the terminal. */
31 int do_detach = 1;
32
33 /*
34   Detach from current terminal, write pidfile, kill parent
35 */
36 int detach(void)
37 {
38   int fd;
39   pid_t pid;
40
41   if(do_detach)
42     {
43       ppid = getpid();
44
45       if((pid = fork()) < 0)
46         {
47           perror("fork");
48           return -1;
49         }
50       if(pid) /* parent process */
51         {
52           signal(SIGTERM, parent_exit);
53           sleep(600); /* wait 10 minutes */
54           exit(1);
55         }
56     }
57   
58   if(write_pidfile())
59     return -1;
60
61   if(do_detach)
62     {
63       if((fd = open("/dev/tty", O_RDWR)) >= 0)
64         {
65           if(ioctl(fd, TIOCNOTTY, NULL))
66             {
67               perror("ioctl");
68               return -1;
69             }
70           close(fd);
71         }
72
73       if(setsid() < 0)
74         return -1;
75
76       kill(ppid, SIGTERM);
77     }
78   
79   chdir("/"); /* avoid keeping a mointpoint busy */
80
81   openlog(identname, LOG_CONS | LOG_PID, LOG_DAEMON);
82
83   if(debug_lvl > DEBUG_NOTHING)
84     syslog(LOG_NOTICE, _("tincd %s (%s %s) starting, debug level %d"),
85            VERSION, __DATE__, __TIME__, debug_lvl);
86   else
87     syslog(LOG_NOTICE, _("tincd %s starting"), VERSION);
88
89   xalloc_fail_func = memory_full;
90
91   return 0;
92 }
93
94 /*
95   Execute the program name, with sane environment.  All output will be
96   redirected to syslog.
97 */
98 void _execute_script(const char *name)
99 {
100   int error = 0;
101   char *scriptname;
102   char *s;
103   int fd;
104
105   if(netname)
106     {
107       asprintf(&s, "NETNAME=%s", netname);
108       putenv(s);        /* Don't free s! see man 3 putenv */
109     }
110 #ifdef HAVE_UNSETENV
111   else
112     {
113       unsetenv("NETNAME");
114     }
115 #endif
116
117   if(chdir(confbase) < 0)
118     /* This cannot fail since we already read config files from this
119        directory. - Guus */
120     /* Yes this can fail, somebody could have removed this directory
121        when we didn't pay attention. - Ivo */
122     {
123       if(chdir("/") < 0)
124         /* Now if THIS fails, something wicked is going on. - Ivo */
125         syslog(LOG_ERR, _("Couldn't chdir to `/': %m"));
126
127       /* Continue anyway. */
128     }
129   
130   asprintf(&scriptname, "%s/%s", confbase, name);
131
132   /* Close all file descriptors */
133   closelog();
134   fcloseall();
135
136   /* Open standard input */
137   if(open("/dev/null", O_RDONLY) < 0)
138     {
139       syslog(LOG_ERR, _("Opening `/dev/null' failed: %m"));
140       error = 1;
141     }
142
143   if(!error)
144     {
145       /* Standard output directly goes to syslog */
146       openlog(name, LOG_CONS | LOG_PID, LOG_DAEMON);
147       /* Standard error as well */
148       if(dup2(1, 2) < 0)
149         {
150           syslog(LOG_ERR, _("System call `%s' failed: %m"),
151                  "dup2");
152           error = 1;
153         }
154     }
155   
156   if(error && debug_lvl > 1)
157     syslog(LOG_INFO, _("This means that any output the script generates will not be shown in syslog."));
158   
159   execl(scriptname, NULL);
160   /* No return on success */
161   
162   if(errno != ENOENT)  /* Ignore if the file does not exist */
163     syslog(LOG_WARNING, _("Error executing `%s': %m"), scriptname);
164
165   /* No need to free things */
166   exit(0);
167 }
168
169 /*
170   Fork and execute the program pointed to by name.
171 */
172 int execute_script(const char *name)
173 {
174   pid_t pid;
175
176   if((pid = fork()) < 0)
177     {
178       syslog(LOG_ERR, _("System call `%s' failed: %m"),
179              "fork");
180       return -1;
181     }
182
183   if(pid)
184     {
185       list_append(child_pids, pid);
186       return 0;
187     }
188
189   /* Child here */
190
191   _execute_script(name);
192 }
193
194 /*
195   Check a child (the pointer data is actually an integer, the PID of
196   that child.  A non-zero return value means that the child has exited
197   and can be removed from our list.
198 */
199 int check_child(void *data)
200 {
201   pid_t pid;
202   int status;
203
204   pid = (pid_t) data;
205   pid = waitpid(pid, &status, WNOHANG);
206   if(WIFEXITED(status))
207     {
208       if(WIFSIGNALED(status)) /* Child was killed by a signal */
209         {
210           syslog(LOG_ERR, _("Child with PID %d was killed by signal %d (%s)"),
211                  pid, WTERMSIG(status), strsignal(WTERMSIG(status)));
212           return -1;
213         }
214       if(WEXITSTATUS(status) != 0)
215         {
216           syslog(LOG_INFO, _("Child with PID %d exited with code %d"),
217                  WEXITSTATUS(status));
218         }
219       return -1;
220     }
221
222   /* Child is still running */
223   return 0;
224 }
225
226 /*
227   Check the status of all our children.
228 */
229 void check_children(void)
230 {
231   list_forall_nodes(child_pids, check_child);
232 }
233
234
235
236 /*
237   Signal handlers.
238 */
239
240 RETSIGTYPE
241 sigterm_handler(int a)
242 {
243   if(debug_lvl > DEBUG_NOTHING)
244     syslog(LOG_NOTICE, _("Got TERM signal"));
245
246   cleanup_and_exit(0);
247 }
248
249 RETSIGTYPE
250 sigquit_handler(int a)
251 {
252   if(debug_lvl > DEBUG_NOTHING)
253     syslog(LOG_NOTICE, _("Got QUIT signal"));
254   cleanup_and_exit(0);
255 }
256
257 RETSIGTYPE
258 sigsegv_square(int a)
259 {
260   syslog(LOG_ERR, _("Got another SEGV signal: not restarting"));
261   exit(0);
262 }
263
264 RETSIGTYPE
265 sigsegv_handler(int a)
266 {
267   syslog(LOG_ERR, _("Got SEGV signal"));
268   cp_trace();
269
270   if(do_detach)
271     {
272       syslog(LOG_NOTICE, _("Trying to re-execute in 5 seconds..."));
273       signal(SIGSEGV, sigsegv_square);
274       close_network_connections();
275       sleep(5);
276       remove_pid(pidfilename);
277       execvp(g_argv[0], g_argv);
278     }
279   else
280     {
281       syslog(LOG_NOTICE, _("Not restarting."));
282       exit(0);
283     }
284 }
285
286 RETSIGTYPE
287 sighup_handler(int a)
288 {
289   if(debug_lvl > DEBUG_NOTHING)
290     syslog(LOG_NOTICE, _("Got HUP signal"));
291   sighup = 1;
292 }
293
294 RETSIGTYPE
295 sigint_handler(int a)
296 {
297   if(debug_lvl > DEBUG_NOTHING)
298     syslog(LOG_NOTICE, _("Got INT signal, exiting"));
299   cleanup_and_exit(0);
300 }
301
302 RETSIGTYPE
303 sigusr1_handler(int a)
304 {
305   dump_conn_list();
306 }
307
308 RETSIGTYPE
309 sigusr2_handler(int a)
310 {
311   dump_subnet_list();
312 }
313
314 RETSIGTYPE
315 sighuh(int a)
316 {
317   syslog(LOG_WARNING, _("Got unexpected signal %d (%s)"), a, strsignal(a));
318   cp_trace();
319 }
320
321 void
322 setup_signals(void)
323 {
324   int i;
325
326   for(i=0;i<32;i++)
327     signal(i,sighuh);
328
329   if(signal(SIGTERM, SIG_IGN) != SIG_ERR)
330     signal(SIGTERM, sigterm_handler);
331   if(signal(SIGQUIT, SIG_IGN) != SIG_ERR)
332     signal(SIGQUIT, sigquit_handler);
333   if(signal(SIGSEGV, SIG_IGN) != SIG_ERR)
334     signal(SIGSEGV, sigsegv_handler);
335   if(signal(SIGHUP, SIG_IGN) != SIG_ERR)
336     signal(SIGHUP, sighup_handler);
337   signal(SIGPIPE, SIG_IGN);
338   if(signal(SIGINT, SIG_IGN) != SIG_ERR)
339     signal(SIGINT, sigint_handler);
340   signal(SIGUSR1, sigusr1_handler);
341   signal(SIGUSR2, sigusr2_handler);
342   signal(SIGCHLD, SIG_IGN);
343 }
344
345 RETSIGTYPE parent_exit(int a)
346 {
347   exit(0);
348 }