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>
52 extern int bam_rootlen
;
53 extern int bam_alt_root
;
55 extern char *bam_root
;
57 #define BOOT_DIR "/boot"
58 #define CONF_DIR BOOT_DIR "/conf.d"
59 #define MENU BOOT_DIR "/menu.lst"
60 #define TRANSIENT BOOT_DIR "/transient.conf"
61 #define XEN_CONFIG CONF_DIR "/xen"
67 STAILQ_ENTRY(menu_entry
) next
;
69 STAILQ_HEAD(menu_lst
, menu_entry
);
71 static error_t
set_option(struct menu_lst
*, char *, char *);
72 static error_t
list_entry(struct menu_lst
*, char *, char *);
73 static error_t
update_entry(struct menu_lst
*, char *, char *);
74 static error_t
update_temp(struct menu_lst
*, char *, char *);
75 static error_t
list_setting(struct menu_lst
*menu
, char *, char *);
76 static error_t
disable_hyper(struct menu_lst
*, char *, char *);
77 static error_t
enable_hyper(struct menu_lst
*, char *, char *);
79 /* Menu related sub commands */
80 static subcmd_defn_t menu_subcmds
[] = {
81 { "set_option", OPT_ABSENT
, set_option
, 0 }, /* PUB */
82 { "list_entry", OPT_OPTIONAL
, list_entry
, 1 }, /* PUB */
83 { "update_entry", OPT_REQ
, update_entry
, 0 }, /* menu */
84 { "update_temp", OPT_OPTIONAL
, update_temp
, 0 }, /* reboot */
85 { "list_setting", OPT_OPTIONAL
, list_setting
, 1 }, /* menu */
86 { "disable_hypervisor", OPT_ABSENT
, disable_hyper
, 0 }, /* menu */
87 { "enable_hypervisor", OPT_ABSENT
, enable_hyper
, 0 }, /* menu */
88 { NULL
, 0, NULL
, 0 } /* must be last */
98 * all columns output format
101 struct col_info cols
[NUM_COLS
];
105 print_hdr(struct hdr_info
*hdr_info
)
107 boolean_t first
= B_TRUE
;
110 for (i
= 0; i
< NUM_COLS
; i
++) {
111 struct col_info
*col_info
= &hdr_info
->cols
[i
];
112 const char *name
= col_info
->col_name
;
113 size_t width
= col_info
->width
;
119 (void) printf("%-*s", width
, name
);
122 (void) printf(" %-*s", width
, name
);
124 (void) putchar('\n');
128 init_hdr_cols(struct hdr_info
*hdr
)
130 struct col_info
*col
= hdr
->cols
;
133 col
[0].col_name
= _("Index");
134 col
[1].col_name
= _("Default");
135 col
[2].col_name
= _("Dataset");
136 col
[3].col_name
= _("Menu");
137 col
[4].col_name
= NULL
;
139 for (i
= 0; i
< NUM_COLS
; i
++) {
140 const char *name
= col
[i
].col_name
;
145 size_t sz
= mbstowcs(wname
, name
, sizeof (wname
) /
148 int wcsw
= wcswidth(wname
, sz
);
154 col
[i
].width
= strlen(name
);
161 count_widths(struct hdr_info
*hdr
, struct menu_lst
*menu
)
163 size_t len
[NUM_COLS
];
164 struct menu_entry
*entry
;
167 for (i
= 0; i
< NUM_COLS
; i
++)
168 len
[i
] = hdr
->cols
[i
].width
+ 1;
170 STAILQ_FOREACH(entry
, menu
, next
) {
171 size_t bootfs_len
= strlen(entry
->bootfs
);
172 if (bootfs_len
> len
[2])
173 len
[2] = bootfs_len
+ 1;
176 for (i
= 0; i
< NUM_COLS
; i
++)
177 hdr
->cols
[i
].width
= len
[i
];
181 print_menu_nodes(boolean_t parsable
, struct hdr_info
*hdr
,
182 struct menu_lst
*menu
)
184 struct menu_entry
*entry
;
187 be_node_list_t
*be_nodes
, *be_node
;
189 rv
= be_list(NULL
, &be_nodes
);
190 if (rv
!= BE_SUCCESS
)
193 STAILQ_FOREACH(entry
, menu
, next
) {
195 for (be_node
= be_nodes
; be_node
;
196 be_node
= be_node
->be_next_node
)
197 if (strcmp(be_node
->be_root_ds
, entry
->bootfs
) == 0)
201 (void) printf("%d;%s;%s;%s\n", i
,
202 be_node
->be_active_on_boot
== B_TRUE
? "*" : "-",
203 entry
->bootfs
, entry
->title
);
205 (void) printf("%-*d %-*s %-*s %-*s\n",
206 hdr
->cols
[0].width
, i
,
208 be_node
->be_active_on_boot
== B_TRUE
? "*" : "-",
209 hdr
->cols
[2].width
, entry
->bootfs
,
210 hdr
->cols
[3].width
, entry
->title
);
212 be_free_list(be_nodes
);
216 print_nodes(boolean_t parsable
, struct menu_lst
*menu
)
222 count_widths(&hdr
, menu
);
226 print_menu_nodes(parsable
, &hdr
, menu
);
230 menu_read(struct menu_lst
*menu
, char *menu_path
)
233 struct menu_entry
*mp
;
239 int ret
= BAM_SUCCESS
;
241 fp
= fopen(menu_path
, "r");
246 * menu.lst entry is on two lines, one for title, one for bootfs
247 * so we process both lines in succession.
250 if (fgets(buf
, PATH_MAX
, fp
) == NULL
) {
256 ptr
= strchr(buf
, '\n');
260 ptr
= strchr(buf
, ' ');
266 if (strcmp(buf
, "title") != 0) {
270 if ((title
= strdup(ptr
)) == NULL
) {
275 if (fgets(buf
, PATH_MAX
, fp
) == NULL
) {
281 ptr
= strchr(buf
, '\n');
285 ptr
= strchr(buf
, ' ');
292 if (strcmp(buf
, "bootfs") != 0) {
297 if ((bootfs
= strdup(ptr
)) == NULL
) {
302 if ((mp
= malloc(sizeof (struct menu_entry
))) == NULL
) {
311 STAILQ_INSERT_TAIL(menu
, mp
, next
);
312 } while (feof(fp
) == 0);
319 menu_free(struct menu_lst
*menu
)
321 struct menu_entry
*entry
;
322 STAILQ_FOREACH(entry
, menu
, next
) {
323 STAILQ_REMOVE_HEAD(menu
, next
);
331 bam_loader_menu(char *subcmd
, char *opt
, int largc
, char *largv
[])
334 char menu_path
[PATH_MAX
];
335 char clean_menu_root
[PATH_MAX
];
336 char menu_root
[PATH_MAX
];
338 error_t (*f
)(struct menu_lst
*, char *, char *);
345 const char *fcn
= "bam_loader_menu()";
346 struct menu_lst menu
= {0};
353 ret
= check_subcmd_and_options(subcmd
, opt
, menu_subcmds
, &f
);
354 if (ret
== BAM_ERROR
) {
360 (void) strlcpy(menu_root
, bam_root
, sizeof (menu_root
));
361 osdev
= osroot
= NULL
;
363 if (strcmp(subcmd
, "update_entry") == 0) {
366 osdev
= strtok(opt
, ",");
368 osroot
= strtok(NULL
, ",");
370 /* fixup bam_root so that it points at osroot */
371 if (realpath(osroot
, rootbuf
) == NULL
) {
372 bam_error(_("cannot resolve path %s: %s\n"),
373 osroot
, strerror(errno
));
378 bam_rootlen
= strlen(rootbuf
);
382 if (stat(menu_root
, &sb
) == -1) {
383 bam_error(_("cannot find menu\n"));
387 if (!is_zfs(menu_root
)) {
388 bam_error(_("only ZFS root is supported\n"));
392 assert(strcmp(menu_root
, bam_root
) == 0);
393 special
= get_special(menu_root
);
394 INJECT_ERROR1("Z_MENU_GET_SPECIAL", special
= NULL
);
395 if (special
== NULL
) {
396 bam_error(_("cant find special file for mount-point %s\n"),
400 pool
= strtok(special
, "/");
401 INJECT_ERROR1("Z_MENU_GET_POOL", pool
= NULL
);
404 bam_error(_("cant find pool for mount-point %s\n"), menu_root
);
407 BAM_DPRINTF(("%s: derived pool=%s from special\n", fcn
, pool
));
409 zmntpt
= mount_top_dataset(pool
, &zmnted
);
410 INJECT_ERROR1("Z_MENU_MOUNT_TOP_DATASET", zmntpt
= NULL
);
411 if (zmntpt
== NULL
) {
412 bam_error(_("cannot mount pool dataset for pool: %s\n"), pool
);
416 BAM_DPRINTF(("%s: top dataset mountpoint=%s\n", fcn
, zmntpt
));
418 (void) strlcpy(menu_root
, zmntpt
, sizeof (menu_root
));
419 BAM_DPRINTF(("%s: zfs menu_root=%s\n", fcn
, menu_root
));
421 elide_trailing_slash(menu_root
, clean_menu_root
,
422 sizeof (clean_menu_root
));
424 BAM_DPRINTF(("%s: cleaned menu root is <%s>\n", fcn
, clean_menu_root
));
426 (void) strlcpy(menu_path
, clean_menu_root
, sizeof (menu_path
));
427 (void) strlcat(menu_path
, MENU
, sizeof (menu_path
));
429 BAM_DPRINTF(("%s: menu path is: %s\n", fcn
, menu_path
));
432 * update_entry is special case, its used by installer
433 * and needs to create menu.lst file for loader
435 if (menu_read(&menu
, menu_path
) == BAM_ERROR
&&
436 strcmp(subcmd
, "update_entry") != 0) {
437 bam_error(_("cannot find menu file: %s\n"), menu_path
);
444 * If listing the menu, display the menu location
446 if (strcmp(subcmd
, "list_entry") == 0)
447 bam_print(_("the location for the active menu is: %s\n"),
451 * We already checked the following case in
452 * check_subcmd_and_suboptions() above. Complete the
455 if (strcmp(subcmd
, "set_option") == 0) {
456 assert(largc
== 1 && largv
[0] && largv
[1] == NULL
);
458 } else if ((strcmp(subcmd
, "enable_hypervisor") != 0) &&
459 (strcmp(subcmd
, "list_setting") != 0)) {
460 assert(largc
== 0 && largv
== NULL
);
464 * Once the sub-cmd handler has run
465 * only the line field is guaranteed to have valid values
467 if (strcmp(subcmd
, "update_entry") == 0) {
468 ret
= f(&menu
, menu_root
, osdev
);
469 } else if (strcmp(subcmd
, "upgrade") == 0) {
470 ret
= f(&menu
, bam_root
, menu_root
);
471 } else if (strcmp(subcmd
, "list_entry") == 0) {
472 ret
= f(&menu
, menu_path
, opt
);
473 } else if (strcmp(subcmd
, "list_setting") == 0) {
474 ret
= f(&menu
, ((largc
> 0) ? largv
[0] : ""),
475 ((largc
> 1) ? largv
[1] : ""));
476 } else if (strcmp(subcmd
, "disable_hypervisor") == 0) {
478 bam_error(_("%s operation unsupported on SPARC "
479 "machines\n"), subcmd
);
482 ret
= f(&menu
, bam_root
, NULL
);
484 } else if (strcmp(subcmd
, "enable_hypervisor") == 0) {
486 bam_error(_("%s operation unsupported on SPARC "
487 "machines\n"), subcmd
);
490 char *extra_args
= NULL
;
493 * Compress all arguments passed in the largv[] array
494 * into one string that can then be appended to the
495 * end of the kernel$ string the routine to enable the
496 * hypervisor will build.
498 * This allows the caller to supply arbitrary unparsed
499 * arguments, such as dom0 memory settings or APIC
502 * This concatenation will be done without ANY syntax
503 * checking whatsoever, so it's the responsibility of
504 * the caller to make sure the arguments are valid and
505 * do not duplicate arguments the conversion routines
511 for (extra_len
= 0, i
= 0; i
< largc
; i
++)
512 extra_len
+= strlen(largv
[i
]);
515 * Allocate space for argument strings,
516 * intervening spaces and terminating NULL.
518 extra_args
= alloca(extra_len
+ largc
);
520 (void) strcpy(extra_args
, largv
[0]);
522 for (i
= 1; i
< largc
; i
++) {
523 (void) strcat(extra_args
, " ");
524 (void) strcat(extra_args
, largv
[i
]);
528 ret
= f(&menu
, bam_root
, extra_args
);
531 ret
= f(&menu
, NULL
, opt
);
533 if (ret
== BAM_WRITE
) {
534 BAM_DPRINTF(("%s: writing menu to clean-menu-root: <%s>\n",
535 fcn
, clean_menu_root
));
536 /* ret = menu_write(clean_menu_root, menu); */
539 INJECT_ERROR1("POOL_SET", pool
= "/pooldata");
540 assert((is_zfs(menu_root
)) ^ (pool
== NULL
));
542 (void) umount_top_dataset(pool
, zmnted
, zmntpt
);
551 * To suppress output from ficl. We do not want to see messages
552 * from interpreting loader config.
557 ficlTextOutSilent(ficlCallback
*cb
, char *text
)
563 set_option(struct menu_lst
*menu
, char *dummy
, char *opt
)
569 struct menu_entry
*entry
;
572 int rv
, ret
= BAM_SUCCESS
;
576 assert(dummy
== NULL
);
578 val
= strchr(opt
, '=');
583 if (strcmp(opt
, "default") == 0) {
585 optval
= strtol(val
, &rest
, 10);
586 if (errno
!= 0 || *rest
!= '\0') {
587 bam_error(_("invalid boot entry number: %s\n"), val
);
590 STAILQ_FOREACH(entry
, menu
, next
) {
591 if (entry
->entry
== optval
)
595 bam_error(_("invalid boot entry number: %s\n"), val
);
598 if (nvlist_alloc(&be_attrs
, NV_UNIQUE_NAME
, 0) != 0) {
599 bam_error(_("out of memory\n"));
602 if (nvlist_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
,
603 entry
->title
) != 0) {
604 bam_error(_("out of memory\n"));
605 nvlist_free(be_attrs
);
608 ret
= be_activate(be_attrs
);
609 nvlist_free(be_attrs
);
613 } else if (strcmp(opt
, "timeout") == 0) {
615 optval
= strtol(val
, &rest
, 10);
616 if (errno
!= 0 || *rest
!= '\0') {
617 bam_error(_("invalid timeout: %s\n"), val
);
621 (void) snprintf(path
, PATH_MAX
, "%s" CONF_DIR
"/timeout",
624 fp
= fopen(path
, "w");
626 bam_error(_("failed to open file: %s: %s\n"),
627 path
, strerror(errno
));
631 * timeout=-1 is to disable auto boot in illumos, but
632 * loader needs "NO" to disable auto boot.
635 rv
= fprintf(fp
, "autoboot_delay=\"NO\"\n");
637 rv
= fprintf(fp
, "autoboot_delay=\"%d\"\n", optval
);
640 bam_error(_("write to file failed: %s: %s\n"),
641 path
, strerror(errno
));
648 bam_error(_("failed to close file: %s: %s\n"),
649 path
, strerror(errno
));
652 if (ret
== BAM_ERROR
)
655 return (BAM_SUCCESS
);
658 bam_error(_("invalid option: %s\n"), opt
);
663 bam_mount_be(struct menu_entry
*entry
, char **dir
)
665 nvlist_t
*be_attrs
= NULL
;
666 const char *tmpdir
= getenv("TMPDIR");
667 const char *tmpname
= "bam.XXXXXX";
668 be_node_list_t
*be_node
, *be_nodes
= NULL
;
675 ret
= asprintf(dir
, "%s/%s", tmpdir
, tmpname
);
677 return (BE_ERR_NOMEM
);
679 *dir
= mkdtemp(*dir
);
681 if (nvlist_alloc(&be_attrs
, NV_UNIQUE_NAME
, 0) != 0) {
686 ret
= be_list(NULL
, &be_nodes
);
687 if (ret
!= BE_SUCCESS
) {
691 for (be_node
= be_nodes
; be_node
;
692 be_node
= be_node
->be_next_node
)
693 if (strcmp(be_node
->be_root_ds
, entry
->bootfs
) == 0)
696 if (nvlist_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
,
697 be_node
->be_node_name
) != 0) {
702 if (nvlist_add_string(be_attrs
, BE_ATTR_MOUNTPOINT
, *dir
) != 0) {
707 ret
= be_mount(be_attrs
);
708 if (ret
== BE_ERR_MOUNTED
) {
710 * if BE is mounted, dir does not point to correct directory
717 if (be_nodes
!= NULL
)
718 be_free_list(be_nodes
);
719 nvlist_free(be_attrs
);
724 bam_umount_be(char *dir
)
729 if (dir
== NULL
) /* nothing to do */
732 if (nvlist_alloc(&be_attrs
, NV_UNIQUE_NAME
, 0) != 0)
733 return (BE_ERR_NOMEM
);
735 if (nvlist_add_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, dir
) != 0) {
740 ret
= be_unmount(be_attrs
);
742 nvlist_free(be_attrs
);
747 * display details of menu entry or single property
750 list_menu_entry(struct menu_entry
*entry
, char *setting
)
752 int ret
= BAM_SUCCESS
;
758 mounted
= bam_mount_be(entry
, &dir
);
759 if (mounted
!= BE_SUCCESS
&& mounted
!= BE_ERR_MOUNTED
) {
764 bam_error(_("%s is not mounted\n"), entry
->title
);
768 vm
= bf_init("", ficlTextOutSilent
);
770 bam_error(_("error setting up forth interpreter\n"));
775 /* should only get FICL_VM_STATUS_OUT_OF_TEXT */
776 (void) snprintf(buf
, MAX_INPUT
, "set currdev=zfs:%s:",
778 ret
= ficlVmEvaluate(vm
, buf
);
779 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
780 bam_error(_("error interpreting boot config\n"));
784 (void) snprintf(buf
, MAX_INPUT
, "include /boot/forth/loader.4th");
785 ret
= ficlVmEvaluate(vm
, buf
);
786 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
787 bam_error(_("error interpreting boot config\n"));
791 (void) snprintf(buf
, MAX_INPUT
, "start");
792 ret
= ficlVmEvaluate(vm
, buf
);
793 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
794 bam_error(_("error interpreting boot config\n"));
798 (void) snprintf(buf
, MAX_INPUT
, "boot");
799 ret
= ficlVmEvaluate(vm
, buf
);
800 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
801 bam_error(_("error interpreting boot config\n"));
807 if (*setting
== '\0')
808 (void) printf("\nTitle: %s\n", entry
->title
);
809 else if (strcasecmp(setting
, "title") == 0) {
810 (void) printf("%s\n", entry
->title
);
814 ptr
= getenv("autoboot_delay");
816 char *timeout
= "-1";
818 if (strcasecmp(ptr
, "NO") != 0)
821 if (*setting
== '\0')
822 (void) printf("Timeout: %s\n", timeout
);
823 else if (strcasecmp(setting
, "timeout") == 0) {
824 (void) printf("%s\n", timeout
);
829 ptr
= getenv("console");
831 if (*setting
== '\0')
832 (void) printf("Console: %s\n", ptr
);
833 else if (strcasecmp(setting
, "console") == 0) {
834 (void) printf("%s\n", ptr
);
839 if (*setting
== '\0')
840 (void) printf("Bootfs: %s\n", entry
->bootfs
);
841 else if (strcasecmp(setting
, "bootfs") == 0) {
842 (void) printf("%s\n", entry
->bootfs
);
846 ptr
= getenv("xen_kernel");
848 if (*setting
== '\0') {
849 (void) printf("Xen kernel: %s\n", ptr
);
850 } else if (strcasecmp(setting
, "xen_kernel") == 0) {
851 (void) printf("%s\n", ptr
);
855 if (*setting
== '\0') {
856 (void) printf("Xen args: \"%s\"\n",
857 getenv("xen_cmdline"));
858 } else if (strcasecmp(setting
, "xen_cmdline") == 0) {
859 (void) printf("%s\n", getenv("xen_cmdline"));
863 if (*setting
== '\0') {
864 (void) printf("Kernel: %s\n",
866 } if (strcasecmp(setting
, "kernel") == 0) {
867 (void) printf("%s\n", getenv("bootfile"));
871 ptr
= getenv("kernelname");
873 if (*setting
== '\0') {
874 (void) printf("Kernel: %s\n", ptr
);
875 } else if (strcasecmp(setting
, "kernel") == 0) {
876 (void) printf("%s\n", ptr
);
882 ptr
= getenv("boot-args");
884 if (*setting
== '\0') {
885 (void) printf("Boot-args: \"%s\"\n", ptr
);
886 } else if (strcasecmp(setting
, "boot-args") == 0) {
887 (void) printf("%s\n", ptr
);
892 if (*setting
== '\0' || strcasecmp(setting
, "modules") == 0) {
893 (void) printf("\nModules:\n");
894 ficlVmSetTextOut(vm
, ficlCallbackDefaultTextOut
);
895 (void) snprintf(buf
, MAX_INPUT
, "show-module-options");
896 ret
= ficlVmEvaluate(vm
, buf
);
897 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
898 bam_error(_("error interpreting boot config\n"));
906 /* if we got here with setting string, its unknown property */
907 if (*setting
!= '\0') {
908 bam_error(_("unknown property: %s\n"), setting
);
914 if (mounted
!= BE_ERR_MOUNTED
) {
915 (void) bam_umount_be(dir
);
928 list_entry(struct menu_lst
*menu
, char *menu_root
, char *opt
)
930 error_t ret
= BAM_SUCCESS
;
931 struct menu_entry
*entry
;
932 char *ptr
, *title
= NULL
;
936 print_nodes(B_FALSE
, menu
);
940 if ((ptr
= strchr(opt
, '=')) == NULL
) {
941 bam_error(_("invalid option: %s\n"), opt
);
946 if (strncmp(opt
, "entry", i
) == 0) {
948 } else if (strncmp(opt
, "title", i
) == 0) {
951 bam_error(_("invalid option: %s\n"), opt
);
955 STAILQ_FOREACH(entry
, menu
, next
) {
957 if (strcmp(title
, entry
->title
) == 0)
959 } else if (entry
->entry
== e
)
964 bam_error(_("no matching entry found\n"));
968 return (list_menu_entry(entry
, ""));
972 * For now this is just stub entry to support grub interface, the
973 * known consumer is installer ict.py code, calling as:
974 * bootadm update-menu -R /a -Z -o rdisk
975 * Later this can be converted to do something useful.
979 update_entry(struct menu_lst
*menu
, char *menu_root
, char *osdev
)
982 char *pool
= menu_root
+ 1;
983 be_node_list_t
*be_nodes
, *be_node
;
987 (void) snprintf(path
, PATH_MAX
, "%s%s", menu_root
, MENU
);
988 rv
= be_list(NULL
, &be_nodes
);
990 if (rv
!= BE_SUCCESS
)
993 fp
= fopen(path
, "w");
995 be_free_list(be_nodes
);
999 for (be_node
= be_nodes
; be_node
; be_node
= be_node
->be_next_node
) {
1000 if (strcmp(be_node
->be_rpool
, pool
) == 0) {
1001 (void) fprintf(fp
, "title %s\n", be_node
->be_node_name
);
1002 (void) fprintf(fp
, "bootfs %s\n", be_node
->be_root_ds
);
1006 be_free_list(be_nodes
);
1008 return (BAM_SUCCESS
);
1013 update_temp(struct menu_lst
*menu
, char *dummy
, char *opt
)
1015 error_t ret
= BAM_ERROR
;
1016 char path
[PATH_MAX
];
1017 char buf
[MAX_INPUT
];
1018 struct mnttab mpref
= { 0 };
1019 struct mnttab mp
= { 0 };
1024 (void) snprintf(path
, PATH_MAX
, "%s" TRANSIENT
, bam_root
);
1026 * if opt == NULL, remove transient config
1029 (void) unlink(path
);
1030 return (BAM_SUCCESS
);
1033 fp
= fopen(MNTTAB
, "r");
1037 mpref
.mnt_mountp
= "/";
1038 if (getmntany(fp
, &mp
, &mpref
) != 0) {
1044 vm
= bf_init("", ficlTextOutSilent
);
1046 bam_error(_("Error setting up forth interpreter\n"));
1051 * need to check current boot config, so fire up the ficl
1052 * if its xen setup, we add option to boot-args list, not replacing it.
1054 (void) snprintf(buf
, MAX_INPUT
, "set currdev=zfs:%s:", mp
.mnt_special
);
1055 ret
= ficlVmEvaluate(vm
, buf
);
1056 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1057 bam_error(_("Error interpreting boot config\n"));
1061 (void) snprintf(buf
, MAX_INPUT
, "include /boot/forth/loader.4th");
1062 ret
= ficlVmEvaluate(vm
, buf
);
1063 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1064 bam_error(_("Error interpreting boot config\n"));
1068 (void) snprintf(buf
, MAX_INPUT
, "start");
1069 ret
= ficlVmEvaluate(vm
, buf
);
1070 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1071 bam_error(_("Error interpreting boot config\n"));
1075 (void) snprintf(buf
, MAX_INPUT
, "boot");
1076 ret
= ficlVmEvaluate(vm
, buf
);
1077 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1078 bam_error(_("Error interpreting boot config\n"));
1084 if (opt
[0] == '-') {
1085 env
= getenv("xen_kernel");
1086 fp
= fopen(path
, "w");
1091 env
= getenv("boot-args");
1092 (void) fprintf(fp
, "boot-args=\"%s %s\"\n", env
, opt
);
1094 (void) fprintf(fp
, "boot-args=\"%s\"\n", opt
);
1096 return (BAM_SUCCESS
);
1100 * it should be the case with "kernel args"
1101 * so, we split the opt at first space
1102 * and store bootfile= and boot-args=
1104 env
= getenv("xen_kernel");
1106 o
= strchr(opt
, ' ');
1108 fp
= fopen(path
, "w");
1111 (void) fprintf(fp
, "bootfile=\"%s\"\n", opt
);
1113 return (BAM_SUCCESS
);
1116 fp
= fopen(path
, "w");
1119 (void) fprintf(fp
, "bootfile=\"%s\"\n", opt
);
1122 env
= getenv("boot-args");
1123 (void) fprintf(fp
, "boot-args=\"%s %s\"\n", env
, opt
);
1125 (void) fprintf(fp
, "boot-args=\"%s\"\n", o
);
1133 list_setting(struct menu_lst
*menu
, char *which
, char *setting
)
1136 struct menu_entry
*m
;
1137 be_node_list_t
*be_nodes
, *be_node
= NULL
;
1145 * "" - list default entry
1146 * number - use for entry number
1149 if (*which
!= '\0') {
1150 if (isdigit(*which
)) {
1153 entry
= strtol(which
, &rest
, 10);
1154 if (errno
!= 0 || *rest
!= '\0') {
1155 bam_error(_("invalid boot entry number: %s\n"),
1163 /* find default entry */
1165 ret
= be_list(NULL
, &be_nodes
);
1166 if (ret
!= BE_SUCCESS
) {
1167 bam_error(_("No BE's found\n"));
1170 STAILQ_FOREACH(m
, menu
, next
) {
1172 for (be_node
= be_nodes
; be_node
;
1173 be_node
= be_node
->be_next_node
)
1174 if (strcmp(be_node
->be_root_ds
, m
->bootfs
) == 0)
1176 if (be_node
->be_active_on_boot
== B_TRUE
)
1177 break; /* found active node */
1179 be_free_list(be_nodes
);
1180 if (be_node
== NULL
) {
1181 bam_error(_("None of BE nodes is marked active\n"));
1185 STAILQ_FOREACH(m
, menu
, next
)
1186 if (m
->entry
== entry
)
1190 bam_error(_("no matching entry found\n"));
1195 return (list_menu_entry(m
, setting
));
1200 disable_hyper(struct menu_lst
*menu
, char *osroot
, char *opt
)
1202 char path
[PATH_MAX
];
1204 (void) snprintf(path
, PATH_MAX
, "%s" XEN_CONFIG
, bam_root
);
1205 (void) unlink(path
);
1206 return (BAM_SUCCESS
);
1211 enable_hyper(struct menu_lst
*menu
, char *osroot
, char *opt
)
1214 char path
[PATH_MAX
];
1215 char buf
[MAX_INPUT
];
1218 struct mnttab mpref
= { 0 };
1219 struct mnttab mp
= { 0 };
1222 fp
= fopen(MNTTAB
, "r");
1226 mpref
.mnt_mountp
= "/";
1227 if (getmntany(fp
, &mp
, &mpref
) != 0) {
1233 vm
= bf_init("", ficlTextOutSilent
);
1235 bam_error(_("Error setting up forth interpreter\n"));
1240 * need to check current boot config, so fire up the ficl
1241 * if its xen setup, we add option to boot-args list, not replacing it.
1243 (void) snprintf(buf
, MAX_INPUT
, "set currdev=zfs:%s:", mp
.mnt_special
);
1244 ret
= ficlVmEvaluate(vm
, buf
);
1245 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1246 bam_error(_("Error interpreting boot config\n"));
1250 (void) snprintf(buf
, MAX_INPUT
, "include /boot/forth/loader.4th");
1251 ret
= ficlVmEvaluate(vm
, buf
);
1252 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1253 bam_error(_("Error interpreting boot config\n"));
1257 (void) snprintf(buf
, MAX_INPUT
, "start");
1258 ret
= ficlVmEvaluate(vm
, buf
);
1259 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1260 bam_error(_("Error interpreting boot config\n"));
1264 (void) snprintf(buf
, MAX_INPUT
, "boot");
1265 ret
= ficlVmEvaluate(vm
, buf
);
1266 if (ret
!= FICL_VM_STATUS_OUT_OF_TEXT
) {
1267 bam_error(_("Error interpreting boot config\n"));
1273 (void) mkdir(CONF_DIR
, 0755);
1274 (void) snprintf(path
, PATH_MAX
, "%s" XEN_CONFIG
, bam_root
);
1275 fp
= fopen(path
, "w");
1277 return (BAM_ERROR
); /* error, cant write config */
1282 * on write error, remove file to ensure we have bootable config.
1283 * note we dont mind if config exists, it will get updated
1285 (void) fprintf(fp
, "xen_kernel=\"/boot/${ISADIR}/xen\"\n");
1290 * really simple and stupid console conversion.
1291 * it really has to be gone, it belongs to milestone/xvm properties.
1293 env
= getenv("console");
1295 if (strcmp(env
, "ttya") == 0)
1296 (void) fprintf(fp
, "xen_cmdline=\"console=com1 %s\"\n",
1298 else if (strcmp(env
, "ttyb") == 0)
1299 (void) fprintf(fp
, "xen_cmdline=\"console=com2 %s\"\n",
1302 (void) fprintf(fp
, "xen_cmdline=\"console=vga %s\"\n",
1305 (void) fprintf(fp
, "xen_cmdline=\"%s\"\n", opt
);
1310 "bootfile=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1315 "boot-args=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1321 (void) unlink(path
);
1324 return (BAM_SUCCESS
);
1327 (void) unlink(path
);