Print this page
8980 BIOS clock is sometimes one hour fast
Reviewed by: Toomas Soome <tsoome@me.com>
Reviewed by: C Fraire <cfraire@me.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/rtc/rtc.c
+++ new/usr/src/cmd/rtc/rtc.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 + * Copyright 2018 Gary Mills
23 24 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 25 * Use is subject to license terms.
25 26 */
26 27
27 -#pragma ident "%Z%%M% %I% %E% SMI"
28 -
29 28 #include <stdio.h>
30 29 #include <stdlib.h>
31 30 #include <unistd.h>
32 31 #include <sys/types.h>
33 32 #include <sys/sysi86.h>
34 33 #include <errno.h>
35 34 #include <time.h>
36 35 #include <string.h>
37 36 #include <sys/stat.h>
38 37
38 +/* RTC modes */
39 +#define M_UNSET 0 /* Mode never set */
40 +#define M_VAR 1 /* Tracks local time including DST */
41 +#define M_UTC 2 /* Clock runs in UTC */
42 +#define M_STD 3 /* Clock runs in local standard time */
43 +
39 44 static char *progname;
40 45 static char *zonefile = "/etc/rtc_config";
41 46 static FILE *zonefptr;
42 47 static char zone_info[256];
43 48 static char zone_lag[256];
44 49 static char tz[256] = "TZ=";
50 +static char *utc_zone = "UTC";
45 51 int debug = 0;
52 +int rtc_mode = M_UNSET;
46 53 int lag;
47 54 int errors_ok = 0; /* allow "rtc no-args" to be quiet when not configured */
48 55 static time_t clock_val;
49 56 static char zone_comment[] =
50 57 "#\n"
51 58 "# This file (%s) contains information used to manage the\n"
52 59 "# x86 real time clock hardware. The hardware is kept in\n"
53 60 "# the machine's local time for compatibility with other x86\n"
54 61 "# operating systems. This file is read by the kernel at\n"
55 62 "# boot time. It is set and updated by the /usr/sbin/rtc\n"
56 63 "# command. The 'zone_info' field designates the local\n"
57 64 "# time zone. The 'zone_lag' field indicates the number\n"
58 65 "# of seconds between local time and Greenwich Mean Time.\n"
59 66 "#\n";
60 67
61 68 /*
62 69 * Open the configuration file and extract the
63 70 * zone_info and the zone_lag. Return 0 if successful.
↓ open down ↓ |
8 lines elided |
↑ open up ↑ |
64 71 */
65 72 int
66 73 open_zonefile()
67 74 {
68 75 char b[256], *s;
69 76 int lag_hrs;
70 77
71 78 if ((zonefptr = fopen(zonefile, "r")) == NULL) {
72 79 if (errors_ok == 0)
73 80 (void) fprintf(stderr,
74 - "%s: cannot open %s: errno = %d\n",
75 - progname, zonefile, errno);
81 + "%s: cannot open %s: errno = %d\n",
82 + progname, zonefile, errno);
76 83 return (1);
77 84 }
78 85
79 86 for (;;) {
80 87 if ((s = fgets(b, sizeof (b), zonefptr)) == NULL)
81 88 break;
82 89 if ((s = strchr(s, 'z')) == NULL)
83 90 continue;
84 91 if (strncmp(s, "zone_info", 9) == 0) {
85 92 s += 9;
86 93 while (*s != 0 && *s != '=')
87 94 s++;
88 95 if (*s == '=') {
89 96 s++;
90 97 while (*s != 0 && (*s == ' ' || *s == '\t'))
91 98 s++;
92 99 (void) strncpy(zone_info, s,
93 100 sizeof (zone_info));
94 101 s = zone_info;
95 102 while (*s != 0 && *s != '\n')
96 103 s++;
97 104 if (*s == '\n')
98 105 *s = 0;
99 106 }
100 107 } else if (strncmp(s, "zone_lag", 8) == 0) {
101 108 s += 8;
102 109 while (*s != 0 && *s != '=')
103 110 s++;
104 111 if (*s == '=') {
105 112 s++;
106 113 while (*s != 0 && (*s == ' ' || *s == '\t'))
107 114 s++;
108 115 (void) strncpy(zone_lag, s, sizeof (zone_lag));
109 116 s = zone_lag;
110 117 while (*s != 0 && *s != '\n')
111 118 s++;
112 119 if (*s == '\n')
113 120 *s = 0;
114 121 }
115 122 }
116 123 }
117 124 lag = atoi(zone_lag);
118 125 lag_hrs = lag / 3600;
119 126 if (zone_info[0] == 0) {
120 127 (void) fprintf(stderr, "%s: zone_info field is invalid\n",
121 128 progname);
122 129 zone_info[0] = 0;
123 130 zone_lag[0] = 0;
124 131 return (1);
125 132 }
126 133 if (zone_lag[0] == 0) {
127 134 (void) fprintf(stderr, "%s: zone_lag field is invalid\n",
128 135 progname);
129 136 zone_lag[0] = 0;
130 137 return (1);
131 138 }
132 139 if ((lag_hrs < -24) || (lag_hrs > 24)) {
133 140 (void) fprintf(stderr, "%s: a GMT lag of %d is out of range\n",
134 141 progname, lag_hrs);
135 142 zone_info[0] = 0;
136 143 zone_lag[0] = 0;
137 144 return (1);
138 145 }
139 146 if (debug)
140 147 (void) fprintf(stderr, "zone_info = %s, zone_lag = %s\n",
141 148 zone_info, zone_lag);
142 149 if (debug)
143 150 (void) fprintf(stderr, "lag (decimal) is %d\n", lag);
144 151
145 152 (void) fclose(zonefptr);
146 153 zonefptr = NULL;
147 154 return (0);
148 155 }
↓ open down ↓ |
63 lines elided |
↑ open up ↑ |
149 156
150 157 void
151 158 display_zone_string(void)
152 159 {
153 160 if (open_zonefile() == 0)
154 161 (void) printf("%s\n", zone_info);
155 162 else
156 163 (void) printf("GMT\n");
157 164 }
158 165
159 -long
160 -set_zone(char *zone_string)
166 +int
167 +get_local(char *z)
161 168 {
162 169 struct tm *tm;
163 - long current_lag;
164 170
165 - (void) umask(0022);
166 - if ((zonefptr = fopen(zonefile, "w")) == NULL) {
167 - (void) fprintf(stderr, "%s: cannot open %s: errno = %d\n",
168 - progname, zonefile, errno);
169 - return (0);
170 - }
171 -
172 171 tz[3] = 0;
173 - (void) strncat(tz, zone_string, 253);
172 + (void) strncat(tz, z, 253);
174 173 if (debug)
175 174 (void) fprintf(stderr, "Time Zone string is '%s'\n", tz);
176 175
177 176 (void) putenv(tz);
178 177 if (debug)
179 178 (void) system("env | grep TZ");
180 179
181 180 (void) time(&clock_val);
182 181
183 182 tm = localtime(&clock_val);
184 - current_lag = tm->tm_isdst ? altzone : timezone;
183 + return (tm->tm_isdst);
184 +}
185 +
186 +long
187 +set_zone(char *zone_string)
188 +{
189 + int isdst;
190 + long current_lag;
191 +
192 + (void) umask(0022);
193 + if ((zonefptr = fopen(zonefile, "w")) == NULL) {
194 + (void) fprintf(stderr, "%s: cannot open %s: errno = %d\n",
195 + progname, zonefile, errno);
196 + return (0);
197 + }
198 +
199 + switch (rtc_mode) {
200 + case M_VAR:
201 + isdst = get_local(zone_string);
202 + current_lag = isdst ? altzone : timezone;
203 + break;
204 + case M_STD:
205 + isdst = get_local(zone_string);
206 + current_lag = timezone;
207 + break;
208 + default: /* Includes M_UTC */
209 + isdst = 0;
210 + current_lag = 0;
211 + zone_string = utc_zone;
212 + break;
213 + }
185 214 if (debug)
186 - (void) printf("%s DST. Lag is %ld.\n", tm->tm_isdst ? "Is" :
187 - "Is NOT", tm->tm_isdst ? altzone : timezone);
215 + (void) printf("%s DST. Lag is %ld.\n", isdst ? "Is" :
216 + "Is NOT", current_lag);
188 217
189 218 (void) fprintf(zonefptr, zone_comment, zonefile);
190 219 (void) fprintf(zonefptr, "zone_info=%s\n", zone_string);
191 - (void) fprintf(zonefptr, "zone_lag=%ld\n",
192 - tm->tm_isdst ? altzone : timezone);
220 + (void) fprintf(zonefptr, "zone_lag=%ld\n", current_lag);
193 221 (void) fclose(zonefptr);
194 222 zonefptr = NULL;
195 223 return (current_lag);
196 224 }
197 225
198 226 void
199 227 correct_rtc_and_lag()
200 228 {
201 - struct tm *tm;
229 + int isdst;
202 230 long kernels_lag;
203 231 long current_lag;
204 232
205 233 if (open_zonefile())
206 234 return;
207 235
208 - tz[3] = 0;
209 - (void) strncat(tz, zone_info, 253);
210 - if (debug)
211 - (void) fprintf(stderr, "Time Zone string is '%s'\n", tz);
236 + switch (rtc_mode) {
237 + case M_VAR:
238 + isdst = get_local(zone_info);
239 + current_lag = isdst ? altzone : timezone;
240 + break;
241 + case M_STD:
242 + (void) get_local(zone_info);
243 + current_lag = timezone;
244 + break;
245 + default: /* Includes M_UTC */
246 + current_lag = 0;
247 + break;
248 + }
212 249
213 - (void) putenv(tz);
214 - if (debug)
215 - (void) system("env | grep TZ");
216 -
217 - (void) time(&clock_val);
218 - tm = localtime(&clock_val);
219 - current_lag = tm->tm_isdst ? altzone : timezone;
220 -
221 250 if (current_lag != lag) { /* if file is wrong */
222 251 if (debug)
223 - (void) fprintf(stderr, "correcting file");
252 + (void) fprintf(stderr, "correcting file\n");
224 253 (void) set_zone(zone_info); /* then rewrite file */
225 254 }
226 255
227 256 (void) sysi86(GGMTL, &kernels_lag);
228 257 if (current_lag != kernels_lag) {
229 258 if (debug)
230 - (void) fprintf(stderr, "correcting kernel's lag");
259 + (void) fprintf(stderr, "correcting kernel's lag\n");
231 260 (void) sysi86(SGMTL, current_lag); /* correct the lag */
232 261 (void) sysi86(WTODC); /* set the rtc to */
233 262 /* new local time */
234 263 }
235 264 }
236 265
237 266 void
238 267 initialize_zone(char *zone_string)
239 268 {
240 269 long current_lag;
241 270
242 271 /* write the config file */
243 272 current_lag = set_zone(zone_string);
244 273
245 274 /* correct the lag */
246 275 (void) sysi86(SGMTL, current_lag);
247 276
248 277 /*
249 278 * set the unix time from the rtc,
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
250 279 * assuming the rtc was the correct
251 280 * local time.
252 281 */
253 282 (void) sysi86(RTCSYNC);
254 283 }
255 284
256 285 void
257 286 usage()
258 287 {
259 288 static char Usage[] = "Usage:\n\
260 -rtc [-c] [-z time_zone] [-?]\n";
289 +rtc [-w] [-s|-u|-v] [-c] [-z time_zone] [-?]\n";
261 290
262 291 (void) fprintf(stderr, Usage);
263 292 }
264 293
265 294 void
266 295 verbose_usage()
267 296 {
268 297 static char Usage1[] = "\
269 298 Options:\n\
299 + -w\t\tDoes nothing.\n\
300 + -s\t\tRTC runs in local standard time.\n\
301 + -u\t\tRTC runs in UTC time.\n\
302 + -v\t\tRTC tracks local time (with cron command).\n\
270 303 -c\t\tCheck and correct for daylight savings time rollover.\n\
271 304 -z [zone]\tRecord the zone info in the config file.\n";
272 305
273 306 (void) fprintf(stderr, Usage1);
274 307 }
275 308
309 +void
310 +set_default()
311 +{
312 + switch (rtc_mode) {
313 + default: /* Includes M_UNSET */
314 + rtc_mode = M_VAR;
315 + break;
316 + case M_VAR:
317 + /*FALLTHROUGH*/
318 + case M_UTC:
319 + /*FALLTHROUGH*/
320 + case M_STD:
321 + break;
322 + }
323 +}
324 +
325 +void
326 +check_mode(int letter, int mode)
327 +{
328 + if (rtc_mode == M_UNSET || rtc_mode == mode) {
329 + rtc_mode = mode;
330 + return;
331 + }
332 + (void) fprintf(stderr, "%s: option -%c conflicts with other options\n",
333 + progname, letter);
334 + exit(1);
335 +}
336 +
337 +
276 338 int
277 339 main(int argc, char *argv[])
278 340 {
279 341 int c;
342 + int cflg = 0;
343 + char *zone_name = NULL;
280 344
281 345 progname = argv[0];
282 346
283 347 if (argc == 1) {
284 348 errors_ok = 1;
285 349 display_zone_string();
350 + exit(0);
286 351 }
287 352
288 - while ((c = getopt(argc, argv, "cz:d")) != EOF) {
353 + while ((c = getopt(argc, argv, "suvwcz:d")) != EOF) {
289 354 switch (c) {
290 355 case 'c':
291 - correct_rtc_and_lag();
356 + cflg++;
292 357 continue;
293 358 case 'z':
294 - initialize_zone(optarg);
359 + zone_name = optarg;
295 360 continue;
296 361 case 'd':
297 362 debug = 1;
298 363 continue;
364 + case 's': /* standard: RTC runs local standard time */
365 + check_mode(c, M_STD);
366 + continue;
367 + case 'u': /* utc: RTC runs UTC time */
368 + check_mode(c, M_UTC);
369 + continue;
370 + case 'v': /* varies: RTC tracks local time */
371 + check_mode(c, M_VAR);
372 + continue;
373 + case 'w': /* Does nothing */
374 + continue;
299 375 case '?':
300 376 verbose_usage();
301 - return (0);
377 + exit(0);
302 378 default:
303 379 usage();
304 - return (1);
380 + exit(1);
305 381 }
306 382 }
307 - return (0);
383 + set_default();
384 + if (zone_name != NULL)
385 + initialize_zone(zone_name);
386 + if (cflg > 0)
387 + correct_rtc_and_lag();
388 + exit(0);
389 + /*LINTED*/
308 390 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX