]> git.ipfire.org Git - thirdparty/chrony.git/blame - main.c
sys_macosx: fix adjustment correction after step
[thirdparty/chrony.git] / main.c
CommitLineData
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
33967780 7 * Copyright (C) Miroslav Lichvar 2012-2015
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"
38#include "ntp_sources.h"
39#include "ntp_core.h"
40#include "sources.h"
41#include "sourcestats.h"
42#include "reference.h"
43#include "logging.h"
44#include "conf.h"
45#include "cmdmon.h"
46#include "keys.h"
88840341 47#include "manual.h"
88840341 48#include "rtc.h"
ac30bb06 49#include "refclock.h"
88840341 50#include "clientlog.h"
fbd20c42 51#include "nameserv.h"
610f2340 52#include "privops.h"
7f45eb79 53#include "smooth.h"
c386d117 54#include "tempcomp.h"
ceef8ad2 55#include "util.h"
88840341
RC
56
57/* ================================================== */
58
59/* Set when the initialisation chain has been completed. Prevents finalisation
60 * chain being run if a fatal error happened early. */
61
62static int initialised = 0;
63
93b66ac1 64static int exit_status = 0;
88840341
RC
65
66static int reload = 0;
67
e176587e 68static REF_Mode ref_mode = REF_ModeNormal;
7fda9c67 69
88840341
RC
70/* ================================================== */
71
bafb434f
ML
72static void
73do_platform_checks(void)
74{
75 /* Require at least 32-bit integers, two's complement representation and
76 the usual implementation of conversion of unsigned integers */
77 assert(sizeof (int) >= 4);
78 assert(-1 == ~0);
fe502128 79 assert((int32_t)4294967295U == (int32_t)-1);
bafb434f
ML
80}
81
82/* ================================================== */
83
88840341
RC
84static void
85delete_pidfile(void)
86{
87 const char *pidfile = CNF_GetPidFile();
88 /* Don't care if this fails, there's not a lot we can do */
89 unlink(pidfile);
90}
91
92/* ================================================== */
93
1e7e7d32 94void
88840341
RC
95MAI_CleanupAndExit(void)
96{
93b66ac1 97 if (!initialised) exit(exit_status);
88840341
RC
98
99 if (CNF_GetDumpOnExit()) {
100 SRC_DumpSources();
101 }
102
f6ed7844
ML
103 /* Don't update clock when removing sources */
104 REF_SetMode(REF_ModeIgnore);
105
7f45eb79 106 SMT_Finalise();
c386d117 107 TMC_Finalise();
88840341 108 MNL_Finalise();
88840341 109 CLG_Finalise();
88840341 110 NSR_Finalise();
8854c00d 111 SST_Finalise();
88840341 112 NCR_Finalise();
4e54770f 113 NIO_Finalise();
8854c00d 114 CAM_Finalise();
610f2340 115 PRV_Finalise();
1c901b82 116 KEY_Finalise();
ac30bb06 117 RCL_Finalise();
3a222336 118 SRC_Finalise();
f6ed7844 119 REF_Finalise();
be42b4ee 120 RTC_Finalise();
88840341
RC
121 SYS_Finalise();
122 SCH_Finalise();
123 LCL_Finalise();
124
125 delete_pidfile();
126
f6ed7844 127 CNF_Finalise();
88840341
RC
128 LOG_Finalise();
129
f6ed7844
ML
130 HSH_Finalise();
131
93b66ac1 132 exit(exit_status);
88840341
RC
133}
134
135/* ================================================== */
136
137static void
138signal_cleanup(int x)
139{
9416a24f
ML
140 if (!initialised) exit(0);
141 SCH_QuitProgram();
88840341
RC
142}
143
144/* ================================================== */
145
146static void
6ee357d2 147ntp_source_resolving_end(void)
88840341 148{
6ee357d2 149 NSR_SetSourceResolvingEndHandler(NULL);
88840341 150
88840341
RC
151 if (reload) {
152 /* Note, we want reload to come well after the initialisation from
153 the real time clock - this gives us a fighting chance that the
154 system-clock scale for the reloaded samples still has a
155 semblence of validity about it. */
156 SRC_ReloadSources();
157 }
88840341
RC
158
159 RTC_StartMeasurements();
ac30bb06 160 RCL_StartRefclocks();
779e40ed
ML
161 NSR_StartSources();
162 NSR_AutoStartSources();
70feea48
ML
163
164 /* Special modes can end only when sources update their reachability.
7fa22d4c
ML
165 Give up immediatelly if there are no active sources. */
166 if (ref_mode != REF_ModeNormal && !SRC_ActiveSources()) {
70feea48
ML
167 REF_SetUnsynchronised();
168 }
88840341
RC
169}
170
171/* ================================================== */
172
6ee357d2
ML
173static void
174post_init_ntp_hook(void *anything)
175{
176 if (ref_mode == REF_ModeInitStepSlew) {
177 /* Remove the initstepslew sources and set normal mode */
178 NSR_RemoveAllSources();
179 ref_mode = REF_ModeNormal;
180 REF_SetMode(ref_mode);
181 }
182
183 /* Close the pipe to the foreground process so it can exit */
184 LOG_CloseParentFd();
185
186 CNF_AddSources();
187 CNF_AddBroadcasts();
188
189 NSR_SetSourceResolvingEndHandler(ntp_source_resolving_end);
190 NSR_ResolveSources();
191}
192
193/* ================================================== */
194
7fda9c67
ML
195static void
196reference_mode_end(int result)
197{
198 switch (ref_mode) {
199 case REF_ModeNormal:
70feea48
ML
200 case REF_ModeUpdateOnce:
201 case REF_ModePrintOnce:
93b66ac1
ML
202 exit_status = !result;
203 SCH_QuitProgram();
7fda9c67
ML
204 break;
205 case REF_ModeInitStepSlew:
ead3ca14
ML
206 /* Switch to the normal mode, the delay is used to prevent polling
207 interval shorter than the burst interval if some configured servers
208 were used also for initstepslew */
209 SCH_AddTimeoutByDelay(2.0, post_init_ntp_hook, NULL);
7fda9c67
ML
210 break;
211 default:
212 assert(0);
213 }
214}
215
216/* ================================================== */
217
88840341
RC
218static void
219post_init_rtc_hook(void *anything)
220{
7fda9c67
ML
221 if (CNF_GetInitSources() > 0) {
222 CNF_AddInitSources();
779e40ed 223 NSR_StartSources();
7fda9c67
ML
224 assert(REF_GetMode() != REF_ModeNormal);
225 /* Wait for mode end notification */
226 } else {
227 (post_init_ntp_hook)(NULL);
228 }
88840341
RC
229}
230
231/* ================================================== */
232/* Return 1 if the process exists on the system. */
233
234static int
235does_process_exist(int pid)
236{
237 int status;
238 status = getsid(pid);
239 if (status >= 0) {
240 return 1;
241 } else {
242 return 0;
243 }
244}
245
246/* ================================================== */
247
248static int
249maybe_another_chronyd_running(int *other_pid)
250{
251 const char *pidfile = CNF_GetPidFile();
252 FILE *in;
253 int pid, count;
254
255 *other_pid = 0;
256
257 in = fopen(pidfile, "r");
258 if (!in) return 0;
259
260 count = fscanf(in, "%d", &pid);
261 fclose(in);
262
263 if (count != 1) return 0;
264
265 *other_pid = pid;
266 return does_process_exist(pid);
267
268}
269
270/* ================================================== */
271
272static void
273write_lockfile(void)
274{
275 const char *pidfile = CNF_GetPidFile();
276 FILE *out;
277
278 out = fopen(pidfile, "w");
279 if (!out) {
fe35de69 280 LOG_FATAL(LOGF_Main, "could not open lockfile %s for writing", pidfile);
88840341 281 } else {
f444561a 282 fprintf(out, "%d\n", (int)getpid());
88840341
RC
283 fclose(out);
284 }
285}
286
287/* ================================================== */
288
fe4b661f
ML
289static void
290go_daemon(void)
291{
1d2a0856
ML
292 int pid, fd, pipefd[2];
293
294 /* Create pipe which will the daemon use to notify the grandparent
295 when it's initialised or send an error message */
296 if (pipe(pipefd)) {
fe35de69 297 LOG_FATAL(LOGF_Logging, "Could not detach, pipe failed : %s", strerror(errno));
1d2a0856 298 }
fe4b661f
ML
299
300 /* Does this preserve existing signal handlers? */
301 pid = fork();
302
303 if (pid < 0) {
fe35de69 304 LOG_FATAL(LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
fe4b661f 305 } else if (pid > 0) {
1d2a0856
ML
306 /* In the 'grandparent' */
307 char message[1024];
308 int r;
309
310 close(pipefd[1]);
311 r = read(pipefd[0], message, sizeof (message));
312 if (r) {
313 if (r > 0) {
314 /* Print the error message from the child */
315 fprintf(stderr, "%.1024s\n", message);
316 }
317 exit(1);
318 } else
319 exit(0);
fe4b661f 320 } else {
1d2a0856 321 close(pipefd[0]);
fe4b661f
ML
322
323 setsid();
324
325 /* Do 2nd fork, as-per recommended practice for launching daemons. */
326 pid = fork();
327
328 if (pid < 0) {
fe35de69 329 LOG_FATAL(LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
fe4b661f
ML
330 } else if (pid > 0) {
331 exit(0); /* In the 'parent' */
332 } else {
333 /* In the child we want to leave running as the daemon */
334
2a305d8e
ML
335 /* Change current directory to / */
336 if (chdir("/") < 0) {
fe35de69 337 LOG_FATAL(LOGF_Logging, "Could not chdir to / : %s", strerror(errno));
2a305d8e
ML
338 }
339
1d2a0856
ML
340 /* Don't keep stdin/out/err from before. But don't close
341 the parent pipe yet. */
fe4b661f 342 for (fd=0; fd<1024; fd++) {
1d2a0856
ML
343 if (fd != pipefd[1])
344 close(fd);
fe4b661f 345 }
919b5b5a 346
1d2a0856 347 LOG_SetParentFd(pipefd[1]);
fe4b661f
ML
348 }
349 }
fe4b661f
ML
350}
351
352/* ================================================== */
353
88840341
RC
354int main
355(int argc, char **argv)
356{
0f8def4c 357 const char *conf_file = DEFAULT_CONF_FILE;
1cda2db4 358 const char *progname = argv[0];
be42b4ee 359 char *user = NULL;
6402350c 360 struct passwd *pw;
72d0b3c9 361 int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
f2eb6b16 362 int do_init_rtc = 0, restarted = 0;
88840341 363 int other_pid;
434faeec 364 int scfilter_level = 0, lock_memory = 0, sched_priority = 0;
788e7fcd 365 int system_log = 1;
3edd3fe5 366 int config_args = 0;
35e662d8 367
bafb434f
ML
368 do_platform_checks();
369
88840341
RC
370 LOG_Initialise();
371
372 /* Parse command line options */
373 while (++argv, (--argc)>0) {
374
375 if (!strcmp("-f", *argv)) {
376 ++argv, --argc;
377 conf_file = *argv;
35e662d8
JH
378 } else if (!strcmp("-P", *argv)) {
379 ++argv, --argc;
e3234465
ML
380 if (argc == 0 || sscanf(*argv, "%d", &sched_priority) != 1) {
381 LOG_FATAL(LOGF_Main, "Bad scheduler priority");
35e662d8 382 }
35e662d8 383 } else if (!strcmp("-m", *argv)) {
e3234465 384 lock_memory = 1;
88840341
RC
385 } else if (!strcmp("-r", *argv)) {
386 reload = 1;
f2eb6b16
ML
387 } else if (!strcmp("-R", *argv)) {
388 restarted = 1;
be42b4ee
ML
389 } else if (!strcmp("-u", *argv)) {
390 ++argv, --argc;
e3234465
ML
391 if (argc == 0) {
392 LOG_FATAL(LOGF_Main, "Missing user name");
393 } else {
394 user = *argv;
395 }
434faeec
ML
396 } else if (!strcmp("-F", *argv)) {
397 ++argv, --argc;
398 if (argc == 0 || sscanf(*argv, "%d", &scfilter_level) != 1)
399 LOG_FATAL(LOGF_Main, "Bad syscall filter level");
88840341
RC
400 } else if (!strcmp("-s", *argv)) {
401 do_init_rtc = 1;
402 } else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
403 /* This write to the terminal is OK, it comes before we turn into a daemon */
f2710d5b 404 printf("chronyd (chrony) version %s (%s)\n", CHRONY_VERSION, CHRONYD_FEATURES);
1769b8ea 405 return 0;
fe4b661f
ML
406 } else if (!strcmp("-n", *argv)) {
407 nofork = 1;
88840341 408 } else if (!strcmp("-d", *argv)) {
4bbc5520 409 debug++;
fe4b661f 410 nofork = 1;
788e7fcd 411 system_log = 0;
70feea48
ML
412 } else if (!strcmp("-q", *argv)) {
413 ref_mode = REF_ModeUpdateOnce;
414 nofork = 1;
415 system_log = 0;
416 } else if (!strcmp("-Q", *argv)) {
417 ref_mode = REF_ModePrintOnce;
418 nofork = 1;
419 system_log = 0;
fbd20c42 420 } else if (!strcmp("-4", *argv)) {
72d0b3c9 421 address_family = IPADDR_INET4;
fbd20c42 422 } else if (!strcmp("-6", *argv)) {
72d0b3c9 423 address_family = IPADDR_INET6;
1cda2db4
ML
424 } else if (!strcmp("-h", *argv) || !strcmp("--help", *argv)) {
425 printf("Usage: %s [-4|-6] [-n|-d] [-q|-Q] [-r] [-R] [-s] [-f FILE|COMMAND...]\n",
426 progname);
1769b8ea 427 return 0;
3edd3fe5 428 } else if (*argv[0] == '-') {
dbb550e6 429 LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
3edd3fe5
ML
430 } else {
431 /* Process remaining arguments and configuration lines */
432 config_args = argc;
433 break;
88840341
RC
434 }
435 }
436
88840341
RC
437 if (getuid() != 0) {
438 /* This write to the terminal is OK, it comes before we turn into a daemon */
439 fprintf(stderr,"Not superuser\n");
1769b8ea 440 return 1;
88840341
RC
441 }
442
88840341 443 /* Turn into a daemon */
fe4b661f
ML
444 if (!nofork) {
445 go_daemon();
446 }
447
788e7fcd 448 if (system_log) {
fe4b661f 449 LOG_OpenSystemLog();
88840341
RC
450 }
451
788e7fcd 452 LOG_SetDebugLevel(debug);
4bbc5520 453
f2710d5b
ML
454 LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting (%s)",
455 CHRONY_VERSION, CHRONYD_FEATURES);
cb905507 456
72d0b3c9
ML
457 DNS_SetAddressFamily(address_family);
458
f6ed7844 459 CNF_Initialise(restarted);
3edd3fe5
ML
460
461 /* Parse the config file or the remaining command line arguments */
462 if (!config_args) {
463 CNF_ReadFile(conf_file);
464 } else {
465 do {
466 CNF_ParseLine(NULL, config_args - argc + 1, *argv);
467 } while (++argv, --argc);
468 }
1e35b268 469
88840341
RC
470 /* Check whether another chronyd may already be running. Do this after
471 * forking, so that message logging goes to the right place (i.e. syslog), in
472 * case this chronyd is being run from a boot script. */
473 if (maybe_another_chronyd_running(&other_pid)) {
474 LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
475 other_pid, CNF_GetPidFile());
88840341
RC
476 }
477
478 /* Write our lockfile to prevent other chronyds running. This has *GOT* to
479 * be done *AFTER* the daemon-creation fork() */
480 write_lockfile();
88840341 481
88840341
RC
482 LCL_Initialise();
483 SCH_Initialise();
484 SYS_Initialise();
c6e06420 485 RTC_Initialise(do_init_rtc);
3a222336 486 SRC_Initialise();
ac30bb06 487 RCL_Initialise();
1c901b82 488 KEY_Initialise();
610f2340 489 PRV_Initialise();
be42b4ee 490
8854c00d
ML
491 /* Open privileged ports before dropping root */
492 CAM_Initialise(address_family);
493 NIO_Initialise(address_family);
494 NCR_Initialise();
495 CNF_SetupAccessRestrictions();
496
e3234465
ML
497 /* Command-line switch must have priority */
498 if (!sched_priority) {
499 sched_priority = CNF_GetSchedPriority();
500 }
501 if (sched_priority) {
502 SYS_SetScheduler(sched_priority);
96759116
ML
503 }
504
e3234465
ML
505 if (lock_memory || CNF_GetLockMemory()) {
506 SYS_LockMemory();
96759116
ML
507 }
508
edda0c60
ML
509 if (!user) {
510 user = CNF_GetUser();
511 }
6402350c 512
e7100e10
ML
513 if ((pw = getpwnam(user)) == NULL)
514 LOG_FATAL(LOGF_Main, "Could not get %s uid/gid", user);
6402350c 515
6d42dd86
ML
516 /* Create all directories before dropping root */
517 CNF_CreateDirs(pw->pw_uid, pw->pw_gid);
518
e7100e10
ML
519 /* Drop root privileges if the user has non-zero uid or gid */
520 if (pw->pw_uid || pw->pw_gid)
6402350c 521 SYS_DropRoot(pw->pw_uid, pw->pw_gid);
be42b4ee 522
88840341
RC
523 REF_Initialise();
524 SST_Initialise();
88840341 525 NSR_Initialise();
88840341 526 CLG_Initialise();
88840341 527 MNL_Initialise();
c386d117 528 TMC_Initialise();
7f45eb79 529 SMT_Initialise();
88840341
RC
530
531 /* From now on, it is safe to do finalisation on exit */
532 initialised = 1;
533
ea2858b3
ML
534 UTI_SetQuitSignalsHandler(signal_cleanup);
535
8854c00d 536 CAM_OpenUnixSocket();
46951b85 537
434faeec
ML
538 if (scfilter_level)
539 SYS_EnableSystemCallFilter(scfilter_level);
540
70feea48 541 if (ref_mode == REF_ModeNormal && CNF_GetInitSources() > 0) {
7fda9c67
ML
542 ref_mode = REF_ModeInitStepSlew;
543 }
544
545 REF_SetModeEndHandler(reference_mode_end);
546 REF_SetMode(ref_mode);
547
88840341
RC
548 if (do_init_rtc) {
549 RTC_TimeInit(post_init_rtc_hook, NULL);
550 } else {
551 post_init_rtc_hook(NULL);
552 }
553
88840341
RC
554 /* The program normally runs under control of the main loop in
555 the scheduler. */
556 SCH_MainLoop();
557
0fc9b555
ML
558 LOG(LOGS_INFO, LOGF_Main, "chronyd exiting");
559
88840341
RC
560 MAI_CleanupAndExit();
561
562 return 0;
563}
564
565/* ================================================== */