Start a tinc service if it already exists.
[tinc] / src / process.c
1 /*
2     process.c -- process management functions
3     Copyright (C) 1999-2005 Ivo Timmermans,
4                   2000-2009 Guus Sliepen <guus@tinc-vpn.org>
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 along
17     with this program; if not, write to the Free Software Foundation, Inc.,
18     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 */
20
21 #include "system.h"
22
23 #include "conf.h"
24 #include "connection.h"
25 #include "device.h"
26 #include "edge.h"
27 #include "logger.h"
28 #include "node.h"
29 #include "pidfile.h"
30 #include "process.h"
31 #include "subnet.h"
32 #include "utils.h"
33 #include "xalloc.h"
34
35 /* If zero, don't detach from the terminal. */
36 bool do_detach = true;
37 bool sighup = false;
38 bool sigalrm = false;
39
40 extern char *identname;
41 extern char *pidfilename;
42 extern char **g_argv;
43 extern bool use_logfile;
44 extern volatile bool running;
45
46 sigset_t emptysigset;
47
48 static int saved_debug_level = -1;
49
50 static void memory_full(int size) {
51         logger(LOG_ERR, "Memory exhausted (couldn't allocate %d bytes), exitting.", size);
52         exit(1);
53 }
54
55 /* Some functions the less gifted operating systems might lack... */
56
57 #ifdef HAVE_MINGW
58 extern char *identname;
59 extern char *program_name;
60 extern char **g_argv;
61
62 static SC_HANDLE manager = NULL;
63 static SC_HANDLE service = NULL;
64 static SERVICE_STATUS status = {0};
65 static SERVICE_STATUS_HANDLE statushandle = 0;
66
67 bool install_service(void) {
68         char command[4096] = "\"";
69         char **argp;
70         bool space;
71         SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"};
72
73         manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
74         if(!manager) {
75                 logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
76                 return false;
77         }
78
79         if(!strchr(program_name, '\\')) {
80                 GetCurrentDirectory(sizeof command - 1, command + 1);
81                 strncat(command, "\\", sizeof command - strlen(command));
82         }
83
84         strncat(command, program_name, sizeof command - strlen(command));
85
86         strncat(command, "\"", sizeof command - strlen(command));
87
88         for(argp = g_argv + 1; *argp; argp++) {
89                 space = strchr(*argp, ' ');
90                 strncat(command, " ", sizeof command - strlen(command));
91                 
92                 if(space)
93                         strncat(command, "\"", sizeof command - strlen(command));
94                 
95                 strncat(command, *argp, sizeof command - strlen(command));
96
97                 if(space)
98                         strncat(command, "\"", sizeof command - strlen(command));
99         }
100
101         service = CreateService(manager, identname, identname,
102                         SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
103                         command, NULL, NULL, NULL, NULL, NULL);
104         
105         if(!service) {
106                 DWORD lasterror = GetLastError();
107                 logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(lasterror));
108                 if(lasterror != ERROR_SERVICE_EXISTS)
109                         return false;
110         }
111
112         if(service) {
113                 ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
114                 logger(LOG_INFO, "%s service installed", identname);
115         } else {
116                 service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
117         }
118
119         if(!StartService(service, 0, NULL))
120                 logger(LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError()));
121         else
122                 logger(LOG_INFO, "%s service started", identname);
123
124         return true;
125 }
126
127 bool remove_service(void) {
128         manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
129         if(!manager) {
130                 logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
131                 return false;
132         }
133
134         service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
135
136         if(!service) {
137                 logger(LOG_ERR, "Could not open %s service: %s", identname, winerror(GetLastError()));
138                 return false;
139         }
140
141         if(!ControlService(service, SERVICE_CONTROL_STOP, &status))
142                 logger(LOG_ERR, "Could not stop %s service: %s", identname, winerror(GetLastError()));
143         else
144                 logger(LOG_INFO, "%s service stopped", identname);
145
146         if(!DeleteService(service)) {
147                 logger(LOG_ERR, "Could not remove %s service: %s", identname, winerror(GetLastError()));
148                 return false;
149         }
150
151         logger(LOG_INFO, "%s service removed", identname);
152
153         return true;
154 }
155
156 DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
157         switch(request) {
158                 case SERVICE_CONTROL_INTERROGATE:
159                         SetServiceStatus(statushandle, &status);
160                         return NO_ERROR;
161                 case SERVICE_CONTROL_STOP:
162                         logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_STOP");
163                         break;
164                 case SERVICE_CONTROL_SHUTDOWN:
165                         logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_SHUTDOWN");
166                         break;
167                 default:
168                         logger(LOG_WARNING, "Got unexpected request %d", request);
169                         return ERROR_CALL_NOT_IMPLEMENTED;
170         }
171
172         if(running) {
173                 running = false;
174                 status.dwWaitHint = 30000; 
175                 status.dwCurrentState = SERVICE_STOP_PENDING; 
176                 SetServiceStatus(statushandle, &status);
177                 return NO_ERROR;
178         } else {
179                 status.dwWaitHint = 0; 
180                 status.dwCurrentState = SERVICE_STOPPED; 
181                 SetServiceStatus(statushandle, &status);
182                 exit(1);
183         }
184
185 }
186
187 VOID WINAPI run_service(DWORD argc, LPTSTR* argv) {
188         int err = 1;
189         extern int main2(int argc, char **argv);
190
191
192         status.dwServiceType = SERVICE_WIN32; 
193         status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
194         status.dwWin32ExitCode = 0; 
195         status.dwServiceSpecificExitCode = 0; 
196         status.dwCheckPoint = 0; 
197
198         statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL); 
199
200         if (!statushandle) {
201                 logger(LOG_ERR, "System call `%s' failed: %s", "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
202                 err = 1;
203         } else {
204                 status.dwWaitHint = 30000; 
205                 status.dwCurrentState = SERVICE_START_PENDING; 
206                 SetServiceStatus(statushandle, &status);
207
208                 status.dwWaitHint = 0; 
209                 status.dwCurrentState = SERVICE_RUNNING;
210                 SetServiceStatus(statushandle, &status);
211
212                 err = main2(argc, argv);
213
214                 status.dwWaitHint = 0;
215                 status.dwCurrentState = SERVICE_STOPPED; 
216                 //status.dwWin32ExitCode = err; 
217                 SetServiceStatus(statushandle, &status);
218         }
219
220         return;
221 }
222
223 bool init_service(void) {
224         SERVICE_TABLE_ENTRY services[] = {
225                 {identname, run_service},
226                 {NULL, NULL}
227         };
228
229         if(!StartServiceCtrlDispatcher(services)) {
230                 if(GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
231                         return false;
232                 }
233                 else
234                         logger(LOG_ERR, "System call `%s' failed: %s", "StartServiceCtrlDispatcher", winerror(GetLastError()));
235         }
236
237         return true;
238 }
239 #endif
240
241 #ifndef HAVE_MINGW
242 /*
243   check for an existing tinc for this net, and write pid to pidfile
244 */
245 static bool write_pidfile(void) {
246         pid_t pid;
247
248         pid = check_pid(pidfilename);
249
250         if(pid) {
251                 if(netname)
252                         fprintf(stderr, "A tincd is already running for net `%s' with pid %ld.\n",
253                                         netname, (long)pid);
254                 else
255                         fprintf(stderr, "A tincd is already running with pid %ld.\n", (long)pid);
256                 return false;
257         }
258
259         /* if it's locked, write-protected, or whatever */
260         if(!write_pid(pidfilename)) {
261                 fprintf(stderr, "Could write pid file %s: %s\n", pidfilename, strerror(errno));
262                 return false;
263         }
264
265         return true;
266 }
267 #endif
268
269 /*
270   kill older tincd for this net
271 */
272 bool kill_other(int signal) {
273 #ifndef HAVE_MINGW
274         pid_t pid;
275
276         pid = read_pid(pidfilename);
277
278         if(!pid) {
279                 if(netname)
280                         fprintf(stderr, "No other tincd is running for net `%s'.\n",
281                                         netname);
282                 else
283                         fprintf(stderr, "No other tincd is running.\n");
284                 return false;
285         }
286
287         errno = 0;                                      /* No error, sometimes errno is only changed on error */
288
289         /* ESRCH is returned when no process with that pid is found */
290         if(kill(pid, signal) && errno == ESRCH) {
291                 if(netname)
292                         fprintf(stderr, "The tincd for net `%s' is no longer running. ",
293                                         netname);
294                 else
295                         fprintf(stderr, "The tincd is no longer running. ");
296
297                 fprintf(stderr, "Removing stale lock file.\n");
298                 remove_pid(pidfilename);
299         }
300
301         return true;
302 #else
303         return remove_service();
304 #endif
305 }
306
307 /*
308   Detach from current terminal, write pidfile, kill parent
309 */
310 bool detach(void) {
311         setup_signals();
312
313         /* First check if we can open a fresh new pidfile */
314
315 #ifndef HAVE_MINGW
316         if(!write_pidfile())
317                 return false;
318
319         /* If we succeeded in doing that, detach */
320
321         closelogger();
322 #endif
323
324         if(do_detach) {
325 #ifndef HAVE_MINGW
326                 if(daemon(0, 0)) {
327                         fprintf(stderr, "Couldn't detach from terminal: %s",
328                                         strerror(errno));
329                         return false;
330                 }
331
332                 /* Now UPDATE the pid in the pidfile, because we changed it... */
333
334                 if(!write_pid(pidfilename)) {
335                         fprintf(stderr, "Could not write pid file %s: %s\n", pidfilename, strerror(errno));
336                         return false;
337                 }
338 #else
339                 if(!statushandle)
340                         exit(install_service());
341 #endif
342         }
343
344         openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR));
345
346         logger(LOG_NOTICE, "tincd %s (%s %s) starting, debug level %d",
347                            VERSION, __DATE__, __TIME__, debug_level);
348
349         xalloc_fail_func = memory_full;
350
351         return true;
352 }
353
354 bool execute_script(const char *name, char **envp) {
355 #ifdef HAVE_SYSTEM
356         int status, len;
357         char *scriptname, *p;
358         int i;
359
360 #ifndef HAVE_MINGW
361         len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name);
362 #else
363         len = xasprintf(&scriptname, "\"%s/%s.bat\"", confbase, name);
364 #endif
365         if(len < 0)
366                 return false;
367
368         scriptname[len - 1] = '\0';
369
370 #ifndef HAVE_TUNEMU
371         /* First check if there is a script */
372
373         if(access(scriptname + 1, F_OK)) {
374                 free(scriptname);
375                 return true;
376         }
377 #endif
378
379         ifdebug(STATUS) logger(LOG_INFO, "Executing script %s", name);
380
381 #ifdef HAVE_PUTENV
382         /* Set environment */
383         
384         for(i = 0; envp[i]; i++)
385                 putenv(envp[i]);
386 #endif
387
388         scriptname[len - 1] = '\"';
389         status = system(scriptname);
390
391         free(scriptname);
392
393         /* Unset environment */
394
395         for(i = 0; envp[i]; i++) {
396                 char *e = strchr(envp[i], '=');
397                 if(e) {
398                         p = alloca(e - envp[i] + 1);
399                         strncpy(p, envp[i], e - envp[i]);
400                         p[e - envp[i]] = '\0';
401                         putenv(p);
402                 }
403         }
404
405 #ifdef WEXITSTATUS
406         if(status != -1) {
407                 if(WIFEXITED(status)) { /* Child exited by itself */
408                         if(WEXITSTATUS(status)) {
409                                 logger(LOG_ERR, "Script %s exited with non-zero status %d",
410                                            name, WEXITSTATUS(status));
411                                 return false;
412                         }
413                 } else if(WIFSIGNALED(status)) {        /* Child was killed by a signal */
414                         logger(LOG_ERR, "Script %s was killed by signal %d (%s)",
415                                    name, WTERMSIG(status), strsignal(WTERMSIG(status)));
416                         return false;
417                 } else {                        /* Something strange happened */
418                         logger(LOG_ERR, "Script %s terminated abnormally", name);
419                         return false;
420                 }
421         } else {
422                 logger(LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
423                 return false;
424         }
425 #endif
426 #endif
427         return true;
428 }
429
430
431 /*
432   Signal handlers.
433 */
434
435 #ifndef HAVE_MINGW
436 static RETSIGTYPE sigterm_handler(int a) {
437         logger(LOG_NOTICE, "Got %s signal", "TERM");
438         if(running)
439                 running = false;
440         else
441                 exit(1);
442 }
443
444 static RETSIGTYPE sigquit_handler(int a) {
445         logger(LOG_NOTICE, "Got %s signal", "QUIT");
446         if(running)
447                 running = false;
448         else
449                 exit(1);
450 }
451
452 static RETSIGTYPE fatal_signal_square(int a) {
453         logger(LOG_ERR, "Got another fatal signal %d (%s): not restarting.", a,
454                    strsignal(a));
455         exit(1);
456 }
457
458 static RETSIGTYPE fatal_signal_handler(int a) {
459         struct sigaction act;
460         logger(LOG_ERR, "Got fatal signal %d (%s)", a, strsignal(a));
461
462         if(do_detach) {
463                 logger(LOG_NOTICE, "Trying to re-execute in 5 seconds...");
464
465                 act.sa_handler = fatal_signal_square;
466                 act.sa_mask = emptysigset;
467                 act.sa_flags = 0;
468                 sigaction(SIGSEGV, &act, NULL);
469
470                 close_network_connections();
471                 sleep(5);
472                 remove_pid(pidfilename);
473                 execvp(g_argv[0], g_argv);
474         } else {
475                 logger(LOG_NOTICE, "Not restarting.");
476                 exit(1);
477         }
478 }
479
480 static RETSIGTYPE sighup_handler(int a) {
481         logger(LOG_NOTICE, "Got %s signal", "HUP");
482         sighup = true;
483 }
484
485 static RETSIGTYPE sigint_handler(int a) {
486         logger(LOG_NOTICE, "Got %s signal", "INT");
487
488         if(saved_debug_level != -1) {
489                 logger(LOG_NOTICE, "Reverting to old debug level (%d)",
490                         saved_debug_level);
491                 debug_level = saved_debug_level;
492                 saved_debug_level = -1;
493         } else {
494                 logger(LOG_NOTICE,
495                         "Temporarily setting debug level to 5.  Kill me with SIGINT again to go back to level %d.",
496                         debug_level);
497                 saved_debug_level = debug_level;
498                 debug_level = 5;
499         }
500 }
501
502 static RETSIGTYPE sigalrm_handler(int a) {
503         logger(LOG_NOTICE, "Got %s signal", "ALRM");
504         sigalrm = true;
505 }
506
507 static RETSIGTYPE sigusr1_handler(int a) {
508         dump_connections();
509 }
510
511 static RETSIGTYPE sigusr2_handler(int a) {
512         dump_device_stats();
513         dump_nodes();
514         dump_edges();
515         dump_subnets();
516 }
517
518 static RETSIGTYPE sigwinch_handler(int a) {
519         do_purge = true;
520 }
521
522 static RETSIGTYPE unexpected_signal_handler(int a) {
523         logger(LOG_WARNING, "Got unexpected signal %d (%s)", a, strsignal(a));
524 }
525
526 static RETSIGTYPE ignore_signal_handler(int a) {
527         ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignored signal %d (%s)", a, strsignal(a));
528 }
529
530 static struct {
531         int signal;
532         void (*handler)(int);
533 } sighandlers[] = {
534         {SIGHUP, sighup_handler},
535         {SIGTERM, sigterm_handler},
536         {SIGQUIT, sigquit_handler},
537         {SIGSEGV, fatal_signal_handler},
538         {SIGBUS, fatal_signal_handler},
539         {SIGILL, fatal_signal_handler},
540         {SIGPIPE, ignore_signal_handler},
541         {SIGINT, sigint_handler},
542         {SIGUSR1, sigusr1_handler},
543         {SIGUSR2, sigusr2_handler},
544         {SIGCHLD, ignore_signal_handler},
545         {SIGALRM, sigalrm_handler},
546         {SIGWINCH, sigwinch_handler},
547         {0, NULL}
548 };
549 #endif
550
551 void setup_signals(void) {
552 #ifndef HAVE_MINGW
553         int i;
554         struct sigaction act;
555
556         sigemptyset(&emptysigset);
557         act.sa_handler = NULL;
558         act.sa_mask = emptysigset;
559         act.sa_flags = 0;
560
561         /* Set a default signal handler for every signal, errors will be
562            ignored. */
563         for(i = 1; i < NSIG; i++) {
564                 if(!do_detach)
565                         act.sa_handler = SIG_DFL;
566                 else
567                         act.sa_handler = unexpected_signal_handler;
568                 sigaction(i, &act, NULL);
569         }
570
571         /* If we didn't detach, allow coredumps */
572         if(!do_detach)
573                 sighandlers[3].handler = SIG_DFL;
574
575         /* Then, for each known signal that we want to catch, assign a
576            handler to the signal, with error checking this time. */
577         for(i = 0; sighandlers[i].signal; i++) {
578                 act.sa_handler = sighandlers[i].handler;
579                 if(sigaction(sighandlers[i].signal, &act, NULL) < 0)
580                         fprintf(stderr, "Installing signal handler for signal %d (%s) failed: %s\n",
581                                         sighandlers[i].signal, strsignal(sighandlers[i].signal),
582                                         strerror(errno));
583         }
584 #endif
585 }