1 | /* setime - set the system time from the real time clock
|
---|
2 | Authors: T. Holm & E. Froese
|
---|
3 | Adapted by: Jorrit .N. Herder */
|
---|
4 |
|
---|
5 | /************************************************************************/
|
---|
6 | /* Readclock was updated for security reasons: openeing /dev/mem no */
|
---|
7 | /* longer automatically grants I/O privileges to the calling process */
|
---|
8 | /* so that the CMOS' clock could not be read from this program. The */
|
---|
9 | /* new approach is to rely on the FS to do the CMOS I/O, via the new */
|
---|
10 | /* system call CMOSTIME (which only reads the current clock value and */
|
---|
11 | /* cannot update the CMOS clock). */
|
---|
12 | /* The original readclock.c is still available under backup.c. */
|
---|
13 | /************************************************************************/
|
---|
14 | /* */
|
---|
15 | /* readclock.c */
|
---|
16 | /* */
|
---|
17 | /* Read the clock value from the 64 byte CMOS RAM */
|
---|
18 | /* area, then set system time. */
|
---|
19 | /* */
|
---|
20 | /* If the machine ID byte is 0xFC or 0xF8, the device */
|
---|
21 | /* /dev/mem exists and can be opened for reading, */
|
---|
22 | /* and no errors in the CMOS RAM are reported by the */
|
---|
23 | /* RTC, then the time is read from the clock RAM */
|
---|
24 | /* area maintained by the RTC. */
|
---|
25 | /* */
|
---|
26 | /* The clock RAM values are decoded and fed to mktime */
|
---|
27 | /* to make a time_t value, then stime(2) is called. */
|
---|
28 | /* */
|
---|
29 | /* This fails if: */
|
---|
30 | /* */
|
---|
31 | /* If the machine ID does not match 0xFC or 0xF8 (no */
|
---|
32 | /* error message.) */
|
---|
33 | /* */
|
---|
34 | /* If the machine ID is 0xFC or 0xF8 and /dev/mem */
|
---|
35 | /* is missing, or cannot be accessed. */
|
---|
36 | /* */
|
---|
37 | /* If the RTC reports errors in the CMOS RAM. */
|
---|
38 | /* */
|
---|
39 | /************************************************************************/
|
---|
40 | /* origination 1987-Dec-29 efth */
|
---|
41 | /* robustness 1990-Oct-06 C. Sylvain */
|
---|
42 | /* incorp. B. Evans ideas 1991-Jul-06 C. Sylvain */
|
---|
43 | /* set time & calibrate 1992-Dec-17 Kees J. Bot */
|
---|
44 | /* clock timezone 1993-Oct-10 Kees J. Bot */
|
---|
45 | /* set CMOS clock 1994-Jun-12 Kees J. Bot */
|
---|
46 | /* removed set CMOS 2004-Sep-06 Jorrit N. Herder */
|
---|
47 | /************************************************************************/
|
---|
48 |
|
---|
49 | #include <minix/callnr.h>
|
---|
50 | #include <minix/config.h>
|
---|
51 | #include <minix/type.h>
|
---|
52 | #include <minix/const.h>
|
---|
53 | #include <minix/com.h>
|
---|
54 | #include <minix/syslib.h>
|
---|
55 |
|
---|
56 | #include <sys/types.h>
|
---|
57 | #include <sys/stat.h>
|
---|
58 | #include <sys/ioc_cmos.h>
|
---|
59 | #include <stdlib.h>
|
---|
60 | #include <unistd.h>
|
---|
61 | #include <fcntl.h>
|
---|
62 | #include <stdio.h>
|
---|
63 | #include <string.h>
|
---|
64 | #include <time.h>
|
---|
65 | #include <errno.h>
|
---|
66 | #include <signal.h>
|
---|
67 | #include <ibm/portio.h>
|
---|
68 | #include <ibm/cmos.h>
|
---|
69 | #include <sys/svrctl.h>
|
---|
70 |
|
---|
71 | #define MAX_RETRIES 1
|
---|
72 |
|
---|
73 | int nflag = 0; /* Tell what, but don't do it. */
|
---|
74 | int y2kflag = 0; /* Interpret 1980 as 2000 for clock with Y2K bug. */
|
---|
75 |
|
---|
76 | char clocktz[128]; /* Timezone of the clock. */
|
---|
77 |
|
---|
78 | #define MACH_ID_ADDR 0xFFFFE /* BIOS Machine ID at FFFF:000E */
|
---|
79 |
|
---|
80 | #define PC_AT 0xFC /* Machine ID byte for PC/AT,
|
---|
81 | PC/XT286, and PS/2 Models 50, 60 */
|
---|
82 | #define PS_386 0xF8 /* Machine ID byte for PS/2 Model 80 */
|
---|
83 |
|
---|
84 | /* Manufacturers usually use the ID value of the IBM model they emulate.
|
---|
85 | * However some manufacturers, notably HP and COMPAQ, have had different
|
---|
86 | * ideas in the past.
|
---|
87 | *
|
---|
88 | * Machine ID byte information source:
|
---|
89 | * _The Programmer's PC Sourcebook_ by Thom Hogan,
|
---|
90 | * published by Microsoft Press
|
---|
91 | */
|
---|
92 |
|
---|
93 | void errmsg(char *s);
|
---|
94 | int bcd_to_dec(int n);
|
---|
95 | int dec_to_bcd(int n);
|
---|
96 | void usage(void);
|
---|
97 |
|
---|
98 | #define CMOS_DEV "/dev/cmos"
|
---|
99 |
|
---|
100 | PUBLIC int main(int argc, char **argv)
|
---|
101 | {
|
---|
102 | int fd;
|
---|
103 | struct tm time1;
|
---|
104 | struct tm time2;
|
---|
105 | struct tm tmnow;
|
---|
106 | char date[64];
|
---|
107 | time_t now, rtc;
|
---|
108 | int i, s, mem;
|
---|
109 | unsigned char mach_id, cmos_state;
|
---|
110 | struct sysgetenv sysgetenv;
|
---|
111 | message m;
|
---|
112 | int request;
|
---|
113 |
|
---|
114 |
|
---|
115 | /* Process options. */
|
---|
116 | while (argc > 1) {
|
---|
117 | char *p = *++argv;
|
---|
118 |
|
---|
119 | if (*p++ != '-') usage();
|
---|
120 |
|
---|
121 | while (*p != 0) {
|
---|
122 | switch (*p++) {
|
---|
123 | case 'n': nflag = 1; break;
|
---|
124 | case '2': y2kflag = 1; break;
|
---|
125 | default: usage();
|
---|
126 | }
|
---|
127 | }
|
---|
128 | argc--;
|
---|
129 | }
|
---|
130 |
|
---|
131 | #if DEAD_CODE
|
---|
132 | /* The hardware clock may run in a different time zone, likely GMT or
|
---|
133 | * winter time. Select that time zone.
|
---|
134 | */
|
---|
135 | strcpy(clocktz, "TZ=");
|
---|
136 | sysgetenv.key = "TZ";
|
---|
137 | sysgetenv.keylen = 2+1;
|
---|
138 | sysgetenv.val = clocktz+3;
|
---|
139 | sysgetenv.vallen = sizeof(clocktz)-3;
|
---|
140 | if (svrctl(SYSGETENV, &sysgetenv) == 0) {
|
---|
141 | putenv(clocktz);
|
---|
142 | tzset();
|
---|
143 | }
|
---|
144 | #endif
|
---|
145 |
|
---|
146 | /* Read the CMOS real time clock. */
|
---|
147 | for (i = 0; i < MAX_RETRIES; i++) {
|
---|
148 |
|
---|
149 | /* sleep, unless first iteration */
|
---|
150 | if (i > 0) sleep(5);
|
---|
151 |
|
---|
152 | /* Open the CMOS device to read the system time. */
|
---|
153 | if ((fd = open(CMOS_DEV, O_RDONLY)) < 0) {
|
---|
154 | perror(CMOS_DEV);
|
---|
155 | fprintf(stderr, "Couldn't open CMOS device.\n");
|
---|
156 | exit(1);
|
---|
157 | }
|
---|
158 | request = (y2kflag) ? CIOCGETTIME : CIOCGETTIMEY2K;
|
---|
159 | if ((s=ioctl(fd, request, (void *) &time1)) < 0) {
|
---|
160 | perror("ioctl");
|
---|
161 | fprintf(stderr, "Couldn't do CMOS ioctl.\n");
|
---|
162 | exit(1);
|
---|
163 | }
|
---|
164 | close(fd);
|
---|
165 |
|
---|
166 | now = time(NULL);
|
---|
167 |
|
---|
168 | time1.tm_isdst = -1; /* Do timezone calculations. */
|
---|
169 | time2 = time1;
|
---|
170 |
|
---|
171 | rtc= mktime(&time1); /* Transform to a time_t. */
|
---|
172 | if (rtc != -1) {
|
---|
173 | break;
|
---|
174 | }
|
---|
175 |
|
---|
176 | fprintf(stderr,
|
---|
177 | "readclock: Invalid time read from CMOS RTC: %d-%02d-%02d %02d:%02d:%02d\n",
|
---|
178 | time2.tm_year+1900, time2.tm_mon+1, time2.tm_mday,
|
---|
179 | time2.tm_hour, time2.tm_min, time2.tm_sec);
|
---|
180 | }
|
---|
181 | if (i >= MAX_RETRIES) exit(1);
|
---|
182 |
|
---|
183 | /* Now set system time. */
|
---|
184 | if (nflag) {
|
---|
185 | printf("stime(%lu)\n", (unsigned long) rtc);
|
---|
186 | } else {
|
---|
187 | if (stime(&rtc) < 0) {
|
---|
188 | errmsg( "Not allowed to set time." );
|
---|
189 | exit(1);
|
---|
190 | }
|
---|
191 | }
|
---|
192 | tmnow = *localtime(&rtc);
|
---|
193 | if (strftime(date, sizeof(date),
|
---|
194 | "%a %b %d %H:%M:%S %Z %Y", &tmnow) != 0) {
|
---|
195 | if (date[8] == '0') date[8]= ' ';
|
---|
196 | #if 0
|
---|
197 | printf("%s [CMOS read via FS, see command/ibm/readclock.c]\n", date);
|
---|
198 | #endif
|
---|
199 | }
|
---|
200 | exit(0);
|
---|
201 | }
|
---|
202 |
|
---|
203 | void errmsg(char *s)
|
---|
204 | {
|
---|
205 | static char *prompt = "readclock: ";
|
---|
206 |
|
---|
207 | fprintf(stderr, "%s%s\n", prompt, s);
|
---|
208 | prompt = "";
|
---|
209 | }
|
---|
210 |
|
---|
211 |
|
---|
212 | int bcd_to_dec(int n)
|
---|
213 | {
|
---|
214 | return ((n >> 4) & 0x0F) * 10 + (n & 0x0F);
|
---|
215 | }
|
---|
216 |
|
---|
217 | int dec_to_bcd(int n)
|
---|
218 | {
|
---|
219 | return ((n / 10) << 4) | (n % 10);
|
---|
220 | }
|
---|
221 |
|
---|
222 | void usage(void)
|
---|
223 | {
|
---|
224 | fprintf(stderr, "Usage: settime [-n2]\n");
|
---|
225 | exit(1);
|
---|
226 | }
|
---|