1 /* $OpenBSD: eehandlers.c,v 1.12 2004/08/01 18:32:17 deraadt Exp $ */
2 /* $NetBSD: eehandlers.c,v 1.2 1996/02/28 01:13:22 thorpej Exp $ */
3
4 /*-
5 * Copyright (c) 1996 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
31 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 #include <sys/types.h>
41 #include <ctype.h>
42 #include <err.h>
43 #include <errno.h>
44 #include <fcntl.h>
45 #include <string.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <time.h>
50 #include <unistd.h>
51
52 #include <machine/eeprom.h>
53 #ifdef __sparc__
54 #include <machine/openpromio.h>
55 #endif /* __sparc__ */
56
57 #include "defs.h"
58
59 extern char *path_eeprom;
60 extern int eval;
61 extern int update_checksums;
62 extern int ignore_checksum;
63 extern int fix_checksum;
64 extern int cksumfail;
65 extern u_short writecount;
66
67 struct timeb;
68 extern time_t get_date(char *, struct timeb *);
69
70 static char err_str[BUFSIZE];
71
72 static void badval(struct keytabent *, char *);
73 static int doio(struct keytabent *, u_char *, ssize_t, int);
74
75 #define BARF(kt) { \
76 badval((kt), arg); \
77 ++eval; \
78 return; \
79 }
80
81 #define FAILEDREAD(kt) { \
82 warnx("%s", err_str); \
83 warnx("failed to read field `%s'", (kt)->kt_keyword); \
84 ++eval; \
85 return; \
86 }
87
88 #define FAILEDWRITE(kt) { \
89 warnx("%s", err_str); \
90 warnx("failed to update field `%s'", (kt)->kt_keyword); \
91 ++eval; \
92 return; \
93 }
94
95 void
ee_hwupdate(struct keytabent * ktent,char * arg)96 ee_hwupdate(struct keytabent *ktent, char *arg)
97 {
98 time_t t;
99 char *cp, *cp2;
100
101 if (arg) {
102 if ((strcmp(arg, "now") == 0) ||
103 (strcmp(arg, "today") == 0)) {
104 if ((t = time(NULL)) == (time_t)(-1)) {
105 warnx("can't get current time");
106 ++eval;
107 return;
108 }
109 } else
110 if ((t = get_date(arg, NULL)) == (time_t)(-1))
111 BARF(ktent);
112
113 if (doio(ktent, (u_char *)&t, sizeof(t), IO_WRITE))
114 FAILEDWRITE(ktent);
115 } else
116 if (doio(ktent, (u_char *)&t, sizeof(t), IO_READ))
117 FAILEDREAD(ktent);
118
119 cp = ctime(&t);
120 if ((cp2 = strrchr(cp, '\n')) != NULL)
121 *cp2 = '\0';
122
123 printf("%s=%d (%s)\n", ktent->kt_keyword, t, cp);
124 }
125
126 void
ee_num8(struct keytabent * ktent,char * arg)127 ee_num8(struct keytabent *ktent, char *arg)
128 {
129 u_char num8 = 0;
130 u_int num32;
131 int i;
132
133 if (arg) {
134 for (i = 0; i < (strlen(arg) - 1); ++i)
135 if (!isdigit(arg[i]))
136 BARF(ktent);
137 num32 = atoi(arg);
138 if (num32 > 0xff)
139 BARF(ktent);
140 num8 += num32;
141 if (doio(ktent, &num8, sizeof(num8), IO_WRITE))
142 FAILEDWRITE(ktent);
143 } else
144 if (doio(ktent, &num8, sizeof(num8), IO_READ))
145 FAILEDREAD(ktent);
146
147 printf("%s=%d\n", ktent->kt_keyword, num8);
148 }
149
150 void
ee_num16(struct keytabent * ktent,char * arg)151 ee_num16(struct keytabent *ktent, char *arg)
152 {
153 u_int16_t num16 = 0;
154 u_int num32;
155 int i;
156
157 if (arg) {
158 for (i = 0; i < (strlen(arg) - 1); ++i)
159 if (!isdigit(arg[i]))
160 BARF(ktent);
161 num32 = atoi(arg);
162 if (num32 > 0xffff)
163 BARF(ktent);
164 num16 += num32;
165 if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_WRITE))
166 FAILEDWRITE(ktent);
167 } else
168 if (doio(ktent, (u_char *)&num16, sizeof(num16), IO_READ))
169 FAILEDREAD(ktent);
170
171 printf("%s=%d\n", ktent->kt_keyword, num16);
172 }
173
174 #ifndef __sparc64__
175 static struct strvaltabent scrsizetab[] = {
176 { "640x480", EED_SCR_640X480 },
177 { "1152x900", EED_SCR_1152X900 },
178 { "1024x1024", EED_SCR_1024X1024 },
179 { "1600x1280", EED_SCR_1600X1280 },
180 { "1280x1024", EED_SCR_1280X1024 },
181 { "1440x1440", EED_SCR_1440X1440 },
182 { NULL, 0 },
183 };
184
185 void
ee_screensize(struct keytabent * ktent,char * arg)186 ee_screensize(struct keytabent *ktent, char *arg)
187 {
188 struct strvaltabent *svp;
189 u_char scsize;
190
191 if (arg) {
192 for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
193 if (strcmp(svp->sv_str, arg) == 0)
194 break;
195 if (svp->sv_str == NULL)
196 BARF(ktent);
197
198 scsize = svp->sv_val;
199 if (doio(ktent, &scsize, sizeof(scsize), IO_WRITE))
200 FAILEDWRITE(ktent);
201 } else {
202 if (doio(ktent, &scsize, sizeof(scsize), IO_READ))
203 FAILEDREAD(ktent);
204
205 for (svp = scrsizetab; svp->sv_str != NULL; ++svp)
206 if (svp->sv_val == scsize)
207 break;
208 if (svp->sv_str == NULL) {
209 warnx("unknown %s value %d", ktent->kt_keyword,
210 scsize);
211 return;
212 }
213 }
214 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
215 }
216 #endif
217
218 static struct strvaltabent truthtab[] = {
219 { "true", EE_TRUE },
220 { "false", EE_FALSE },
221 { NULL, 0 },
222 };
223
224 void
ee_truefalse(struct keytabent * ktent,char * arg)225 ee_truefalse(struct keytabent *ktent, char *arg)
226 {
227 struct strvaltabent *svp;
228 u_char truth;
229
230 if (arg) {
231 for (svp = truthtab; svp->sv_str != NULL; ++svp)
232 if (strcmp(svp->sv_str, arg) == 0)
233 break;
234 if (svp->sv_str == NULL)
235 BARF(ktent);
236
237 truth = svp->sv_val;
238 if (doio(ktent, &truth, sizeof(truth), IO_WRITE))
239 FAILEDWRITE(ktent);
240 } else {
241 if (doio(ktent, &truth, sizeof(truth), IO_READ))
242 FAILEDREAD(ktent);
243
244 for (svp = truthtab; svp->sv_str != NULL; ++svp)
245 if (svp->sv_val == truth)
246 break;
247 if (svp->sv_str == NULL) {
248 warnx("unknown truth value 0x%x for %s", truth,
249 ktent->kt_keyword);
250 return;
251 }
252 }
253 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
254 }
255
256 void
ee_bootdev(struct keytabent * ktent,char * arg)257 ee_bootdev(struct keytabent *ktent, char *arg)
258 {
259 u_char dev[5];
260 int i;
261 size_t arglen;
262 char *cp;
263
264 if (arg) {
265 /*
266 * The format of the string we accept is the following:
267 * cc(n,n,n)
268 * where:
269 * c -- an alphabetical character [a-z]
270 * n -- a number in hexadecimal, between 0 and ff,
271 * with no leading `0x'.
272 */
273 arglen = strlen(arg);
274 if (arglen < 9 || arglen > 12 || arg[2] != '(' ||
275 arg[arglen - 1] != ')')
276 BARF(ktent);
277
278 /* Handle the first 2 letters. */
279 for (i = 0; i < 2; ++i) {
280 if (arg[i] < 'a' || arg[i] > 'z')
281 BARF(ktent);
282 dev[i] = (u_char)arg[i];
283 }
284
285 /* Handle the 3 `0x'-less hex values. */
286 cp = &arg[3];
287 for (i = 2; i < 5; ++i) {
288 if (*cp == '\0')
289 BARF(ktent);
290
291 if (*cp >= '0' && *cp <= '9')
292 dev[i] = *cp++ - '0';
293 else if (*cp >= 'a' && *cp <= 'f')
294 dev[i] = 10 + (*cp++ - 'a');
295 else
296 BARF(ktent);
297
298 /* Deal with a second digit. */
299 if (*cp >= '0' && *cp <= '9') {
300 dev[i] <<= 4;
301 dev[i] &= 0xf0;
302 dev[i] += *cp++ - '0';
303 } else if (*cp >= 'a' && *cp <= 'f') {
304 dev[i] <<= 4;
305 dev[i] &= 0xf0;
306 dev[i] += 10 + (*cp++ - 'a');
307 }
308
309 /* Ensure we have the correct delimiter. */
310 if ((*cp == ',' && i < 4) || (*cp == ')' && i == 4)) {
311 ++cp;
312 continue;
313 } else
314 BARF(ktent);
315 }
316 if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_WRITE))
317 FAILEDWRITE(ktent);
318 } else
319 if (doio(ktent, (u_char *)&dev[0], sizeof(dev), IO_READ))
320 FAILEDREAD(ktent);
321
322 printf("%s=%c%c(%x,%x,%x)\n", ktent->kt_keyword, dev[0],
323 dev[1], dev[2], dev[3], dev[4]);
324 }
325
326 void
ee_kbdtype(struct keytabent * ktent,char * arg)327 ee_kbdtype(struct keytabent *ktent, char *arg)
328 {
329 u_char kbd = 0;
330 u_int kbd2;
331 int i;
332
333 if (arg) {
334 for (i = 0; i < (strlen(arg) - 1); ++i)
335 if (!isdigit(arg[i]))
336 BARF(ktent);
337 kbd2 = atoi(arg);
338 if (kbd2 > 0xff)
339 BARF(ktent);
340 kbd += kbd2;
341 if (doio(ktent, &kbd, sizeof(kbd), IO_WRITE))
342 FAILEDWRITE(ktent);
343 } else
344 if (doio(ktent, &kbd, sizeof(kbd), IO_READ))
345 FAILEDREAD(ktent);
346
347 printf("%s=%d (%s)\n", ktent->kt_keyword, kbd, kbd ? "other" : "Sun");
348 }
349
350 #ifndef __sparc64__
351 static struct strvaltabent constab[] = {
352 { "b&w", EED_CONS_BW },
353 { "ttya", EED_CONS_TTYA },
354 { "ttyb", EED_CONS_TTYB },
355 { "color", EED_CONS_COLOR },
356 { "p4opt", EED_CONS_P4 },
357 { NULL, 0 },
358 };
359
360 void
ee_constype(struct keytabent * ktent,char * arg)361 ee_constype(struct keytabent *ktent, char *arg)
362 {
363 struct strvaltabent *svp;
364 u_char cons;
365
366 if (arg) {
367 for (svp = constab; svp->sv_str != NULL; ++svp)
368 if (strcmp(svp->sv_str, arg) == 0)
369 break;
370 if (svp->sv_str == NULL)
371 BARF(ktent);
372
373 cons = svp->sv_val;
374 if (doio(ktent, &cons, sizeof(cons), IO_WRITE))
375 FAILEDWRITE(ktent);
376 } else {
377 if (doio(ktent, &cons, sizeof(cons), IO_READ))
378 FAILEDREAD(ktent);
379
380 for (svp = constab; svp->sv_str != NULL; ++svp)
381 if (svp->sv_val == cons)
382 break;
383 if (svp->sv_str == NULL) {
384 warnx("unknown type 0x%x for %s", cons,
385 ktent->kt_keyword);
386 return;
387 }
388 }
389 printf("%s=%s\n", ktent->kt_keyword, svp->sv_str);
390
391 }
392 #endif
393
394 void
ee_diagpath(struct keytabent * ktent,char * arg)395 ee_diagpath(struct keytabent *ktent, char *arg)
396 {
397 char path[40];
398
399 bzero(path, sizeof(path));
400 if (arg) {
401 if (strlen(arg) > sizeof(path))
402 BARF(ktent);
403 snprintf(path, sizeof path, arg);
404 if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_WRITE))
405 FAILEDWRITE(ktent);
406 } else
407 if (doio(ktent, (u_char *)&path[0], sizeof(path), IO_READ))
408 FAILEDREAD(ktent);
409
410 printf("%s=%s\n", ktent->kt_keyword, path);
411 }
412
413 void
ee_banner(struct keytabent * ktent,char * arg)414 ee_banner(struct keytabent *ktent, char *arg)
415 {
416 char string[80];
417 u_char enable;
418 struct keytabent kt;
419
420 kt.kt_keyword = "enable_banner";
421 kt.kt_offset = EE_BANNER_ENABLE_LOC;
422 kt.kt_handler = ee_notsupp;
423
424 bzero(string, sizeof(string));
425 if (arg) {
426 if (strlen(arg) > sizeof(string))
427 BARF(ktent);
428 if (*arg != '\0') {
429 enable = EE_TRUE;
430 snprintf(string, sizeof string, arg);
431 if (doio(ktent, (u_char *)string,
432 sizeof(string), IO_WRITE))
433 FAILEDWRITE(ktent);
434 } else {
435 enable = EE_FALSE;
436 if (doio(ktent, (u_char *)string,
437 sizeof(string), IO_READ))
438 FAILEDREAD(ktent);
439 }
440
441 if (doio(&kt, &enable, sizeof(enable), IO_WRITE))
442 FAILEDWRITE(&kt);
443 } else {
444 if (doio(ktent, (u_char *)string, sizeof(string), IO_READ))
445 FAILEDREAD(ktent);
446 if (doio(&kt, &enable, sizeof(enable), IO_READ))
447 FAILEDREAD(&kt);
448 }
449 printf("%s=%s (%s)\n", ktent->kt_keyword, string,
450 enable == EE_TRUE ? "enabled" : "disabled");
451 }
452
453 /* ARGSUSED */
454 void
ee_notsupp(struct keytabent * ktent,char * arg)455 ee_notsupp(struct keytabent *ktent, char *arg)
456 {
457
458 warnx("field `%s' not yet supported", ktent->kt_keyword);
459 }
460
461 static void
badval(struct keytabent * ktent,char * arg)462 badval(struct keytabent *ktent, char *arg)
463 {
464
465 warnx("inappropriate value `%s' for field `%s'", arg,
466 ktent->kt_keyword);
467 }
468
469 static int
doio(struct keytabent * ktent,u_char * buf,ssize_t len,int wr)470 doio(struct keytabent *ktent, u_char *buf, ssize_t len, int wr)
471 {
472 int fd, rval = 0;
473 u_char *buf2;
474
475 buf2 = (u_char *)calloc(1, len);
476 if (buf2 == NULL) {
477 snprintf(err_str, sizeof err_str, "memory allocation failed");
478 return (1);
479 }
480
481 fd = open(path_eeprom, wr == IO_WRITE ? O_RDWR : O_RDONLY, 0640);
482 if (fd < 0) {
483 snprintf(err_str, sizeof err_str, "open: %s: %s", path_eeprom,
484 strerror(errno));
485 free(buf2);
486 return (1);
487 }
488
489 if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
490 snprintf(err_str, sizeof err_str, "lseek: %s: %s", path_eeprom,
491 strerror(errno));
492 rval = 1;
493 goto done;
494 }
495
496 if (read(fd, buf2, len) != len) {
497 snprintf(err_str, sizeof err_str, "read: %s: %s", path_eeprom,
498 strerror(errno));
499 return (1);
500 }
501
502 if (wr == IO_WRITE) {
503 if (bcmp(buf, buf2, len) == 0)
504 goto done;
505
506 if (lseek(fd, (off_t)ktent->kt_offset, SEEK_SET) < (off_t)0) {
507 snprintf(err_str, sizeof err_str, "lseek: %s: %s",
508 path_eeprom, strerror(errno));
509 rval = 1;
510 goto done;
511 }
512
513 ++update_checksums;
514 if (write(fd, buf, len) < 0) {
515 snprintf(err_str, sizeof err_str, "write: %s: %s",
516 path_eeprom, strerror(errno));
517 rval = 1;
518 goto done;
519 }
520 } else
521 memmove(buf, buf2, len);
522
523 done:
524 free(buf2);
525 (void)close(fd);
526 return (rval);
527 }
528
529 /*
530 * Read from eeLastHwUpdate to just before eeReserved. Calculate
531 * a checksum, and deposit 3 copies of it sequentially starting at
532 * eeChecksum[0]. Increment the write count, and deposit 3 copies
533 * of it sequentially starting at eeWriteCount[0].
534 */
535 void
ee_updatechecksums(void)536 ee_updatechecksums(void)
537 {
538 struct keytabent kt;
539 u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
540 u_char checksum;
541 int i;
542
543 kt.kt_keyword = "eeprom contents";
544 kt.kt_offset = EE_HWUPDATE_LOC;
545 kt.kt_handler = ee_notsupp;
546
547 if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
548 cksumfail = 1;
549 FAILEDREAD(&kt);
550 }
551
552 checksum = ee_checksum(checkme, sizeof(checkme));
553
554 kt.kt_keyword = "eeprom checksum";
555 for (i = 0; i < 4; ++i) {
556 kt.kt_offset = EE_CKSUM_LOC + (i * sizeof(checksum));
557 if (doio(&kt, &checksum, sizeof(checksum), IO_WRITE)) {
558 cksumfail = 1;
559 FAILEDWRITE(&kt);
560 }
561 }
562
563 kt.kt_keyword = "eeprom writecount";
564 for (i = 0; i < 4; ++i) {
565 kt.kt_offset = EE_WC_LOC + (i * sizeof(writecount));
566 if (doio(&kt, (u_char *)&writecount, sizeof(writecount),
567 IO_WRITE)) {
568 cksumfail = 1;
569 FAILEDWRITE(&kt);
570 }
571 }
572 }
573
574 void
ee_verifychecksums(void)575 ee_verifychecksums(void)
576 {
577 struct keytabent kt;
578 u_char checkme[EE_SIZE - EE_HWUPDATE_LOC];
579 u_char checksum, ochecksum[3];
580 u_short owritecount[3];
581
582 /*
583 * Verify that the EEPROM's write counts match, and update the
584 * global copy for use later.
585 */
586 kt.kt_keyword = "eeprom writecount";
587 kt.kt_offset = EE_WC_LOC;
588 kt.kt_handler = ee_notsupp;
589
590 if (doio(&kt, (u_char *)&owritecount, sizeof(owritecount), IO_READ)) {
591 cksumfail = 1;
592 FAILEDREAD(&kt);
593 }
594
595 if (owritecount[0] != owritecount[1] ||
596 owritecount[0] != owritecount[2]) {
597 warnx("eeprom writecount mismatch %s",
598 ignore_checksum ? "(ignoring)" :
599 (fix_checksum ? "(fixing)" : ""));
600
601 if (!ignore_checksum && !fix_checksum) {
602 cksumfail = 1;
603 return;
604 }
605
606 writecount = MAXIMUM(owritecount[0], owritecount[1]);
607 writecount = MAXIMUM(writecount, owritecount[2]);
608 } else
609 writecount = owritecount[0];
610
611 /*
612 * Verify that the EEPROM's checksums match and are correct.
613 */
614 kt.kt_keyword = "eeprom checksum";
615 kt.kt_offset = EE_CKSUM_LOC;
616
617 if (doio(&kt, ochecksum, sizeof(ochecksum), IO_READ)) {
618 cksumfail = 1;
619 FAILEDREAD(&kt);
620 }
621
622 if (ochecksum[0] != ochecksum[1] ||
623 ochecksum[0] != ochecksum[2]) {
624 warnx("eeprom checksum mismatch %s",
625 ignore_checksum ? "(ignoring)" :
626 (fix_checksum ? "(fixing)" : ""));
627
628 if (!ignore_checksum && !fix_checksum) {
629 cksumfail = 1;
630 return;
631 }
632 }
633
634 kt.kt_keyword = "eeprom contents";
635 kt.kt_offset = EE_HWUPDATE_LOC;
636
637 if (doio(&kt, checkme, sizeof(checkme), IO_READ)) {
638 cksumfail = 1;
639 FAILEDREAD(&kt);
640 }
641
642 checksum = ee_checksum(checkme, sizeof(checkme));
643
644 if (ochecksum[0] != checksum) {
645 warnx("eeprom checksum incorrect %s",
646 ignore_checksum ? "(ignoring)" :
647 (fix_checksum ? "(fixing)" : ""));
648
649 if (!ignore_checksum && !fix_checksum) {
650 cksumfail = 1;
651 return;
652 }
653 }
654
655 if (fix_checksum)
656 ee_updatechecksums();
657 }
658
659 u_char
ee_checksum(u_char * area,size_t len)660 ee_checksum(u_char *area, size_t len)
661 {
662 u_char sum = 0;
663
664 while (len--)
665 sum += *area++;
666
667 return (0x100 - sum);
668 }
669