8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / eeprom / sparc / openprom.c
blob31043ea172a6d3358c6b729a487209bc8b26ecfc
1 /*
2 * Open Boot Prom eeprom utility
3 */
5 /*
6 * Copyright (c) 1991, 2010, Oracle and/or its affiliates. All rights reserved.
7 */
9 /*
10 * Copyright (c) 1983 Regents of the University of California.
11 * All rights reserved. The Berkeley software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #include <sys/types.h>
16 #include <sys/param.h>
17 #include <sys/openpromio.h>
18 #include <stdio.h>
19 #include <fcntl.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <unistd.h>
26 * Usage: % eeprom [-v] [-f promdev] [-]
27 * % eeprom [-v] [-f promdev] field[=value] ...
31 * 128 is the size of the largest (currently) property name buffer
32 * 8192 - MAXPROPSIZE - sizeof (int) is the size of the largest
33 * (currently) property value, viz. nvramrc.
34 * the sizeof(u_int) is from struct openpromio
37 #define MAXPROPSIZE 128
38 #define MAXNAMESIZE MAXPROPSIZE
39 #define MAXVALSIZE (8192 - MAXPROPSIZE - sizeof (uint_t))
40 #define BUFSIZE (MAXPROPSIZE + MAXVALSIZE + sizeof (uint_t))
41 typedef union {
42 char buf[BUFSIZE];
43 struct openpromio opp;
44 } Oppbuf;
46 extern int _error(int do_perror, char *fmt, ...);
47 extern void setpname(char *);
48 static int get_password(char *, int);
49 extern int loadlogo(char *, int, int, char *);
51 #define NO_PERROR 0
52 #define PERROR 1
54 static int prom_fd;
55 static char *promdev;
56 static int verbose;
58 static void do_var(char *);
59 static void dump_all();
60 static void print_one(char *);
61 static void set_one(char *, char *);
62 static void promclose();
63 static int promopen(int);
65 static int getpropval(struct openpromio *);
66 static int setpropval(struct openpromio *);
68 static char *badarchmsg = "Architecture does not support this command.\n";
70 typedef void (*func)();
73 /* We have to special-case two properties related to security */
74 static void i_secure();
75 static void i_passwd(), o_passwd();
76 static void i_oemlogo();
79 * It's unfortunate that we have to know the names of certain properties
80 * in this program (the whole idea of openprom was to avoid it), but at
81 * least we can isolate them to these defines here.
83 #define PASSWORD_PROPERTY "security-password"
84 #define MODE_PROPERTY "security-mode"
85 #define LOGO_PROPERTY "oem-logo"
86 #define PW_SIZE 8
89 * Unlike the old-style eeprom command, where every property needed an
90 * i_foo and an o_foo function, we only need them when the default case
91 * isn't sufficient.
93 static struct opvar {
94 char *name;
95 func in;
96 func out;
97 } opvar[] = {
98 #define e(n, i, o) {n, i, o}
99 e(MODE_PROPERTY, i_secure, (func)NULL),
100 e(PASSWORD_PROPERTY, i_passwd, o_passwd),
101 e(LOGO_PROPERTY, i_oemlogo, (func)NULL),
102 { (char *)NULL, (func)NULL, (func)NULL}
103 #undef e
108 * sun4c openprom
112 main(int argc, char **argv)
114 int c;
115 extern char *optarg;
116 extern int optind;
118 promdev = "/dev/openprom";
120 while ((c = getopt(argc, argv, "cif:v")) != -1)
121 switch (c) {
122 case 'c':
123 case 'i':
124 /* ignore for openprom */
125 break;
126 case 'v':
127 verbose++;
128 break;
129 case 'f':
130 promdev = optarg;
131 break;
132 default:
133 exit(_error(NO_PERROR,
134 "Usage: %s [-v] [-f prom-device] "
135 "[variable[=value] ...]", argv[0]));
138 setpname(argv[0]);
141 * If no arguments, dump all fields.
143 if (optind >= argc) {
144 dump_all();
145 exit(0);
148 while (optind < argc) {
150 * If "-" specified, read variables from stdin.
152 if (strcmp(argv[optind], "-") == 0) {
153 int c;
154 char *nl, line[BUFSIZE];
156 while (fgets(line, sizeof (line), stdin) != NULL) {
157 /* zap newline if present */
158 if (nl = strchr(line, '\n'))
159 *nl = 0;
160 /* otherwise discard rest of line */
161 else
162 while ((c = getchar()) != '\n' &&
163 c != EOF)
164 /* nothing */;
166 do_var(line);
168 clearerr(stdin);
171 * Process each argument as a variable print or set request.
173 else
174 do_var(argv[optind]);
176 optind++;
178 return (0);
182 * Print or set an EEPROM field.
184 static void
185 do_var(char *var)
187 char *val;
189 val = strchr(var, '=');
191 if (val == NULL) {
193 * print specific property
195 if (promopen(O_RDONLY)) {
196 (void) fprintf(stderr, badarchmsg);
197 exit(1);
199 print_one(var);
200 } else {
202 * set specific property to value
204 *val++ = '\0';
206 if (promopen(O_RDWR)) {
207 (void) fprintf(stderr, badarchmsg);
208 exit(1);
210 set_one(var, val);
212 promclose();
216 * Print all properties and values
218 static void
219 dump_all()
221 Oppbuf oppbuf;
222 struct openpromio *opp = &(oppbuf.opp);
224 if (promopen(O_RDONLY)) {
225 (void) fprintf(stderr, badarchmsg);
226 exit(1);
228 /* get first prop by asking for null string */
229 (void) memset(oppbuf.buf, '\0', BUFSIZE);
230 /* CONSTCOND */
231 while (1) {
233 * get property
235 opp->oprom_size = MAXPROPSIZE;
237 if (ioctl(prom_fd, OPROMNXTOPT, opp) < 0)
238 exit(_error(PERROR, "OPROMNXTOPT"));
240 if (opp->oprom_size == 0) {
241 promclose();
242 return;
244 print_one(opp->oprom_array);
249 * Print one property and its value.
251 static void
252 print_one(char *var)
254 Oppbuf oppbuf;
255 struct openpromio *opp = &(oppbuf.opp);
256 char bootargs[MAXVALSIZE];
258 if (strcmp(var, "bootcmd") == 0) {
259 opp->oprom_size = MAXVALSIZE;
260 if (ioctl(prom_fd, OPROMGETBOOTARGS, opp) < 0) {
261 (void) _error(PERROR, "OPROMGETBOOTARGS");
262 return;
264 (void) strlcpy(bootargs, opp->oprom_array, MAXVALSIZE);
266 opp->oprom_size = MAXVALSIZE;
267 if (ioctl(prom_fd, OPROMGETBOOTPATH, opp) < 0) {
268 (void) _error(PERROR, "OPROMGETBOOTPATH");
269 return;
271 (void) printf("%s=%s %s\n", var, opp->oprom_array, bootargs);
272 return;
275 (void) strlcpy(opp->oprom_array, var, MAXNAMESIZE);
276 if (getpropval(opp) || opp->oprom_size <= 0)
277 (void) printf("%s: data not available.\n", var);
278 else {
279 /* If necessary, massage the output */
280 struct opvar *v;
282 for (v = opvar; v->name; v++)
283 if (strcmp(var, v->name) == 0)
284 break;
286 if (v->name && v->out)
287 (*v->out)(v->name, opp->oprom_array);
288 else
289 (void) printf("%s=%s\n", var, opp->oprom_array);
294 * Set one property to the given value.
296 static void
297 set_one(char *var, char *val)
299 Oppbuf oppbuf;
300 struct openpromio *opp = &(oppbuf.opp);
301 struct opvar *v;
303 if (verbose) {
304 (void) printf("old:");
305 print_one(var);
308 /* If necessary, massage the input */
310 for (v = opvar; v->name; v++)
311 if (strcmp(var, v->name) == 0)
312 break;
314 if (v->name && v->in)
315 (*v->in)(v->name, val, opp);
316 else {
317 int varlen = strlen(var) + 1;
318 int vallen = strlen(val);
320 if (varlen > MAXNAMESIZE) {
321 (void) printf("%s: invalid property.\n", var);
322 return;
324 if (vallen >= MAXVALSIZE) {
325 (void) printf("%s: invalid property value.\n", var);
326 return;
328 (void) strcpy(opp->oprom_array, var);
329 (void) strcpy(opp->oprom_array + varlen, val);
330 opp->oprom_size = varlen + vallen;
331 if (setpropval(opp))
332 (void) printf("%s: invalid property.\n", var);
335 if (verbose) {
336 (void) printf("new:");
337 print_one(var);
341 static int
342 promopen(int oflag)
344 /* CONSTCOND */
345 while (1) {
346 if ((prom_fd = open(promdev, oflag)) < 0) {
347 if (errno == EAGAIN)
348 continue;
349 else if (errno == ENXIO)
350 return (-1);
351 else
352 exit(_error(PERROR, "cannot open %s", promdev));
353 } else
354 break;
356 return (0);
359 static void
360 promclose()
362 if (close(prom_fd) < 0)
363 exit(_error(PERROR, "close error on %s", promdev));
366 static int
367 getpropval(struct openpromio *opp)
369 opp->oprom_size = MAXVALSIZE;
371 if (ioctl(prom_fd, OPROMGETOPT, opp) < 0)
372 return (_error(PERROR, "OPROMGETOPT"));
374 return (0);
377 static int
378 setpropval(struct openpromio *opp)
380 /* Caller must set opp->oprom_size */
382 if (ioctl(prom_fd, OPROMSETOPT, opp) < 0)
383 return (_error(PERROR, "OPROMSETOPT"));
384 return (0);
389 * The next set of functions handle the special cases.
392 static void
393 i_oemlogo(char *var, char *val, struct openpromio *opp)
395 int varlen = strlen(var) + 1;
397 (void) strcpy(opp->oprom_array, var); /* safe - we know the name */
399 if (loadlogo(val, 64, 64, opp->oprom_array + varlen))
400 exit(1);
401 opp->oprom_size = varlen + 512;
402 if (ioctl(prom_fd, OPROMSETOPT2, opp) < 0)
403 exit(_error(PERROR, "OPROMSETOPT2"));
407 * Set security mode.
408 * If oldmode was none, and new mode is not none, get and set password,
409 * too.
410 * If old mode was not none, and new mode is none, wipe out old
411 * password.
413 static void
414 i_secure(char *var, char *val, struct openpromio *opp)
416 int secure;
417 Oppbuf oppbuf;
418 struct openpromio *opp2 = &(oppbuf.opp);
419 char pwbuf[PW_SIZE + 2];
420 int varlen1, varlen2;
422 (void) strcpy(opp2->oprom_array, var); /* safe; we know the name */
423 if (getpropval(opp2) || opp2->oprom_size <= 0) {
424 (void) printf("%s: data not available.\n", var);
425 exit(1);
427 secure = strcmp(opp2->oprom_array, "none");
429 /* Set up opp for mode */
430 (void) strcpy(opp->oprom_array, var); /* safe; we know the name */
431 varlen1 = strlen(opp->oprom_array) + 1;
432 if (strlen(val) > 32) { /* 32 > [ "full", "command", "none" ] */
433 (void) printf("Invalid security mode, mode unchanged.\n");
434 exit(1);
436 (void) strcpy(opp->oprom_array + varlen1, val);
437 opp->oprom_size = varlen1 + strlen(val);
439 /* Set up opp2 for password */
440 (void) strcpy(opp2->oprom_array, PASSWORD_PROPERTY);
441 varlen2 = strlen(opp2->oprom_array) + 1;
443 if ((strcmp(val, "full") == 0) || (strcmp(val, "command") == 0)) {
444 if (! secure) {
445 /* no password yet, get one */
446 if (get_password(pwbuf, PW_SIZE)) {
447 (void) strcpy(opp2->oprom_array + varlen2,
448 pwbuf);
449 opp2->oprom_size = varlen2 + strlen(pwbuf);
450 /* set password first */
451 if (setpropval(opp2) || setpropval(opp))
452 exit(1);
453 } else
454 exit(1);
455 } else {
456 if (setpropval(opp))
457 exit(1);
459 } else if (strcmp(val, "none") == 0) {
460 if (secure) {
461 (void) memset(opp2->oprom_array + varlen2, '\0',
462 PW_SIZE);
463 opp2->oprom_size = varlen2 + PW_SIZE;
464 /* set mode first */
465 if (setpropval(opp) || setpropval(opp2))
466 exit(1);
467 } else {
468 if (setpropval(opp))
469 exit(1);
471 } else {
472 (void) printf("Invalid security mode, mode unchanged.\n");
473 exit(1);
478 * Set password.
479 * We must be in a secure mode in order to do this.
481 /* ARGSUSED */
482 static void
483 i_passwd(char *var, char *val, struct openpromio *opp)
485 int secure;
486 Oppbuf oppbuf;
487 struct openpromio *opp2 = &(oppbuf.opp);
488 char pwbuf[PW_SIZE + 2];
489 int varlen;
491 (void) strcpy(opp2->oprom_array, MODE_PROPERTY);
492 if (getpropval(opp2) || opp2->oprom_size <= 0) {
493 (void) printf("%s: data not available.\n", opp2->oprom_array);
494 exit(1);
496 secure = strcmp(opp2->oprom_array, "none");
498 if (!secure) {
499 (void) printf("Not in secure mode\n");
500 exit(1);
503 /* Set up opp for password */
504 (void) strcpy(opp->oprom_array, var); /* Safe; We know the name */
505 varlen = strlen(opp->oprom_array) + 1;
507 if (get_password(pwbuf, PW_SIZE)) {
508 (void) strcpy(opp->oprom_array + varlen, pwbuf); /* Bounded */
509 opp->oprom_size = varlen + strlen(pwbuf);
510 if (setpropval(opp))
511 exit(1);
512 } else
513 exit(1);
516 /* ARGSUSED */
517 static void
518 o_passwd(char *var, char *val)
520 /* Don't print the password */
523 static int
524 get_password(char *pw_dest, int pwsize)
526 int insist = 0, ok, flags;
527 int c, pwlen;
528 char *p;
529 static char pwbuf[256];
530 char *pasword = NULL;
532 tryagain:
533 (void) printf("Changing PROM password:\n");
534 if ((pasword = getpass("New password:")) == NULL) {
535 exit(_error(NO_PERROR, "failed to get password"));
537 (void) strcpy(pwbuf, pasword);
538 pwlen = strlen(pwbuf);
539 if (pwlen == 0) {
540 (void) printf("Password unchanged.\n");
541 return (0);
544 * Insure password is of reasonable length and
545 * composition. If we really wanted to make things
546 * sticky, we could check the dictionary for common
547 * words, but then things would really be slow.
549 ok = 0;
550 flags = 0;
551 p = pwbuf;
552 while ((c = *p++) != 0) {
553 if (c >= 'a' && c <= 'z')
554 flags |= 2;
555 else if (c >= 'A' && c <= 'Z')
556 flags |= 4;
557 else if (c >= '0' && c <= '9')
558 flags |= 1;
559 else
560 flags |= 8;
562 if (flags >= 7 && pwlen >= 4)
563 ok = 1;
564 if ((flags == 2 || flags == 4) && pwlen >= 6)
565 ok = 1;
566 if ((flags == 3 || flags == 5 || flags == 6) && pwlen >= 5)
567 ok = 1;
568 if (!ok && insist < 2) {
569 (void) printf("Please use %s.\n", flags == 1 ?
570 "at least one non-numeric character" : "a longer password");
571 insist++;
572 goto tryagain;
574 if (strcmp(pwbuf, getpass("Retype new password:")) != 0) {
575 (void) printf("Mismatch - password unchanged.\n");
576 return (0);
578 (void) strncpy(pw_dest, pwbuf, pwsize);
579 return (1);