4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
27 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 * Copyright 2016 Toomas Soome <tsoome@me.com>
32 * Loader menu management.
43 #include <sys/types.h>
45 #include <sys/queue.h>
48 #include <ficlplatform/emu.h>
53 extern int bam_rootlen
;
54 extern int bam_alt_root
;
56 extern char *bam_root
;
58 #define BOOT_DIR "/boot"
59 #define CONF_DIR BOOT_DIR "/conf.d"
60 #define MENU BOOT_DIR "/menu.lst"
61 #define TRANSIENT BOOT_DIR "/transient.conf"
62 #define XEN_CONFIG CONF_DIR "/xen"
64 typedef struct menu_entry
{
70 STAILQ_ENTRY(menu_entry
) me_next
;
72 STAILQ_HEAD(menu_lst
, menu_entry
);
74 static error_t
set_option(struct menu_lst
*, char *, char *);
75 static error_t
list_entry(struct menu_lst
*, char *, char *);
76 static error_t
update_entry(struct menu_lst
*, char *, char *);
77 static error_t
update_temp(struct menu_lst
*, char *, char *);
78 static error_t
list_setting(struct menu_lst
*menu
, char *, char *);
79 static error_t
disable_hyper(struct menu_lst
*, char *, char *);
80 static error_t
enable_hyper(struct menu_lst
*, char *, char *);
82 /* Menu related sub commands */
83 static subcmd_defn_t menu_subcmds
[] = {
84 "set_option", OPT_ABSENT
, set_option
, 0, /* PUB */
85 "list_entry", OPT_OPTIONAL
, list_entry
, 1, /* PUB */
86 "update_entry", OPT_REQ
, update_entry
, 0, /* menu */
87 "update_temp", OPT_OPTIONAL
, update_temp
, 0, /* reboot */
88 "list_setting", OPT_OPTIONAL
, list_setting
, 1, /* menu */
89 "disable_hypervisor", OPT_ABSENT
, disable_hyper
, 0, /* menu */
90 "enable_hypervisor", OPT_ABSENT
, enable_hyper
, 0, /* menu */
91 NULL
, 0, NULL
, 0 /* must be last */
97 print_menu_cb(ofmt_arg_t
*ofarg
, char *buf
, uint_t bufsize
)
99 menu_entry_t
*entry
= ofarg
->ofmt_cbarg
;
101 switch (ofarg
->ofmt_id
) {
103 (void) snprintf(buf
, bufsize
, "%d", entry
->me_idx
);
106 (void) snprintf(buf
, bufsize
, "%s", entry
->me_title
);
109 (void) snprintf(buf
, bufsize
, "%s", entry
->me_bootfs
);
112 (void) snprintf(buf
, bufsize
, "%s", entry
->me_type
);
115 if (entry
->me_active
== B_TRUE
)
116 (void) snprintf(buf
, bufsize
, " *");
118 (void) snprintf(buf
, bufsize
, " -");
127 init_hdr_cols(ofmt_field_t
*hdr
)
131 for (i
= 0; i
< NUM_COLS
; i
++) {
152 hdr
[i
].of_name
= name
;
154 hdr
[i
].of_cb
= print_menu_cb
;
158 size_t sz
= mbstowcs(wname
, name
, sizeof (wname
) /
161 int wcsw
= wcswidth(wname
, sz
);
163 hdr
[i
].of_width
= wcsw
;
165 hdr
[i
].of_width
= sz
;
167 hdr
[i
].of_width
= strlen(name
);
174 menu_update_widths(ofmt_field_t
*hdr
, struct menu_lst
*menu
)
176 size_t len
[NUM_COLS
];
180 for (i
= 0; i
< NUM_COLS
; i
++)
181 len
[i
] = hdr
[i
].of_width
+ 1;
183 STAILQ_FOREACH(entry
, menu
, me_next
) {
186 entry_len
= strlen(entry
->me_title
) + 1;
187 if (entry_len
> len
[1])
190 entry_len
= strlen(entry
->me_bootfs
) + 1;
191 if (entry_len
> len
[2])
194 entry_len
= strlen(entry
->me_type
) + 1;
195 if (entry_len
> len
[3])
199 for (i
= 0; i
< NUM_COLS
; i
++)
200 hdr
[i
].of_width
= len
[i
];
203 static ofmt_field_t
*
204 init_menu_template(struct menu_lst
*menu
)
208 if ((temp
= calloc(NUM_COLS
+ 1, sizeof (ofmt_field_t
))) == NULL
)
212 menu_update_widths(temp
, menu
);
217 print_nodes(boolean_t parsable
, struct menu_lst
*menu
)
221 uint_t ofmtflags
= 0;
222 ofmt_field_t
*menu_template
;
225 if (parsable
== B_TRUE
)
226 ofmtflags
= OFMT_PARSABLE
;
228 menu_template
= init_menu_template(menu
);
229 oferr
= ofmt_open(NULL
, menu_template
, ofmtflags
, 0, &ofmt
);
231 if (oferr
!= OFMT_SUCCESS
) {
232 char buf
[OFMT_BUFSIZE
];
234 (void) ofmt_strerror(ofmt
, oferr
, buf
, sizeof (buf
));
235 (void) printf("bootadm: %s\n", buf
);
240 STAILQ_FOREACH(entry
, menu
, me_next
)
241 ofmt_print(ofmt
, entry
);
248 * Get the be_active_on_boot for bootfs.
251 menu_active_on_boot(be_node_list_t
*be_nodes
, const char *bootfs
)
253 be_node_list_t
*be_node
;
254 boolean_t rv
= B_FALSE
;
256 for (be_node
= be_nodes
; be_node
!= NULL
;
257 be_node
= be_node
->be_next_node
) {
258 if (strcmp(be_node
->be_root_ds
, bootfs
) == 0) {
259 rv
= be_node
->be_active_on_boot
;
268 menu_read(struct menu_lst
*menu
, char *menu_path
)
271 be_node_list_t
*be_nodes
;
279 int ret
= BAM_SUCCESS
;
281 fp
= fopen(menu_path
, "r");
285 if (be_list(NULL
, &be_nodes
) != BE_SUCCESS
)
289 * menu.lst entry is on two lines, one for title, one for bootfs
290 * so we process both lines in succession.
296 if (fgets(buf
, PATH_MAX
, fp
) == NULL
) {
301 key
= strtok(buf
, " \n");
302 if (strcmp(key
, "title") != 0) {
306 value
= strtok(NULL
, " \n");
307 if ((title
= strdup(value
)) == NULL
) {
312 if (fgets(buf
, PATH_MAX
, fp
) == NULL
) {
317 key
= strtok(buf
, " \n");
318 if ((type
= strdup(key
)) == NULL
) {
322 value
= strtok(NULL
, " \n");
323 if ((bootfs
= strdup(value
)) == NULL
) {
327 if ((mp
= malloc(sizeof (menu_entry_t
))) == NULL
) {
332 mp
->me_title
= title
;
334 mp
->me_bootfs
= bootfs
;
335 mp
->me_active
= menu_active_on_boot(be_nodes
, bootfs
);
336 STAILQ_INSERT_TAIL(menu
, mp
, me_next
);
341 } while (feof(fp
) == 0);
348 be_free_list(be_nodes
);
353 menu_free(struct menu_lst
*menu
)
356 STAILQ_FOREACH(entry
, menu
, me_next
) {
357 STAILQ_REMOVE_HEAD(menu
, me_next
);
358 free(entry
->me_title
);
359 free(entry
->me_type
);
360 free(entry
->me_bootfs
);
366 bam_loader_menu(char *subcmd
, char *opt
, int largc
, char *largv
[])
369 char menu_path
[PATH_MAX
];
370 char clean_menu_root
[PATH_MAX
];
371 char menu_root
[PATH_MAX
];
373 error_t (*f
)(struct menu_lst
*, char *, char *);
380 const char *fcn
= "bam_loader_menu()";
381 struct menu_lst menu
= {0};
388 ret
= check_subcmd_and_options(subcmd
, opt
, menu_subcmds
, &f
);
389 if (ret
== BAM_ERROR
) {
395 (void) strlcpy(menu_root
, bam_root
, sizeof (menu_root
));
396 osdev
= osroot
= NULL
;
398 if (strcmp(subcmd
, "update_entry") == 0) {
401 osdev
= strtok(opt
, ",");
403 osroot
= strtok(NULL
, ",");
405 /* fixup bam_root so that it points at osroot */
406 if (realpath(osroot
, rootbuf
) == NULL
) {
407 bam_error(_("cannot resolve path %s: %s\n"),
408 osroot
, strerror(errno
));
413 bam_rootlen
= strlen(rootbuf
);
417 if (stat(menu_root
, &sb
) == -1) {
418 bam_error(_("cannot find menu\n"));
422 if (!is_zfs(menu_root
)) {
423 bam_error(_("only ZFS root is supported\n"));
427 assert(strcmp(menu_root
, bam_root
) == 0);
428 special
= get_special(menu_root
);
429 INJECT_ERROR1("Z_MENU_GET_SPECIAL", special
= NULL
);
430 if (special
== NULL
) {
431 bam_error(_("cant find special file for mount-point %s\n"),
435 pool
= strtok(special
, "/");
436 INJECT_ERROR1("Z_MENU_GET_POOL", pool
= NULL
);
439 bam_error(_("cant find pool for mount-point %s\n"), menu_root
);
442 BAM_DPRINTF(("%s: derived pool=%s from special\n", fcn
, pool
));
444 zmntpt
= mount_top_dataset(pool
, &zmnted
);
445 INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt
= NULL
);
446 if (zmntpt
== NULL
) {
447 bam_error(_("cannot mount pool dataset for pool: %s\n"), pool
);
451 BAM_DPRINTF(("%s: top dataset mountpoint=%s\n", fcn
, zmntpt
));
453 (void) strlcpy(menu_root
, zmntpt
, sizeof (menu_root
));
454 BAM_DPRINTF(("%s: zfs menu_root=%s\n", fcn
, menu_root
));
456 elide_trailing_slash(menu_root
, clean_menu_root
,
457 sizeof (clean_menu_root
));
459 BAM_DPRINTF(("%s: cleaned menu root is <%s>\n", fcn
, clean_menu_root
));
461 (void) strlcpy(menu_path
, clean_menu_root
, sizeof (menu_path
));
462 (void) strlcat(menu_path
, MENU
, sizeof (menu_path
));
464 BAM_DPRINTF(("%s: menu path is: %s\n", fcn
, menu_path
));
467 * update_entry is special case, its used by installer
468 * and needs to create menu.lst file for loader
470 if (menu_read(&menu
, menu_path
) == BAM_ERROR
&&
471 strcmp(subcmd
, "update_entry") != 0) {
472 bam_error(_("cannot find menu file: %s\n"), menu_path
);
479 * If listing the menu, display the menu location
481 if (strcmp(subcmd
, "list_entry") == 0)
482 bam_print(_("the location for the active menu is: %s\n"),
486 * We already checked the following case in
487 * check_subcmd_and_suboptions() above. Complete the
490 if (strcmp(subcmd
, "set_option") == 0) {
491 assert(largc
== 1 && largv
[0] && largv
[1] == NULL
);
493 } else if ((strcmp(subcmd
, "enable_hypervisor") != 0) &&
494 (strcmp(subcmd
, "list_setting") != 0)) {
495 assert(largc
== 0 && largv
== NULL
);
499 * Once the sub-cmd handler has run
500 * only the line field is guaranteed to have valid values
502 if (strcmp(subcmd
, "update_entry") == 0) {
503 ret
= f(&menu
, menu_root
, osdev
);
504 } else if (strcmp(subcmd
, "upgrade") == 0) {
505 ret
= f(&menu
, bam_root
, menu_root
);
506 } else if (strcmp(subcmd
, "list_entry") == 0) {
507 ret
= f(&menu
, menu_path
, opt
);
508 } else if (strcmp(subcmd
, "list_setting") == 0) {
509 ret
= f(&menu
, ((largc
> 0) ? largv
[0] : ""),
510 ((largc
> 1) ? largv
[1] : ""));
511 } else if (strcmp(subcmd
, "disable_hypervisor") == 0) {
513 bam_error(_("%s operation unsupported on SPARC "
514 "machines\n"), subcmd
);
517 ret
= f(&menu
, bam_root
, NULL
);
519 } else if (strcmp(subcmd
, "enable_hypervisor") == 0) {
521 bam_error(_("%s operation unsupported on SPARC "
522 "machines\n"), subcmd
);
525 char *extra_args
= NULL
;
528 * Compress all arguments passed in the largv[] array
529 * into one string that can then be appended to the
530 * end of the kernel$ string the routine to enable the
531 * hypervisor will build.
533 * This allows the caller to supply arbitrary unparsed
534 * arguments, such as dom0 memory settings or APIC
537 * This concatenation will be done without ANY syntax
538 * checking whatsoever, so it's the responsibility of
539 * the caller to make sure the arguments are valid and
540 * do not duplicate arguments the conversion routines
546 for (extra_len
= 0, i
= 0; i
< largc
; i
++)
547 extra_len
+= strlen(largv
[i
]);
550 * Allocate space for argument strings,
551 * intervening spaces and terminating NULL.
553 extra_args
= alloca(extra_len
+ largc
);
555 (void) strcpy(extra_args
, largv
[0]);
557 for (i
= 1; i
< largc
; i
++) {
558 (void) strcat(extra_args
, " ");
559 (void) strcat(extra_args
, largv
[i
]);
563 ret
= f(&menu
, bam_root
, extra_args
);
566 ret
= f(&menu
, NULL
, opt
);
568 if (ret
== BAM_WRITE
) {
569 BAM_DPRINTF(("%s: writing menu to clean-menu-root: <%s>\n",
570 fcn
, clean_menu_root
));
571 /* ret = menu_write(clean_menu_root, menu); */
574 INJECT_ERROR1("POOL_SET", pool
= "/pooldata");
575 assert((is_zfs(menu_root
)) ^ (pool
== NULL
));
577 (void) umount_top_dataset(pool
, zmnted
, zmntpt
);
586 * To suppress output from ficl. We do not want to see messages
587 * from interpreting loader config.
592 ficlTextOutSilent(ficlCallback
*cb
, char *text
)
598 set_option(struct menu_lst
*menu
, char *dummy
, char *opt
)
607 int rv
, ret
= BAM_SUCCESS
;
611 assert(dummy
== NULL
);
613 val
= strchr(opt
, '=');
618 if (strcmp(opt
, "default") == 0) {
620 optval
= strtol(val
, &rest
, 10);
621 if (errno
!= 0 || *rest
!= '\0') {
622 bam_error(_("invalid boot entry number: %s\n"), val
);
625 STAILQ_FOREACH(entry
, menu
, me_next
) {
626 if (entry
->me_idx
== optval
)
630 bam_error(_("invalid boot entry number: %s\n"), val
);
633 if (nvlist_alloc(&be_attrs
, NV_UNIQUE_NAME
, 0) != 0) {
634 bam_error(_("out of memory\n"));
637 if (nvlist_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
,
638 entry
->me_title
) != 0) {
639 bam_error(_("out of memory\n"));
640 nvlist_free(be_attrs
);
643 ret
= be_activate(be_attrs
);
644 nvlist_free(be_attrs
);
648 } else if (strcmp(opt
, "timeout") == 0) {
650 optval
= strtol(val
, &rest
, 10);
651 if (errno
!= 0 || *rest
!= '\0') {
652 bam_error(_("invalid timeout: %s\n"), val
);
656 (void) snprintf(path
, PATH_MAX
, "%s" CONF_DIR
"/timeout",
659 fp
= fopen(path
, "w");
661 bam_error(_("failed to open file: %s: %s\n"),
662 path
, strerror(errno
));
666 * timeout=-1 is to disable auto boot in illumos, but
667 * loader needs "NO" to disable auto boot.
670 rv
= fprintf(fp
, "autoboot_delay=\"NO\"\n");
672 rv
= fprintf(fp
, "autoboot_delay=\"%d\"\n", optval
);
675 bam_error(_("write to file failed: %s: %s\n"),
676 path
, strerror(errno
));
683 bam_error(_("failed to close file: %s: %s\n"),
684 path
, strerror(errno
));
687 if (ret
== BAM_ERROR
)
690 return (BAM_SUCCESS
);
693 bam_error(_("invalid option: %s\n"), opt
);
698 bam_mount_be(menu_entry_t
*entry
, char **dir
)
700 nvlist_t
*be_attrs
= NULL
;
701 const char *tmpdir
= getenv("TMPDIR");
702 const char *tmpname
= "bam.XXXXXX";
703 be_node_list_t
*be_node
, *be_nodes
= NULL
;
710 ret
= asprintf(dir
, "%s/%s", tmpdir
, tmpname
);
712 return (BE_ERR_NOMEM
);
714 *dir
= mkdtemp(*dir
);
716 if (nvlist_alloc(&be_attrs
, NV_UNIQUE_NAME
, 0) != 0) {
721 ret
= be_list(NULL
, &be_nodes
);
722 if (ret
!= BE_SUCCESS
) {
726 for (be_node
= be_nodes
; be_node
;
727 be_node
= be_node
->be_next_node
)
728 if (strcmp(be_node
->be_root_ds
, entry
->me_bootfs
) == 0)
731 if (nvlist_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
,
732 be_node
->be_node_name
) != 0) {
737 if (nvlist_add_string(be_attrs
, BE_ATTR_MOUNTPOINT
, *dir
) != 0) {
742 ret
= be_mount(be_attrs
);
743 if (ret
== BE_ERR_MOUNTED
) {
745 * if BE is mounted, dir does not point to correct directory
752 if (be_nodes
!= NULL
)
753 be_free_list(be_nodes
);
754 nvlist_free(be_attrs
);
759 bam_umount_be(char *dir
)
764 if (dir
== NULL
) /* nothing to do */
767 if (nvlist_alloc(&be_attrs
, NV_UNIQUE_NAME
, 0) != 0)
768 return (BE_ERR_NOMEM
);
770 if (nvlist_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, dir
) != 0) {
775 ret
= be_unmount(be_attrs
);
777 nvlist_free(be_attrs
);
782 * display details of menu entry or single property
785 list_menu_entry(menu_entry_t
*entry
, char *setting
)
787 int ret
= BAM_SUCCESS
;
793 if (strcmp(entry
->me_type
, "bootfs") != 0 ||
794 strchr(entry
->me_bootfs
, ':') != NULL
) {
795 (void) printf("\nTitle: %s\n", entry
->me_title
);
796 (void) printf("Type: %s\n", entry
->me_type
);
797 (void) printf("Device: %s\n", entry
->me_bootfs
);
801 mounted
= bam_mount_be(entry
, &dir
);
802 if (mounted
!= BE_SUCCESS
&& mounted
!= BE_ERR_MOUNTED
) {
807 bam_error(_("%s is not mounted\n"), entry
->me_title
);
811 vm
= bf_init("", ficlTextOutSilent
);
813 bam_error(_("error setting up forth interpreter\n"));
818 /* should only get FICL_VM_STATUS_OUT_OF_TEXT */
819 (void) snprintf(buf
, MAX_INPUT
, "set currdev=zfs:%s:",
821 ret
= ficlVmEvaluate(vm
, buf
);
822 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
823 bam_error(_("error interpreting boot config\n"));
827 (void) snprintf(buf
, MAX_INPUT
, "include /boot/forth/loader.4th");
828 ret
= ficlVmEvaluate(vm
, buf
);
829 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
830 bam_error(_("error interpreting boot config\n"));
834 (void) snprintf(buf
, MAX_INPUT
, "start");
835 ret
= ficlVmEvaluate(vm
, buf
);
836 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
837 bam_error(_("error interpreting boot config\n"));
841 (void) snprintf(buf
, MAX_INPUT
, "boot");
842 ret
= ficlVmEvaluate(vm
, buf
);
843 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
844 bam_error(_("error interpreting boot config\n"));
850 if (*setting
== '\0')
851 (void) printf("\nTitle: %s\n", entry
->me_title
);
852 else if (strcasecmp(setting
, "title") == 0) {
853 (void) printf("%s\n", entry
->me_title
);
857 ptr
= getenv("autoboot_delay");
859 char *timeout
= "-1";
861 if (strcasecmp(ptr
, "NO") != 0)
864 if (*setting
== '\0')
865 (void) printf("Timeout: %s\n", timeout
);
866 else if (strcasecmp(setting
, "timeout") == 0) {
867 (void) printf("%s\n", timeout
);
872 ptr
= getenv("console");
874 if (*setting
== '\0')
875 (void) printf("Console: %s\n", ptr
);
876 else if (strcasecmp(setting
, "console") == 0) {
877 (void) printf("%s\n", ptr
);
882 if (*setting
== '\0')
883 (void) printf("Bootfs: %s\n", entry
->me_bootfs
);
884 else if (strcasecmp(setting
, "bootfs") == 0) {
885 (void) printf("%s\n", entry
->me_bootfs
);
889 ptr
= getenv("xen_kernel");
891 if (*setting
== '\0') {
892 (void) printf("Xen kernel: %s\n", ptr
);
893 } else if (strcasecmp(setting
, "xen_kernel") == 0) {
894 (void) printf("%s\n", ptr
);
898 if (*setting
== '\0') {
899 (void) printf("Xen args: \"%s\"\n",
900 getenv("xen_cmdline"));
901 } else if (strcasecmp(setting
, "xen_cmdline") == 0) {
902 (void) printf("%s\n", getenv("xen_cmdline"));
906 if (*setting
== '\0') {
907 (void) printf("Kernel: %s\n",
909 } if (strcasecmp(setting
, "kernel") == 0) {
910 (void) printf("%s\n", getenv("bootfile"));
914 ptr
= getenv("kernelname");
916 if (*setting
== '\0') {
917 (void) printf("Kernel: %s\n", ptr
);
918 } else if (strcasecmp(setting
, "kernel") == 0) {
919 (void) printf("%s\n", ptr
);
925 ptr
= getenv("boot-args");
927 if (*setting
== '\0') {
928 (void) printf("Boot-args: \"%s\"\n", ptr
);
929 } else if (strcasecmp(setting
, "boot-args") == 0) {
930 (void) printf("%s\n", ptr
);
935 if (*setting
== '\0' || strcasecmp(setting
, "modules") == 0) {
936 (void) printf("\nModules:\n");
937 ficlVmSetTextOut(vm
, ficlCallbackDefaultTextOut
);
938 (void) snprintf(buf
, MAX_INPUT
, "show-module-options");
939 ret
= ficlVmEvaluate(vm
, buf
);
940 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
941 bam_error(_("error interpreting boot config\n"));
949 /* if we got here with setting string, its unknown property */
950 if (*setting
!= '\0') {
951 bam_error(_("unknown property: %s\n"), setting
);
957 if (mounted
!= BE_ERR_MOUNTED
) {
958 (void) bam_umount_be(dir
);
971 list_entry(struct menu_lst
*menu
, char *menu_root
, char *opt
)
973 error_t ret
= BAM_SUCCESS
;
975 char *ptr
, *title
= NULL
;
979 print_nodes(B_FALSE
, menu
);
983 if ((ptr
= strchr(opt
, '=')) == NULL
) {
984 bam_error(_("invalid option: %s\n"), opt
);
989 if (strncmp(opt
, "entry", i
) == 0) {
991 } else if (strncmp(opt
, "title", i
) == 0) {
994 bam_error(_("invalid option: %s\n"), opt
);
998 STAILQ_FOREACH(entry
, menu
, me_next
) {
1000 if (strcmp(title
, entry
->me_title
) == 0)
1002 } else if (entry
->me_idx
== e
)
1006 if (entry
== NULL
) {
1007 bam_error(_("no matching entry found\n"));
1011 return (list_menu_entry(entry
, ""));
1015 * For now this is just stub entry to support grub interface, the
1016 * known consumer is installer ict.py code, calling as:
1017 * bootadm update-menu -R /a -Z -o rdisk
1018 * Later this can be converted to do something useful.
1022 update_entry(struct menu_lst
*menu
, char *menu_root
, char *osdev
)
1024 char path
[PATH_MAX
];
1025 char *pool
= menu_root
+ 1;
1026 be_node_list_t
*be_nodes
, *be_node
;
1030 (void) snprintf(path
, PATH_MAX
, "%s%s", menu_root
, MENU
);
1031 rv
= be_list(NULL
, &be_nodes
);
1033 if (rv
!= BE_SUCCESS
)
1036 fp
= fopen(path
, "w");
1038 be_free_list(be_nodes
);
1042 for (be_node
= be_nodes
; be_node
; be_node
= be_node
->be_next_node
) {
1043 if (strcmp(be_node
->be_rpool
, pool
) == 0) {
1044 (void) fprintf(fp
, "title %s\n", be_node
->be_node_name
);
1045 (void) fprintf(fp
, "bootfs %s\n", be_node
->be_root_ds
);
1049 be_free_list(be_nodes
);
1051 return (BAM_SUCCESS
);
1056 update_temp(struct menu_lst
*menu
, char *dummy
, char *opt
)
1058 error_t ret
= BAM_ERROR
;
1059 char path
[PATH_MAX
];
1060 char buf
[MAX_INPUT
];
1061 struct mnttab mpref
= { 0 };
1062 struct mnttab mp
= { 0 };
1067 (void) snprintf(path
, PATH_MAX
, "%s" TRANSIENT
, bam_root
);
1069 * if opt == NULL, remove transient config
1072 (void) unlink(path
);
1073 return (BAM_SUCCESS
);
1076 fp
= fopen(MNTTAB
, "r");
1080 mpref
.mnt_mountp
= "/";
1081 if (getmntany(fp
, &mp
, &mpref
) != 0) {
1087 vm
= bf_init("", ficlTextOutSilent
);
1089 bam_error(_("Error setting up forth interpreter\n"));
1094 * need to check current boot config, so fire up the ficl
1095 * if its xen setup, we add option to boot-args list, not replacing it.
1097 (void) snprintf(buf
, MAX_INPUT
, "set currdev=zfs:%s:", mp
.mnt_special
);
1098 ret
= ficlVmEvaluate(vm
, buf
);
1099 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1100 bam_error(_("Error interpreting boot config\n"));
1104 (void) snprintf(buf
, MAX_INPUT
, "include /boot/forth/loader.4th");
1105 ret
= ficlVmEvaluate(vm
, buf
);
1106 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1107 bam_error(_("Error interpreting boot config\n"));
1111 (void) snprintf(buf
, MAX_INPUT
, "start");
1112 ret
= ficlVmEvaluate(vm
, buf
);
1113 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1114 bam_error(_("Error interpreting boot config\n"));
1118 (void) snprintf(buf
, MAX_INPUT
, "boot");
1119 ret
= ficlVmEvaluate(vm
, buf
);
1120 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1121 bam_error(_("Error interpreting boot config\n"));
1127 if (opt
[0] == '-') {
1128 env
= getenv("xen_kernel");
1129 fp
= fopen(path
, "w");
1134 env
= getenv("boot-args");
1135 (void) fprintf(fp
, "boot-args=\"%s %s\"\n", env
, opt
);
1137 (void) fprintf(fp
, "boot-args=\"%s\"\n", opt
);
1139 return (BAM_SUCCESS
);
1143 * it should be the case with "kernel args"
1144 * so, we split the opt at first space
1145 * and store bootfile= and boot-args=
1147 env
= getenv("xen_kernel");
1149 o
= strchr(opt
, ' ');
1151 fp
= fopen(path
, "w");
1154 (void) fprintf(fp
, "bootfile=\"%s\"\n", opt
);
1156 return (BAM_SUCCESS
);
1159 fp
= fopen(path
, "w");
1162 (void) fprintf(fp
, "bootfile=\"%s\"\n", opt
);
1165 env
= getenv("boot-args");
1166 (void) fprintf(fp
, "boot-args=\"%s %s\"\n", env
, opt
);
1168 (void) fprintf(fp
, "boot-args=\"%s\"\n", o
);
1176 list_setting(struct menu_lst
*menu
, char *which
, char *setting
)
1180 be_node_list_t
*be_nodes
, *be_node
= NULL
;
1188 * "" - list default entry
1189 * number - use for entry number
1192 if (*which
!= '\0') {
1193 if (isdigit(*which
)) {
1196 entry
= strtol(which
, &rest
, 10);
1197 if (errno
!= 0 || *rest
!= '\0') {
1198 bam_error(_("invalid boot entry number: %s\n"),
1206 /* find default entry */
1208 ret
= be_list(NULL
, &be_nodes
);
1209 if (ret
!= BE_SUCCESS
) {
1210 bam_error(_("No BE's found\n"));
1213 STAILQ_FOREACH(m
, menu
, me_next
) {
1215 for (be_node
= be_nodes
; be_node
;
1216 be_node
= be_node
->be_next_node
) {
1217 if (strcmp(be_node
->be_root_ds
,
1221 if (be_node
!= NULL
&&
1222 be_node
->be_active_on_boot
== B_TRUE
)
1223 break; /* found active node */
1225 be_free_list(be_nodes
);
1226 if (be_node
== NULL
) {
1227 bam_error(_("None of BE nodes is marked active\n"));
1231 STAILQ_FOREACH(m
, menu
, me_next
)
1232 if (m
->me_idx
== entry
)
1236 bam_error(_("no matching entry found\n"));
1241 return (list_menu_entry(m
, setting
));
1246 disable_hyper(struct menu_lst
*menu
, char *osroot
, char *opt
)
1248 char path
[PATH_MAX
];
1250 (void) snprintf(path
, PATH_MAX
, "%s" XEN_CONFIG
, bam_root
);
1251 (void) unlink(path
);
1252 return (BAM_SUCCESS
);
1257 enable_hyper(struct menu_lst
*menu
, char *osroot
, char *opt
)
1260 char path
[PATH_MAX
];
1261 char buf
[MAX_INPUT
];
1264 struct mnttab mpref
= { 0 };
1265 struct mnttab mp
= { 0 };
1268 fp
= fopen(MNTTAB
, "r");
1272 mpref
.mnt_mountp
= "/";
1273 if (getmntany(fp
, &mp
, &mpref
) != 0) {
1279 vm
= bf_init("", ficlTextOutSilent
);
1281 bam_error(_("Error setting up forth interpreter\n"));
1286 * need to check current boot config, so fire up the ficl
1287 * if its xen setup, we add option to boot-args list, not replacing it.
1289 (void) snprintf(buf
, MAX_INPUT
, "set currdev=zfs:%s:", mp
.mnt_special
);
1290 ret
= ficlVmEvaluate(vm
, buf
);
1291 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1292 bam_error(_("Error interpreting boot config\n"));
1296 (void) snprintf(buf
, MAX_INPUT
, "include /boot/forth/loader.4th");
1297 ret
= ficlVmEvaluate(vm
, buf
);
1298 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1299 bam_error(_("Error interpreting boot config\n"));
1303 (void) snprintf(buf
, MAX_INPUT
, "start");
1304 ret
= ficlVmEvaluate(vm
, buf
);
1305 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1306 bam_error(_("Error interpreting boot config\n"));
1310 (void) snprintf(buf
, MAX_INPUT
, "boot");
1311 ret
= ficlVmEvaluate(vm
, buf
);
1312 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1313 bam_error(_("Error interpreting boot config\n"));
1319 (void) mkdir(CONF_DIR
, 0755);
1320 (void) snprintf(path
, PATH_MAX
, "%s" XEN_CONFIG
, bam_root
);
1321 fp
= fopen(path
, "w");
1323 return (BAM_ERROR
); /* error, cant write config */
1328 * on write error, remove file to ensure we have bootable config.
1329 * note we dont mind if config exists, it will get updated
1331 (void) fprintf(fp
, "xen_kernel=\"/boot/${ISADIR}/xen\"\n");
1336 * really simple and stupid console conversion.
1337 * it really has to be gone, it belongs to milestone/xvm properties.
1339 env
= getenv("console");
1341 if (strcmp(env
, "ttya") == 0)
1342 (void) fprintf(fp
, "xen_cmdline=\"console=com1 %s\"\n",
1344 else if (strcmp(env
, "ttyb") == 0)
1345 (void) fprintf(fp
, "xen_cmdline=\"console=com2 %s\"\n",
1348 (void) fprintf(fp
, "xen_cmdline=\"console=vga %s\"\n",
1351 (void) fprintf(fp
, "xen_cmdline=\"%s\"\n", opt
);
1356 "bootfile=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1361 "boot-args=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1367 (void) unlink(path
);
1370 return (BAM_SUCCESS
);
1373 (void) unlink(path
);