Deleted Added
full compact
1/*
2 * Copyright (C) 1993, 1994, 1995 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, 1994, 1995 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#define REPORT_PERIOD (30*60)
58
59void fake() {}
60
61int main(argc, argv)
62 int argc;
63 char **argv;
64{
65 struct tm local, utc;
66 struct timeval tv, *stv;
67 struct timezone tz, *stz;
68 int kern_offset;
69 size_t len;
70 int mib[2];
71 /* Avoid time_t here, can be unsigned long or worse */
72 long offset, utcsec, localsec, diff;
73 time_t initial_sec, final_sec;
74 int ch, init = -1;
75 int initial_isdst = -1, final_isdst, looping;
76 int disrtcset, need_restore = 0;
77 sigset_t mask, emask;
78
79 while ((ch = getopt(argc, argv, "ai")) != EOF)
80 switch((char)ch) {
81 case 'i': /* initial call, save offset */
82 if (init != -1)
83 goto usage;
84 init = 1;
85 break;
86 case 'a': /* adjustment call, use saved offset */
87 if (init != -1)
88 goto usage;
89 init = 0;
90 break;
91 default:
92 usage:
93 fprintf(stderr, "Usage:\n\
94\tadjkerntz -i\t(initial call from /etc/rc)\n\
95\tadjkerntz -a\t(adjustment call from crontab)\n");
96 return 2;
97 }
98 if (init == -1)
99 goto usage;
100
101 if (access(_PATH_CLOCK, F_OK))
102 return 0;
103
104 sigemptyset(&mask);
105 sigemptyset(&emask);
106 sigaddset(&mask, SIGTERM);
107
108 openlog("adjkerntz", LOG_PID|LOG_PERROR, LOG_DAEMON);
109
110 (void) signal(SIGHUP, SIG_IGN);
111
112 if (init && daemon(0, 1)) {
113 syslog(LOG_ERR, "daemon: %m");
114 return 1;
115 }
116
117again:
118
119 (void) sigprocmask(SIG_BLOCK, &mask, NULL);
120 (void) signal(SIGTERM, fake);
121
122 diff = 0;
123 stv = NULL;
124 stz = NULL;
125 looping = 0;
126
127 mib[0] = CTL_MACHDEP;
128 mib[1] = CPU_ADJKERNTZ;
129 len = sizeof(kern_offset);
130 if (sysctl(mib, 2, &kern_offset, &len, NULL, 0) == -1) {
131 syslog(LOG_ERR, "sysctl(get_offset): %m");
132 return 1;
133 }

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

156 localsec = mktime(&local);
157 if (utcsec == -1 || localsec == -1) {
158 /*
159 * XXX user can only control local time, and it is
160 * unacceptable to fail here for init. 2:30 am in the
161 * middle of the nonexistent hour means 3:30 am.
162 */
163 syslog(LOG_WARNING,
164 "Nonexistent local time -- will retry after %d secs", REPORT_PERIOD);
165 (void) signal(SIGTERM, SIG_DFL);
166 (void) sigprocmask(SIG_UNBLOCK, &mask, NULL);
167 (void) sleep(REPORT_PERIOD);
168 goto again;
169 }
170 offset = utcsec - localsec;
171#ifdef DEBUG
172 fprintf(stderr, "Initial offset: %ld secs\n", offset);

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

186 final_sec = initial_sec + diff;
187
188 /* get the actual local timezone difference */
189 local = *localtime(&final_sec);
190 final_isdst = diff < 0 ? initial_isdst : local.tm_isdst;
191 if (diff > 0 && initial_isdst != final_isdst) {
192 if (looping)
193 goto bad_final;
194 looping++;
195 initial_isdst = final_isdst;
196 goto recalculate;
197 }
198 utc = *gmtime(&final_sec);
199 local.tm_isdst = utc.tm_isdst = final_isdst;
200
201 utcsec = mktime(&utc);
202 localsec = mktime(&local);
203 if (utcsec == -1 || localsec == -1) {
204 bad_final:
205 /*
206 * XXX as above. The user has even less control,
207 * but perhaps we never get here.
208 */
209 syslog(LOG_WARNING,
210 "Nonexistent (final) local time -- will retry after %d secs", REPORT_PERIOD);
211 (void) signal(SIGTERM, SIG_DFL);
212 (void) sigprocmask(SIG_UNBLOCK, &mask, NULL);
213 (void) sleep(REPORT_PERIOD);
214 goto again;
215 }
216 offset = utcsec - localsec;
217#ifdef DEBUG
218 fprintf(stderr, "Final offset: %ld secs\n", offset);

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

232 stv = &tv;
233 }
234 }
235
236 if (tz.tz_dsttime != 0 || tz.tz_minuteswest != 0) {
237 tz.tz_dsttime = tz.tz_minuteswest = 0; /* zone info is garbage */
238 stz = &tz;
239 }
240
241 /* if init and something will be changed, don't touch RTC at all */
242 if (init && (stv != NULL || kern_offset != offset)) {
243 mib[0] = CTL_MACHDEP;
244 mib[1] = CPU_DISRTCSET;
245 len = sizeof(disrtcset);
246 if (sysctl(mib, 2, &disrtcset, &len, NULL, 0) == -1) {
247 syslog(LOG_ERR, "sysctl(get_disrtcset): %m");
248 return 1;
249 }
250 if (disrtcset == 0) {
251 disrtcset = 1;
252 need_restore = 1;
253 if (sysctl(mib, 2, NULL, NULL, &disrtcset, len) == -1) {
254 syslog(LOG_ERR, "sysctl(set_disrtcset): %m");
255 return 1;
256 }
257 }
258 }
259
260 if (( (init && (stv != NULL || stz != NULL))
261 || (stz != NULL && stv == NULL)
262 )
263 && settimeofday(stv, stz)
264 ) {
265 syslog(LOG_ERR, "settimeofday: %m");
266 return 1;
267 }
268
269 /* init: don't write RTC, !init: write RTC */
270 if (kern_offset != offset) {
271 kern_offset = offset;
272 mib[0] = CTL_MACHDEP;
273 mib[1] = CPU_ADJKERNTZ;
274 len = sizeof(kern_offset);
275 if (sysctl(mib, 2, NULL, NULL, &kern_offset, len) == -1) {
276 syslog(LOG_ERR, "sysctl(update_offset): %m");
277 return 1;
278 }
279 }
280
281 if (need_restore) {
282 need_restore = 0;
283 mib[0] = CTL_MACHDEP;
284 mib[1] = CPU_DISRTCSET;
285 disrtcset = 0;
286 len = sizeof(disrtcset);
287 if (sysctl(mib, 2, NULL, NULL, &disrtcset, len) == -1) {
288 syslog(LOG_ERR, "sysctl(restore_disrtcset): %m");
289 return 1;
290 }
291 }
292
293/****** End of critical section ******/
294
295 if (init) {
296 init = 0;
297 /* wait for signals and acts like -a */
298 (void) sigsuspend(&emask);
299 goto again;
300 }
301
302 return 0;
303}