Deleted Added
sdiff udiff text old ( 8871 ) new ( 15046 )
full compact
1/*
2 * Copyright (C) 1993-1996 by Andrey A. Chernov, Moscow, Russia.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright

--- 10 unchanged lines hidden (view full) ---

21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#ifndef lint
28char copyright[] =
29"@(#)Copyright (C) 1993-1996 by Andrey A. Chernov, Moscow, Russia.\n\
30 All rights reserved.\n";
31#endif /* not lint */
32
33/*
34 * Andrey A. Chernov <ache@astral.msk.su> Dec 20 1993
35 *
36 * Fix kernel time value if machine run wall CMOS clock
37 * (and /etc/wall_cmos_clock file present)

--- 11 unchanged lines hidden (view full) ---

49#include <sys/time.h>
50#include <sys/param.h>
51#include <machine/cpu.h>
52#include <sys/sysctl.h>
53
54#include "pathnames.h"
55
56/*#define DEBUG*/
57
58#define True (1)
59#define False (0)
60#define Unknown (-1)
61
62#define REPORT_PERIOD (30*60)
63
64void fake() {}
65
66int main(argc, argv)
67 int argc;
68 char **argv;
69{
70 struct tm local, utc;
71 struct timeval tv, *stv;
72 struct timezone tz, *stz;
73 int kern_offset, wall_clock, disrtcset;
74 size_t len;
75 int mib[2];
76 /* Avoid time_t here, can be unsigned long or worse */
77 long offset, utcsec, localsec, diff;
78 time_t initial_sec, final_sec;
79 int ch;
80 int initial_isdst = -1, final_isdst;
81 int need_restore = False, sleep_mode = False, looping,
82 init = Unknown;
83 sigset_t mask, emask;
84
85 while ((ch = getopt(argc, argv, "ais")) != EOF)
86 switch((char)ch) {
87 case 'i': /* initial call, save offset */
88 if (init != Unknown)
89 goto usage;
90 init = True;
91 break;
92 case 'a': /* adjustment call, use saved offset */
93 if (init != Unknown)
94 goto usage;
95 init = False;
96 break;
97 case 's':
98 sleep_mode = True;
99 break;
100 default:
101 usage:
102 fprintf(stderr, "Usage:\n\
103\tadjkerntz -i\t\t(initial call from /etc/rc)\n\
104\tadjkerntz -a [-s]\t(adjustment call, -s for sleep/retry mode)\n");
105 return 2;
106 }
107 if (init == Unknown)
108 goto usage;
109 if (init)
110 sleep_mode = True;
111
112 sigemptyset(&mask);
113 sigemptyset(&emask);
114 sigaddset(&mask, SIGTERM);
115
116 openlog("adjkerntz", LOG_PID|LOG_PERROR, LOG_DAEMON);
117
118 (void) signal(SIGHUP, SIG_IGN);
119
120 if (init && daemon(0, 1)) {
121 syslog(LOG_ERR, "daemon: %m");
122 return 1;
123 }
124
125 if (init)
126 wall_clock = (access(_PATH_CLOCK, F_OK) == 0);
127 else {
128 mib[0] = CTL_MACHDEP;
129 mib[1] = CPU_WALLCLOCK;
130 len = sizeof(wall_clock);
131 if (sysctl(mib, 2, &wall_clock, &len, NULL, 0) == -1) {
132 syslog(LOG_ERR, "sysctl(get_wallclock): %m");
133 return 1;
134 }
135 }
136
137again:
138 (void) sigprocmask(SIG_BLOCK, &mask, NULL);
139 (void) signal(SIGTERM, fake);
140
141 diff = 0;
142 stv = NULL;
143 stz = NULL;
144 looping = False;
145
146 mib[0] = CTL_MACHDEP;
147 mib[1] = CPU_ADJKERNTZ;
148 len = sizeof(kern_offset);
149 if (sysctl(mib, 2, &kern_offset, &len, NULL, 0) == -1) {
150 syslog(LOG_ERR, "sysctl(get_offset): %m");
151 return 1;
152 }

--- 22 unchanged lines hidden (view full) ---

175 localsec = mktime(&local);
176 if (utcsec == -1 || localsec == -1) {
177 /*
178 * XXX user can only control local time, and it is
179 * unacceptable to fail here for init. 2:30 am in the
180 * middle of the nonexistent hour means 3:30 am.
181 */
182 syslog(LOG_WARNING,
183 "Warning: nonexistent %s time.",
184 utcsec == -1 && localsec == -1 ? "UTC time and local" :
185 utcsec == -1 ? "UTC" : "local");
186 if (!sleep_mode) {
187 syslog(LOG_WARNING, "Giving up.");
188 return 1;
189 }
190 syslog(LOG_WARNING, "Will retry after %d minutes.",
191 REPORT_PERIOD / 60);
192 (void) signal(SIGTERM, SIG_DFL);
193 (void) sigprocmask(SIG_UNBLOCK, &mask, NULL);
194 (void) sleep(REPORT_PERIOD);
195 goto again;
196 }
197 offset = utcsec - localsec;
198#ifdef DEBUG
199 fprintf(stderr, "Initial offset: %ld secs\n", offset);

--- 13 unchanged lines hidden (view full) ---

213 final_sec = initial_sec + diff;
214
215 /* get the actual local timezone difference */
216 local = *localtime(&final_sec);
217 final_isdst = diff < 0 ? initial_isdst : local.tm_isdst;
218 if (diff > 0 && initial_isdst != final_isdst) {
219 if (looping)
220 goto bad_final;
221 looping = True;
222 initial_isdst = final_isdst;
223 goto recalculate;
224 }
225 utc = *gmtime(&final_sec);
226 local.tm_isdst = utc.tm_isdst = final_isdst;
227
228 utcsec = mktime(&utc);
229 localsec = mktime(&local);
230 if (utcsec == -1 || localsec == -1) {
231 bad_final:
232 /*
233 * XXX as above. The user has even less control,
234 * but perhaps we never get here.
235 */
236 syslog(LOG_WARNING,
237 "Warning: nonexistent final %s time.",
238 utcsec == -1 && localsec == -1 ? "UTC time and local" :
239 utcsec == -1 ? "UTC" : "local");
240 if (!sleep_mode) {
241 syslog(LOG_WARNING, "Giving up.");
242 return 1;
243 }
244 syslog(LOG_WARNING, "Will retry after %d minutes.",
245 REPORT_PERIOD / 60);
246 (void) signal(SIGTERM, SIG_DFL);
247 (void) sigprocmask(SIG_UNBLOCK, &mask, NULL);
248 (void) sleep(REPORT_PERIOD);
249 goto again;
250 }
251 offset = utcsec - localsec;
252#ifdef DEBUG
253 fprintf(stderr, "Final offset: %ld secs\n", offset);

--- 13 unchanged lines hidden (view full) ---

267 stv = &tv;
268 }
269 }
270
271 if (tz.tz_dsttime != 0 || tz.tz_minuteswest != 0) {
272 tz.tz_dsttime = tz.tz_minuteswest = 0; /* zone info is garbage */
273 stz = &tz;
274 }
275 if (!wall_clock && stz == NULL)
276 stv = NULL;
277
278 /* if init or UTC clock and offset/date will be changed, */
279 /* disable RTC modification for a while. */
280
281 if ( (init && stv != NULL)
282 || ((init || !wall_clock) && kern_offset != offset)
283 ) {
284 mib[0] = CTL_MACHDEP;
285 mib[1] = CPU_DISRTCSET;
286 len = sizeof(disrtcset);
287 if (sysctl(mib, 2, &disrtcset, &len, NULL, 0) == -1) {
288 syslog(LOG_ERR, "sysctl(get_disrtcset): %m");
289 return 1;
290 }
291 if (disrtcset == 0) {
292 disrtcset = 1;
293 need_restore = True;
294 if (sysctl(mib, 2, NULL, NULL, &disrtcset, len) == -1) {
295 syslog(LOG_ERR, "sysctl(set_disrtcset): %m");
296 return 1;
297 }
298 }
299 }
300
301 if ( ( (init && (stv != NULL || stz != NULL))
302 || (stz != NULL && stv == NULL)
303 )
304 && settimeofday(stv, stz)
305 ) {
306 syslog(LOG_ERR, "settimeofday: %m");
307 return 1;
308 }
309
310 /* setting CPU_ADJKERNTZ have a side effect: resettodr(), which */
311 /* can be disabled by CPU_DISRTCSET, so if init or UTC clock */
312 /* -- don't write RTC, else write RTC. */
313
314 if (kern_offset != offset) {
315 kern_offset = offset;
316 mib[0] = CTL_MACHDEP;
317 mib[1] = CPU_ADJKERNTZ;
318 len = sizeof(kern_offset);
319 if (sysctl(mib, 2, NULL, NULL, &kern_offset, len) == -1) {
320 syslog(LOG_ERR, "sysctl(update_offset): %m");
321 return 1;
322 }
323 }
324
325 if (init) {
326 mib[0] = CTL_MACHDEP;
327 mib[1] = CPU_WALLCLOCK;
328 len = sizeof(wall_clock);
329 if (sysctl(mib, 2, NULL, NULL, &wall_clock, len) == -1) {
330 syslog(LOG_ERR, "sysctl(put_wallclock): %m");
331 return 1;
332 }
333 }
334
335 if (need_restore) {
336 need_restore = False;
337 mib[0] = CTL_MACHDEP;
338 mib[1] = CPU_DISRTCSET;
339 disrtcset = 0;
340 len = sizeof(disrtcset);
341 if (sysctl(mib, 2, NULL, NULL, &disrtcset, len) == -1) {
342 syslog(LOG_ERR, "sysctl(restore_disrtcset): %m");
343 return 1;
344 }
345 }
346
347/****** End of critical section ******/
348
349 if (init && wall_clock) {
350 init = False;
351 /* wait for signals and acts like -a */
352 (void) sigsuspend(&emask);
353 goto again;
354 }
355
356 return 0;
357}