Print this page
eeprom
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/eeprom/i386/benv.c
+++ new/usr/src/cmd/eeprom/i386/benv.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 (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 #include "benv.h"
27 27 #include "message.h"
28 28 #include <ctype.h>
29 29 #include <stdarg.h>
30 30 #include <sys/mman.h>
31 31 #include <unistd.h>
32 32 #include <signal.h>
33 33 #include <sys/wait.h>
34 34
35 35 /*
36 36 * Usage: % eeprom [-v] [-f prom_dev] [-]
37 37 * % eeprom [-v] [-f prom_dev] field[=value] ...
38 38 */
39 39
40 40 extern void get_kbenv(void);
41 41 extern void close_kbenv(void);
42 42 extern caddr_t get_propval(char *name, char *node);
43 43 extern void setpname(char *prog);
44 44 extern char *getbootcmd(void);
45 45
46 46 char *boottree;
47 47 struct utsname uts_buf;
48 48
49 49 static int test;
50 50 int verbose;
51 51
52 52 /*
53 53 * Concatenate a NULL terminated list of strings into
54 54 * a single string.
55 55 */
56 56 char *
57 57 strcats(char *s, ...)
58 58 {
59 59 char *cp, *ret;
60 60 size_t len;
61 61 va_list ap;
62 62
63 63 va_start(ap, s);
64 64 for (ret = NULL, cp = s; cp; cp = va_arg(ap, char *)) {
65 65 if (ret == NULL) {
66 66 ret = strdup(s);
67 67 len = strlen(ret) + 1;
68 68 } else {
69 69 len += strlen(cp);
70 70 ret = realloc(ret, len);
71 71 (void) strcat(ret, cp);
72 72 }
73 73 }
74 74 va_end(ap);
75 75
76 76 return (ret);
77 77 }
78 78
79 79 eplist_t *
80 80 new_list(void)
81 81 {
82 82 eplist_t *list;
83 83
84 84 list = (eplist_t *)malloc(sizeof (eplist_t));
85 85 (void) memset(list, 0, sizeof (eplist_t));
86 86
87 87 list->next = list;
88 88 list->prev = list;
89 89 list->item = NULL;
90 90
91 91 return (list);
92 92 }
93 93
94 94 void
95 95 add_item(void *item, eplist_t *list)
96 96 {
97 97 eplist_t *entry;
98 98
99 99 entry = (eplist_t *)malloc(sizeof (eplist_t));
100 100 (void) memset(entry, 0, sizeof (eplist_t));
101 101 entry->item = item;
102 102
103 103 entry->next = list;
104 104 entry->prev = list->prev;
105 105 list->prev->next = entry;
106 106 list->prev = entry;
107 107 }
108 108
109 109 typedef struct benv_ent {
110 110 char *cmd;
111 111 char *name;
112 112 char *val;
113 113 } benv_ent_t;
114 114
115 115 typedef struct benv_des {
116 116 char *name;
117 117 int fd;
118 118 caddr_t adr;
119 119 size_t len;
120 120 eplist_t *elist;
121 121 } benv_des_t;
122 122
123 123 static benv_des_t *
124 124 new_bd(void)
125 125 {
126 126
127 127 benv_des_t *bd;
128 128
129 129 bd = (benv_des_t *)malloc(sizeof (benv_des_t));
130 130 (void) memset(bd, 0, sizeof (benv_des_t));
131 131
132 132 bd->elist = new_list();
133 133
134 134 return (bd);
135 135 }
136 136
137 137 /*
138 138 * Create a new entry. Comment entries have NULL names.
139 139 */
140 140 static benv_ent_t *
141 141 new_bent(char *comm, char *cmd, char *name, char *val)
142 142 {
143 143 benv_ent_t *bent;
144 144
145 145 bent = (benv_ent_t *)malloc(sizeof (benv_ent_t));
146 146 (void) memset(bent, 0, sizeof (benv_ent_t));
147 147
148 148 if (comm) {
149 149 bent->cmd = strdup(comm);
150 150 comm = NULL;
151 151 } else {
152 152 bent->cmd = strdup(cmd);
153 153 bent->name = strdup(name);
154 154 if (val)
155 155 bent->val = strdup(val);
156 156 }
157 157
158 158 return (bent);
159 159 }
160 160
161 161 /*
162 162 * Add a new entry to the benv entry list. Entries can be
163 163 * comments or commands.
164 164 */
165 165 static void
166 166 add_bent(eplist_t *list, char *comm, char *cmd, char *name, char *val)
167 167 {
168 168 benv_ent_t *bent;
169 169
170 170 bent = new_bent(comm, cmd, name, val);
171 171 add_item((void *)bent, list);
172 172 }
173 173
174 174 static benv_ent_t *
175 175 get_var(char *name, eplist_t *list)
176 176 {
177 177 eplist_t *e;
178 178 benv_ent_t *p;
179 179
180 180 for (e = list->next; e != list; e = e->next) {
181 181 p = (benv_ent_t *)e->item;
182 182 if (p->name != NULL && strcmp(p->name, name) == 0)
183 183 return (p);
184 184 }
185 185
186 186 return (NULL);
187 187 }
188 188
189 189 /*PRINTFLIKE1*/
190 190 static void
191 191 eeprom_error(const char *format, ...)
192 192 {
193 193 va_list ap;
194 194
195 195 va_start(ap, format);
196 196 (void) fprintf(stderr, "eeprom: ");
197 197 (void) vfprintf(stderr, format, ap);
198 198 va_end(ap);
199 199 }
200 200
201 201 static int
202 202 exec_cmd(char *cmdline, char *output, int64_t osize)
203 203 {
204 204 char buf[BUFSIZ];
205 205 int ret;
206 206 size_t len;
207 207 FILE *ptr;
208 208 sigset_t set;
209 209 void (*disp)(int);
210 210
211 211 if (output)
212 212 output[0] = '\0';
213 213
214 214 /*
215 215 * For security
216 216 * - only absolute paths are allowed
217 217 * - set IFS to space and tab
218 218 */
219 219 if (*cmdline != '/') {
220 220 eeprom_error(ABS_PATH_REQ, cmdline);
221 221 return (-1);
222 222 }
223 223 (void) putenv("IFS= \t");
224 224
225 225 /*
226 226 * We may have been exec'ed with SIGCHLD blocked
227 227 * unblock it here
228 228 */
229 229 (void) sigemptyset(&set);
230 230 (void) sigaddset(&set, SIGCHLD);
231 231 if (sigprocmask(SIG_UNBLOCK, &set, NULL) != 0) {
232 232 eeprom_error(FAILED_SIG, strerror(errno));
233 233 return (-1);
234 234 }
235 235
236 236 /*
237 237 * Set SIGCHLD disposition to SIG_DFL for popen/pclose
238 238 */
239 239 disp = sigset(SIGCHLD, SIG_DFL);
240 240 if (disp == SIG_ERR) {
241 241 eeprom_error(FAILED_SIG, strerror(errno));
242 242 return (-1);
243 243 }
244 244 if (disp == SIG_HOLD) {
245 245 eeprom_error(BLOCKED_SIG, cmdline);
246 246 return (-1);
247 247 }
248 248
249 249 ptr = popen(cmdline, "r");
250 250 if (ptr == NULL) {
251 251 eeprom_error(POPEN_FAIL, cmdline, strerror(errno));
252 252 return (-1);
253 253 }
254 254
255 255 /*
256 256 * If we simply do a pclose() following a popen(), pclose()
257 257 * will close the reader end of the pipe immediately even
258 258 * if the child process has not started/exited. pclose()
259 259 * does wait for cmd to terminate before returning though.
260 260 * When the executed command writes its output to the pipe
261 261 * there is no reader process and the command dies with
262 262 * SIGPIPE. To avoid this we read repeatedly until read
263 263 * terminates with EOF. This indicates that the command
264 264 * (writer) has closed the pipe and we can safely do a
265 265 * pclose().
266 266 *
267 267 * Since pclose() does wait for the command to exit,
268 268 * we can safely reap the exit status of the command
269 269 * from the value returned by pclose()
270 270 */
271 271 while (fgets(buf, sizeof (buf), ptr) != NULL) {
272 272 if (output && osize > 0) {
273 273 (void) snprintf(output, osize, "%s", buf);
274 274 len = strlen(buf);
275 275 output += len;
276 276 osize -= len;
277 277 }
278 278 }
279 279
280 280 /*
281 281 * If there's a "\n" at the end, we want to chop it off
282 282 */
283 283 if (output) {
284 284 len = strlen(output) - 1;
285 285 if (output[len] == '\n')
286 286 output[len] = '\0';
287 287 }
288 288
289 289 ret = pclose(ptr);
290 290 if (ret == -1) {
291 291 eeprom_error(PCLOSE_FAIL, cmdline, strerror(errno));
292 292 return (-1);
↓ open down ↓ |
292 lines elided |
↑ open up ↑ |
293 293 }
294 294
295 295 if (WIFEXITED(ret)) {
296 296 return (WEXITSTATUS(ret));
297 297 } else {
298 298 eeprom_error(EXEC_FAIL, cmdline, ret);
299 299 return (-1);
300 300 }
301 301 }
302 302
303 -#define BOOTADM_STR "bootadm: "
303 +#define GRUBADM_STR "grubadm: "
304 304
305 305 /*
306 - * bootadm starts all error messages with "bootadm: ".
307 - * Add a note so users don't get confused on how they ran bootadm.
306 + * grubadm starts all error messages with "grubadm: ".
307 + * Add a note so users don't get confused on how they ran grubadm.
308 308 */
309 309 static void
310 310 output_error_msg(const char *msg)
311 311 {
312 - size_t len = sizeof (BOOTADM_STR) - 1;
312 + size_t len = sizeof (GRUBADM_STR) - 1;
313 313
314 - if (strncmp(msg, BOOTADM_STR, len) == 0) {
314 + if (strncmp(msg, GRUBADM_STR, len) == 0) {
315 315 eeprom_error("error returned from %s\n", msg);
316 316 } else if (msg[0] != '\0') {
317 317 eeprom_error("%s\n", msg);
318 318 }
319 319 }
320 320
321 321 static char *
322 -get_bootadm_value(char *name, const int quiet)
322 +get_grubadm_value(char *name, const int quiet)
323 323 {
324 324 char *ptr, *ret_str, *end_ptr, *orig_ptr;
325 325 char output[BUFSIZ];
326 326 int is_console, is_kernel = 0;
327 327 size_t len;
328 328
329 329 is_console = (strcmp(name, "console") == 0);
330 330
331 331 if (strcmp(name, "boot-file") == 0) {
332 332 is_kernel = 1;
333 - ptr = "/sbin/bootadm set-menu kernel 2>&1";
333 + ptr = "/sbin/grubadm --number -1 --get-kernel 2>&1";
334 334 } else if (is_console || (strcmp(name, "boot-args") == 0)) {
335 - ptr = "/sbin/bootadm set-menu args 2>&1";
335 + ptr = "/sbin/grubadm --number -1 --get-opts 2>&1";
336 336 } else {
337 - eeprom_error("Unknown value in get_bootadm_value: %s\n", name);
337 + eeprom_error("Unknown value in get_grubadm_value: %s\n", name);
338 338 return (NULL);
339 339 }
340 340
341 341 if (exec_cmd(ptr, output, BUFSIZ) != 0) {
342 342 if (quiet == 0) {
343 343 output_error_msg(output);
344 344 }
345 345 return (NULL);
346 346 }
347 347
348 348 if (is_console) {
349 349 if ((ptr = strstr(output, "console=")) == NULL) {
350 350 return (NULL);
351 351 }
352 352 ptr += strlen("console=");
353 353
354 354 /*
355 355 * -B may have comma-separated values. It may also be
356 356 * followed by other flags.
357 357 */
358 358 len = strcspn(ptr, " \t,");
359 359 ret_str = calloc(len + 1, 1);
360 360 if (ret_str == NULL) {
361 361 eeprom_error(NO_MEM, len + 1);
362 362 return (NULL);
363 363 }
364 364 (void) strncpy(ret_str, ptr, len);
365 365 return (ret_str);
366 366 } else if (is_kernel) {
367 367 ret_str = strdup(output);
368 368 if (ret_str == NULL)
369 369 eeprom_error(NO_MEM, strlen(output) + 1);
370 370 return (ret_str);
371 371 } else {
372 372 /* If there's no console setting, we can return */
373 373 if ((orig_ptr = strstr(output, "console=")) == NULL) {
374 374 return (strdup(output));
375 375 }
376 376 len = strcspn(orig_ptr, " \t,");
377 377 ptr = orig_ptr;
378 378 end_ptr = orig_ptr + len + 1;
379 379
380 380 /* Eat up any white space */
381 381 while ((*end_ptr == ' ') || (*end_ptr == '\t'))
382 382 end_ptr++;
383 383
384 384 /*
385 385 * If there's data following the console string, copy it.
386 386 * If not, cut off the new string.
387 387 */
388 388 if (*end_ptr == '\0')
389 389 *ptr = '\0';
390 390
391 391 while (*end_ptr != '\0') {
392 392 *ptr = *end_ptr;
393 393 ptr++;
394 394 end_ptr++;
395 395 }
396 396 *ptr = '\0';
397 397 if ((strchr(output, '=') == NULL) &&
398 398 (strncmp(output, "-B ", 3) == 0)) {
399 399 /*
400 400 * Since we removed the console setting, we no
401 401 * longer need the initial "-B "
402 402 */
403 403 orig_ptr = output + 3;
404 404 } else {
405 405 orig_ptr = output;
406 406 }
407 407
408 408 ret_str = strdup(orig_ptr);
409 409 if (ret_str == NULL)
↓ open down ↓ |
62 lines elided |
↑ open up ↑ |
410 410 eeprom_error(NO_MEM, strlen(orig_ptr) + 1);
411 411 return (ret_str);
412 412 }
413 413 }
414 414
415 415 /*
416 416 * If quiet is 1, print nothing if there is no value. If quiet is 0, print
417 417 * a message. Return 1 if the value is printed, 0 otherwise.
418 418 */
419 419 static int
420 -print_bootadm_value(char *name, const int quiet)
420 +print_grubadm_value(char *name, const int quiet)
421 421 {
422 422 int rv = 0;
423 - char *value = get_bootadm_value(name, quiet);
423 + char *value = get_grubadm_value(name, quiet);
424 424
425 425 if ((value != NULL) && (value[0] != '\0')) {
426 426 (void) printf("%s=%s\n", name, value);
427 427 rv = 1;
428 428 } else if (quiet == 0) {
429 429 (void) printf("%s: data not available.\n", name);
430 430 }
431 431
432 432 if (value != NULL)
433 433 free(value);
434 434 return (rv);
435 435 }
436 436
437 437 static void
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
438 438 print_var(char *name, eplist_t *list)
439 439 {
440 440 benv_ent_t *p;
441 441 char *bootcmd;
442 442
443 443 /*
444 444 * The console property is kept in both menu.lst and bootenv.rc. The
445 445 * menu.lst value takes precedence.
446 446 */
447 447 if (strcmp(name, "console") == 0) {
448 - if (print_bootadm_value(name, 1) == 0) {
448 + if (print_grubadm_value(name, 1) == 0) {
449 449 if ((p = get_var(name, list)) != NULL) {
450 450 (void) printf("%s=%s\n", name, p->val ?
451 451 p->val : "");
452 452 } else {
453 453 (void) printf("%s: data not available.\n",
454 454 name);
455 455 }
456 456 }
457 457 } else if (strcmp(name, "bootcmd") == 0) {
458 458 bootcmd = getbootcmd();
459 459 (void) printf("%s=%s\n", name, bootcmd ? bootcmd : "");
460 460 } else if ((strcmp(name, "boot-file") == 0) ||
461 461 (strcmp(name, "boot-args") == 0)) {
462 - (void) print_bootadm_value(name, 0);
462 + (void) print_grubadm_value(name, 0);
463 463 } else if ((p = get_var(name, list)) == NULL) {
464 464 (void) printf("%s: data not available.\n", name);
465 465 } else {
466 466 (void) printf("%s=%s\n", name, p->val ? p->val : "");
467 467 }
468 468 }
469 469
470 470 static void
471 471 print_vars(eplist_t *list)
472 472 {
473 473 eplist_t *e;
474 474 benv_ent_t *p;
475 475 int console_printed = 0;
476 476
477 477 /*
478 478 * The console property is kept both in menu.lst and bootenv.rc.
479 479 * The menu.lst value takes precedence, so try printing that one
480 480 * first.
481 481 */
482 - console_printed = print_bootadm_value("console", 1);
482 + console_printed = print_grubadm_value("console", 1);
483 483
484 484 for (e = list->next; e != list; e = e->next) {
485 485 p = (benv_ent_t *)e->item;
486 486 if (p->name != NULL) {
487 487 if (((strcmp(p->name, "console") == 0) &&
488 488 (console_printed == 1)) ||
489 489 ((strcmp(p->name, "boot-file") == 0) ||
490 490 (strcmp(p->name, "boot-args") == 0))) {
491 491 /* handle these separately */
492 492 continue;
493 493 }
494 494 (void) printf("%s=%s\n", p->name, p->val ? p->val : "");
495 495 }
496 496 }
497 - (void) print_bootadm_value("boot-file", 1);
498 - (void) print_bootadm_value("boot-args", 1);
497 + (void) print_grubadm_value("boot-file", 1);
498 + (void) print_grubadm_value("boot-args", 1);
499 499 }
500 500
501 501 /*
502 502 * Write a string to a file, quoted appropriately. We use single
503 503 * quotes to prevent any variable expansion. Of course, we backslash-quote
504 504 * any single quotes or backslashes.
505 505 */
506 506 static void
507 507 put_quoted(FILE *fp, char *val)
508 508 {
509 509 (void) putc('\'', fp);
510 510 while (*val) {
511 511 switch (*val) {
512 512 case '\'':
513 513 case '\\':
514 514 (void) putc('\\', fp);
515 515 /* FALLTHROUGH */
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
516 516 default:
517 517 (void) putc(*val, fp);
518 518 break;
519 519 }
520 520 val++;
521 521 }
522 522 (void) putc('\'', fp);
523 523 }
524 524
525 525 static void
526 -set_bootadm_var(char *name, char *value)
526 +set_grubadm_var(char *name, char *value)
527 527 {
528 528 char buf[BUFSIZ];
529 529 char output[BUFSIZ] = "";
530 530 char *console, *args;
531 531 int is_console;
532 532
533 533 if (verbose) {
534 534 (void) printf("old:");
535 - (void) print_bootadm_value(name, 0);
535 + (void) print_grubadm_value(name, 0);
536 536 }
537 537
538 538 /*
539 539 * For security, we single-quote whatever we run on the command line,
540 540 * and we don't allow single quotes in the string.
541 541 */
542 542 if (strchr(value, '\'') != NULL) {
543 543 eeprom_error("Single quotes are not allowed "
544 544 "in the %s property.\n", name);
545 545 return;
546 546 }
547 547
548 548 is_console = (strcmp(name, "console") == 0);
549 549 if (strcmp(name, "boot-file") == 0) {
550 - (void) snprintf(buf, BUFSIZ, "/sbin/bootadm set-menu "
551 - "kernel='%s' 2>&1", value);
550 + (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
551 + "--set-kernel '%s' 2>&1", value);
552 552 } else if (is_console || (strcmp(name, "boot-args") == 0)) {
553 553 if (is_console) {
554 - args = get_bootadm_value("boot-args", 1);
554 + args = get_grubadm_value("boot-args", 1);
555 555 console = value;
556 556 } else {
557 557 args = value;
558 - console = get_bootadm_value("console", 1);
558 + console = get_grubadm_value("console", 1);
559 559 }
560 560 if (((args == NULL) || (args[0] == '\0')) &&
561 561 ((console == NULL) || (console[0] == '\0'))) {
562 - (void) snprintf(buf, BUFSIZ, "/sbin/bootadm set-menu "
563 - "args= 2>&1");
562 + (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
563 + "--set-opts '-B $ZFS_BOOTFS' 2>&1");
564 564 } else if ((args == NULL) || (args[0] == '\0')) {
565 - (void) snprintf(buf, BUFSIZ, "/sbin/bootadm "
566 - "set-menu args='-B console=%s' 2>&1",
565 + (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
566 + "--set-opts '-B console=%s' 2>&1",
567 567 console);
568 568 } else if ((console == NULL) || (console[0] == '\0')) {
569 - (void) snprintf(buf, BUFSIZ, "/sbin/bootadm "
570 - "set-menu args='%s' 2>&1", args);
569 + (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
570 + "--set-opts '%s' 2>&1", args);
571 571 } else if (strncmp(args, "-B ", 3) != 0) {
572 - (void) snprintf(buf, BUFSIZ, "/sbin/bootadm "
573 - "set-menu args='-B console=%s %s' 2>&1",
572 + (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
573 + "--set-opts '-B console=%s %s' 2>&1",
574 574 console, args);
575 575 } else {
576 - (void) snprintf(buf, BUFSIZ, "/sbin/bootadm "
577 - "set-menu args='-B console=%s,%s' 2>&1",
576 + (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
577 + "--set-opts '-B console=%s,%s' 2>&1",
578 578 console, args + 3);
579 579 }
580 580 } else {
581 - eeprom_error("Unknown value in set_bootadm_value: %s\n", name);
581 + eeprom_error("Unknown value in set_grubadm_value: %s\n", name);
582 582 return;
583 583 }
584 584
585 585 if (exec_cmd(buf, output, BUFSIZ) != 0) {
586 586 output_error_msg(output);
587 587 return;
588 588 }
589 589
590 590 if (verbose) {
591 591 (void) printf("new:");
592 - (void) print_bootadm_value(name, 0);
592 + (void) print_grubadm_value(name, 0);
593 593 }
594 594 }
595 595
596 596 /*
597 597 * Returns 1 if bootenv.rc was modified, 0 otherwise.
598 598 */
599 599 static int
600 600 set_var(char *name, char *val, eplist_t *list)
601 601 {
602 602 benv_ent_t *p;
603 603 int old_verbose;
604 604
605 605 if (strcmp(name, "bootcmd") == 0)
606 606 return (0);
607 607
608 608 if ((strcmp(name, "boot-file") == 0) ||
609 609 (strcmp(name, "boot-args") == 0)) {
610 - set_bootadm_var(name, val);
610 + set_grubadm_var(name, val);
611 611 return (0);
612 612 }
613 613
614 614 /*
615 615 * The console property is kept in two places: menu.lst and bootenv.rc.
616 616 * Update them both. We clear verbose to prevent duplicate messages.
617 617 */
618 618 if (strcmp(name, "console") == 0) {
619 619 old_verbose = verbose;
620 620 verbose = 0;
621 - set_bootadm_var(name, val);
621 + set_grubadm_var(name, val);
622 622 verbose = old_verbose;
623 623 }
624 624
625 625 if (verbose) {
626 626 (void) printf("old:");
627 627 print_var(name, list);
628 628 }
629 629
630 630 if ((p = get_var(name, list)) != NULL) {
631 631 free(p->val);
632 632 p->val = strdup(val);
633 633 } else
634 634 add_bent(list, NULL, "setprop", name, val);
635 635
636 636 if (verbose) {
637 637 (void) printf("new:");
638 638 print_var(name, list);
639 639 }
640 640 return (1);
641 641 }
642 642
643 643 /*
644 644 * Returns 1 if bootenv.rc is modified or 0 if no modification was
645 645 * necessary. This allows us to implement non super-user look-up of
646 646 * variables by name without the user being yelled at for trying to
647 647 * modify the bootenv.rc file.
648 648 */
649 649 static int
650 650 proc_var(char *name, eplist_t *list)
651 651 {
652 652 register char *val;
653 653
654 654 if ((val = strchr(name, '=')) == NULL) {
655 655 print_var(name, list);
656 656 return (0);
657 657 } else {
658 658 *val++ = '\0';
659 659 return (set_var(name, val, list));
660 660 }
661 661 }
662 662
663 663 static void
664 664 init_benv(benv_des_t *bd, char *file)
665 665 {
666 666 get_kbenv();
667 667
668 668 if (test)
669 669 boottree = "/tmp";
670 670 else if ((boottree = (char *)get_propval("boottree", "chosen")) == NULL)
671 671 boottree = strcats("/boot", NULL);
672 672
673 673 if (file != NULL)
674 674 bd->name = file;
675 675 else
676 676 bd->name = strcats(boottree, "/solaris/bootenv.rc", NULL);
677 677 }
678 678
679 679 static void
680 680 map_benv(benv_des_t *bd)
681 681 {
682 682 if ((bd->fd = open(bd->name, O_RDONLY)) == -1)
683 683 if (errno == ENOENT)
684 684 return;
685 685 else
686 686 exit(_error(PERROR, "cannot open %s", bd->name));
687 687
688 688 if ((bd->len = (size_t)lseek(bd->fd, 0, SEEK_END)) == 0) {
689 689 if (close(bd->fd) == -1)
690 690 exit(_error(PERROR, "close error on %s", bd->name));
691 691 return;
692 692 }
693 693
694 694 (void) lseek(bd->fd, 0, SEEK_SET);
695 695
696 696 if ((bd->adr = mmap((caddr_t)0, bd->len, (PROT_READ | PROT_WRITE),
697 697 MAP_PRIVATE, bd->fd, 0)) == MAP_FAILED)
698 698 exit(_error(PERROR, "cannot map %s", bd->name));
699 699 }
700 700
701 701 static void
702 702 unmap_benv(benv_des_t *bd)
703 703 {
704 704 if (munmap(bd->adr, bd->len) == -1)
705 705 exit(_error(PERROR, "unmap error on %s", bd->name));
706 706
707 707 if (close(bd->fd) == -1)
708 708 exit(_error(PERROR, "close error on %s", bd->name));
709 709 }
710 710
711 711 #define NL '\n'
712 712 #define COMM '#'
713 713
714 714 /*
715 715 * Add a comment block to the benv list.
716 716 */
717 717 static void
718 718 add_comm(benv_des_t *bd, char *base, char *last, char **next, int *line)
719 719 {
720 720 int nl, lines;
721 721 char *p;
722 722
723 723 nl = 0;
724 724 for (p = base, lines = 0; p < last; p++) {
725 725 if (*p == NL) {
726 726 nl++;
727 727 lines++;
728 728 } else if (nl) {
729 729 if (*p != COMM)
730 730 break;
731 731 nl = 0;
732 732 }
733 733 }
734 734 *(p - 1) = NULL;
735 735 add_bent(bd->elist, base, NULL, NULL, NULL);
736 736 *next = p;
737 737 *line += lines;
738 738 }
739 739
740 740 /*
741 741 * Parse out an operator (setprop) from the boot environment
742 742 */
743 743 static char *
744 744 parse_cmd(benv_des_t *bd, char **next, int *line)
745 745 {
746 746 char *strbegin;
747 747 char *badeof = "unexpected EOF in %s line %d";
748 748 char *syntax = "syntax error in %s line %d";
749 749 char *c = *next;
750 750
751 751 /*
752 752 * Skip spaces or tabs. New lines increase the line count.
753 753 */
754 754 while (isspace(*c)) {
755 755 if (*c++ == '\n')
756 756 (*line)++;
757 757 }
758 758
759 759 /*
760 760 * Check for a the setprop command. Currently that's all we
761 761 * seem to support.
762 762 *
763 763 * XXX need support for setbinprop?
764 764 */
765 765
766 766 /*
767 767 * Check first for end of file. Finding one now would be okay.
768 768 * We should also bail if we are at the start of a comment.
769 769 */
770 770 if (*c == '\0' || *c == COMM) {
771 771 *next = c;
772 772 return (NULL);
773 773 }
774 774
775 775 strbegin = c;
776 776 while (*c && !isspace(*c))
777 777 c++;
778 778
779 779 /*
780 780 * Check again for end of file. Finding one now would NOT be okay.
781 781 */
782 782 if (*c == '\0') {
783 783 exit(_error(NO_PERROR, badeof, bd->name, *line));
784 784 }
785 785
786 786 *c++ = '\0';
787 787 *next = c;
788 788
789 789 /*
790 790 * Last check is to make sure the command is a setprop!
791 791 */
792 792 if (strcmp(strbegin, "setprop") != 0) {
793 793 exit(_error(NO_PERROR, syntax, bd->name, *line));
794 794 /* NOTREACHED */
795 795 }
796 796 return (strbegin);
797 797 }
798 798
799 799 /*
800 800 * Parse out the name (LHS) of a setprop from the boot environment
801 801 */
802 802 static char *
803 803 parse_name(benv_des_t *bd, char **next, int *line)
804 804 {
805 805 char *strbegin;
806 806 char *badeof = "unexpected EOF in %s line %d";
807 807 char *syntax = "syntax error in %s line %d";
808 808 char *c = *next;
809 809
810 810 /*
811 811 * Skip spaces or tabs. No tolerance for new lines now.
812 812 */
813 813 while (isspace(*c)) {
814 814 if (*c++ == '\n')
815 815 exit(_error(NO_PERROR, syntax, bd->name, *line));
816 816 }
817 817
818 818 /*
819 819 * Grab a name for the property to set.
820 820 */
821 821
822 822 /*
823 823 * Check first for end of file. Finding one now would NOT be okay.
824 824 */
825 825 if (*c == '\0') {
826 826 exit(_error(NO_PERROR, badeof, bd->name, *line));
827 827 }
828 828
829 829 strbegin = c;
830 830 while (*c && !isspace(*c))
831 831 c++;
832 832
833 833 /*
834 834 * At this point in parsing we have 'setprop name'. What follows
835 835 * is a newline, other whitespace, or EOF. Most of the time we
836 836 * want to replace a white space character with a NULL to terminate
837 837 * the name, and then continue on processing. A newline here provides
838 838 * the most grief. If we just replace it with a null we'll
839 839 * potentially get the setprop on the next line as the value of this
840 840 * setprop! So, if the last thing we see is a newline we'll have to
841 841 * dup the string.
842 842 */
843 843 if (isspace(*c)) {
844 844 if (*c == '\n') {
845 845 *c = '\0';
846 846 strbegin = strdup(strbegin);
847 847 *c = '\n';
848 848 } else {
849 849 *c++ = '\0';
850 850 }
851 851 }
852 852
853 853 *next = c;
854 854 return (strbegin);
855 855 }
856 856
857 857 /*
858 858 * Parse out the value (RHS) of a setprop line from the boot environment
859 859 */
860 860 static char *
861 861 parse_value(benv_des_t *bd, char **next, int *line)
862 862 {
863 863 char *strbegin;
864 864 char *badeof = "unexpected EOF in %s line %d";
865 865 char *result;
866 866 char *c = *next;
867 867 char quote;
868 868
869 869 /*
870 870 * Skip spaces or tabs. A newline here would indicate a
871 871 * NULL property value.
872 872 */
873 873 while (isspace(*c)) {
874 874 if (*c++ == '\n') {
875 875 (*line)++;
876 876 *next = c;
877 877 return (NULL);
878 878 }
879 879 }
880 880
881 881 /*
882 882 * Grab the value of the property to set.
883 883 */
884 884
885 885 /*
886 886 * Check first for end of file. Finding one now would
887 887 * also indicate a NULL property.
888 888 */
889 889 if (*c == '\0') {
890 890 *next = c;
891 891 return (NULL);
892 892 }
893 893
894 894 /*
895 895 * Value may be quoted, in which case we assume the end of the value
896 896 * comes with a closing quote.
897 897 *
898 898 * We also allow escaped quote characters inside the quoted value.
899 899 *
900 900 * For obvious reasons we do not attempt to parse variable references.
901 901 */
902 902 if (*c == '"' || *c == '\'') {
903 903 quote = *c;
904 904 c++;
905 905 strbegin = c;
906 906 result = c;
907 907 while (*c != quote) {
908 908 if (*c == '\\') {
909 909 c++;
910 910 }
911 911 if (*c == '\0') {
912 912 break;
913 913 }
914 914 *result++ = *c++;
915 915 }
916 916
917 917 /*
918 918 * Throw fatal exception if no end quote found.
919 919 */
920 920 if (*c != quote) {
921 921 exit(_error(NO_PERROR, badeof, bd->name, *line));
922 922 }
923 923
924 924 *result = '\0'; /* Terminate the result */
925 925 c++; /* and step past the close quote */
926 926 } else {
927 927 strbegin = c;
928 928 while (*c && !isspace(*c))
929 929 c++;
930 930 }
931 931
932 932 /*
933 933 * Check again for end of file. Finding one now is okay.
934 934 */
935 935 if (*c == '\0') {
936 936 *next = c;
937 937 return (strbegin);
938 938 }
939 939
940 940 *c++ = '\0';
941 941 *next = c;
942 942 return (strbegin);
943 943 }
944 944
945 945 /*
946 946 * Add a command to the benv list.
947 947 */
948 948 static void
949 949 add_cmd(benv_des_t *bd, char *last, char **next, int *line)
950 950 {
951 951 char *cmd, *name, *val;
952 952
953 953 while (*next <= last && **next != COMM) {
954 954 if ((cmd = parse_cmd(bd, next, line)) == NULL)
955 955 break;
956 956 name = parse_name(bd, next, line);
957 957 val = parse_value(bd, next, line);
958 958 add_bent(bd->elist, NULL, cmd, name, val);
959 959 (*line)++;
960 960 };
961 961
962 962 }
963 963
964 964 /*
965 965 * Parse the benv (bootenv.rc) file and break it into a benv
966 966 * list. List entries may be comment blocks or commands.
967 967 */
968 968 static void
969 969 parse_benv(benv_des_t *bd)
970 970 {
971 971 int line;
972 972 char *pbase, *pend;
973 973 char *tok, *tnext;
974 974
975 975 line = 1;
976 976 pbase = (char *)bd->adr;
977 977 pend = pbase + bd->len;
978 978
979 979 for (tok = tnext = pbase; tnext < pend && '\0' != *tnext; tok = tnext)
980 980 if (*tok == COMM)
981 981 add_comm(bd, tok, pend, &tnext, &line);
982 982 else
983 983 add_cmd(bd, pend, &tnext, &line);
984 984 }
985 985
986 986 static void
987 987 write_benv(benv_des_t *bd)
988 988 {
989 989 FILE *fp;
990 990 eplist_t *list, *e;
991 991 benv_ent_t *bent;
992 992 char *name;
993 993
994 994 list = bd->elist;
995 995
996 996 if (list->next == list)
997 997 return;
998 998
999 999 if ((fp = fopen(bd->name, "w")) == NULL)
1000 1000 exit(_error(PERROR, "cannot open %s", bd->name));
1001 1001
1002 1002 for (e = list->next; e != list; e = e->next) {
1003 1003 bent = (benv_ent_t *)e->item;
1004 1004 name = bent->name;
1005 1005 if (name) {
1006 1006 if (bent->val) {
1007 1007 (void) fprintf(fp, "%s %s ",
1008 1008 bent->cmd, bent->name);
1009 1009 put_quoted(fp, bent->val);
1010 1010 (void) fprintf(fp, "\n");
1011 1011 } else {
1012 1012 (void) fprintf(fp, "%s %s\n",
1013 1013 bent->cmd, bent->name);
1014 1014 }
1015 1015 } else {
1016 1016 (void) fprintf(fp, "%s\n", bent->cmd);
1017 1017 }
1018 1018 }
1019 1019
1020 1020 (void) fclose(fp);
1021 1021 }
1022 1022
1023 1023 static char *
1024 1024 get_line(void)
1025 1025 {
1026 1026 int c;
1027 1027 char *nl;
1028 1028 static char line[256];
1029 1029
1030 1030 if (fgets(line, sizeof (line), stdin) != NULL) {
1031 1031 /*
1032 1032 * Remove newline if present,
1033 1033 * otherwise discard rest of line.
1034 1034 */
1035 1035 if (nl = strchr(line, '\n'))
1036 1036 *nl = 0;
1037 1037 else
1038 1038 while ((c = getchar()) != '\n' && c != EOF)
1039 1039 ;
1040 1040 return (line);
1041 1041 } else
1042 1042 return (NULL);
1043 1043 }
1044 1044
1045 1045 int
1046 1046 main(int argc, char **argv)
1047 1047 {
1048 1048 int c;
1049 1049 int updates = 0;
1050 1050 char *usage = "Usage: %s [-v] [-f prom-device]"
1051 1051 " [variable[=value] ...]";
1052 1052 eplist_t *elist;
1053 1053 benv_des_t *bd;
1054 1054 char *file = NULL;
1055 1055
1056 1056 setpname(argv[0]);
1057 1057
1058 1058 while ((c = getopt(argc, argv, "f:Itv")) != -1)
1059 1059 switch (c) {
1060 1060 case 'v':
1061 1061 verbose++;
1062 1062 break;
1063 1063 case 'f':
1064 1064 file = optarg;
1065 1065 break;
1066 1066 case 't':
1067 1067 test++;
1068 1068 break;
1069 1069 default:
1070 1070 exit(_error(NO_PERROR, usage, argv[0]));
1071 1071 }
1072 1072
1073 1073 (void) uname(&uts_buf);
1074 1074 bd = new_bd();
1075 1075 init_benv(bd, file);
1076 1076
1077 1077 map_benv(bd);
1078 1078 if (bd->len) {
1079 1079 parse_benv(bd);
1080 1080 unmap_benv(bd);
1081 1081 }
1082 1082
1083 1083 elist = bd->elist;
1084 1084
1085 1085 if (optind >= argc) {
1086 1086 print_vars(elist);
1087 1087 return (0);
1088 1088 } else
1089 1089 while (optind < argc) {
1090 1090 /*
1091 1091 * If "-" specified, read variables from stdin;
1092 1092 * otherwise, process each argument as a variable
1093 1093 * print or set request.
1094 1094 */
1095 1095 if (strcmp(argv[optind], "-") == 0) {
1096 1096 char *line;
1097 1097
1098 1098 while ((line = get_line()) != NULL)
1099 1099 updates += proc_var(line, elist);
1100 1100 clearerr(stdin);
1101 1101 } else
1102 1102 updates += proc_var(argv[optind], elist);
1103 1103
1104 1104 optind++;
1105 1105 }
1106 1106
1107 1107 /*
1108 1108 * don't write benv if we are processing delayed writes since
1109 1109 * it is likely that the delayed writes changes bootenv.rc anyway...
1110 1110 */
1111 1111 if (updates)
1112 1112 write_benv(bd);
1113 1113 close_kbenv();
1114 1114
1115 1115 return (0);
1116 1116 }
↓ open down ↓ |
485 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX