]>
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 |
3916c336 | 7 | * Copyright (C) Miroslav Lichvar 2012-2020 |
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" | |
a420ed57 | 41 | #include "nts_ke_server.h" |
6043632f | 42 | #include "nts_ntp_server.h" |
2de24cfd | 43 | #include "socket.h" |
88840341 RC |
44 | #include "sources.h" |
45 | #include "sourcestats.h" | |
46 | #include "reference.h" | |
47 | #include "logging.h" | |
48 | #include "conf.h" | |
49 | #include "cmdmon.h" | |
50 | #include "keys.h" | |
88840341 | 51 | #include "manual.h" |
88840341 | 52 | #include "rtc.h" |
ac30bb06 | 53 | #include "refclock.h" |
88840341 | 54 | #include "clientlog.h" |
fbd20c42 | 55 | #include "nameserv.h" |
610f2340 | 56 | #include "privops.h" |
7f45eb79 | 57 | #include "smooth.h" |
c386d117 | 58 | #include "tempcomp.h" |
ceef8ad2 | 59 | #include "util.h" |
88840341 RC |
60 | |
61 | /* ================================================== */ | |
62 | ||
63 | /* Set when the initialisation chain has been completed. Prevents finalisation | |
64 | * chain being run if a fatal error happened early. */ | |
65 | ||
66 | static int initialised = 0; | |
67 | ||
93b66ac1 | 68 | static int exit_status = 0; |
88840341 RC |
69 | |
70 | static int reload = 0; | |
71 | ||
e176587e | 72 | static REF_Mode ref_mode = REF_ModeNormal; |
7fda9c67 | 73 | |
88840341 RC |
74 | /* ================================================== */ |
75 | ||
bafb434f ML |
76 | static void |
77 | do_platform_checks(void) | |
78 | { | |
79 | /* Require at least 32-bit integers, two's complement representation and | |
80 | the usual implementation of conversion of unsigned integers */ | |
81 | assert(sizeof (int) >= 4); | |
82 | assert(-1 == ~0); | |
fe502128 | 83 | assert((int32_t)4294967295U == (int32_t)-1); |
bafb434f ML |
84 | } |
85 | ||
86 | /* ================================================== */ | |
87 | ||
88840341 RC |
88 | static void |
89 | delete_pidfile(void) | |
90 | { | |
91 | const char *pidfile = CNF_GetPidFile(); | |
778fce40 | 92 | |
60049f15 | 93 | if (!pidfile) |
778fce40 ML |
94 | return; |
95 | ||
e18903a6 ML |
96 | if (!UTI_RemoveFile(NULL, pidfile, NULL)) |
97 | ; | |
88840341 RC |
98 | } |
99 | ||
100 | /* ================================================== */ | |
101 | ||
1e7e7d32 | 102 | void |
88840341 RC |
103 | MAI_CleanupAndExit(void) |
104 | { | |
93b66ac1 | 105 | if (!initialised) exit(exit_status); |
88840341 | 106 | |
3cef7f97 | 107 | LCL_CancelOffsetCorrection(); |
60049f15 | 108 | SRC_DumpSources(); |
88840341 | 109 | |
f6ed7844 ML |
110 | /* Don't update clock when removing sources */ |
111 | REF_SetMode(REF_ModeIgnore); | |
112 | ||
7f45eb79 | 113 | SMT_Finalise(); |
c386d117 | 114 | TMC_Finalise(); |
88840341 | 115 | MNL_Finalise(); |
88840341 | 116 | CLG_Finalise(); |
a420ed57 | 117 | NKS_Finalise(); |
6043632f | 118 | NNS_Finalise(); |
577aed48 | 119 | NSD_Finalise(); |
88840341 | 120 | NSR_Finalise(); |
8854c00d | 121 | SST_Finalise(); |
88840341 | 122 | NCR_Finalise(); |
4e54770f | 123 | NIO_Finalise(); |
8854c00d | 124 | CAM_Finalise(); |
66e097e3 | 125 | |
1c901b82 | 126 | KEY_Finalise(); |
ac30bb06 | 127 | RCL_Finalise(); |
3a222336 | 128 | SRC_Finalise(); |
f6ed7844 | 129 | REF_Finalise(); |
be42b4ee | 130 | RTC_Finalise(); |
88840341 | 131 | SYS_Finalise(); |
66e097e3 ML |
132 | |
133 | SCK_Finalise(); | |
88840341 RC |
134 | SCH_Finalise(); |
135 | LCL_Finalise(); | |
334ac061 | 136 | PRV_Finalise(); |
88840341 RC |
137 | |
138 | delete_pidfile(); | |
139 | ||
f6ed7844 | 140 | CNF_Finalise(); |
f6ed7844 | 141 | HSH_Finalise(); |
b712c100 | 142 | LOG_Finalise(); |
f6ed7844 | 143 | |
93b66ac1 | 144 | exit(exit_status); |
88840341 RC |
145 | } |
146 | ||
147 | /* ================================================== */ | |
148 | ||
149 | static void | |
150 | signal_cleanup(int x) | |
151 | { | |
9416a24f | 152 | SCH_QuitProgram(); |
88840341 RC |
153 | } |
154 | ||
155 | /* ================================================== */ | |
156 | ||
35134848 ML |
157 | static void |
158 | quit_timeout(void *arg) | |
159 | { | |
160 | /* Return with non-zero status if the clock is not synchronised */ | |
161 | exit_status = REF_GetOurStratum() >= NTP_MAX_STRATUM; | |
162 | SCH_QuitProgram(); | |
163 | } | |
164 | ||
165 | /* ================================================== */ | |
166 | ||
88840341 | 167 | static void |
6ee357d2 | 168 | ntp_source_resolving_end(void) |
88840341 | 169 | { |
6ee357d2 | 170 | NSR_SetSourceResolvingEndHandler(NULL); |
88840341 | 171 | |
88840341 RC |
172 | if (reload) { |
173 | /* Note, we want reload to come well after the initialisation from | |
174 | the real time clock - this gives us a fighting chance that the | |
175 | system-clock scale for the reloaded samples still has a | |
176 | semblence of validity about it. */ | |
177 | SRC_ReloadSources(); | |
178 | } | |
88840341 | 179 | |
a06a5f1b | 180 | SRC_RemoveDumpFiles(); |
88840341 | 181 | RTC_StartMeasurements(); |
ac30bb06 | 182 | RCL_StartRefclocks(); |
779e40ed ML |
183 | NSR_StartSources(); |
184 | NSR_AutoStartSources(); | |
70feea48 ML |
185 | |
186 | /* Special modes can end only when sources update their reachability. | |
144fcdde | 187 | Give up immediately if there are no active sources. */ |
7fa22d4c | 188 | if (ref_mode != REF_ModeNormal && !SRC_ActiveSources()) { |
70feea48 ML |
189 | REF_SetUnsynchronised(); |
190 | } | |
88840341 RC |
191 | } |
192 | ||
193 | /* ================================================== */ | |
194 | ||
6ee357d2 ML |
195 | static void |
196 | post_init_ntp_hook(void *anything) | |
197 | { | |
198 | if (ref_mode == REF_ModeInitStepSlew) { | |
199 | /* Remove the initstepslew sources and set normal mode */ | |
200 | NSR_RemoveAllSources(); | |
201 | ref_mode = REF_ModeNormal; | |
202 | REF_SetMode(ref_mode); | |
203 | } | |
204 | ||
205 | /* Close the pipe to the foreground process so it can exit */ | |
206 | LOG_CloseParentFd(); | |
207 | ||
208 | CNF_AddSources(); | |
209 | CNF_AddBroadcasts(); | |
210 | ||
211 | NSR_SetSourceResolvingEndHandler(ntp_source_resolving_end); | |
212 | NSR_ResolveSources(); | |
213 | } | |
214 | ||
215 | /* ================================================== */ | |
216 | ||
7fda9c67 ML |
217 | static void |
218 | reference_mode_end(int result) | |
219 | { | |
220 | switch (ref_mode) { | |
221 | case REF_ModeNormal: | |
70feea48 ML |
222 | case REF_ModeUpdateOnce: |
223 | case REF_ModePrintOnce: | |
93b66ac1 ML |
224 | exit_status = !result; |
225 | SCH_QuitProgram(); | |
7fda9c67 ML |
226 | break; |
227 | case REF_ModeInitStepSlew: | |
ead3ca14 ML |
228 | /* Switch to the normal mode, the delay is used to prevent polling |
229 | interval shorter than the burst interval if some configured servers | |
230 | were used also for initstepslew */ | |
231 | SCH_AddTimeoutByDelay(2.0, post_init_ntp_hook, NULL); | |
7fda9c67 ML |
232 | break; |
233 | default: | |
234 | assert(0); | |
235 | } | |
236 | } | |
237 | ||
238 | /* ================================================== */ | |
239 | ||
88840341 RC |
240 | static void |
241 | post_init_rtc_hook(void *anything) | |
242 | { | |
7fda9c67 ML |
243 | if (CNF_GetInitSources() > 0) { |
244 | CNF_AddInitSources(); | |
779e40ed | 245 | NSR_StartSources(); |
7fda9c67 ML |
246 | assert(REF_GetMode() != REF_ModeNormal); |
247 | /* Wait for mode end notification */ | |
248 | } else { | |
249 | (post_init_ntp_hook)(NULL); | |
250 | } | |
88840341 RC |
251 | } |
252 | ||
253 | /* ================================================== */ | |
88840341 | 254 | |
7bd1c027 ML |
255 | static void |
256 | check_pidfile(void) | |
88840341 RC |
257 | { |
258 | const char *pidfile = CNF_GetPidFile(); | |
259 | FILE *in; | |
260 | int pid, count; | |
261 | ||
60049f15 | 262 | if (!pidfile) |
077dbd56 ML |
263 | return; |
264 | ||
e18903a6 | 265 | in = UTI_OpenFile(NULL, pidfile, NULL, 'r', 0); |
7bd1c027 ML |
266 | if (!in) |
267 | return; | |
88840341 RC |
268 | |
269 | count = fscanf(in, "%d", &pid); | |
270 | fclose(in); | |
271 | ||
7bd1c027 ML |
272 | if (count != 1) |
273 | return; | |
88840341 | 274 | |
7bd1c027 ML |
275 | if (getsid(pid) < 0) |
276 | return; | |
277 | ||
278 | LOG_FATAL("Another chronyd may already be running (pid=%d), check %s", | |
279 | pid, pidfile); | |
88840341 RC |
280 | } |
281 | ||
282 | /* ================================================== */ | |
283 | ||
284 | static void | |
7bd1c027 | 285 | write_pidfile(void) |
88840341 RC |
286 | { |
287 | const char *pidfile = CNF_GetPidFile(); | |
288 | FILE *out; | |
289 | ||
60049f15 | 290 | if (!pidfile) |
778fce40 ML |
291 | return; |
292 | ||
e18903a6 ML |
293 | out = UTI_OpenFile(NULL, pidfile, NULL, 'W', 0644); |
294 | fprintf(out, "%d\n", (int)getpid()); | |
295 | fclose(out); | |
88840341 RC |
296 | } |
297 | ||
298 | /* ================================================== */ | |
299 | ||
da862158 ML |
300 | #define DEV_NULL "/dev/null" |
301 | ||
fe4b661f ML |
302 | static void |
303 | go_daemon(void) | |
304 | { | |
1d2a0856 ML |
305 | int pid, fd, pipefd[2]; |
306 | ||
307 | /* Create pipe which will the daemon use to notify the grandparent | |
308 | when it's initialised or send an error message */ | |
309 | if (pipe(pipefd)) { | |
539ef3f7 | 310 | LOG_FATAL("pipe() failed : %s", strerror(errno)); |
1d2a0856 | 311 | } |
fe4b661f ML |
312 | |
313 | /* Does this preserve existing signal handlers? */ | |
314 | pid = fork(); | |
315 | ||
316 | if (pid < 0) { | |
539ef3f7 | 317 | LOG_FATAL("fork() failed : %s", strerror(errno)); |
fe4b661f | 318 | } else if (pid > 0) { |
1d2a0856 ML |
319 | /* In the 'grandparent' */ |
320 | char message[1024]; | |
321 | int r; | |
322 | ||
323 | close(pipefd[1]); | |
324 | r = read(pipefd[0], message, sizeof (message)); | |
325 | if (r) { | |
326 | if (r > 0) { | |
327 | /* Print the error message from the child */ | |
a7802e9a ML |
328 | message[sizeof (message) - 1] = '\0'; |
329 | fprintf(stderr, "%s\n", message); | |
1d2a0856 ML |
330 | } |
331 | exit(1); | |
332 | } else | |
333 | exit(0); | |
fe4b661f | 334 | } else { |
1d2a0856 | 335 | close(pipefd[0]); |
fe4b661f ML |
336 | |
337 | setsid(); | |
338 | ||
339 | /* Do 2nd fork, as-per recommended practice for launching daemons. */ | |
340 | pid = fork(); | |
341 | ||
342 | if (pid < 0) { | |
539ef3f7 | 343 | LOG_FATAL("fork() failed : %s", strerror(errno)); |
fe4b661f ML |
344 | } else if (pid > 0) { |
345 | exit(0); /* In the 'parent' */ | |
346 | } else { | |
347 | /* In the child we want to leave running as the daemon */ | |
348 | ||
2a305d8e ML |
349 | /* Change current directory to / */ |
350 | if (chdir("/") < 0) { | |
539ef3f7 | 351 | LOG_FATAL("chdir() failed : %s", strerror(errno)); |
2a305d8e ML |
352 | } |
353 | ||
1d2a0856 ML |
354 | /* Don't keep stdin/out/err from before. But don't close |
355 | the parent pipe yet. */ | |
fe4b661f | 356 | for (fd=0; fd<1024; fd++) { |
1d2a0856 ML |
357 | if (fd != pipefd[1]) |
358 | close(fd); | |
fe4b661f | 359 | } |
919b5b5a | 360 | |
1d2a0856 | 361 | LOG_SetParentFd(pipefd[1]); |
da862158 ML |
362 | |
363 | /* Open /dev/null as new stdin/out/err */ | |
364 | errno = 0; | |
365 | if (open(DEV_NULL, O_RDONLY) != STDIN_FILENO || | |
366 | open(DEV_NULL, O_WRONLY) != STDOUT_FILENO || | |
367 | open(DEV_NULL, O_RDWR) != STDERR_FILENO) | |
368 | LOG_FATAL("Could not open %s : %s", DEV_NULL, strerror(errno)); | |
fe4b661f ML |
369 | } |
370 | } | |
fe4b661f ML |
371 | } |
372 | ||
373 | /* ================================================== */ | |
374 | ||
ae0c3bbb ML |
375 | static void |
376 | print_help(const char *progname) | |
377 | { | |
0e08ca7c ML |
378 | printf("Usage: %s [OPTION]... [DIRECTIVE]...\n\n" |
379 | "Options:\n" | |
380 | " -4\t\tUse IPv4 addresses only\n" | |
381 | " -6\t\tUse IPv6 addresses only\n" | |
382 | " -f FILE\tSpecify configuration file (%s)\n" | |
383 | " -n\t\tDon't run as daemon\n" | |
384 | " -d\t\tDon't run as daemon and log to stderr\n" | |
385 | #if DEBUG > 0 | |
386 | " -d -d\t\tEnable debug messages\n" | |
387 | #endif | |
388 | " -l FILE\tLog to file\n" | |
389 | " -L LEVEL\tSet logging threshold (0)\n" | |
390 | " -p\t\tPrint configuration and exit\n" | |
391 | " -q\t\tSet clock and exit\n" | |
392 | " -Q\t\tLog offset and exit\n" | |
393 | " -r\t\tReload dump files\n" | |
394 | " -R\t\tAdapt configuration for restart\n" | |
395 | " -s\t\tSet clock from RTC\n" | |
396 | " -t SECONDS\tExit after elapsed time\n" | |
397 | " -u USER\tSpecify user (%s)\n" | |
398 | " -U\t\tDon't check for root\n" | |
399 | " -F LEVEL\tSet system call filter level (0)\n" | |
400 | " -P PRIORITY\tSet process priority (0)\n" | |
401 | " -m\t\tLock memory\n" | |
402 | " -x\t\tDon't control clock\n" | |
403 | " -v, --version\tPrint version and exit\n" | |
404 | " -h, --help\tPrint usage and exit\n", | |
405 | progname, DEFAULT_CONF_FILE, DEFAULT_USER); | |
ae0c3bbb ML |
406 | } |
407 | ||
408 | /* ================================================== */ | |
409 | ||
410 | static void | |
411 | print_version(void) | |
412 | { | |
413 | printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES); | |
414 | } | |
415 | ||
416 | /* ================================================== */ | |
417 | ||
418 | static int | |
419 | parse_int_arg(const char *arg) | |
420 | { | |
421 | int i; | |
422 | ||
423 | if (sscanf(arg, "%d", &i) != 1) | |
424 | LOG_FATAL("Invalid argument %s", arg); | |
425 | return i; | |
426 | } | |
427 | ||
428 | /* ================================================== */ | |
429 | ||
88840341 RC |
430 | int main |
431 | (int argc, char **argv) | |
432 | { | |
0f8def4c | 433 | const char *conf_file = DEFAULT_CONF_FILE; |
1cda2db4 | 434 | const char *progname = argv[0]; |
a1cbd4eb | 435 | char *user = NULL, *log_file = NULL; |
6402350c | 436 | struct passwd *pw; |
ae0c3bbb | 437 | int opt, debug = 0, nofork = 0, address_family = IPADDR_UNSPEC; |
552d3b53 | 438 | int do_init_rtc = 0, restarted = 0, client_only = 0, timeout = -1; |
434faeec | 439 | int scfilter_level = 0, lock_memory = 0, sched_priority = 0; |
70fa3a69 | 440 | int clock_control = 1, system_log = 1, log_severity = LOGS_INFO; |
02c38934 | 441 | int user_check = 1, config_args = 0, print_config = 0; |
35e662d8 | 442 | |
bafb434f ML |
443 | do_platform_checks(); |
444 | ||
88840341 RC |
445 | LOG_Initialise(); |
446 | ||
068cd3c3 | 447 | /* Parse long command-line options */ |
ae0c3bbb ML |
448 | for (optind = 1; optind < argc; optind++) { |
449 | if (!strcmp("--help", argv[optind])) { | |
450 | print_help(progname); | |
1769b8ea | 451 | return 0; |
ae0c3bbb ML |
452 | } else if (!strcmp("--version", argv[optind])) { |
453 | print_version(); | |
1769b8ea | 454 | return 0; |
ae0c3bbb ML |
455 | } |
456 | } | |
457 | ||
458 | optind = 1; | |
459 | ||
460 | /* Parse short command-line options */ | |
02c38934 | 461 | while ((opt = getopt(argc, argv, "46df:F:hl:L:mnpP:qQrRst:u:Uvx")) != -1) { |
ae0c3bbb ML |
462 | switch (opt) { |
463 | case '4': | |
464 | case '6': | |
465 | address_family = opt == '4' ? IPADDR_INET4 : IPADDR_INET6; | |
466 | break; | |
467 | case 'd': | |
468 | debug++; | |
469 | nofork = 1; | |
470 | system_log = 0; | |
471 | break; | |
472 | case 'f': | |
473 | conf_file = optarg; | |
474 | break; | |
475 | case 'F': | |
476 | scfilter_level = parse_int_arg(optarg); | |
477 | break; | |
478 | case 'l': | |
479 | log_file = optarg; | |
480 | break; | |
70fa3a69 ML |
481 | case 'L': |
482 | log_severity = parse_int_arg(optarg); | |
483 | break; | |
ae0c3bbb ML |
484 | case 'm': |
485 | lock_memory = 1; | |
486 | break; | |
487 | case 'n': | |
488 | nofork = 1; | |
489 | break; | |
1b82604f ML |
490 | case 'p': |
491 | print_config = 1; | |
02c38934 | 492 | user_check = 0; |
1b82604f ML |
493 | nofork = 1; |
494 | system_log = 0; | |
517b1ae2 | 495 | log_severity = LOGS_WARN; |
1b82604f | 496 | break; |
ae0c3bbb ML |
497 | case 'P': |
498 | sched_priority = parse_int_arg(optarg); | |
499 | break; | |
500 | case 'q': | |
4f1fc1ee BC |
501 | ref_mode = REF_ModeUpdateOnce; |
502 | nofork = 1; | |
503 | client_only = 0; | |
504 | system_log = 0; | |
505 | break; | |
ae0c3bbb | 506 | case 'Q': |
4f1fc1ee | 507 | ref_mode = REF_ModePrintOnce; |
ae0c3bbb | 508 | nofork = 1; |
778fce40 | 509 | client_only = 1; |
02c38934 | 510 | user_check = 0; |
778fce40 | 511 | clock_control = 0; |
ae0c3bbb ML |
512 | system_log = 0; |
513 | break; | |
514 | case 'r': | |
515 | reload = 1; | |
516 | break; | |
517 | case 'R': | |
518 | restarted = 1; | |
519 | break; | |
520 | case 's': | |
521 | do_init_rtc = 1; | |
522 | break; | |
523 | case 't': | |
524 | timeout = parse_int_arg(optarg); | |
525 | break; | |
526 | case 'u': | |
527 | user = optarg; | |
528 | break; | |
02c38934 ML |
529 | case 'U': |
530 | user_check = 0; | |
531 | break; | |
ae0c3bbb ML |
532 | case 'v': |
533 | print_version(); | |
534 | return 0; | |
535 | case 'x': | |
536 | clock_control = 0; | |
537 | break; | |
538 | default: | |
539 | print_help(progname); | |
540 | return opt != 'h'; | |
88840341 RC |
541 | } |
542 | } | |
543 | ||
02c38934 | 544 | if (user_check && getuid() != 0) |
3a5566c6 | 545 | LOG_FATAL("Not superuser"); |
88840341 | 546 | |
88840341 | 547 | /* Turn into a daemon */ |
fe4b661f ML |
548 | if (!nofork) { |
549 | go_daemon(); | |
550 | } | |
551 | ||
a1cbd4eb ML |
552 | if (log_file) { |
553 | LOG_OpenFileLog(log_file); | |
554 | } else if (system_log) { | |
fe4b661f | 555 | LOG_OpenSystemLog(); |
88840341 RC |
556 | } |
557 | ||
70fa3a69 | 558 | LOG_SetMinSeverity(debug >= 2 ? LOGS_DEBUG : log_severity); |
4bbc5520 | 559 | |
f282856c | 560 | LOG(LOGS_INFO, "chronyd version %s starting (%s)", CHRONY_VERSION, CHRONYD_FEATURES); |
cb905507 | 561 | |
72d0b3c9 ML |
562 | DNS_SetAddressFamily(address_family); |
563 | ||
778fce40 | 564 | CNF_Initialise(restarted, client_only); |
1b82604f ML |
565 | if (print_config) |
566 | CNF_EnablePrint(); | |
3edd3fe5 ML |
567 | |
568 | /* Parse the config file or the remaining command line arguments */ | |
ae0c3bbb | 569 | config_args = argc - optind; |
3edd3fe5 ML |
570 | if (!config_args) { |
571 | CNF_ReadFile(conf_file); | |
572 | } else { | |
ae0c3bbb ML |
573 | for (; optind < argc; optind++) |
574 | CNF_ParseLine(NULL, config_args + optind - argc + 1, argv[optind]); | |
3edd3fe5 | 575 | } |
1e35b268 | 576 | |
1b82604f ML |
577 | if (print_config) |
578 | return 0; | |
579 | ||
7bd1c027 ML |
580 | /* Check whether another chronyd may already be running */ |
581 | check_pidfile(); | |
88840341 | 582 | |
c5d8af02 ML |
583 | if (!user) |
584 | user = CNF_GetUser(); | |
585 | ||
586 | pw = getpwnam(user); | |
587 | if (!pw) | |
588 | LOG_FATAL("Could not get user/group ID of %s", user); | |
589 | ||
590 | /* Create directories for sockets, log files, and dump files */ | |
591 | CNF_CreateDirs(pw->pw_uid, pw->pw_gid); | |
592 | ||
26e08abe ML |
593 | /* Write our pidfile to prevent other instances from running */ |
594 | write_pidfile(); | |
595 | ||
334ac061 | 596 | PRV_Initialise(); |
88840341 RC |
597 | LCL_Initialise(); |
598 | SCH_Initialise(); | |
66e097e3 ML |
599 | SCK_Initialise(address_family); |
600 | ||
601 | /* Start helper processes if needed */ | |
602 | NKS_PreInitialise(pw->pw_uid, pw->pw_gid, scfilter_level); | |
603 | ||
c4434609 | 604 | SYS_Initialise(clock_control); |
c6e06420 | 605 | RTC_Initialise(do_init_rtc); |
3a222336 | 606 | SRC_Initialise(); |
ac30bb06 | 607 | RCL_Initialise(); |
1c901b82 | 608 | KEY_Initialise(); |
be42b4ee | 609 | |
8854c00d | 610 | /* Open privileged ports before dropping root */ |
27e20a56 ML |
611 | CAM_Initialise(); |
612 | NIO_Initialise(); | |
8854c00d ML |
613 | NCR_Initialise(); |
614 | CNF_SetupAccessRestrictions(); | |
615 | ||
e3234465 ML |
616 | /* Command-line switch must have priority */ |
617 | if (!sched_priority) { | |
618 | sched_priority = CNF_GetSchedPriority(); | |
619 | } | |
620 | if (sched_priority) { | |
621 | SYS_SetScheduler(sched_priority); | |
96759116 ML |
622 | } |
623 | ||
e3234465 ML |
624 | if (lock_memory || CNF_GetLockMemory()) { |
625 | SYS_LockMemory(); | |
96759116 ML |
626 | } |
627 | ||
778fce40 ML |
628 | /* Drop root privileges if the specified user has a non-zero UID */ |
629 | if (!geteuid() && (pw->pw_uid || pw->pw_gid)) | |
a96d2880 | 630 | SYS_DropRoot(pw->pw_uid, pw->pw_gid, SYS_MAIN_PROCESS); |
be42b4ee | 631 | |
4f878ba1 ML |
632 | if (!geteuid()) |
633 | LOG(LOGS_WARN, "Running with root privileges"); | |
634 | ||
88840341 RC |
635 | REF_Initialise(); |
636 | SST_Initialise(); | |
88840341 | 637 | NSR_Initialise(); |
577aed48 | 638 | NSD_Initialise(); |
6043632f | 639 | NNS_Initialise(); |
66e097e3 | 640 | NKS_Initialise(); |
88840341 | 641 | CLG_Initialise(); |
88840341 | 642 | MNL_Initialise(); |
c386d117 | 643 | TMC_Initialise(); |
7f45eb79 | 644 | SMT_Initialise(); |
88840341 RC |
645 | |
646 | /* From now on, it is safe to do finalisation on exit */ | |
647 | initialised = 1; | |
648 | ||
879d9362 | 649 | UTI_SetQuitSignalsHandler(signal_cleanup, 1); |
ea2858b3 | 650 | |
8854c00d | 651 | CAM_OpenUnixSocket(); |
46951b85 | 652 | |
434faeec | 653 | if (scfilter_level) |
e6848b1e | 654 | SYS_EnableSystemCallFilter(scfilter_level, SYS_MAIN_PROCESS); |
434faeec | 655 | |
70feea48 | 656 | if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) { |
7fda9c67 ML |
657 | ref_mode = REF_ModeInitStepSlew; |
658 | } | |
659 | ||
660 | REF_SetModeEndHandler(reference_mode_end); | |
661 | REF_SetMode(ref_mode); | |
662 | ||
552d3b53 | 663 | if (timeout >= 0) |
35134848 ML |
664 | SCH_AddTimeoutByDelay(timeout, quit_timeout, NULL); |
665 | ||
88840341 RC |
666 | if (do_init_rtc) { |
667 | RTC_TimeInit(post_init_rtc_hook, NULL); | |
668 | } else { | |
669 | post_init_rtc_hook(NULL); | |
670 | } | |
671 | ||
88840341 RC |
672 | /* The program normally runs under control of the main loop in |
673 | the scheduler. */ | |
674 | SCH_MainLoop(); | |
675 | ||
f282856c | 676 | LOG(LOGS_INFO, "chronyd exiting"); |
0fc9b555 | 677 | |
88840341 RC |
678 | MAI_CleanupAndExit(); |
679 | ||
680 | return 0; | |
681 | } | |
682 | ||
683 | /* ================================================== */ |