]>
Commit | Line | Data |
---|---|---|
88840341 | 1 | /* |
88840341 RC |
2 | chronyd/chronyc - Programs for keeping computer clocks accurate. |
3 | ||
4 | ********************************************************************** | |
6672f045 | 5 | * Copyright (C) Richard P. Curnow 1997-2003 |
f7e08d0c | 6 | * Copyright (C) John G. Hasler 2009 |
c9f50fc6 | 7 | * Copyright (C) Miroslav Lichvar 2012-2017 |
88840341 RC |
8 | * |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of version 2 of the GNU General Public License as | |
11 | * published by the Free Software Foundation. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License along | |
19 | * with this program; if not, write to the Free Software Foundation, Inc., | |
8e23110a | 20 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
88840341 RC |
21 | * |
22 | ********************************************************************** | |
23 | ||
24 | ======================================================================= | |
25 | ||
26 | The main program | |
27 | */ | |
28 | ||
da2c8d90 ML |
29 | #include "config.h" |
30 | ||
88840341 RC |
31 | #include "sysincl.h" |
32 | ||
33 | #include "main.h" | |
34 | #include "sched.h" | |
35 | #include "local.h" | |
36 | #include "sys.h" | |
37 | #include "ntp_io.h" | |
577aed48 | 38 | #include "ntp_signd.h" |
88840341 RC |
39 | #include "ntp_sources.h" |
40 | #include "ntp_core.h" | |
41 | #include "sources.h" | |
42 | #include "sourcestats.h" | |
43 | #include "reference.h" | |
44 | #include "logging.h" | |
45 | #include "conf.h" | |
46 | #include "cmdmon.h" | |
47 | #include "keys.h" | |
88840341 | 48 | #include "manual.h" |
88840341 | 49 | #include "rtc.h" |
ac30bb06 | 50 | #include "refclock.h" |
88840341 | 51 | #include "clientlog.h" |
fbd20c42 | 52 | #include "nameserv.h" |
610f2340 | 53 | #include "privops.h" |
7f45eb79 | 54 | #include "smooth.h" |
c386d117 | 55 | #include "tempcomp.h" |
ceef8ad2 | 56 | #include "util.h" |
88840341 RC |
57 | |
58 | /* ================================================== */ | |
59 | ||
60 | /* Set when the initialisation chain has been completed. Prevents finalisation | |
61 | * chain being run if a fatal error happened early. */ | |
62 | ||
63 | static int initialised = 0; | |
64 | ||
93b66ac1 | 65 | static int exit_status = 0; |
88840341 RC |
66 | |
67 | static int reload = 0; | |
68 | ||
e176587e | 69 | static REF_Mode ref_mode = REF_ModeNormal; |
7fda9c67 | 70 | |
88840341 RC |
71 | /* ================================================== */ |
72 | ||
bafb434f ML |
73 | static void |
74 | do_platform_checks(void) | |
75 | { | |
76 | /* Require at least 32-bit integers, two's complement representation and | |
77 | the usual implementation of conversion of unsigned integers */ | |
78 | assert(sizeof (int) >= 4); | |
79 | assert(-1 == ~0); | |
fe502128 | 80 | assert((int32_t)4294967295U == (int32_t)-1); |
bafb434f ML |
81 | } |
82 | ||
83 | /* ================================================== */ | |
84 | ||
88840341 RC |
85 | static void |
86 | delete_pidfile(void) | |
87 | { | |
88 | const char *pidfile = CNF_GetPidFile(); | |
778fce40 ML |
89 | |
90 | if (!pidfile[0]) | |
91 | return; | |
92 | ||
88840341 RC |
93 | /* Don't care if this fails, there's not a lot we can do */ |
94 | unlink(pidfile); | |
95 | } | |
96 | ||
97 | /* ================================================== */ | |
98 | ||
1e7e7d32 | 99 | void |
88840341 RC |
100 | MAI_CleanupAndExit(void) |
101 | { | |
93b66ac1 | 102 | if (!initialised) exit(exit_status); |
88840341 | 103 | |
f3a16383 | 104 | if (CNF_GetDumpDir()[0] != '\0') { |
88840341 RC |
105 | SRC_DumpSources(); |
106 | } | |
107 | ||
f6ed7844 ML |
108 | /* Don't update clock when removing sources */ |
109 | REF_SetMode(REF_ModeIgnore); | |
110 | ||
7f45eb79 | 111 | SMT_Finalise(); |
c386d117 | 112 | TMC_Finalise(); |
88840341 | 113 | MNL_Finalise(); |
88840341 | 114 | CLG_Finalise(); |
577aed48 | 115 | NSD_Finalise(); |
88840341 | 116 | NSR_Finalise(); |
8854c00d | 117 | SST_Finalise(); |
88840341 | 118 | NCR_Finalise(); |
4e54770f | 119 | NIO_Finalise(); |
8854c00d | 120 | CAM_Finalise(); |
1c901b82 | 121 | KEY_Finalise(); |
ac30bb06 | 122 | RCL_Finalise(); |
3a222336 | 123 | SRC_Finalise(); |
f6ed7844 | 124 | REF_Finalise(); |
be42b4ee | 125 | RTC_Finalise(); |
88840341 RC |
126 | SYS_Finalise(); |
127 | SCH_Finalise(); | |
128 | LCL_Finalise(); | |
334ac061 | 129 | PRV_Finalise(); |
88840341 RC |
130 | |
131 | delete_pidfile(); | |
132 | ||
f6ed7844 | 133 | CNF_Finalise(); |
f6ed7844 | 134 | HSH_Finalise(); |
b712c100 | 135 | LOG_Finalise(); |
f6ed7844 | 136 | |
93b66ac1 | 137 | exit(exit_status); |
88840341 RC |
138 | } |
139 | ||
140 | /* ================================================== */ | |
141 | ||
142 | static void | |
143 | signal_cleanup(int x) | |
144 | { | |
9416a24f ML |
145 | if (!initialised) exit(0); |
146 | SCH_QuitProgram(); | |
88840341 RC |
147 | } |
148 | ||
149 | /* ================================================== */ | |
150 | ||
35134848 ML |
151 | static void |
152 | quit_timeout(void *arg) | |
153 | { | |
154 | /* Return with non-zero status if the clock is not synchronised */ | |
155 | exit_status = REF_GetOurStratum() >= NTP_MAX_STRATUM; | |
156 | SCH_QuitProgram(); | |
157 | } | |
158 | ||
159 | /* ================================================== */ | |
160 | ||
88840341 | 161 | static void |
6ee357d2 | 162 | ntp_source_resolving_end(void) |
88840341 | 163 | { |
6ee357d2 | 164 | NSR_SetSourceResolvingEndHandler(NULL); |
88840341 | 165 | |
88840341 RC |
166 | if (reload) { |
167 | /* Note, we want reload to come well after the initialisation from | |
168 | the real time clock - this gives us a fighting chance that the | |
169 | system-clock scale for the reloaded samples still has a | |
170 | semblence of validity about it. */ | |
171 | SRC_ReloadSources(); | |
172 | } | |
88840341 | 173 | |
a06a5f1b | 174 | SRC_RemoveDumpFiles(); |
88840341 | 175 | RTC_StartMeasurements(); |
ac30bb06 | 176 | RCL_StartRefclocks(); |
779e40ed ML |
177 | NSR_StartSources(); |
178 | NSR_AutoStartSources(); | |
70feea48 ML |
179 | |
180 | /* Special modes can end only when sources update their reachability. | |
7fa22d4c ML |
181 | Give up immediatelly if there are no active sources. */ |
182 | if (ref_mode != REF_ModeNormal && !SRC_ActiveSources()) { | |
70feea48 ML |
183 | REF_SetUnsynchronised(); |
184 | } | |
88840341 RC |
185 | } |
186 | ||
187 | /* ================================================== */ | |
188 | ||
6ee357d2 ML |
189 | static void |
190 | post_init_ntp_hook(void *anything) | |
191 | { | |
192 | if (ref_mode == REF_ModeInitStepSlew) { | |
193 | /* Remove the initstepslew sources and set normal mode */ | |
194 | NSR_RemoveAllSources(); | |
195 | ref_mode = REF_ModeNormal; | |
196 | REF_SetMode(ref_mode); | |
197 | } | |
198 | ||
199 | /* Close the pipe to the foreground process so it can exit */ | |
200 | LOG_CloseParentFd(); | |
201 | ||
202 | CNF_AddSources(); | |
203 | CNF_AddBroadcasts(); | |
204 | ||
205 | NSR_SetSourceResolvingEndHandler(ntp_source_resolving_end); | |
206 | NSR_ResolveSources(); | |
207 | } | |
208 | ||
209 | /* ================================================== */ | |
210 | ||
7fda9c67 ML |
211 | static void |
212 | reference_mode_end(int result) | |
213 | { | |
214 | switch (ref_mode) { | |
215 | case REF_ModeNormal: | |
70feea48 ML |
216 | case REF_ModeUpdateOnce: |
217 | case REF_ModePrintOnce: | |
93b66ac1 ML |
218 | exit_status = !result; |
219 | SCH_QuitProgram(); | |
7fda9c67 ML |
220 | break; |
221 | case REF_ModeInitStepSlew: | |
ead3ca14 ML |
222 | /* Switch to the normal mode, the delay is used to prevent polling |
223 | interval shorter than the burst interval if some configured servers | |
224 | were used also for initstepslew */ | |
225 | SCH_AddTimeoutByDelay(2.0, post_init_ntp_hook, NULL); | |
7fda9c67 ML |
226 | break; |
227 | default: | |
228 | assert(0); | |
229 | } | |
230 | } | |
231 | ||
232 | /* ================================================== */ | |
233 | ||
88840341 RC |
234 | static void |
235 | post_init_rtc_hook(void *anything) | |
236 | { | |
7fda9c67 ML |
237 | if (CNF_GetInitSources() > 0) { |
238 | CNF_AddInitSources(); | |
779e40ed | 239 | NSR_StartSources(); |
7fda9c67 ML |
240 | assert(REF_GetMode() != REF_ModeNormal); |
241 | /* Wait for mode end notification */ | |
242 | } else { | |
243 | (post_init_ntp_hook)(NULL); | |
244 | } | |
88840341 RC |
245 | } |
246 | ||
247 | /* ================================================== */ | |
88840341 | 248 | |
7bd1c027 ML |
249 | static void |
250 | check_pidfile(void) | |
88840341 RC |
251 | { |
252 | const char *pidfile = CNF_GetPidFile(); | |
253 | FILE *in; | |
254 | int pid, count; | |
255 | ||
88840341 | 256 | in = fopen(pidfile, "r"); |
7bd1c027 ML |
257 | if (!in) |
258 | return; | |
88840341 RC |
259 | |
260 | count = fscanf(in, "%d", &pid); | |
261 | fclose(in); | |
262 | ||
7bd1c027 ML |
263 | if (count != 1) |
264 | return; | |
88840341 | 265 | |
7bd1c027 ML |
266 | if (getsid(pid) < 0) |
267 | return; | |
268 | ||
269 | LOG_FATAL("Another chronyd may already be running (pid=%d), check %s", | |
270 | pid, pidfile); | |
88840341 RC |
271 | } |
272 | ||
273 | /* ================================================== */ | |
274 | ||
275 | static void | |
7bd1c027 | 276 | write_pidfile(void) |
88840341 RC |
277 | { |
278 | const char *pidfile = CNF_GetPidFile(); | |
279 | FILE *out; | |
280 | ||
778fce40 ML |
281 | if (!pidfile[0]) |
282 | return; | |
283 | ||
88840341 RC |
284 | out = fopen(pidfile, "w"); |
285 | if (!out) { | |
539ef3f7 | 286 | LOG_FATAL("Could not open %s : %s", pidfile, strerror(errno)); |
88840341 | 287 | } else { |
f444561a | 288 | fprintf(out, "%d\n", (int)getpid()); |
88840341 RC |
289 | fclose(out); |
290 | } | |
291 | } | |
292 | ||
293 | /* ================================================== */ | |
294 | ||
fe4b661f ML |
295 | static void |
296 | go_daemon(void) | |
297 | { | |
1d2a0856 ML |
298 | int pid, fd, pipefd[2]; |
299 | ||
300 | /* Create pipe which will the daemon use to notify the grandparent | |
301 | when it's initialised or send an error message */ | |
302 | if (pipe(pipefd)) { | |
539ef3f7 | 303 | LOG_FATAL("pipe() failed : %s", strerror(errno)); |
1d2a0856 | 304 | } |
fe4b661f ML |
305 | |
306 | /* Does this preserve existing signal handlers? */ | |
307 | pid = fork(); | |
308 | ||
309 | if (pid < 0) { | |
539ef3f7 | 310 | LOG_FATAL("fork() failed : %s", strerror(errno)); |
fe4b661f | 311 | } else if (pid > 0) { |
1d2a0856 ML |
312 | /* In the 'grandparent' */ |
313 | char message[1024]; | |
314 | int r; | |
315 | ||
316 | close(pipefd[1]); | |
317 | r = read(pipefd[0], message, sizeof (message)); | |
318 | if (r) { | |
319 | if (r > 0) { | |
320 | /* Print the error message from the child */ | |
a7802e9a ML |
321 | message[sizeof (message) - 1] = '\0'; |
322 | fprintf(stderr, "%s\n", message); | |
1d2a0856 ML |
323 | } |
324 | exit(1); | |
325 | } else | |
326 | exit(0); | |
fe4b661f | 327 | } else { |
1d2a0856 | 328 | close(pipefd[0]); |
fe4b661f ML |
329 | |
330 | setsid(); | |
331 | ||
332 | /* Do 2nd fork, as-per recommended practice for launching daemons. */ | |
333 | pid = fork(); | |
334 | ||
335 | if (pid < 0) { | |
539ef3f7 | 336 | LOG_FATAL("fork() failed : %s", strerror(errno)); |
fe4b661f ML |
337 | } else if (pid > 0) { |
338 | exit(0); /* In the 'parent' */ | |
339 | } else { | |
340 | /* In the child we want to leave running as the daemon */ | |
341 | ||
2a305d8e ML |
342 | /* Change current directory to / */ |
343 | if (chdir("/") < 0) { | |
539ef3f7 | 344 | LOG_FATAL("chdir() failed : %s", strerror(errno)); |
2a305d8e ML |
345 | } |
346 | ||
1d2a0856 ML |
347 | /* Don't keep stdin/out/err from before. But don't close |
348 | the parent pipe yet. */ | |
fe4b661f | 349 | for (fd=0; fd<1024; fd++) { |
1d2a0856 ML |
350 | if (fd != pipefd[1]) |
351 | close(fd); | |
fe4b661f | 352 | } |
919b5b5a | 353 | |
1d2a0856 | 354 | LOG_SetParentFd(pipefd[1]); |
fe4b661f ML |
355 | } |
356 | } | |
fe4b661f ML |
357 | } |
358 | ||
359 | /* ================================================== */ | |
360 | ||
ae0c3bbb ML |
361 | static void |
362 | print_help(const char *progname) | |
363 | { | |
364 | printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-t TIMEOUT] [-f FILE|COMMAND...]\n", | |
365 | progname); | |
366 | } | |
367 | ||
368 | /* ================================================== */ | |
369 | ||
370 | static void | |
371 | print_version(void) | |
372 | { | |
373 | printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES); | |
374 | } | |
375 | ||
376 | /* ================================================== */ | |
377 | ||
378 | static int | |
379 | parse_int_arg(const char *arg) | |
380 | { | |
381 | int i; | |
382 | ||
383 | if (sscanf(arg, "%d", &i) != 1) | |
384 | LOG_FATAL("Invalid argument %s", arg); | |
385 | return i; | |
386 | } | |
387 | ||
388 | /* ================================================== */ | |
389 | ||
88840341 RC |
390 | int main |
391 | (int argc, char **argv) | |
392 | { | |
0f8def4c | 393 | const char *conf_file = DEFAULT_CONF_FILE; |
1cda2db4 | 394 | const char *progname = argv[0]; |
a1cbd4eb | 395 | char *user = NULL, *log_file = NULL; |
6402350c | 396 | struct passwd *pw; |
ae0c3bbb | 397 | int opt, debug = 0, nofork = 0, address_family = IPADDR_UNSPEC; |
778fce40 | 398 | int do_init_rtc = 0, restarted = 0, client_only = 0, timeout = 0; |
434faeec | 399 | int scfilter_level = 0, lock_memory = 0, sched_priority = 0; |
c4434609 | 400 | int clock_control = 1, system_log = 1; |
3edd3fe5 | 401 | int config_args = 0; |
35e662d8 | 402 | |
bafb434f ML |
403 | do_platform_checks(); |
404 | ||
88840341 RC |
405 | LOG_Initialise(); |
406 | ||
ae0c3bbb ML |
407 | /* Parse (undocumented) long command-line options */ |
408 | for (optind = 1; optind < argc; optind++) { | |
409 | if (!strcmp("--help", argv[optind])) { | |
410 | print_help(progname); | |
1769b8ea | 411 | return 0; |
ae0c3bbb ML |
412 | } else if (!strcmp("--version", argv[optind])) { |
413 | print_version(); | |
1769b8ea | 414 | return 0; |
ae0c3bbb ML |
415 | } |
416 | } | |
417 | ||
418 | optind = 1; | |
419 | ||
420 | /* Parse short command-line options */ | |
421 | while ((opt = getopt(argc, argv, "46df:F:hl:mnP:qQrRst:u:vx")) != -1) { | |
422 | switch (opt) { | |
423 | case '4': | |
424 | case '6': | |
425 | address_family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6; | |
426 | break; | |
427 | case 'd': | |
428 | debug++; | |
429 | nofork = 1; | |
430 | system_log = 0; | |
431 | break; | |
432 | case 'f': | |
433 | conf_file = optarg; | |
434 | break; | |
435 | case 'F': | |
436 | scfilter_level = parse_int_arg(optarg); | |
437 | break; | |
438 | case 'l': | |
439 | log_file = optarg; | |
440 | break; | |
441 | case 'm': | |
442 | lock_memory = 1; | |
443 | break; | |
444 | case 'n': | |
445 | nofork = 1; | |
446 | break; | |
447 | case 'P': | |
448 | sched_priority = parse_int_arg(optarg); | |
449 | break; | |
450 | case 'q': | |
4f1fc1ee BC |
451 | ref_mode = REF_ModeUpdateOnce; |
452 | nofork = 1; | |
453 | client_only = 0; | |
454 | system_log = 0; | |
455 | break; | |
ae0c3bbb | 456 | case 'Q': |
4f1fc1ee | 457 | ref_mode = REF_ModePrintOnce; |
ae0c3bbb | 458 | nofork = 1; |
778fce40 ML |
459 | client_only = 1; |
460 | clock_control = 0; | |
ae0c3bbb ML |
461 | system_log = 0; |
462 | break; | |
463 | case 'r': | |
464 | reload = 1; | |
465 | break; | |
466 | case 'R': | |
467 | restarted = 1; | |
468 | break; | |
469 | case 's': | |
470 | do_init_rtc = 1; | |
471 | break; | |
472 | case 't': | |
473 | timeout = parse_int_arg(optarg); | |
474 | break; | |
475 | case 'u': | |
476 | user = optarg; | |
477 | break; | |
478 | case 'v': | |
479 | print_version(); | |
480 | return 0; | |
481 | case 'x': | |
482 | clock_control = 0; | |
483 | break; | |
484 | default: | |
485 | print_help(progname); | |
486 | return opt != 'h'; | |
88840341 RC |
487 | } |
488 | } | |
489 | ||
778fce40 | 490 | if (getuid() && !client_only) |
3a5566c6 | 491 | LOG_FATAL("Not superuser"); |
88840341 | 492 | |
88840341 | 493 | /* Turn into a daemon */ |
fe4b661f ML |
494 | if (!nofork) { |
495 | go_daemon(); | |
496 | } | |
497 | ||
a1cbd4eb ML |
498 | if (log_file) { |
499 | LOG_OpenFileLog(log_file); | |
500 | } else if (system_log) { | |
fe4b661f | 501 | LOG_OpenSystemLog(); |
88840341 RC |
502 | } |
503 | ||
788e7fcd | 504 | LOG_SetDebugLevel(debug); |
4bbc5520 | 505 | |
f282856c | 506 | LOG(LOGS_INFO, "chronyd version %s starting (%s)", CHRONY_VERSION, CHRONYD_FEATURES); |
cb905507 | 507 | |
72d0b3c9 ML |
508 | DNS_SetAddressFamily(address_family); |
509 | ||
778fce40 | 510 | CNF_Initialise(restarted, client_only); |
3edd3fe5 ML |
511 | |
512 | /* Parse the config file or the remaining command line arguments */ | |
ae0c3bbb | 513 | config_args = argc - optind; |
3edd3fe5 ML |
514 | if (!config_args) { |
515 | CNF_ReadFile(conf_file); | |
516 | } else { | |
ae0c3bbb ML |
517 | for (; optind < argc; optind++) |
518 | CNF_ParseLine(NULL, config_args + optind - argc + 1, argv[optind]); | |
3edd3fe5 | 519 | } |
1e35b268 | 520 | |
7bd1c027 ML |
521 | /* Check whether another chronyd may already be running */ |
522 | check_pidfile(); | |
88840341 | 523 | |
7bd1c027 ML |
524 | /* Write our pidfile to prevent other chronyds running */ |
525 | write_pidfile(); | |
88840341 | 526 | |
334ac061 | 527 | PRV_Initialise(); |
88840341 RC |
528 | LCL_Initialise(); |
529 | SCH_Initialise(); | |
c4434609 | 530 | SYS_Initialise(clock_control); |
c6e06420 | 531 | RTC_Initialise(do_init_rtc); |
3a222336 | 532 | SRC_Initialise(); |
ac30bb06 | 533 | RCL_Initialise(); |
1c901b82 | 534 | KEY_Initialise(); |
be42b4ee | 535 | |
8854c00d ML |
536 | /* Open privileged ports before dropping root */ |
537 | CAM_Initialise(address_family); | |
538 | NIO_Initialise(address_family); | |
539 | NCR_Initialise(); | |
540 | CNF_SetupAccessRestrictions(); | |
541 | ||
e3234465 ML |
542 | /* Command-line switch must have priority */ |
543 | if (!sched_priority) { | |
544 | sched_priority = CNF_GetSchedPriority(); | |
545 | } | |
546 | if (sched_priority) { | |
547 | SYS_SetScheduler(sched_priority); | |
96759116 ML |
548 | } |
549 | ||
e3234465 ML |
550 | if (lock_memory || CNF_GetLockMemory()) { |
551 | SYS_LockMemory(); | |
96759116 ML |
552 | } |
553 | ||
edda0c60 ML |
554 | if (!user) { |
555 | user = CNF_GetUser(); | |
556 | } | |
6402350c | 557 | |
e7100e10 | 558 | if ((pw = getpwnam(user)) == NULL) |
0ce15a84 | 559 | LOG_FATAL("Could not get user/group ID of %s", user); |
6402350c | 560 | |
6d42dd86 ML |
561 | /* Create all directories before dropping root */ |
562 | CNF_CreateDirs(pw->pw_uid, pw->pw_gid); | |
563 | ||
778fce40 ML |
564 | /* Drop root privileges if the specified user has a non-zero UID */ |
565 | if (!geteuid() && (pw->pw_uid || pw->pw_gid)) | |
6402350c | 566 | SYS_DropRoot(pw->pw_uid, pw->pw_gid); |
be42b4ee | 567 | |
88840341 RC |
568 | REF_Initialise(); |
569 | SST_Initialise(); | |
88840341 | 570 | NSR_Initialise(); |
577aed48 | 571 | NSD_Initialise(); |
88840341 | 572 | CLG_Initialise(); |
88840341 | 573 | MNL_Initialise(); |
c386d117 | 574 | TMC_Initialise(); |
7f45eb79 | 575 | SMT_Initialise(); |
88840341 RC |
576 | |
577 | /* From now on, it is safe to do finalisation on exit */ | |
578 | initialised = 1; | |
579 | ||
ea2858b3 ML |
580 | UTI_SetQuitSignalsHandler(signal_cleanup); |
581 | ||
8854c00d | 582 | CAM_OpenUnixSocket(); |
46951b85 | 583 | |
434faeec ML |
584 | if (scfilter_level) |
585 | SYS_EnableSystemCallFilter(scfilter_level); | |
586 | ||
70feea48 | 587 | if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) { |
7fda9c67 ML |
588 | ref_mode = REF_ModeInitStepSlew; |
589 | } | |
590 | ||
591 | REF_SetModeEndHandler(reference_mode_end); | |
592 | REF_SetMode(ref_mode); | |
593 | ||
ae0c3bbb | 594 | if (timeout > 0) |
35134848 ML |
595 | SCH_AddTimeoutByDelay(timeout, quit_timeout, NULL); |
596 | ||
88840341 RC |
597 | if (do_init_rtc) { |
598 | RTC_TimeInit(post_init_rtc_hook, NULL); | |
599 | } else { | |
600 | post_init_rtc_hook(NULL); | |
601 | } | |
602 | ||
88840341 RC |
603 | /* The program normally runs under control of the main loop in |
604 | the scheduler. */ | |
605 | SCH_MainLoop(); | |
606 | ||
f282856c | 607 | LOG(LOGS_INFO, "chronyd exiting"); |
0fc9b555 | 608 | |
88840341 RC |
609 | MAI_CleanupAndExit(); |
610 | ||
611 | return 0; | |
612 | } | |
613 | ||
614 | /* ================================================== */ |