283 if (output) {
284 len = strlen(output) - 1;
285 if (output[len] == '\n')
286 output[len] = '\0';
287 }
288
289 ret = pclose(ptr);
290 if (ret == -1) {
291 eeprom_error(PCLOSE_FAIL, cmdline, strerror(errno));
292 return (-1);
293 }
294
295 if (WIFEXITED(ret)) {
296 return (WEXITSTATUS(ret));
297 } else {
298 eeprom_error(EXEC_FAIL, cmdline, ret);
299 return (-1);
300 }
301 }
302
303 #define BOOTADM_STR "bootadm: "
304
305 /*
306 * bootadm starts all error messages with "bootadm: ".
307 * Add a note so users don't get confused on how they ran bootadm.
308 */
309 static void
310 output_error_msg(const char *msg)
311 {
312 size_t len = sizeof (BOOTADM_STR) - 1;
313
314 if (strncmp(msg, BOOTADM_STR, len) == 0) {
315 eeprom_error("error returned from %s\n", msg);
316 } else if (msg[0] != '\0') {
317 eeprom_error("%s\n", msg);
318 }
319 }
320
321 static char *
322 get_bootadm_value(char *name, const int quiet)
323 {
324 char *ptr, *ret_str, *end_ptr, *orig_ptr;
325 char output[BUFSIZ];
326 int is_console, is_kernel = 0;
327 size_t len;
328
329 is_console = (strcmp(name, "console") == 0);
330
331 if (strcmp(name, "boot-file") == 0) {
332 is_kernel = 1;
333 ptr = "/sbin/bootadm set-menu kernel 2>&1";
334 } else if (is_console || (strcmp(name, "boot-args") == 0)) {
335 ptr = "/sbin/bootadm set-menu args 2>&1";
336 } else {
337 eeprom_error("Unknown value in get_bootadm_value: %s\n", name);
338 return (NULL);
339 }
340
341 if (exec_cmd(ptr, output, BUFSIZ) != 0) {
342 if (quiet == 0) {
343 output_error_msg(output);
344 }
345 return (NULL);
346 }
347
348 if (is_console) {
349 if ((ptr = strstr(output, "console=")) == NULL) {
350 return (NULL);
351 }
352 ptr += strlen("console=");
353
354 /*
355 * -B may have comma-separated values. It may also be
356 * followed by other flags.
357 */
400 * Since we removed the console setting, we no
401 * longer need the initial "-B "
402 */
403 orig_ptr = output + 3;
404 } else {
405 orig_ptr = output;
406 }
407
408 ret_str = strdup(orig_ptr);
409 if (ret_str == NULL)
410 eeprom_error(NO_MEM, strlen(orig_ptr) + 1);
411 return (ret_str);
412 }
413 }
414
415 /*
416 * If quiet is 1, print nothing if there is no value. If quiet is 0, print
417 * a message. Return 1 if the value is printed, 0 otherwise.
418 */
419 static int
420 print_bootadm_value(char *name, const int quiet)
421 {
422 int rv = 0;
423 char *value = get_bootadm_value(name, quiet);
424
425 if ((value != NULL) && (value[0] != '\0')) {
426 (void) printf("%s=%s\n", name, value);
427 rv = 1;
428 } else if (quiet == 0) {
429 (void) printf("%s: data not available.\n", name);
430 }
431
432 if (value != NULL)
433 free(value);
434 return (rv);
435 }
436
437 static void
438 print_var(char *name, eplist_t *list)
439 {
440 benv_ent_t *p;
441 char *bootcmd;
442
443 /*
444 * The console property is kept in both menu.lst and bootenv.rc. The
445 * menu.lst value takes precedence.
446 */
447 if (strcmp(name, "console") == 0) {
448 if (print_bootadm_value(name, 1) == 0) {
449 if ((p = get_var(name, list)) != NULL) {
450 (void) printf("%s=%s\n", name, p->val ?
451 p->val : "");
452 } else {
453 (void) printf("%s: data not available.\n",
454 name);
455 }
456 }
457 } else if (strcmp(name, "bootcmd") == 0) {
458 bootcmd = getbootcmd();
459 (void) printf("%s=%s\n", name, bootcmd ? bootcmd : "");
460 } else if ((strcmp(name, "boot-file") == 0) ||
461 (strcmp(name, "boot-args") == 0)) {
462 (void) print_bootadm_value(name, 0);
463 } else if ((p = get_var(name, list)) == NULL) {
464 (void) printf("%s: data not available.\n", name);
465 } else {
466 (void) printf("%s=%s\n", name, p->val ? p->val : "");
467 }
468 }
469
470 static void
471 print_vars(eplist_t *list)
472 {
473 eplist_t *e;
474 benv_ent_t *p;
475 int console_printed = 0;
476
477 /*
478 * The console property is kept both in menu.lst and bootenv.rc.
479 * The menu.lst value takes precedence, so try printing that one
480 * first.
481 */
482 console_printed = print_bootadm_value("console", 1);
483
484 for (e = list->next; e != list; e = e->next) {
485 p = (benv_ent_t *)e->item;
486 if (p->name != NULL) {
487 if (((strcmp(p->name, "console") == 0) &&
488 (console_printed == 1)) ||
489 ((strcmp(p->name, "boot-file") == 0) ||
490 (strcmp(p->name, "boot-args") == 0))) {
491 /* handle these separately */
492 continue;
493 }
494 (void) printf("%s=%s\n", p->name, p->val ? p->val : "");
495 }
496 }
497 (void) print_bootadm_value("boot-file", 1);
498 (void) print_bootadm_value("boot-args", 1);
499 }
500
501 /*
502 * Write a string to a file, quoted appropriately. We use single
503 * quotes to prevent any variable expansion. Of course, we backslash-quote
504 * any single quotes or backslashes.
505 */
506 static void
507 put_quoted(FILE *fp, char *val)
508 {
509 (void) putc('\'', fp);
510 while (*val) {
511 switch (*val) {
512 case '\'':
513 case '\\':
514 (void) putc('\\', fp);
515 /* FALLTHROUGH */
516 default:
517 (void) putc(*val, fp);
518 break;
519 }
520 val++;
521 }
522 (void) putc('\'', fp);
523 }
524
525 static void
526 set_bootadm_var(char *name, char *value)
527 {
528 char buf[BUFSIZ];
529 char output[BUFSIZ] = "";
530 char *console, *args;
531 int is_console;
532
533 if (verbose) {
534 (void) printf("old:");
535 (void) print_bootadm_value(name, 0);
536 }
537
538 /*
539 * For security, we single-quote whatever we run on the command line,
540 * and we don't allow single quotes in the string.
541 */
542 if (strchr(value, '\'') != NULL) {
543 eeprom_error("Single quotes are not allowed "
544 "in the %s property.\n", name);
545 return;
546 }
547
548 is_console = (strcmp(name, "console") == 0);
549 if (strcmp(name, "boot-file") == 0) {
550 (void) snprintf(buf, BUFSIZ, "/sbin/bootadm set-menu "
551 "kernel='%s' 2>&1", value);
552 } else if (is_console || (strcmp(name, "boot-args") == 0)) {
553 if (is_console) {
554 args = get_bootadm_value("boot-args", 1);
555 console = value;
556 } else {
557 args = value;
558 console = get_bootadm_value("console", 1);
559 }
560 if (((args == NULL) || (args[0] == '\0')) &&
561 ((console == NULL) || (console[0] == '\0'))) {
562 (void) snprintf(buf, BUFSIZ, "/sbin/bootadm set-menu "
563 "args= 2>&1");
564 } else if ((args == NULL) || (args[0] == '\0')) {
565 (void) snprintf(buf, BUFSIZ, "/sbin/bootadm "
566 "set-menu args='-B console=%s' 2>&1",
567 console);
568 } else if ((console == NULL) || (console[0] == '\0')) {
569 (void) snprintf(buf, BUFSIZ, "/sbin/bootadm "
570 "set-menu args='%s' 2>&1", args);
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",
574 console, args);
575 } else {
576 (void) snprintf(buf, BUFSIZ, "/sbin/bootadm "
577 "set-menu args='-B console=%s,%s' 2>&1",
578 console, args + 3);
579 }
580 } else {
581 eeprom_error("Unknown value in set_bootadm_value: %s\n", name);
582 return;
583 }
584
585 if (exec_cmd(buf, output, BUFSIZ) != 0) {
586 output_error_msg(output);
587 return;
588 }
589
590 if (verbose) {
591 (void) printf("new:");
592 (void) print_bootadm_value(name, 0);
593 }
594 }
595
596 /*
597 * Returns 1 if bootenv.rc was modified, 0 otherwise.
598 */
599 static int
600 set_var(char *name, char *val, eplist_t *list)
601 {
602 benv_ent_t *p;
603 int old_verbose;
604
605 if (strcmp(name, "bootcmd") == 0)
606 return (0);
607
608 if ((strcmp(name, "boot-file") == 0) ||
609 (strcmp(name, "boot-args") == 0)) {
610 set_bootadm_var(name, val);
611 return (0);
612 }
613
614 /*
615 * The console property is kept in two places: menu.lst and bootenv.rc.
616 * Update them both. We clear verbose to prevent duplicate messages.
617 */
618 if (strcmp(name, "console") == 0) {
619 old_verbose = verbose;
620 verbose = 0;
621 set_bootadm_var(name, val);
622 verbose = old_verbose;
623 }
624
625 if (verbose) {
626 (void) printf("old:");
627 print_var(name, list);
628 }
629
630 if ((p = get_var(name, list)) != NULL) {
631 free(p->val);
632 p->val = strdup(val);
633 } else
634 add_bent(list, NULL, "setprop", name, val);
635
636 if (verbose) {
637 (void) printf("new:");
638 print_var(name, list);
639 }
640 return (1);
641 }
|
283 if (output) {
284 len = strlen(output) - 1;
285 if (output[len] == '\n')
286 output[len] = '\0';
287 }
288
289 ret = pclose(ptr);
290 if (ret == -1) {
291 eeprom_error(PCLOSE_FAIL, cmdline, strerror(errno));
292 return (-1);
293 }
294
295 if (WIFEXITED(ret)) {
296 return (WEXITSTATUS(ret));
297 } else {
298 eeprom_error(EXEC_FAIL, cmdline, ret);
299 return (-1);
300 }
301 }
302
303 #define GRUBADM_STR "grubadm: "
304
305 /*
306 * grubadm starts all error messages with "grubadm: ".
307 * Add a note so users don't get confused on how they ran grubadm.
308 */
309 static void
310 output_error_msg(const char *msg)
311 {
312 size_t len = sizeof (GRUBADM_STR) - 1;
313
314 if (strncmp(msg, GRUBADM_STR, len) == 0) {
315 eeprom_error("error returned from %s\n", msg);
316 } else if (msg[0] != '\0') {
317 eeprom_error("%s\n", msg);
318 }
319 }
320
321 static char *
322 get_grubadm_value(char *name, const int quiet)
323 {
324 char *ptr, *ret_str, *end_ptr, *orig_ptr;
325 char output[BUFSIZ];
326 int is_console, is_kernel = 0;
327 size_t len;
328
329 is_console = (strcmp(name, "console") == 0);
330
331 if (strcmp(name, "boot-file") == 0) {
332 is_kernel = 1;
333 ptr = "/sbin/grubadm --number -1 --get-kernel 2>&1";
334 } else if (is_console || (strcmp(name, "boot-args") == 0)) {
335 ptr = "/sbin/grubadm --number -1 --get-opts 2>&1";
336 } else {
337 eeprom_error("Unknown value in get_grubadm_value: %s\n", name);
338 return (NULL);
339 }
340
341 if (exec_cmd(ptr, output, BUFSIZ) != 0) {
342 if (quiet == 0) {
343 output_error_msg(output);
344 }
345 return (NULL);
346 }
347
348 if (is_console) {
349 if ((ptr = strstr(output, "console=")) == NULL) {
350 return (NULL);
351 }
352 ptr += strlen("console=");
353
354 /*
355 * -B may have comma-separated values. It may also be
356 * followed by other flags.
357 */
400 * Since we removed the console setting, we no
401 * longer need the initial "-B "
402 */
403 orig_ptr = output + 3;
404 } else {
405 orig_ptr = output;
406 }
407
408 ret_str = strdup(orig_ptr);
409 if (ret_str == NULL)
410 eeprom_error(NO_MEM, strlen(orig_ptr) + 1);
411 return (ret_str);
412 }
413 }
414
415 /*
416 * If quiet is 1, print nothing if there is no value. If quiet is 0, print
417 * a message. Return 1 if the value is printed, 0 otherwise.
418 */
419 static int
420 print_grubadm_value(char *name, const int quiet)
421 {
422 int rv = 0;
423 char *value = get_grubadm_value(name, quiet);
424
425 if ((value != NULL) && (value[0] != '\0')) {
426 (void) printf("%s=%s\n", name, value);
427 rv = 1;
428 } else if (quiet == 0) {
429 (void) printf("%s: data not available.\n", name);
430 }
431
432 if (value != NULL)
433 free(value);
434 return (rv);
435 }
436
437 static void
438 print_var(char *name, eplist_t *list)
439 {
440 benv_ent_t *p;
441 char *bootcmd;
442
443 /*
444 * The console property is kept in both menu.lst and bootenv.rc. The
445 * menu.lst value takes precedence.
446 */
447 if (strcmp(name, "console") == 0) {
448 if (print_grubadm_value(name, 1) == 0) {
449 if ((p = get_var(name, list)) != NULL) {
450 (void) printf("%s=%s\n", name, p->val ?
451 p->val : "");
452 } else {
453 (void) printf("%s: data not available.\n",
454 name);
455 }
456 }
457 } else if (strcmp(name, "bootcmd") == 0) {
458 bootcmd = getbootcmd();
459 (void) printf("%s=%s\n", name, bootcmd ? bootcmd : "");
460 } else if ((strcmp(name, "boot-file") == 0) ||
461 (strcmp(name, "boot-args") == 0)) {
462 (void) print_grubadm_value(name, 0);
463 } else if ((p = get_var(name, list)) == NULL) {
464 (void) printf("%s: data not available.\n", name);
465 } else {
466 (void) printf("%s=%s\n", name, p->val ? p->val : "");
467 }
468 }
469
470 static void
471 print_vars(eplist_t *list)
472 {
473 eplist_t *e;
474 benv_ent_t *p;
475 int console_printed = 0;
476
477 /*
478 * The console property is kept both in menu.lst and bootenv.rc.
479 * The menu.lst value takes precedence, so try printing that one
480 * first.
481 */
482 console_printed = print_grubadm_value("console", 1);
483
484 for (e = list->next; e != list; e = e->next) {
485 p = (benv_ent_t *)e->item;
486 if (p->name != NULL) {
487 if (((strcmp(p->name, "console") == 0) &&
488 (console_printed == 1)) ||
489 ((strcmp(p->name, "boot-file") == 0) ||
490 (strcmp(p->name, "boot-args") == 0))) {
491 /* handle these separately */
492 continue;
493 }
494 (void) printf("%s=%s\n", p->name, p->val ? p->val : "");
495 }
496 }
497 (void) print_grubadm_value("boot-file", 1);
498 (void) print_grubadm_value("boot-args", 1);
499 }
500
501 /*
502 * Write a string to a file, quoted appropriately. We use single
503 * quotes to prevent any variable expansion. Of course, we backslash-quote
504 * any single quotes or backslashes.
505 */
506 static void
507 put_quoted(FILE *fp, char *val)
508 {
509 (void) putc('\'', fp);
510 while (*val) {
511 switch (*val) {
512 case '\'':
513 case '\\':
514 (void) putc('\\', fp);
515 /* FALLTHROUGH */
516 default:
517 (void) putc(*val, fp);
518 break;
519 }
520 val++;
521 }
522 (void) putc('\'', fp);
523 }
524
525 static void
526 set_grubadm_var(char *name, char *value)
527 {
528 char buf[BUFSIZ];
529 char output[BUFSIZ] = "";
530 char *console, *args;
531 int is_console;
532
533 if (verbose) {
534 (void) printf("old:");
535 (void) print_grubadm_value(name, 0);
536 }
537
538 /*
539 * For security, we single-quote whatever we run on the command line,
540 * and we don't allow single quotes in the string.
541 */
542 if (strchr(value, '\'') != NULL) {
543 eeprom_error("Single quotes are not allowed "
544 "in the %s property.\n", name);
545 return;
546 }
547
548 is_console = (strcmp(name, "console") == 0);
549 if (strcmp(name, "boot-file") == 0) {
550 (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
551 "--set-kernel '%s' 2>&1", value);
552 } else if (is_console || (strcmp(name, "boot-args") == 0)) {
553 if (is_console) {
554 args = get_grubadm_value("boot-args", 1);
555 console = value;
556 } else {
557 args = value;
558 console = get_grubadm_value("console", 1);
559 }
560 if (((args == NULL) || (args[0] == '\0')) &&
561 ((console == NULL) || (console[0] == '\0'))) {
562 (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
563 "--set-opts '-B $ZFS_BOOTFS' 2>&1");
564 } else if ((args == NULL) || (args[0] == '\0')) {
565 (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
566 "--set-opts '-B console=%s' 2>&1",
567 console);
568 } else if ((console == NULL) || (console[0] == '\0')) {
569 (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
570 "--set-opts '%s' 2>&1", args);
571 } else if (strncmp(args, "-B ", 3) != 0) {
572 (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
573 "--set-opts '-B console=%s %s' 2>&1",
574 console, args);
575 } else {
576 (void) snprintf(buf, BUFSIZ, "/sbin/grubadm --number -1 "
577 "--set-opts '-B console=%s,%s' 2>&1",
578 console, args + 3);
579 }
580 } else {
581 eeprom_error("Unknown value in set_grubadm_value: %s\n", name);
582 return;
583 }
584
585 if (exec_cmd(buf, output, BUFSIZ) != 0) {
586 output_error_msg(output);
587 return;
588 }
589
590 if (verbose) {
591 (void) printf("new:");
592 (void) print_grubadm_value(name, 0);
593 }
594 }
595
596 /*
597 * Returns 1 if bootenv.rc was modified, 0 otherwise.
598 */
599 static int
600 set_var(char *name, char *val, eplist_t *list)
601 {
602 benv_ent_t *p;
603 int old_verbose;
604
605 if (strcmp(name, "bootcmd") == 0)
606 return (0);
607
608 if ((strcmp(name, "boot-file") == 0) ||
609 (strcmp(name, "boot-args") == 0)) {
610 set_grubadm_var(name, val);
611 return (0);
612 }
613
614 /*
615 * The console property is kept in two places: menu.lst and bootenv.rc.
616 * Update them both. We clear verbose to prevent duplicate messages.
617 */
618 if (strcmp(name, "console") == 0) {
619 old_verbose = verbose;
620 verbose = 0;
621 set_grubadm_var(name, val);
622 verbose = old_verbose;
623 }
624
625 if (verbose) {
626 (void) printf("old:");
627 print_var(name, list);
628 }
629
630 if ((p = get_var(name, list)) != NULL) {
631 free(p->val);
632 p->val = strdup(val);
633 } else
634 add_bent(list, NULL, "setprop", name, val);
635
636 if (verbose) {
637 (void) printf("new:");
638 print_var(name, list);
639 }
640 return (1);
641 }
|