Deleted Added
full compact
adjkerntz.c (4039) adjkerntz.c (4048)
1/*
2 * Copyright (C) 1993 by Andrew 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

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

38 * using zoneinfo rules or direct TZ environment variable set.
39 * Use Joerg Wunsch idea for seconds accurate offset calculation
40 * with Garrett Wollman and Bruce Evans fixes.
41 *
42 */
43#include <stdio.h>
44#include <stdlib.h>
45#include <unistd.h>
1/*
2 * Copyright (C) 1993 by Andrew 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

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

38 * using zoneinfo rules or direct TZ environment variable set.
39 * Use Joerg Wunsch idea for seconds accurate offset calculation
40 * with Garrett Wollman and Bruce Evans fixes.
41 *
42 */
43#include <stdio.h>
44#include <stdlib.h>
45#include <unistd.h>
46#include <syslog.h>
46#include <sys/stat.h>
47#include <sys/time.h>
48#include <sys/param.h>
49#include <machine/cpu.h>
50#include <sys/sysctl.h>
51
52#include "pathnames.h"
53
47#include <sys/stat.h>
48#include <sys/time.h>
49#include <sys/param.h>
50#include <machine/cpu.h>
51#include <sys/sysctl.h>
52
53#include "pathnames.h"
54
55#define REPORT_PERIOD (30*60)
56
54int main(argc, argv)
55 int argc;
56 char **argv;
57{
58 struct tm local, utc;
59 struct timeval tv, *stv;
60 struct timezone tz, *stz;
61 int kern_offset;
62 size_t len;
63 int mib[2];
64 /* Avoid time_t here, can be unsigned long or worse */
65 long offset, utcsec, localsec, diff;
66 time_t initial_sec, final_sec;
57int main(argc, argv)
58 int argc;
59 char **argv;
60{
61 struct tm local, utc;
62 struct timeval tv, *stv;
63 struct timezone tz, *stz;
64 int kern_offset;
65 size_t len;
66 int mib[2];
67 /* Avoid time_t here, can be unsigned long or worse */
68 long offset, utcsec, localsec, diff;
69 time_t initial_sec, final_sec;
67 int ch, init = -1, verbose = 0;
70 int init = 1, nonex1 = 0, nonex2 = 0;
68 int disrtcset, need_restore = 0;
69
71 int disrtcset, need_restore = 0;
72
70 while ((ch = getopt(argc, argv, "aiv")) != EOF)
71 switch((char)ch) {
72 case 'i': /* initial call, save offset */
73 if (init != -1)
74 goto usage;
75 init = 1;
76 break;
77 case 'a': /* adjustment call, use saved offset */
78 if (init != -1)
79 goto usage;
80 init = 0;
81 break;
82 case 'v': /* verbose */
83 verbose = 1;
84 break;
85 default:
86 usage:
87 fprintf(stderr, "Usage:\n\
88\tadjkerntz -i [-v]\t(initial call from /etc/rc)\n\
89\tadjkerntz -a [-v]\t(adjustment call from crontab)\n");
90 return 2;
91 }
92 if (init == -1)
93 goto usage;
73 if (argc != 1) {
74 fprintf(stderr, "Usage:\tadjkerntz\n");
75 return 2;
76 }
94
95 if (access(_PATH_CLOCK, F_OK))
96 return 0;
97
77
78 if (access(_PATH_CLOCK, F_OK))
79 return 0;
80
98 /* Restore saved offset */
99
100 mib[0] = CTL_MACHDEP;
101 mib[1] = CPU_ADJKERNTZ;
102 len = sizeof(kern_offset);
103 if (sysctl(mib, 2, &kern_offset, &len, NULL, 0) == -1) {
104 perror("sysctl(get_offset)");
81 if (daemon(0, 0)) {
82 perror("daemon");
105 return 1;
106 }
107
83 return 1;
84 }
85
108/****** Critical section, do all things as fast as possible ******/
86 openlog("adjkerntz", LOG_PID, LOG_DAEMON);
109
87
110 /* get local CMOS clock and possible kernel offset */
111 if (gettimeofday(&tv, &tz)) {
112 perror("gettimeofday");
113 return 1;
114 }
88 /* Spy on timezone changes with 1sec accurancy */
89 for (;;sleep(1)) {
115
90
116 /* get the actual local timezone difference */
117 initial_sec = tv.tv_sec;
118 local = *localtime(&initial_sec);
119 utc = *gmtime(&initial_sec);
120 utc.tm_isdst = local.tm_isdst; /* Use current timezone for mktime(), */
121 /* because it assumed local time */
91/****** Critical section, do all things as fast as possible ******/
122
92
123 /* calculate local CMOS diff from GMT */
93 /* get local CMOS clock and possible kernel offset */
94 if (gettimeofday(&tv, &tz)) {
95 syslog(LOG_ERR, "gettimeofday: %m");
96 return 1;
97 }
124
98
125 utcsec = mktime(&utc);
126 localsec = mktime(&local);
127 if (utcsec == -1 || localsec == -1) {
128 /*
129 * XXX user can only control local time, and it is
130 * unacceptable to fail here for -i. 2:30 am in the
131 * middle of the nonexistent hour means 3:30 am.
132 */
133 fprintf(stderr,
134 "Nonexistent local time - try again in an hour\n");
135 return 1;
136 }
137 offset = utcsec - localsec;
138
139 /* correct the kerneltime for this diffs */
140 /* subtract kernel offset, if present, old offset too */
141
142 diff = offset - tz.tz_minuteswest * 60 - kern_offset;
143
144 if (diff != 0) {
145
146 /* Yet one step for final time */
147
148 final_sec = tv.tv_sec + diff;
149
150 /* get the actual local timezone difference */
99 /* get the actual local timezone difference */
151 local = *localtime(&final_sec);
152 utc = *gmtime(&final_sec);
100 initial_sec = tv.tv_sec;
101 local = *localtime(&initial_sec);
102 utc = *gmtime(&initial_sec);
153 utc.tm_isdst = local.tm_isdst; /* Use current timezone for mktime(), */
154 /* because it assumed local time */
155
103 utc.tm_isdst = local.tm_isdst; /* Use current timezone for mktime(), */
104 /* because it assumed local time */
105
106 /* calculate local CMOS diff from GMT */
107
156 utcsec = mktime(&utc);
157 localsec = mktime(&local);
158 if (utcsec == -1 || localsec == -1) {
159 /*
108 utcsec = mktime(&utc);
109 localsec = mktime(&local);
110 if (utcsec == -1 || localsec == -1) {
111 /*
160 * XXX as above. The user has even less control,
161 * but perhaps we never get here.
112 * XXX user can only control local time, and it is
113 * unacceptable to fail here for init. 2:30 am in the
114 * middle of the nonexistent hour means 3:30 am.
162 */
115 */
163 fprintf(stderr,
164 "Nonexistent (final) local time - try again in an hour\n");
165 return 1;
116 if (!(nonex1++ % REPORT_PERIOD)) {
117 if (nonex1 > 1)
118 nonex1 = 0;
119 syslog(LOG_WARNING,
120 "Nonexistent local time -- retry each second");
121 }
122 continue;
166 }
167 offset = utcsec - localsec;
168
123 }
124 offset = utcsec - localsec;
125
126 mib[0] = CTL_MACHDEP;
127 mib[1] = CPU_ADJKERNTZ;
128 len = sizeof(kern_offset);
129 if (sysctl(mib, 2, &kern_offset, &len, NULL, 0) == -1) {
130 syslog(LOG_ERR, "sysctl(get_offset): %m");
131 return 1;
132 }
133
169 /* correct the kerneltime for this diffs */
170 /* subtract kernel offset, if present, old offset too */
171
172 diff = offset - tz.tz_minuteswest * 60 - kern_offset;
173
174 if (diff != 0) {
134 /* correct the kerneltime for this diffs */
135 /* subtract kernel offset, if present, old offset too */
136
137 diff = offset - tz.tz_minuteswest * 60 - kern_offset;
138
139 if (diff != 0) {
175 tv.tv_sec += diff;
176 tv.tv_usec = 0; /* we are restarting here... */
177 stv = &tv;
140
141 /* Yet one step for final time */
142
143 final_sec = tv.tv_sec + diff;
144
145 /* get the actual local timezone difference */
146 local = *localtime(&final_sec);
147 utc = *gmtime(&final_sec);
148 utc.tm_isdst = local.tm_isdst; /* Use current timezone for mktime(), */
149 /* because it assumed local time */
150
151 utcsec = mktime(&utc);
152 localsec = mktime(&local);
153 if (utcsec == -1 || localsec == -1) {
154 /*
155 * XXX as above. The user has even less control,
156 * but perhaps we never get here.
157 */
158 if (!(nonex2++ % REPORT_PERIOD)) {
159 if (nonex2 > 1)
160 nonex2 = 0;
161 syslog(LOG_WARNING,
162 "Nonexistent (final) local time -- retry each second");
163 }
164 continue;
165 }
166 offset = utcsec - localsec;
167
168 /* correct the kerneltime for this diffs */
169 /* subtract kernel offset, if present, old offset too */
170
171 diff = offset - tz.tz_minuteswest * 60 - kern_offset;
172
173 if (diff != 0) {
174 tv.tv_sec += diff;
175 tv.tv_usec = 0; /* we are restarting here... */
176 stv = &tv;
177 }
178 else
179 stv = NULL;
178 }
179 else
180 stv = NULL;
180 }
181 else
182 stv = NULL;
181 }
182 else
183 stv = NULL;
184
183
185 if (tz.tz_dsttime != 0 || tz.tz_minuteswest != 0) {
186 tz.tz_dsttime = tz.tz_minuteswest = 0; /* zone info is garbage */
187 stz = &tz;
188 }
189 else
190 stz = NULL;
184 if (tz.tz_dsttime != 0 || tz.tz_minuteswest != 0) {
185 tz.tz_dsttime = tz.tz_minuteswest = 0; /* zone info is garbage */
186 stz = &tz;
187 }
188 else
189 stz = NULL;
191
190
192 if (stz != NULL || stv != NULL) {
193 if (init && stv != NULL) {
194 mib[0] = CTL_MACHDEP;
195 mib[1] = CPU_DISRTCSET;
196 len = sizeof(disrtcset);
197 if (sysctl(mib, 2, &disrtcset, &len, NULL, 0) == -1) {
198 perror("sysctl(get_disrtcset)");
199 return 1;
200 }
201 if (disrtcset == 0) {
202 disrtcset = 1;
203 need_restore = 1;
204 if (sysctl(mib, 2, NULL, NULL, &disrtcset, len) == -1) {
205 perror("sysctl(set_disrtcset)");
191 if (stz != NULL || stv != NULL) {
192 if (init && stv != NULL) {
193 mib[0] = CTL_MACHDEP;
194 mib[1] = CPU_DISRTCSET;
195 len = sizeof(disrtcset);
196 if (sysctl(mib, 2, &disrtcset, &len, NULL, 0) == -1) {
197 syslog(LOG_ERR, "sysctl(get_disrtcset): %m");
206 return 1;
207 }
198 return 1;
199 }
200 if (disrtcset == 0) {
201 disrtcset = 1;
202 need_restore = 1;
203 if (sysctl(mib, 2, NULL, NULL, &disrtcset, len) == -1) {
204 syslog(LOG_ERR, "sysctl(set_disrtcset): %m");
205 return 1;
206 }
207 }
208 }
208 }
209 /* stz means that kernel zone shifted */
210 /* clock needs adjustment even if !init */
211 if ((init || stz != NULL) && settimeofday(stv, stz)) {
212 syslog(LOG_ERR, "settimeofday: %m");
213 return 1;
214 }
209 }
215 }
210 if ((init || stv == NULL) && settimeofday(stv, stz)) {
211 perror("settimeofday");
212 return 1;
213 }
214 }
215
216
216 if (kern_offset != offset) {
217 kern_offset = offset;
218 mib[0] = CTL_MACHDEP;
219 mib[1] = CPU_ADJKERNTZ;
220 len = sizeof(kern_offset);
221 if (sysctl(mib, 2, NULL, NULL, &kern_offset, len) == -1) {
222 perror("sysctl(update_offset)");
223 return 1;
217 if (kern_offset != offset) {
218 kern_offset = offset;
219 mib[0] = CTL_MACHDEP;
220 mib[1] = CPU_ADJKERNTZ;
221 len = sizeof(kern_offset);
222 if (sysctl(mib, 2, NULL, NULL, &kern_offset, len) == -1) {
223 syslog(LOG_ERR, "sysctl(update_offset): %m");
224 return 1;
225 }
224 }
226 }
225 }
226
227
227 if (need_restore) {
228 disrtcset = 0;
229 if (sysctl(mib, 2, NULL, NULL, &disrtcset, len) == -1) {
230 perror("sysctl(restore_disrtcset)");
231 return 1;
228 if (need_restore) {
229 need_restore = 0;
230 disrtcset = 0;
231 if (sysctl(mib, 2, NULL, NULL, &disrtcset, len) == -1) {
232 syslog(LOG_ERR, "sysctl(restore_disrtcset): %m");
233 return 1;
234 }
232 }
235 }
233 }
234
235/****** End of critical section ******/
236
236
237/****** End of critical section ******/
238
237 if (verbose)
238 printf("Calculated zone offset difference: %ld seconds\n",
239 diff);
240
241 return 0;
239 init = 0;
240 }
241 return 1;
242}
242}
243