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