2 process.c -- process management functions
3 Copyright (C) 1999-2005 Ivo Timmermans,
4 2000-2015 Guus Sliepen <guus@tinc-vpn.org>
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.
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.
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.
24 #include "connection.h"
36 /* If zero, don't detach from the terminal. */
37 bool do_detach = true;
41 extern char *identname;
42 extern char *pidfilename;
44 extern bool use_logfile;
47 static sigset_t emptysigset;
50 /* Some functions the less gifted operating systems might lack... */
53 extern char *identname;
54 extern char *program_name;
57 static SC_HANDLE manager = NULL;
58 static SC_HANDLE service = NULL;
59 static SERVICE_STATUS status = {0};
60 static SERVICE_STATUS_HANDLE statushandle = 0;
62 bool install_service(void) {
63 char command[4096] = "\"";
66 SERVICE_DESCRIPTION description = {"Virtual Private Network daemon"};
68 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
70 logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
74 if(!strchr(program_name, '\\')) {
75 GetCurrentDirectory(sizeof(command) - 1, command + 1);
76 strncat(command, "\\", sizeof(command) - strlen(command));
79 strncat(command, program_name, sizeof(command) - strlen(command));
81 strncat(command, "\"", sizeof(command) - strlen(command));
83 for(argp = g_argv + 1; *argp; argp++) {
84 space = strchr(*argp, ' ');
85 strncat(command, " ", sizeof(command) - strlen(command));
88 strncat(command, "\"", sizeof(command) - strlen(command));
90 strncat(command, *argp, sizeof(command) - strlen(command));
93 strncat(command, "\"", sizeof(command) - strlen(command));
96 service = CreateService(manager, identname, identname,
97 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
98 command, NULL, NULL, NULL, NULL, NULL);
101 DWORD lasterror = GetLastError();
102 logger(LOG_ERR, "Could not create %s service: %s", identname, winerror(lasterror));
103 if(lasterror != ERROR_SERVICE_EXISTS)
108 ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &description);
109 logger(LOG_INFO, "%s service installed", identname);
111 service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
114 if(!StartService(service, 0, NULL))
115 logger(LOG_WARNING, "Could not start %s service: %s", identname, winerror(GetLastError()));
117 logger(LOG_INFO, "%s service started", identname);
122 bool remove_service(void) {
123 manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
125 logger(LOG_ERR, "Could not open service manager: %s", winerror(GetLastError()));
129 service = OpenService(manager, identname, SERVICE_ALL_ACCESS);
132 logger(LOG_ERR, "Could not open %s service: %s", identname, winerror(GetLastError()));
136 if(!ControlService(service, SERVICE_CONTROL_STOP, &status))
137 logger(LOG_ERR, "Could not stop %s service: %s", identname, winerror(GetLastError()));
139 logger(LOG_INFO, "%s service stopped", identname);
141 if(!DeleteService(service)) {
142 logger(LOG_ERR, "Could not remove %s service: %s", identname, winerror(GetLastError()));
146 logger(LOG_INFO, "%s service removed", identname);
151 DWORD WINAPI controlhandler(DWORD request, DWORD type, LPVOID boe, LPVOID bah) {
153 case SERVICE_CONTROL_INTERROGATE:
154 SetServiceStatus(statushandle, &status);
156 case SERVICE_CONTROL_STOP:
157 logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_STOP");
159 case SERVICE_CONTROL_SHUTDOWN:
160 logger(LOG_NOTICE, "Got %s request", "SERVICE_CONTROL_SHUTDOWN");
163 logger(LOG_WARNING, "Got unexpected request %d", (int)request);
164 return ERROR_CALL_NOT_IMPLEMENTED;
169 status.dwWaitHint = 30000;
170 status.dwCurrentState = SERVICE_STOP_PENDING;
171 SetServiceStatus(statushandle, &status);
174 status.dwWaitHint = 0;
175 status.dwCurrentState = SERVICE_STOPPED;
176 SetServiceStatus(statushandle, &status);
182 VOID WINAPI run_service(DWORD argc, LPTSTR* argv) {
183 extern int main2(int argc, char **argv);
185 status.dwServiceType = SERVICE_WIN32;
186 status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
187 status.dwWin32ExitCode = 0;
188 status.dwServiceSpecificExitCode = 0;
189 status.dwCheckPoint = 0;
191 statushandle = RegisterServiceCtrlHandlerEx(identname, controlhandler, NULL);
194 logger(LOG_ERR, "System call `%s' failed: %s", "RegisterServiceCtrlHandlerEx", winerror(GetLastError()));
196 status.dwWaitHint = 30000;
197 status.dwCurrentState = SERVICE_START_PENDING;
198 SetServiceStatus(statushandle, &status);
200 status.dwWaitHint = 0;
201 status.dwCurrentState = SERVICE_RUNNING;
202 SetServiceStatus(statushandle, &status);
206 status.dwWaitHint = 0;
207 status.dwCurrentState = SERVICE_STOPPED;
208 SetServiceStatus(statushandle, &status);
214 bool init_service(void) {
215 SERVICE_TABLE_ENTRY services[] = {
216 {identname, run_service},
220 if(!StartServiceCtrlDispatcher(services)) {
221 if(GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
225 logger(LOG_ERR, "System call `%s' failed: %s", "StartServiceCtrlDispatcher", winerror(GetLastError()));
234 check for an existing tinc for this net, and write pid to pidfile
236 static bool write_pidfile(void) {
239 pid = check_pid(pidfilename);
243 fprintf(stderr, "A tincd is already running for net `%s' with pid %ld.\n",
246 fprintf(stderr, "A tincd is already running with pid %ld.\n", (long)pid);
250 /* if it's locked, write-protected, or whatever */
251 if(!write_pid(pidfilename)) {
252 fprintf(stderr, "Couldn't write pid file %s: %s\n", pidfilename, strerror(errno));
261 kill older tincd for this net
263 bool kill_other(int signal) {
267 pid = read_pid(pidfilename);
271 fprintf(stderr, "No other tincd is running for net `%s'.\n",
274 fprintf(stderr, "No other tincd is running.\n");
278 errno = 0; /* No error, sometimes errno is only changed on error */
280 /* ESRCH is returned when no process with that pid is found */
281 if(kill(pid, signal) && errno == ESRCH) {
283 fprintf(stderr, "The tincd for net `%s' is no longer running. ",
286 fprintf(stderr, "The tincd is no longer running. ");
288 fprintf(stderr, "Removing stale lock file.\n");
289 remove_pid(pidfilename);
294 return remove_service();
299 Detach from current terminal, write pidfile, kill parent
304 /* First check if we can open a fresh new pidfile */
310 /* If we succeeded in doing that, detach */
318 fprintf(stderr, "Couldn't detach from terminal: %s",
323 /* Now UPDATE the pid in the pidfile, because we changed it... */
325 if(!write_pid(pidfilename)) {
326 fprintf(stderr, "Could not write pid file %s: %s\n", pidfilename, strerror(errno));
331 exit(install_service());
335 openlogger(identname, use_logfile?LOGMODE_FILE:(do_detach?LOGMODE_SYSLOG:LOGMODE_STDERR));
337 logger(LOG_NOTICE, "tincd %s starting, debug level %d",
338 VERSION, debug_level);
344 void unputenv(char *p) {
345 char *e = strchr(p, '=');
349 #ifndef HAVE_UNSETENV
351 // Windows requires putenv("FOO=") to unset %FOO%
361 // We must keep what we putenv() around in memory.
362 // To do this without memory leaks, keep things in a list and reuse if possible.
363 static list_t list = {};
364 for(list_node_t *node = list.head; node; node = node->next) {
365 char *data = node->data;
366 if(!strcmp(data, var)) {
371 char *data = xstrdup(var);
372 list_insert_tail(&list, data);
377 void putenv(const char *p) {}
378 void unputenv(const char *p) {}
381 bool execute_script(const char *name, char **envp) {
384 char *interpreter = NULL;
385 config_t *cfg_interpreter;
388 cfg_interpreter = lookup_config(config_tree, "ScriptsInterpreter");
390 len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name);
393 len = xasprintf(&scriptname, "\"%s/%s\"", confbase, name);
395 len = xasprintf(&scriptname, "\"%s/%s.bat\"", confbase, name);
400 scriptname[len - 1] = '\0';
402 /* First check if there is a script */
403 if(access(scriptname + 1, F_OK)) {
408 // Custom scripts interpreter
409 if(get_config_string(cfg_interpreter, &interpreter)) {
410 // Force custom scripts interpreter allowing execution of scripts on android without execution flag (such as on /sdcard)
412 len = xasprintf(&scriptname, "%s \"%s/%s\"", interpreter, confbase, name);
418 ifdebug(STATUS) logger(LOG_INFO, "Executing script %s", name);
420 /* Set environment */
422 for(i = 0; envp[i]; i++)
425 scriptname[len - 1] = '\"';
426 status = system(scriptname);
430 /* Unset environment */
432 for(i = 0; envp[i]; i++)
437 if(WIFEXITED(status)) { /* Child exited by itself */
438 if(WEXITSTATUS(status)) {
439 logger(LOG_ERR, "Script %s exited with non-zero status %d",
440 name, WEXITSTATUS(status));
443 } else if(WIFSIGNALED(status)) { /* Child was killed by a signal */
444 logger(LOG_ERR, "Script %s was killed by signal %d (%s)",
445 name, WTERMSIG(status), strsignal(WTERMSIG(status)));
447 } else { /* Something strange happened */
448 logger(LOG_ERR, "Script %s terminated abnormally", name);
453 logger(LOG_ERR, "System call `%s' failed: %s", "system", strerror(errno));
466 static RETSIGTYPE sigterm_handler(int a) {
467 logger(LOG_NOTICE, "Got %s signal", "TERM");
474 static RETSIGTYPE sigquit_handler(int a) {
475 logger(LOG_NOTICE, "Got %s signal", "QUIT");
482 static RETSIGTYPE fatal_signal_square(int a) {
483 logger(LOG_ERR, "Got another fatal signal %d (%s): not restarting.", a,
488 static RETSIGTYPE fatal_signal_handler(int a) {
489 struct sigaction act;
490 logger(LOG_ERR, "Got fatal signal %d (%s)", a, strsignal(a));
493 logger(LOG_NOTICE, "Trying to re-execute in 5 seconds...");
495 act.sa_handler = fatal_signal_square;
496 act.sa_mask = emptysigset;
498 sigaction(SIGSEGV, &act, NULL);
500 close_network_connections();
502 remove_pid(pidfilename);
503 execvp(g_argv[0], g_argv);
505 logger(LOG_NOTICE, "Not restarting.");
510 static RETSIGTYPE sighup_handler(int a) {
511 logger(LOG_NOTICE, "Got %s signal", "HUP");
515 static RETSIGTYPE sigint_handler(int a) {
516 static int saved_debug_level = -1;
518 logger(LOG_NOTICE, "Got %s signal", "INT");
520 if(saved_debug_level != -1) {
521 logger(LOG_NOTICE, "Reverting to old debug level (%d)",
523 debug_level = saved_debug_level;
524 saved_debug_level = -1;
527 "Temporarily setting debug level to 5. Kill me with SIGINT again to go back to level %d.",
529 saved_debug_level = debug_level;
534 static RETSIGTYPE sigalrm_handler(int a) {
535 logger(LOG_NOTICE, "Got %s signal", "ALRM");
539 static RETSIGTYPE sigusr1_handler(int a) {
543 static RETSIGTYPE sigusr2_handler(int a) {
550 static RETSIGTYPE sigwinch_handler(int a) {
554 static RETSIGTYPE unexpected_signal_handler(int a) {
555 logger(LOG_WARNING, "Got unexpected signal %d (%s)", a, strsignal(a));
558 static RETSIGTYPE ignore_signal_handler(int a) {
559 ifdebug(SCARY_THINGS) logger(LOG_DEBUG, "Ignored signal %d (%s)", a, strsignal(a));
564 void (*handler)(int);
566 {SIGHUP, sighup_handler},
567 {SIGTERM, sigterm_handler},
568 {SIGQUIT, sigquit_handler},
569 {SIGSEGV, fatal_signal_handler},
570 {SIGBUS, fatal_signal_handler},
571 {SIGILL, fatal_signal_handler},
572 {SIGPIPE, ignore_signal_handler},
573 {SIGINT, sigint_handler},
574 {SIGUSR1, sigusr1_handler},
575 {SIGUSR2, sigusr2_handler},
576 {SIGCHLD, ignore_signal_handler},
577 {SIGALRM, sigalrm_handler},
578 {SIGWINCH, sigwinch_handler},
584 void setup_signals(void) {
587 struct sigaction act;
589 sigemptyset(&emptysigset);
590 act.sa_handler = NULL;
591 act.sa_mask = emptysigset;
594 /* Set a default signal handler for every signal, errors will be
596 for(i = 1; i < NSIG; i++) {
598 act.sa_handler = SIG_DFL;
600 act.sa_handler = unexpected_signal_handler;
601 sigaction(i, &act, NULL);
604 /* If we didn't detach, allow coredumps */
606 sighandlers[3].handler = SIG_DFL;
608 /* Then, for each known signal that we want to catch, assign a
609 handler to the signal, with error checking this time. */
610 for(i = 0; sighandlers[i].signal; i++) {
611 act.sa_handler = sighandlers[i].handler;
612 if(sigaction(sighandlers[i].signal, &act, NULL) < 0)
613 fprintf(stderr, "Installing signal handler for signal %d (%s) failed: %s\n",
614 sighandlers[i].signal, strsignal(sighandlers[i].signal),