Annotation of embedaddon/strongswan/src/starter/starter.c, revision 1.1.1.1
1.1 misho 1: /* strongSwan IPsec starter
2: * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
3: *
4: * This program is free software; you can redistribute it and/or modify it
5: * under the terms of the GNU General Public License as published by the
6: * Free Software Foundation; either version 2 of the License, or (at your
7: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
8: *
9: * This program is distributed in the hope that it will be useful, but
10: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12: * for more details.
13: */
14:
15: #define _GNU_SOURCE
16:
17: #include <sys/select.h>
18: #include <sys/types.h>
19: #include <sys/wait.h>
20: #include <sys/stat.h>
21: #include <stdlib.h>
22: #include <stdio.h>
23: #include <signal.h>
24: #include <syslog.h>
25: #include <unistd.h>
26: #include <sys/time.h>
27: #include <time.h>
28: #include <string.h>
29: #include <errno.h>
30: #include <fcntl.h>
31: #include <pwd.h>
32: #include <grp.h>
33: #include <pthread.h>
34:
35: #include <library.h>
36: #include <utils/backtrace.h>
37: #include <threading/thread.h>
38: #include <utils/debug.h>
39:
40: #include "confread.h"
41: #include "files.h"
42: #include "starterstroke.h"
43: #include "invokecharon.h"
44: #include "cmp.h"
45:
46: #ifndef LOG_AUTHPRIV
47: #define LOG_AUTHPRIV LOG_AUTH
48: #endif
49:
50: #define CHARON_RESTART_DELAY 5
51:
52: static const char* cmd_default = IPSEC_DIR "/charon";
53: static const char* pid_file_default = IPSEC_PIDDIR "/charon.pid";
54: static const char* starter_pid_file_default = IPSEC_PIDDIR "/starter.pid";
55:
56: char *daemon_name = NULL;
57: char *cmd = NULL;
58: char *pid_file = NULL;
59: char *starter_pid_file = NULL;
60:
61: static char *config_file = NULL;
62:
63: /* logging */
64: static bool log_to_stderr = TRUE;
65: static bool log_to_syslog = TRUE;
66: static level_t current_loglevel = 1;
67:
68: /**
69: * logging function for scepclient
70: */
71: static void starter_dbg(debug_t group, level_t level, char *fmt, ...)
72: {
73: char buffer[8192];
74: char *current = buffer, *next;
75: va_list args;
76:
77: if (level <= current_loglevel)
78: {
79: if (log_to_stderr)
80: {
81: va_start(args, fmt);
82: vfprintf(stderr, fmt, args);
83: va_end(args);
84: fprintf(stderr, "\n");
85: }
86: if (log_to_syslog)
87: {
88: /* write in memory buffer first */
89: va_start(args, fmt);
90: vsnprintf(buffer, sizeof(buffer), fmt, args);
91: va_end(args);
92:
93: /* do a syslog with every line */
94: while (current)
95: {
96: next = strchr(current, '\n');
97: if (next)
98: {
99: *(next++) = '\0';
100: }
101: syslog(LOG_INFO, "%s\n", current);
102: current = next;
103: }
104: }
105: }
106: }
107:
108: /**
109: * Initialize logging to stderr/syslog
110: */
111: static void init_log(const char *program)
112: {
113: dbg = starter_dbg;
114:
115: if (log_to_stderr)
116: {
117: setbuf(stderr, NULL);
118: }
119: if (log_to_syslog)
120: {
121: openlog(program, LOG_CONS | LOG_NDELAY | LOG_PID, LOG_AUTHPRIV);
122: }
123: }
124:
125: /**
126: * Deinitialize logging to syslog
127: */
128: static void close_log()
129: {
130: if (log_to_syslog)
131: {
132: closelog();
133: }
134: }
135:
136: /**
137: * Return codes defined by Linux Standard Base Core Specification 3.1
138: * in section 20.2. Init Script Actions
139: */
140: #define LSB_RC_SUCCESS 0 /* success */
141: #define LSB_RC_FAILURE 1 /* generic or unspecified error */
142: #define LSB_RC_INVALID_ARGUMENT 2 /* invalid or excess argument(s) */
143: #define LSB_RC_NOT_IMPLEMENTED 3 /* unimplemented feature (reload) */
144: #define LSB_RC_NOT_ALLOWED 4 /* user had insufficient privilege */
145: #define LSB_RC_NOT_INSTALLED 5 /* program is not installed */
146: #define LSB_RC_NOT_CONFIGURED 6 /* program is not configured */
147: #define LSB_RC_NOT_RUNNING 7 /* program is not running */
148:
149: #define FLAG_ACTION_START_PLUTO 0x01
150: #define FLAG_ACTION_UPDATE 0x02
151: #define FLAG_ACTION_RELOAD 0x04
152: #define FLAG_ACTION_QUIT 0x08
153: #define FLAG_ACTION_LISTEN 0x10
154: #define FLAG_ACTION_START_CHARON 0x20
155:
156: static unsigned int _action_ = 0;
157:
158: /**
159: * Handle signals in the main thread
160: */
161: static void signal_handler(int signal)
162: {
163: switch (signal)
164: {
165: case SIGCHLD:
166: {
167: int status, exit_status = 0;
168: pid_t pid;
169: char *name = NULL;
170:
171: while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
172: {
173: if (pid == starter_charon_pid())
174: {
175: if (asprintf(&name, " (%s)", daemon_name) < 0)
176: {
177: name = NULL;
178: }
179: }
180: if (WIFSIGNALED(status))
181: {
182: DBG2(DBG_APP, "child %d%s has been killed by sig %d\n",
183: pid, name?name:"", WTERMSIG(status));
184: }
185: else if (WIFSTOPPED(status))
186: {
187: DBG2(DBG_APP, "child %d%s has been stopped by sig %d\n",
188: pid, name?name:"", WSTOPSIG(status));
189: }
190: else if (WIFEXITED(status))
191: {
192: exit_status = WEXITSTATUS(status);
193: if (exit_status >= SS_RC_FIRST && exit_status <= SS_RC_LAST)
194: {
195: _action_ = FLAG_ACTION_QUIT;
196: }
197: DBG2(DBG_APP, "child %d%s has quit (exit code %d)\n",
198: pid, name?name:"", exit_status);
199: }
200: else
201: {
202: DBG2(DBG_APP, "child %d%s has quit", pid, name?name:"");
203: }
204: if (pid == starter_charon_pid())
205: {
206: starter_charon_sigchild(pid, exit_status);
207: }
208: }
209:
210: if (name)
211: {
212: free(name);
213: }
214: }
215: break;
216:
217: case SIGALRM:
218: _action_ |= FLAG_ACTION_START_CHARON;
219: break;
220:
221: case SIGHUP:
222: _action_ |= FLAG_ACTION_UPDATE;
223: break;
224:
225: case SIGTERM:
226: case SIGQUIT:
227: case SIGINT:
228: _action_ |= FLAG_ACTION_QUIT;
229: break;
230:
231: case SIGUSR1:
232: _action_ |= FLAG_ACTION_RELOAD;
233: _action_ |= FLAG_ACTION_UPDATE;
234: break;
235:
236: default:
237: DBG1(DBG_APP, "fsig(): unknown signal %d -- investigate", signal);
238: break;
239: }
240: }
241:
242: /**
243: * Handle fatal signals raised by threads
244: */
245: static void fatal_signal_handler(int signal)
246: {
247: backtrace_t *backtrace;
248:
249: DBG1(DBG_APP, "thread %u received %d", thread_current_id(), signal);
250: backtrace = backtrace_create(2);
251: backtrace->log(backtrace, stderr, TRUE);
252: backtrace->destroy(backtrace);
253:
254: DBG1(DBG_APP, "killing ourself, received critical signal");
255: abort();
256: }
257:
258: static bool check_pid(char *file)
259: {
260: struct stat stb;
261: FILE *pidfile;
262:
263: if (stat(file, &stb) == 0)
264: {
265: pidfile = fopen(file, "r");
266: if (pidfile)
267: {
268: char buf[64];
269: pid_t pid = 0;
270: memset(buf, 0, sizeof(buf));
271: if (fread(buf, 1, sizeof(buf), pidfile))
272: {
273: buf[sizeof(buf) - 1] = '\0';
274: pid = atoi(buf);
275: }
276: fclose(pidfile);
277: if (pid && pid != getpid() && kill(pid, 0) == 0)
278: { /* such a process is running */
279: return TRUE;
280: }
281: }
282: DBG1(DBG_APP, "removing pidfile '%s', process not running", file);
283: unlink(file);
284: }
285: return FALSE;
286: }
287:
288: /* Set daemon name and adjust command and pid filenames accordingly */
289: static bool set_daemon_name()
290: {
291: if (!daemon_name)
292: {
293: daemon_name = "charon";
294: }
295:
296: if (asprintf(&cmd, IPSEC_DIR"/%s", daemon_name) < 0)
297: {
298: cmd = (char*)cmd_default;
299: }
300:
301: if (asprintf(&pid_file, IPSEC_PIDDIR"/%s.pid", daemon_name) < 0)
302: {
303: pid_file = (char*)pid_file_default;
304: }
305:
306: if (asprintf(&starter_pid_file, IPSEC_PIDDIR"/starter.%s.pid",
307: daemon_name) < 0)
308: {
309: starter_pid_file = (char*)starter_pid_file_default;
310: }
311:
312: return TRUE;
313: }
314:
315: static void cleanup()
316: {
317: if (cmd != cmd_default)
318: {
319: free(cmd);
320: }
321:
322: if (pid_file != pid_file_default)
323: {
324: free(pid_file);
325: }
326:
327: if (starter_pid_file != starter_pid_file_default)
328: {
329: free(starter_pid_file);
330: }
331: }
332:
333: static void usage(char *name)
334: {
335: fprintf(stderr, "Usage: starter [--nofork] [--auto-update <sec>]\n"
336: " [--debug|--debug-more|--debug-all|--nolog]\n"
337: " [--attach-gdb] [--daemon <name>]\n"
338: " [--conf <path to ipsec.conf>]\n");
339: exit(LSB_RC_INVALID_ARGUMENT);
340: }
341:
342: int main (int argc, char **argv)
343: {
344: starter_config_t *cfg = NULL;
345: starter_config_t *new_cfg;
346: starter_conn_t *conn, *conn2;
347: starter_ca_t *ca, *ca2;
348:
349: struct sigaction action;
350: struct stat stb;
351:
352: int i;
353: int id = 1;
354: struct timespec ts;
355: unsigned long auto_update = 0;
356: time_t last_reload;
357: bool no_fork = FALSE;
358: bool attach_gdb = FALSE;
359: bool load_warning = FALSE;
360: bool conftest = FALSE;
361:
362: library_init(NULL, "starter");
363: atexit(library_deinit);
364:
365: /* parse command line */
366: for (i = 1; i < argc; i++)
367: {
368: if (streq(argv[i], "--debug"))
369: {
370: current_loglevel = 2;
371: }
372: else if (streq(argv[i], "--debug-more"))
373: {
374: current_loglevel = 3;
375: }
376: else if (streq(argv[i], "--debug-all"))
377: {
378: current_loglevel = 4;
379: }
380: else if (streq(argv[i], "--nolog"))
381: {
382: current_loglevel = 0;
383: }
384: else if (streq(argv[i], "--nofork"))
385: {
386: no_fork = TRUE;
387: }
388: else if (streq(argv[i], "--attach-gdb"))
389: {
390: no_fork = TRUE;
391: attach_gdb = TRUE;
392: }
393: else if (streq(argv[i], "--auto-update") && i+1 < argc)
394: {
395: auto_update = atoi(argv[++i]);
396: if (!auto_update)
397: usage(argv[0]);
398: }
399: else if (streq(argv[i], "--daemon") && i+1 < argc)
400: {
401: daemon_name = argv[++i];
402: }
403: else if (streq(argv[i], "--conf") && i+1 < argc)
404: {
405: config_file = argv[++i];
406: }
407: else if (streq(argv[i], "--conftest"))
408: {
409: conftest = TRUE;
410: }
411: else
412: {
413: usage(argv[0]);
414: }
415: }
416:
417: if (!set_daemon_name())
418: {
419: DBG1(DBG_APP, "unable to set daemon name");
420: exit(LSB_RC_FAILURE);
421: }
422: if (!config_file)
423: {
424: config_file = lib->settings->get_str(lib->settings,
425: "starter.config_file", CONFIG_FILE);
426: }
427:
428: init_log("ipsec_starter");
429:
430: if (conftest)
431: {
432: int status = LSB_RC_SUCCESS;
433:
434: cfg = confread_load(config_file);
435: if (cfg == NULL || cfg->err > 0)
436: {
437: DBG1(DBG_APP, "config invalid!");
438: status = LSB_RC_INVALID_ARGUMENT;
439: }
440: else
441: {
442: DBG1(DBG_APP, "config OK");
443: }
444: if (cfg)
445: {
446: confread_free(cfg);
447: }
448: cleanup();
449: exit(status);
450: }
451:
452: if (stat(cmd, &stb) != 0)
453: {
454: DBG1(DBG_APP, "IKE daemon '%s' not found", cmd);
455: cleanup();
456: exit(LSB_RC_FAILURE);
457: }
458:
459: DBG1(DBG_APP, "Starting %sSwan "VERSION" IPsec [starter]...",
460: lib->settings->get_bool(lib->settings,
461: "charon.i_dont_care_about_security_and_use_aggressive_mode_psk",
462: FALSE) ? "weak" : "strong");
463:
464: #ifdef LOAD_WARNING
465: load_warning = TRUE;
466: #endif
467:
468: if (lib->settings->get_bool(lib->settings, "starter.load_warning", load_warning))
469: {
470: if (lib->settings->get_str(lib->settings, "charon.load", NULL))
471: {
472: DBG1(DBG_APP, "!! Your strongswan.conf contains manual plugin load options for charon.");
473: DBG1(DBG_APP, "!! This is recommended for experts only, see");
474: DBG1(DBG_APP, "!! http://wiki.strongswan.org/projects/strongswan/wiki/PluginLoad");
475: }
476: }
477:
478: #ifndef STARTER_ALLOW_NON_ROOT
479: /* verify that we can start */
480: if (getuid() != 0)
481: {
482: DBG1(DBG_APP, "permission denied (must be superuser)");
483: cleanup();
484: exit(LSB_RC_NOT_ALLOWED);
485: }
486: #endif
487:
488: if (check_pid(pid_file))
489: {
490: DBG1(DBG_APP, "%s is already running (%s exists) -- skipping daemon start",
491: daemon_name, pid_file);
492: }
493: else
494: {
495: _action_ |= FLAG_ACTION_START_CHARON;
496: }
497: if (stat(DEV_RANDOM, &stb) != 0)
498: {
499: DBG1(DBG_APP, "unable to start strongSwan IPsec -- no %s!", DEV_RANDOM);
500: cleanup();
501: exit(LSB_RC_FAILURE);
502: }
503:
504: if (stat(DEV_URANDOM, &stb)!= 0)
505: {
506: DBG1(DBG_APP, "unable to start strongSwan IPsec -- no %s!", DEV_URANDOM);
507: cleanup();
508: exit(LSB_RC_FAILURE);
509: }
510:
511: cfg = confread_load(config_file);
512: if (cfg == NULL || cfg->err > 0)
513: {
514: DBG1(DBG_APP, "unable to start strongSwan -- fatal errors in config");
515: if (cfg)
516: {
517: confread_free(cfg);
518: }
519: cleanup();
520: exit(LSB_RC_INVALID_ARGUMENT);
521: }
522:
523: last_reload = time_monotonic(NULL);
524:
525: if (check_pid(starter_pid_file))
526: {
527: DBG1(DBG_APP, "starter is already running (%s exists) -- no fork done",
528: starter_pid_file);
529: confread_free(cfg);
530: cleanup();
531: exit(LSB_RC_SUCCESS);
532: }
533:
534: /* fork if we're not debugging stuff */
535: if (!no_fork)
536: {
537: log_to_stderr = FALSE;
538:
539: switch (fork())
540: {
541: case 0:
542: {
543: int fnull;
544:
545: close_log();
546:
547: fnull = open("/dev/null", O_RDWR);
548: if (fnull >= 0)
549: {
550: dup2(fnull, STDIN_FILENO);
551: dup2(fnull, STDOUT_FILENO);
552: dup2(fnull, STDERR_FILENO);
553: close(fnull);
554: }
555:
556: setsid();
557: init_log("ipsec_starter");
558: }
559: break;
560: case -1:
561: DBG1(DBG_APP, "can't fork: %s", strerror(errno));
562: break;
563: default:
564: confread_free(cfg);
565: cleanup();
566: exit(LSB_RC_SUCCESS);
567: }
568: }
569:
570: /* save pid file in /var/run/starter[.daemon_name].pid */
571: {
572: FILE *fd = fopen(starter_pid_file, "w");
573:
574: if (fd)
575: {
576: fprintf(fd, "%u\n", getpid());
577: fclose(fd);
578: }
579: }
580:
581: /* we handle these signals only in pselect() */
582: memset(&action, 0, sizeof(action));
583: sigemptyset(&action.sa_mask);
584: sigaddset(&action.sa_mask, SIGHUP);
585: sigaddset(&action.sa_mask, SIGINT);
586: sigaddset(&action.sa_mask, SIGTERM);
587: sigaddset(&action.sa_mask, SIGQUIT);
588: sigaddset(&action.sa_mask, SIGALRM);
589: sigaddset(&action.sa_mask, SIGUSR1);
590: pthread_sigmask(SIG_SETMASK, &action.sa_mask, NULL);
591:
592: /* install a handler for fatal signals */
593: action.sa_handler = fatal_signal_handler;
594: sigaction(SIGSEGV, &action, NULL);
595: sigaction(SIGILL, &action, NULL);
596: sigaction(SIGBUS, &action, NULL);
597: action.sa_handler = SIG_IGN;
598: sigaction(SIGPIPE, &action, NULL);
599:
600: /* install main signal handler */
601: action.sa_handler = signal_handler;
602: sigaction(SIGHUP, &action, NULL);
603: sigaction(SIGINT, &action, NULL);
604: sigaction(SIGTERM, &action, NULL);
605: sigaction(SIGQUIT, &action, NULL);
606: sigaction(SIGALRM, &action, NULL);
607: sigaction(SIGUSR1, &action, NULL);
608: /* this is not blocked above as we want to receive it asynchronously */
609: sigaction(SIGCHLD, &action, NULL);
610:
611: /* empty mask for pselect() call below */
612: sigemptyset(&action.sa_mask);
613:
614: for (;;)
615: {
616: /*
617: * Stop charon (if started) and exit
618: */
619: if (_action_ & FLAG_ACTION_QUIT)
620: {
621: if (starter_charon_pid())
622: {
623: starter_stop_charon();
624: }
625: confread_free(cfg);
626: unlink(starter_pid_file);
627: cleanup();
628: DBG1(DBG_APP, "ipsec starter stopped");
629: close_log();
630: exit(LSB_RC_SUCCESS);
631: }
632:
633: /*
634: * Delete all connections. Will be added below
635: */
636: if (_action_ & FLAG_ACTION_RELOAD)
637: {
638: _action_ &= ~FLAG_ACTION_RELOAD;
639: if (starter_charon_pid())
640: {
641: for (conn = cfg->conn_first; conn; conn = conn->next)
642: {
643: if (conn->state == STATE_ADDED)
644: {
645: if (starter_charon_pid())
646: {
647: if (conn->startup == STARTUP_ROUTE)
648: {
649: starter_stroke_unroute_conn(conn);
650: }
651: starter_stroke_del_conn(conn);
652: }
653: conn->state = STATE_TO_ADD;
654: }
655: }
656: for (ca = cfg->ca_first; ca; ca = ca->next)
657: {
658: if (ca->state == STATE_ADDED)
659: {
660: if (starter_charon_pid())
661: {
662: starter_stroke_del_ca(ca);
663: }
664: ca->state = STATE_TO_ADD;
665: }
666: }
667: }
668: }
669:
670: /*
671: * Update configuration
672: */
673: if (_action_ & FLAG_ACTION_UPDATE)
674: {
675: _action_ &= ~FLAG_ACTION_UPDATE;
676: DBG2(DBG_APP, "Reloading config...");
677: new_cfg = confread_load(config_file);
678:
679: if (new_cfg && (new_cfg->err == 0))
680: {
681: /* Switch to new config. New conn will be loaded below */
682:
683: /* Look for new connections that are already loaded */
684: for (conn = cfg->conn_first; conn; conn = conn->next)
685: {
686: if (conn->state == STATE_ADDED)
687: {
688: for (conn2 = new_cfg->conn_first; conn2; conn2 = conn2->next)
689: {
690: if (conn2->state == STATE_TO_ADD && starter_cmp_conn(conn, conn2))
691: {
692: conn->state = STATE_REPLACED;
693: conn2->state = STATE_ADDED;
694: conn2->id = conn->id;
695: break;
696: }
697: }
698: }
699: }
700:
701: /* Remove conn sections that have become unused */
702: for (conn = cfg->conn_first; conn; conn = conn->next)
703: {
704: if (conn->state == STATE_ADDED)
705: {
706: if (starter_charon_pid())
707: {
708: if (conn->startup == STARTUP_ROUTE)
709: {
710: starter_stroke_unroute_conn(conn);
711: }
712: starter_stroke_del_conn(conn);
713: }
714: }
715: }
716:
717: /* Look for new ca sections that are already loaded */
718: for (ca = cfg->ca_first; ca; ca = ca->next)
719: {
720: if (ca->state == STATE_ADDED)
721: {
722: for (ca2 = new_cfg->ca_first; ca2; ca2 = ca2->next)
723: {
724: if (ca2->state == STATE_TO_ADD && starter_cmp_ca(ca, ca2))
725: {
726: ca->state = STATE_REPLACED;
727: ca2->state = STATE_ADDED;
728: break;
729: }
730: }
731: }
732: }
733:
734: /* Remove ca sections that have become unused */
735: for (ca = cfg->ca_first; ca; ca = ca->next)
736: {
737: if (ca->state == STATE_ADDED)
738: {
739: if (starter_charon_pid())
740: {
741: starter_stroke_del_ca(ca);
742: }
743: }
744: }
745: confread_free(cfg);
746: cfg = new_cfg;
747: }
748: else
749: {
750: DBG1(DBG_APP, "can't reload config file due to errors -- keeping old one");
751: if (new_cfg)
752: {
753: confread_free(new_cfg);
754: }
755: }
756: last_reload = time_monotonic(NULL);
757: }
758:
759: /*
760: * Start daemon
761: */
762: if (_action_ & FLAG_ACTION_START_CHARON)
763: {
764: _action_ &= ~FLAG_ACTION_START_CHARON;
765: if (!starter_charon_pid())
766: {
767: DBG2(DBG_APP, "Attempting to start %s...", daemon_name);
768: if (starter_start_charon(cfg, no_fork, attach_gdb))
769: {
770: /* schedule next try */
771: alarm(CHARON_RESTART_DELAY);
772: }
773: starter_stroke_configure(cfg);
774: }
775:
776: for (ca = cfg->ca_first; ca; ca = ca->next)
777: {
778: if (ca->state == STATE_ADDED)
779: {
780: ca->state = STATE_TO_ADD;
781: }
782: }
783:
784: for (conn = cfg->conn_first; conn; conn = conn->next)
785: {
786: if (conn->state == STATE_ADDED)
787: {
788: conn->state = STATE_TO_ADD;
789: }
790: }
791: }
792:
793: /*
794: * Add stale conn and ca sections
795: */
796: if (starter_charon_pid())
797: {
798: for (ca = cfg->ca_first; ca; ca = ca->next)
799: {
800: if (ca->state == STATE_TO_ADD)
801: {
802: if (starter_charon_pid())
803: {
804: starter_stroke_add_ca(ca);
805: }
806: ca->state = STATE_ADDED;
807: }
808: }
809:
810: for (conn = cfg->conn_first; conn; conn = conn->next)
811: {
812: if (conn->state == STATE_TO_ADD)
813: {
814: if (conn->id == 0)
815: {
816: /* affect new unique id */
817: conn->id = id++;
818: }
819: if (starter_charon_pid())
820: {
821: starter_stroke_add_conn(cfg, conn);
822: }
823: conn->state = STATE_ADDED;
824:
825: if (conn->startup == STARTUP_START)
826: {
827: if (starter_charon_pid())
828: {
829: starter_stroke_initiate_conn(conn);
830: }
831: }
832: else if (conn->startup == STARTUP_ROUTE)
833: {
834: if (starter_charon_pid())
835: {
836: starter_stroke_route_conn(conn);
837: }
838: }
839: }
840: }
841: }
842:
843: /*
844: * If auto_update activated, when to stop select
845: */
846: if (auto_update)
847: {
848: time_t now = time_monotonic(NULL);
849:
850: ts.tv_sec = (now < last_reload + auto_update) ?
851: (last_reload + auto_update - now) : 0;
852: ts.tv_nsec = 0;
853: }
854:
855: /*
856: * Wait for something to happen
857: */
858: if (!_action_ &&
859: pselect(0, NULL, NULL, NULL, auto_update ? &ts : NULL,
860: &action.sa_mask) == 0)
861: {
862: /* timeout -> auto_update */
863: _action_ |= FLAG_ACTION_UPDATE;
864: }
865: }
866: exit(LSB_RC_SUCCESS);
867: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>