convert-from-bsd-to-posix-string-and-memory-functions-20010807
[openafs.git] / src / ntp / runntp.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 RCSID("$Header$");
14
15 #include <afs/stds.h>
16 #include <signal.h>
17 #include <sys/wait.h>
18 #include <stdio.h>
19 #include <afs/com_err.h>
20 #include <afs/cellconfig.h>
21 #include <afs/afsutil.h>
22
23
24 extern int errno;
25
26 char *whoami;
27
28 static afs_int32 lastTime = 0;
29
30 static afs_int32 GetCellInfo (cellinfoP)
31   struct afsconf_cell *cellinfoP;
32 {
33     struct afsconf_dir *conf;
34     char lcell[MAXHOSTCHARS];
35     afs_int32 code;
36
37     conf = afsconf_Open (AFSDIR_SERVER_ETC_DIRPATH);
38     if (conf == 0) return AFSCONF_NOTFOUND;
39     code = afsconf_GetLocalCell (conf, lcell, sizeof(lcell));
40     if (code) return code;
41     code = afsconf_GetCellInfo (conf, lcell, 0, cellinfoP);
42     lastTime = conf->timeRead;
43     afsconf_Close(conf);
44     return code;
45 }
46
47 /* Check the date of the afsconf stuff and return 0 if its date is the
48    same as the last call the GetCellInfo. */
49
50 static int IsCellInfoNew ()
51 {   struct afsconf_dir *conf;
52     int new;
53
54     /* not using cellinfo, so always return OK */
55     if (lastTime == 0) return 0;
56
57     conf = afsconf_Open (AFSDIR_SERVER_ETC_DIRPATH);
58     if (conf == 0) return 1;            /* something's wrong */
59     new = conf->timeRead != lastTime;
60     afsconf_Close(conf);
61     return (new);
62 }
63
64 int pid = 0;                            /* process id of ntpd */
65
66 void
67 terminate ()
68 {
69     if (pid) kill (pid, 9);             /* kill off ntpd */
70     exit (0);
71 }
72
73 #include "AFS_component_version_number.c"
74
75 main (argc, argv)
76   int   argc;
77   char *argv[];
78 {
79     afs_int32 code;
80     char  *filename;
81     FILE *f;                            /* ntp.conf output file */
82     int   a;
83     int   i;
84     int   local = 0;                    /* just use machine's local clock */
85     int   precision = 0;                /* precision specification */
86     int   stratum = 12;                 /* stratum for local clock */
87     char *logfile;                      /* file for ntpd output streams */
88     char  *ntpdPath;                    /* pathname of ntpd executable */
89     int   nHostArgs = 0;                /* number of explicit hosts */
90     char *explicitHosts[10];            /* hosts names from arglist */
91
92 #ifdef  AFS_AIX32_ENV
93     /*
94      * The following signal action for AIX is necessary so that in case of a 
95      * crash (i.e. core is generated) we can include the user's data section 
96      * in the core dump. Unfortunately, by default, only a partial core is
97      * generated which, in many cases, isn't too useful.
98      */
99     struct sigaction nsa;
100     
101     sigemptyset(&nsa.sa_mask);
102     nsa.sa_handler = SIG_DFL;
103     nsa.sa_flags = SA_FULLDUMP;
104     sigaction(SIGSEGV, &nsa, NULL);
105 #endif
106     whoami = argv[0];
107     logfile = 0;
108
109     /* Initialize dirpaths */
110     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
111         fprintf(stderr,"%s: Unable to obtain AFS server directory.\n", argv[0]);
112         exit(2);
113     }
114
115     ntpdPath = AFSDIR_SERVER_NTPD_FILEPATH;
116     for (a=1; a<argc; a++) {
117         if (strcmp (argv[a], "-localclock") == 0) local = 1;
118         else if (strcmp (argv[a], "-precision") == 0) {
119             if (++a >= argc) goto usage;
120             precision = atoi(argv[a]);  /* next arg is (negative) precision */
121         }
122         else if (strcmp (argv[a], "-logfile") == 0) {
123             if (++a >= argc) goto usage;
124             logfile = argv[a];          /* next arg is pathname for stdout */
125             f = fopen(logfile, "a");
126             if (f == NULL) {
127                 com_err (whoami, errno, "Can't open %s as logfile", logfile);
128                 goto usage;
129             }
130             fclose (f);
131         }
132         else if (strcmp (argv[a], "-ntpdpath") == 0) {
133             if (++a >= argc) goto usage;
134             ntpdPath = argv[a]; /* next arg is pathname of ntpd */
135             f = fopen(ntpdPath, "r");
136             if (f == NULL) {
137                 com_err (whoami, errno,
138                          "Can't find ntp daemon at %s", ntpdPath);
139                 goto usage;
140             }
141             fclose (f);
142         }
143         else if (argv[a][0] != '-') { /* must be a hostname */
144             if (nHostArgs >= sizeof(explicitHosts)/sizeof(explicitHosts[0])) {
145                 com_err (whoami, 0, "Too many hosts specified");
146                 goto usage;
147             } else explicitHosts[nHostArgs++] = argv[a];
148         }
149         else {
150           usage:
151             fprintf (stdout, "Usage: %s [-localclock] [-precision <small-negative-integer>] [-logfile <filename for ntpd's stdout/stderr] [-ntpdpath <pathname of ntpd executable (/usr/afs/bin/ntpd)>] [<host>*] [-help]\n", whoami);
152             exit (-1);
153         }
154     }
155
156     /* setup to write to output file */
157     filename = "/tmp/ntp.conf";
158     f = fopen (filename, "w");
159     if (f == 0) {
160         com_err (whoami, errno, "can't create output file %s", filename);
161         exit (4);
162     }
163
164 #if defined(AFS_SUN_ENV) && !defined(AFS_SUN5_ENV)
165     /*
166      * NOTE: Ntpd does not know how to set kernel variables on Solaris
167      * systems, and it does not seem to be necessary on Solaris 2.6 and
168      * later.
169      */
170
171     /* first, for SUNs set tickadj and dosynctodr */
172     fprintf (f, "setdosynctodr Y\nsettickadj Y\n");
173 #endif
174
175     /* specify precision */
176     if (precision) {
177         fprintf (f, "precision %d\n", precision);
178     }
179
180     /* then dump the appropriate type of host list */
181
182     if (local) { /* use the machines local clock */
183         fprintf (f, "peer\t/dev/null\tLOCL\t%d\t%d\tlocal\n",
184                  stratum, precision);
185     }
186     if (nHostArgs) { /* use the explicitly provided list */
187         for (i=0; i<nHostArgs; i++) {
188             fprintf (f, "peer\t%s\n", explicitHosts[i]);
189         }
190     }
191     if (!(local || nHostArgs)) { /* just use CellServDB info instead */
192         struct afsconf_cell cellinfo;
193
194         code = GetCellInfo (&cellinfo);
195         if (code) {
196             com_err (whoami, 0, "can't get local cell info");
197             exit (1);
198         }
199         for (i=0; i<cellinfo.numServers; i++) {
200             fprintf (f, "peer\t%s\t#%s\n",
201                      inet_ntoa(cellinfo.hostAddr[i].sin_addr),
202                      cellinfo.hostName[i]);
203         }
204     }   
205
206     /* all done with ntp.conf file */
207     if (fclose (f) == EOF) {
208         com_err (whoami, errno, "can't close output file %s", filename);
209         exit (5);
210     }
211
212     /* handle bozo kills right */
213
214     {   struct sigaction sa;
215         memset((char *)&sa, 0, sizeof(sa));
216         sa.sa_handler = terminate;
217         code = sigaction (SIGTERM, &sa, NULL);
218         if (code) {
219             com_err (whoami, errno, "can't set up handler for SIGTERM");
220             exit (9);
221         }
222     }
223
224     /* now start ntpd with proper arguments */
225
226     pid = fork ();
227     if (pid == -1) {
228         com_err (whoami, errno, "forking for ntpd process");
229         exit (6);
230     }
231     if (pid == 0) { /* this is child */
232         char *argv[5];
233         char *envp[1];
234         afs_int32 now = time(0);
235         extern char *ctime();
236         char *nowString = ctime (&now);
237
238         if (logfile == 0) logfile = "/dev/null";
239         freopen (logfile, "a", stdout);
240         freopen (logfile, "a", stderr);
241         nowString[strlen(nowString)-1] = '\0'; /* punt the newline char */
242         fprintf (stdout, "Starting %s at %s with output to logfile\n",
243                  ntpdPath, nowString);
244         fflush (stdout);
245
246         argv[0] = "ntpd";
247         argv[1] = "-f";         /* don't fork */
248         argv[2] = "-c";         /* read our conf file */
249         argv[3] = filename;
250         argv[4] = 0;
251         envp[0] = 0;
252         code = execve (ntpdPath, argv, envp);
253         if (code) com_err (whoami, errno, "execve of %s failed", ntpdPath);
254         exit(errno);
255     }
256     else { /* this is parent */
257         int  status;
258         int  waitInterval = 0;
259         do {
260             i = wait3 (&status, WNOHANG|WUNTRACED, 0);
261             if (i == -1) {
262                 (void) kill (pid, 9);           /* try to kill off ntpd */
263                 com_err (whoami, errno, "wait3 ing");
264                 exit (7);
265             } else if (i == pid) {
266                 printf ("ntpd exited status = %x (code=%d, %ssignal=%d)\n",
267                         status, (status&0xffff)>>8,
268                         ((status&0x80) ? "coredump, ":""), status&0x7f);
269                 exit (8);
270             } else if (i != 0) {
271                 printf ("strange return from wait3 %d\n", i);
272                 break;
273             }
274             sleep (waitInterval>60 ? 60 : waitInterval++);
275         } while (!IsCellInfoNew());
276
277         code = kill (pid, 9);           /* kill off ntpd */
278         if (code) com_err (whoami, errno, "trying to kill ntpd process");
279         else printf ("Exiting due to change in cellinfo\n");
280     }
281
282     exit (0);
283 }