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