|
|
1.1 root 1: /*
2: * ATclock.c
3: * 5/16/90
4: * ATclock - read or set the IBM AT real-time clock
5: * Usage: /etc/ATclock [YY[MM[DD[HH[MM[.SS]]]]]]
6: * cc -s -i -O -o ATclock ATclock.c ATclockas.s
7: *
8: * Prints the current date and time in format 'YYMMDDHHMM.SS'.
9: * Author: Allan Cornish, INETCO Systems, Nov 1984.
10: * Modifications (c) Copyright INETCO Systems Ltd. (1985)
11: *
12: * $Log: /usr/src.inetco/etc/ATclock.c,v $
13: * Revision 1.2 90/05/31 14:07:22 root
14: * steve 5/31/90
15: * Added sanity checking for values read from or written to clock;
16: * the old source allowed out of range values without complaint.
17: * Changed system call output to use stdio, bigger but saner.
18: * Changed spacing, rearranged code, added #defines for clarity.
19: *
20: * 86/07/16 Allan Cornish
21: * Validation of NVRAM contents is no longer performed. It checked
22: * fields which were unused, and could incorrectly report errors.
23: *
24: * 85/09/?? Krish Nair
25: * Modified so that the ATclock may be set.
26: * The "set" format must be 'YYMMDDHHMM.SS'.
27: * The "read" format is always of type 'YYMMDDHHMM.SS'.
28: */
29:
30: #include <stdio.h>
31:
32: #define USAGE "Usage: /etc/ATclock [YY[MM[DD[HH[MM[.SS]]]]]]\n"
33:
34: /* Offsets within clock memory. */
35: #define DIAG 14 /* Diagnostic port: bit(7) -> powerloss */
36: /* bit(2) -> bad time */
37: #define BADCLK 0x84
38: #define STAT 10 /* Status port: bit(7) -> updating */
39: #define UPDATE 0x80
40: #define YEAR 9
41: #define MON 8
42: #define DAY 7
43: #define HOUR 4
44: #define MIN 2
45: #define SEC 0
46:
47: /* Forward. */
48: int bcd();
49: void clock();
50: void clockcheck();
51: void fatal();
52: void sanity();
53: void set();
54: void usage();
55: /* ATclockas.s */
56: void sphi();
57: void splo();
58: int zget();
59: void zput();
60:
61: /* Globals. */
62: unsigned char clkbuf[10]; /* Clock image buffer (ten BCD digits). */
63:
64: main(argc, argv) int argc; char *argv[];
65: {
66: register char *a, *s;
67:
68: if (argc > 2)
69: usage();
70:
71: if (zget(DIAG) & BADCLK)
72: fatal("bad clock"); /* check for valid clock */
73: clock(0); /* read it to clkbuf[] */
74:
75: if (argc == 2) {
76: set(argv[1]); /* initialize clkbuf[] */
77: clock(1); /* and set the clock */
78: } else
79: clockcheck(); /* check clock */
80:
81: /* Print formatted date. */
82: printf("%d%d%d%d%d%d%d%d%d%d.%d%d\n",
83: clkbuf[YEAR] >> 4, clkbuf[YEAR] & 15,
84: clkbuf[MON] >> 4, clkbuf[MON] & 15,
85: clkbuf[DAY] >> 4, clkbuf[DAY] & 15,
86: clkbuf[HOUR] >> 4, clkbuf[HOUR] & 15,
87: clkbuf[MIN] >> 4, clkbuf[MIN] & 15,
88: clkbuf[SEC] >> 4, clkbuf[SEC] & 15
89: );
90: exit (0);
91: }
92:
93: /*
94: * Change a numeric character string into two bcd digits.
95: */
96: int
97: bcd(s) register char *s;
98: {
99: if (('0' <= s[0]) && (s[0] <= '9') && ('0' <= s[1]) && (s[1] <= '9'))
100: return (s[0] << 4) | (s[1] & 15);
101: fatal("argument contains nondigit");
102: }
103:
104: /*
105: * Check the clkbuf[] for sanity.
106: */
107: void
108: clockcheck()
109: {
110: sanity(YEAR, 0, 99, "year");
111: sanity(MON, 1, 12, "month");
112: sanity(DAY, 1, 31, "day");
113: sanity(HOUR, 0, 23, "hour");
114: sanity(MIN, 0, 59, "minute");
115: sanity(SEC, 0, 59, "second");
116: }
117:
118: /*
119: * Wait for clock to stabilize or timeout to occur, then read or set it.
120: */
121: void
122: clock(flag) register int flag;
123: {
124: register int i;
125:
126: i = 0;
127: do {
128: splo();
129: if (--i == 0)
130: fatal("bad clock");
131: sphi();
132: } while (zget(STAT) & UPDATE);
133:
134: if (flag == 0) {
135: /* Read the clock. */
136: for (i = 0; i < sizeof clkbuf; i++)
137: clkbuf[i] = zget(i);
138: } else {
139: /* Write the clock. */
140: for (i = 0; i < sizeof clkbuf; i++)
141: zput(i, clkbuf[i]);
142: }
143: splo();
144: }
145:
146: /*
147: * Cry and die.
148: */
149: void
150: fatal(args) char *args;
151: {
152: fprintf(stderr, "/etc/ATclock: %r\n", &args);
153: exit(1);
154: }
155:
156: /*
157: * Sanity check: make sure BCD clkbuf[i] is in the given range.
158: */
159: void
160: sanity(i, min, max, msg) register int i; int min, max; char *msg;
161: {
162: register int n;
163:
164: n = 10 * (clkbuf[i] >> 4) + (clkbuf[i] & 15);
165: if (n < min || n > max)
166: fatal("%s %d not in range %d to %d", msg, n, min, max);
167: }
168:
169: /*
170: * Set clkbuf[] according to the argument string.
171: */
172: void
173: set(s) register char *s;
174: {
175: register char *a;
176:
177: a = s + strlen(s);
178: if ((&a[-3] >= s) && (a[-3] == '.')) {
179: clkbuf[SEC] = bcd(a -= 2);
180: a--;
181: } else
182: clkbuf[SEC] = 0;
183: if (&a[-2] >= s)
184: clkbuf[MIN] = bcd(a -= 2);
185: if (&a[-2] >= s)
186: clkbuf[HOUR] = bcd(a -= 2);
187: if (&a[-2] >= s)
188: clkbuf[DAY] = bcd(a -= 2);
189: if (&a[-2] >= s)
190: clkbuf[MON] = bcd(a -= 2);
191: if (&a[-2] >= s)
192: clkbuf[YEAR] = bcd(a -= 2);
193: if (a != s)
194: usage();
195: clockcheck();
196: }
197:
198: /*
199: * Print a usage message and exit.
200: */
201: void
202: usage()
203: {
204: fprintf(stderr, USAGE);
205: exit(1);
206: }
207:
208: /* end of ATclock.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.