]> git.ipfire.org Git - thirdparty/chrony.git/blame - main.c
Fix log messages
[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
0c738d84 7 * Copyright (C) Miroslav Lichvar 2012
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"
47#include "acquire.h"
48#include "manual.h"
88840341 49#include "rtc.h"
ac30bb06 50#include "refclock.h"
88840341
RC
51#include "clientlog.h"
52#include "broadcast.h"
fbd20c42 53#include "nameserv.h"
c386d117 54#include "tempcomp.h"
88840341
RC
55
56/* ================================================== */
57
58/* Set when the initialisation chain has been completed. Prevents finalisation
59 * chain being run if a fatal error happened early. */
60
61static int initialised = 0;
62
63/* ================================================== */
64
65static int reload = 0;
66
67/* ================================================== */
68
69static void
70delete_pidfile(void)
71{
72 const char *pidfile = CNF_GetPidFile();
73 /* Don't care if this fails, there's not a lot we can do */
74 unlink(pidfile);
75}
76
77/* ================================================== */
78
1e7e7d32 79void
88840341
RC
80MAI_CleanupAndExit(void)
81{
82 if (!initialised) exit(0);
83
84 if (CNF_GetDumpOnExit()) {
85 SRC_DumpSources();
86 }
87
c386d117 88 TMC_Finalise();
88840341
RC
89 MNL_Finalise();
90 ACQ_Finalise();
88840341 91 CLG_Finalise();
88840341
RC
92 NSR_Finalise();
93 NCR_Finalise();
94 BRD_Finalise();
88840341
RC
95 SST_Finalise();
96 REF_Finalise();
1c901b82 97 KEY_Finalise();
ac30bb06 98 RCL_Finalise();
3a222336 99 SRC_Finalise();
be42b4ee
ML
100 RTC_Finalise();
101 CAM_Finalise();
102 NIO_Finalise();
88840341
RC
103 SYS_Finalise();
104 SCH_Finalise();
105 LCL_Finalise();
106
107 delete_pidfile();
108
109 LOG_Finalise();
110
111 exit(0);
112}
113
114/* ================================================== */
115
116static void
117signal_cleanup(int x)
118{
9416a24f
ML
119 if (!initialised) exit(0);
120 SCH_QuitProgram();
88840341
RC
121}
122
123/* ================================================== */
124
125static void
126post_acquire_hook(void *anything)
127{
1d2a0856
ML
128 /* Close the pipe to the foreground process so it can exit */
129 LOG_CloseParentFd();
88840341
RC
130
131 CNF_AddSources();
132 CNF_AddBroadcasts();
133 if (reload) {
134 /* Note, we want reload to come well after the initialisation from
135 the real time clock - this gives us a fighting chance that the
136 system-clock scale for the reloaded samples still has a
137 semblence of validity about it. */
138 SRC_ReloadSources();
139 }
140 CNF_SetupAccessRestrictions();
141
142 RTC_StartMeasurements();
ac30bb06 143 RCL_StartRefclocks();
88840341
RC
144}
145
146/* ================================================== */
147
148static void
149post_init_rtc_hook(void *anything)
150{
151 CNF_ProcessInitStepSlew(post_acquire_hook, NULL);
152}
153
154/* ================================================== */
155/* Return 1 if the process exists on the system. */
156
157static int
158does_process_exist(int pid)
159{
160 int status;
161 status = getsid(pid);
162 if (status >= 0) {
163 return 1;
164 } else {
165 return 0;
166 }
167}
168
169/* ================================================== */
170
171static int
172maybe_another_chronyd_running(int *other_pid)
173{
174 const char *pidfile = CNF_GetPidFile();
175 FILE *in;
176 int pid, count;
177
178 *other_pid = 0;
179
180 in = fopen(pidfile, "r");
181 if (!in) return 0;
182
183 count = fscanf(in, "%d", &pid);
184 fclose(in);
185
186 if (count != 1) return 0;
187
188 *other_pid = pid;
189 return does_process_exist(pid);
190
191}
192
193/* ================================================== */
194
195static void
196write_lockfile(void)
197{
198 const char *pidfile = CNF_GetPidFile();
199 FILE *out;
200
201 out = fopen(pidfile, "w");
202 if (!out) {
203 LOG(LOGS_ERR, LOGF_Main, "could not open lockfile %s for writing", pidfile);
204 } else {
205 fprintf(out, "%d\n", getpid());
206 fclose(out);
207 }
208}
209
210/* ================================================== */
211
fe4b661f
ML
212static void
213go_daemon(void)
214{
215#ifdef WINNT
216
217
218#else
219
1d2a0856
ML
220 int pid, fd, pipefd[2];
221
222 /* Create pipe which will the daemon use to notify the grandparent
223 when it's initialised or send an error message */
224 if (pipe(pipefd)) {
225 LOG(LOGS_ERR, LOGF_Logging, "Could not detach, pipe failed : %s", strerror(errno));
226 }
fe4b661f
ML
227
228 /* Does this preserve existing signal handlers? */
229 pid = fork();
230
231 if (pid < 0) {
232 LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
233 } else if (pid > 0) {
1d2a0856
ML
234 /* In the 'grandparent' */
235 char message[1024];
236 int r;
237
238 close(pipefd[1]);
239 r = read(pipefd[0], message, sizeof (message));
240 if (r) {
241 if (r > 0) {
242 /* Print the error message from the child */
243 fprintf(stderr, "%.1024s\n", message);
244 }
245 exit(1);
246 } else
247 exit(0);
fe4b661f 248 } else {
1d2a0856 249 close(pipefd[0]);
fe4b661f
ML
250
251 setsid();
252
253 /* Do 2nd fork, as-per recommended practice for launching daemons. */
254 pid = fork();
255
256 if (pid < 0) {
257 LOG(LOGS_ERR, LOGF_Logging, "Could not detach, fork failed : %s", strerror(errno));
258 } else if (pid > 0) {
259 exit(0); /* In the 'parent' */
260 } else {
261 /* In the child we want to leave running as the daemon */
262
2a305d8e
ML
263 /* Change current directory to / */
264 if (chdir("/") < 0) {
265 LOG(LOGS_ERR, LOGF_Logging, "Could not chdir to / : %s", strerror(errno));
266 }
267
1d2a0856
ML
268 /* Don't keep stdin/out/err from before. But don't close
269 the parent pipe yet. */
fe4b661f 270 for (fd=0; fd<1024; fd++) {
1d2a0856
ML
271 if (fd != pipefd[1])
272 close(fd);
fe4b661f 273 }
919b5b5a 274
1d2a0856 275 LOG_SetParentFd(pipefd[1]);
fe4b661f
ML
276 }
277 }
278
279#endif
280}
281
282/* ================================================== */
283
88840341
RC
284int main
285(int argc, char **argv)
286{
0f8def4c 287 const char *conf_file = DEFAULT_CONF_FILE;
be42b4ee 288 char *user = NULL;
72d0b3c9 289 int debug = 0, nofork = 0, address_family = IPADDR_UNSPEC;
f2eb6b16 290 int do_init_rtc = 0, restarted = 0;
88840341 291 int other_pid;
e3234465 292 int lock_memory = 0, sched_priority = 0;
35e662d8 293
88840341
RC
294 LOG_Initialise();
295
296 /* Parse command line options */
297 while (++argv, (--argc)>0) {
298
299 if (!strcmp("-f", *argv)) {
300 ++argv, --argc;
301 conf_file = *argv;
35e662d8
JH
302 } else if (!strcmp("-P", *argv)) {
303 ++argv, --argc;
e3234465
ML
304 if (argc == 0 || sscanf(*argv, "%d", &sched_priority) != 1) {
305 LOG_FATAL(LOGF_Main, "Bad scheduler priority");
35e662d8 306 }
35e662d8 307 } else if (!strcmp("-m", *argv)) {
e3234465 308 lock_memory = 1;
88840341
RC
309 } else if (!strcmp("-r", *argv)) {
310 reload = 1;
f2eb6b16
ML
311 } else if (!strcmp("-R", *argv)) {
312 restarted = 1;
be42b4ee
ML
313 } else if (!strcmp("-u", *argv)) {
314 ++argv, --argc;
e3234465
ML
315 if (argc == 0) {
316 LOG_FATAL(LOGF_Main, "Missing user name");
317 } else {
318 user = *argv;
319 }
88840341
RC
320 } else if (!strcmp("-s", *argv)) {
321 do_init_rtc = 1;
322 } else if (!strcmp("-v", *argv) || !strcmp("--version",*argv)) {
323 /* This write to the terminal is OK, it comes before we turn into a daemon */
4ba3dd66 324 printf("chronyd (chrony) version %s\n", CHRONY_VERSION);
88840341 325 exit(0);
fe4b661f
ML
326 } else if (!strcmp("-n", *argv)) {
327 nofork = 1;
88840341
RC
328 } else if (!strcmp("-d", *argv)) {
329 debug = 1;
fe4b661f 330 nofork = 1;
fbd20c42 331 } else if (!strcmp("-4", *argv)) {
72d0b3c9 332 address_family = IPADDR_INET4;
fbd20c42 333 } else if (!strcmp("-6", *argv)) {
72d0b3c9 334 address_family = IPADDR_INET6;
88840341 335 } else {
dbb550e6 336 LOG_FATAL(LOGF_Main, "Unrecognized command line option [%s]", *argv);
88840341
RC
337 }
338 }
339
88840341
RC
340 if (getuid() != 0) {
341 /* This write to the terminal is OK, it comes before we turn into a daemon */
342 fprintf(stderr,"Not superuser\n");
343 exit(1);
344 }
345
88840341 346 /* Turn into a daemon */
fe4b661f
ML
347 if (!nofork) {
348 go_daemon();
349 }
350
88840341 351 if (!debug) {
fe4b661f 352 LOG_OpenSystemLog();
88840341
RC
353 }
354
4ba3dd66 355 LOG(LOGS_INFO, LOGF_Main, "chronyd version %s starting", CHRONY_VERSION);
cb905507 356
72d0b3c9
ML
357 DNS_SetAddressFamily(address_family);
358
f2eb6b16 359 CNF_SetRestarted(restarted);
1e35b268
ML
360 CNF_ReadFile(conf_file);
361
88840341
RC
362 /* Check whether another chronyd may already be running. Do this after
363 * forking, so that message logging goes to the right place (i.e. syslog), in
364 * case this chronyd is being run from a boot script. */
365 if (maybe_another_chronyd_running(&other_pid)) {
366 LOG_FATAL(LOGF_Main, "Another chronyd may already be running (pid=%d), check lockfile (%s)",
367 other_pid, CNF_GetPidFile());
88840341
RC
368 }
369
370 /* Write our lockfile to prevent other chronyds running. This has *GOT* to
371 * be done *AFTER* the daemon-creation fork() */
372 write_lockfile();
88840341 373
88840341
RC
374 if (do_init_rtc) {
375 RTC_TimePreInit();
376 }
377
378 LCL_Initialise();
379 SCH_Initialise();
380 SYS_Initialise();
72d0b3c9
ML
381 NIO_Initialise(address_family);
382 CAM_Initialise(address_family);
be42b4ee 383 RTC_Initialise();
3a222336 384 SRC_Initialise();
ac30bb06 385 RCL_Initialise();
1c901b82 386 KEY_Initialise();
be42b4ee 387
e3234465
ML
388 /* Command-line switch must have priority */
389 if (!sched_priority) {
390 sched_priority = CNF_GetSchedPriority();
391 }
392 if (sched_priority) {
393 SYS_SetScheduler(sched_priority);
96759116
ML
394 }
395
e3234465
ML
396 if (lock_memory || CNF_GetLockMemory()) {
397 SYS_LockMemory();
96759116
ML
398 }
399
edda0c60
ML
400 if (!user) {
401 user = CNF_GetUser();
402 }
e3234465 403 if (user) {
be42b4ee 404 SYS_DropRoot(user);
e3234465 405 }
be42b4ee 406
103a520a
ML
407 LOG_CreateLogFileDir();
408
88840341
RC
409 REF_Initialise();
410 SST_Initialise();
88840341
RC
411 BRD_Initialise();
412 NCR_Initialise();
413 NSR_Initialise();
88840341 414 CLG_Initialise();
88840341
RC
415 ACQ_Initialise();
416 MNL_Initialise();
c386d117 417 TMC_Initialise();
88840341
RC
418
419 /* From now on, it is safe to do finalisation on exit */
420 initialised = 1;
421
422 if (do_init_rtc) {
423 RTC_TimeInit(post_init_rtc_hook, NULL);
424 } else {
425 post_init_rtc_hook(NULL);
426 }
427
428 signal(SIGINT, signal_cleanup);
429 signal(SIGTERM, signal_cleanup);
430#if !defined(WINNT)
431 signal(SIGQUIT, signal_cleanup);
432 signal(SIGHUP, signal_cleanup);
433#endif /* WINNT */
434
435 /* The program normally runs under control of the main loop in
436 the scheduler. */
437 SCH_MainLoop();
438
0fc9b555
ML
439 LOG(LOGS_INFO, LOGF_Main, "chronyd exiting");
440
88840341
RC
441 MAI_CleanupAndExit();
442
443 return 0;
444}
445
446/* ================================================== */