7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 */
25
26 /*
27 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 * Copyright 2016 Toomas Soome <tsoome@me.com>
29 */
30
31 /*
32 * Loader menu management.
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <wchar.h>
39 #include <errno.h>
40 #include <limits.h>
41 #include <alloca.h>
42 #include <unistd.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/queue.h>
46 #include <libbe.h>
47 #include <ficl.h>
48 #include <ficlplatform/emu.h>
49 #include <ofmt.h>
50
51 #include "bootadm.h"
52
53 extern int bam_rootlen;
54 extern int bam_alt_root;
55 extern char *rootbuf;
56 extern char *bam_root;
57
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"
63
64 typedef struct menu_entry {
65 int me_idx;
66 boolean_t me_active;
67 char *me_title;
68 char *me_type;
69 char *me_bootfs;
70 STAILQ_ENTRY(menu_entry) me_next;
71 } menu_entry_t;
72 STAILQ_HEAD(menu_lst, menu_entry);
73
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 *);
81
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 */
92 };
93
94 #define NUM_COLS (5)
95
96 static boolean_t
97 print_menu_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
98 {
99 menu_entry_t *entry = ofarg->ofmt_cbarg;
100
101 switch (ofarg->ofmt_id) {
102 case 0:
103 (void) snprintf(buf, bufsize, "%d", entry->me_idx);
104 break;
105 case 1:
106 (void) snprintf(buf, bufsize, "%s", entry->me_title);
107 break;
108 case 2:
109 (void) snprintf(buf, bufsize, "%s", entry->me_bootfs);
110 break;
473 if (special != NULL)
474 free(special);
475 return (BAM_ERROR);
476 }
477
478 /*
479 * If listing the menu, display the menu location
480 */
481 if (strcmp(subcmd, "list_entry") == 0)
482 bam_print(_("the location for the active menu is: %s\n"),
483 menu_path);
484
485 /*
486 * We already checked the following case in
487 * check_subcmd_and_suboptions() above. Complete the
488 * final step now.
489 */
490 if (strcmp(subcmd, "set_option") == 0) {
491 assert(largc == 1 && largv[0] && largv[1] == NULL);
492 opt = largv[0];
493 } else if ((strcmp(subcmd, "enable_hypervisor") != 0) &&
494 (strcmp(subcmd, "list_setting") != 0)) {
495 assert(largc == 0 && largv == NULL);
496 }
497
498 /*
499 * Once the sub-cmd handler has run
500 * only the line field is guaranteed to have valid values
501 */
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) {
512 if (is_sparc()) {
513 bam_error(_("%s operation unsupported on SPARC "
514 "machines\n"), subcmd);
515 ret = BAM_ERROR;
516 } else {
517 ret = f(&menu, bam_root, NULL);
518 }
519 } else if (strcmp(subcmd, "enable_hypervisor") == 0) {
520 if (is_sparc()) {
521 bam_error(_("%s operation unsupported on SPARC "
522 "machines\n"), subcmd);
523 ret = BAM_ERROR;
524 } else {
525 char *extra_args = NULL;
526
527 /*
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.
532 *
533 * This allows the caller to supply arbitrary unparsed
534 * arguments, such as dom0 memory settings or APIC
535 * options.
536 *
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
541 * may create.
542 */
543 if (largc > 0) {
544 int extra_len, i;
545
546 for (extra_len = 0, i = 0; i < largc; i++)
547 extra_len += strlen(largv[i]);
548
549 /*
550 * Allocate space for argument strings,
551 * intervening spaces and terminating NULL.
552 */
553 extra_args = alloca(extra_len + largc);
554
555 (void) strcpy(extra_args, largv[0]);
556
557 for (i = 1; i < largc; i++) {
558 (void) strcat(extra_args, " ");
559 (void) strcat(extra_args, largv[i]);
560 }
561 }
562
563 ret = f(&menu, bam_root, extra_args);
564 }
565 } else
566 ret = f(&menu, NULL, opt);
567
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); */
572 }
573
574 INJECT_ERROR1("POOL_SET", pool = "/pooldata");
575 assert((is_zfs(menu_root)) ^ (pool == NULL));
576 if (pool) {
577 (void) umount_top_dataset(pool, zmnted, zmntpt);
578 free(special);
579 }
580
581 menu_free(&menu);
582 return (ret);
583 }
584
869 }
870
871 }
872 ptr = getenv("console");
873 if (ptr != NULL) {
874 if (*setting == '\0')
875 (void) printf("Console: %s\n", ptr);
876 else if (strcasecmp(setting, "console") == 0) {
877 (void) printf("%s\n", ptr);
878 goto done;
879 }
880 }
881
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);
886 goto done;
887 }
888
889 ptr = getenv("xen_kernel");
890 if (ptr != NULL) {
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);
895 goto done;
896 }
897
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"));
903 goto done;
904 }
905
906 if (*setting == '\0') {
907 (void) printf("Kernel: %s\n",
908 getenv("bootfile"));
909 } if (strcasecmp(setting, "kernel") == 0) {
910 (void) printf("%s\n", getenv("bootfile"));
911 goto done;
912 }
913 } else {
914 ptr = getenv("kernelname");
915 if (ptr != NULL) {
916 if (*setting == '\0') {
917 (void) printf("Kernel: %s\n", ptr);
918 } else if (strcasecmp(setting, "kernel") == 0) {
919 (void) printf("%s\n", ptr);
920 goto done;
921 }
922 }
923 }
924
925 ptr = getenv("boot-args");
926 if (ptr != NULL) {
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);
931 goto done;
932 }
933 }
934
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"));
942 ret = BAM_ERROR;
943 goto done;
1044 (void) fprintf(fp, "title %s\n", be_node->be_node_name);
1045 (void) fprintf(fp, "bootfs %s\n", be_node->be_root_ds);
1046 }
1047 }
1048
1049 be_free_list(be_nodes);
1050 (void) fclose(fp);
1051 return (BAM_SUCCESS);
1052 }
1053
1054 /*ARGSUSED*/
1055 static error_t
1056 update_temp(struct menu_lst *menu, char *dummy, char *opt)
1057 {
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 };
1063 ficlVm *vm;
1064 char *env, *o;
1065 FILE *fp;
1066
1067 (void) snprintf(path, PATH_MAX, "%s" TRANSIENT, bam_root);
1068 /*
1069 * if opt == NULL, remove transient config
1070 */
1071 if (opt == NULL) {
1072 (void) unlink(path);
1073 return (BAM_SUCCESS);
1074 }
1075
1076 fp = fopen(MNTTAB, "r");
1077 if (fp == NULL)
1078 return (BAM_ERROR);
1079
1080 mpref.mnt_mountp = "/";
1081 if (getmntany(fp, &mp, &mpref) != 0) {
1082 (void) fclose(fp);
1083 return (BAM_ERROR);
1084 }
1085 (void) fclose(fp);
1086
1087 vm = bf_init("", ficlTextOutSilent);
1088 if (vm == NULL) {
1089 bam_error(_("Error setting up forth interpreter\n"));
1090 return (ret);
1091 }
1092
1093 /*
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.
1096 */
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"));
1101 bf_fini();
1102 return (BAM_ERROR);
1103 }
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"));
1108 bf_fini();
1109 return (BAM_ERROR);
1110 }
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"));
1115 bf_fini();
1116 return (BAM_ERROR);
1117 }
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"));
1122 bf_fini();
1123 return (BAM_ERROR);
1124 }
1125 bf_fini();
1126
1127 if (opt[0] == '-') {
1128 env = getenv("xen_kernel");
1129 fp = fopen(path, "w");
1130 if (fp == NULL)
1131 return (BAM_ERROR);
1132
1133 if (env != NULL) {
1134 env = getenv("boot-args");
1135 (void) fprintf(fp, "boot-args=\"%s %s\"\n", env, opt);
1136 } else
1137 (void) fprintf(fp, "boot-args=\"%s\"\n", opt);
1138 (void) fclose(fp);
1139 return (BAM_SUCCESS);
1140 }
1141
1142 /*
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=
1146 */
1147 env = getenv("xen_kernel");
1148
1149 o = strchr(opt, ' ');
1150 if (o == NULL) {
1151 fp = fopen(path, "w");
1152 if (fp == NULL)
1153 return (BAM_ERROR);
1154 (void) fprintf(fp, "bootfile=\"%s;unix\"\n", opt);
1155 (void) fclose(fp);
1156 return (BAM_SUCCESS);
1157 }
1158 *o++ = '\0';
1159 fp = fopen(path, "w");
1160 if (fp == NULL)
1161 return (BAM_ERROR);
1162 (void) fprintf(fp, "bootfile=\"%s;unix\"\n", opt);
1163
1164 if (env != NULL) {
1165 env = getenv("boot-args");
1166 (void) fprintf(fp, "boot-args=\"%s %s\"\n", env, opt);
1167 } else
1168 (void) fprintf(fp, "boot-args=\"%s\"\n", o);
1169
1170 (void) fflush(fp);
1171 (void) fclose(fp);
1172 return (ret);
1173 }
1174
1175 static error_t
1176 list_setting(struct menu_lst *menu, char *which, char *setting)
1177 {
1178 int entry = -1;
1179 menu_entry_t *m;
1180 be_node_list_t *be_nodes, *be_node = NULL;
1181 int ret;
1182
1183 assert(which);
1184 assert(setting);
1185
1186 /*
1187 * which can be:
1188 * "" - list default entry
1189 * number - use for entry number
1222 be_node->be_active_on_boot == B_TRUE)
1223 break; /* found active node */
1224 }
1225 be_free_list(be_nodes);
1226 if (be_node == NULL) {
1227 bam_error(_("None of BE nodes is marked active\n"));
1228 return (BAM_ERROR);
1229 }
1230 } else {
1231 STAILQ_FOREACH(m, menu, me_next)
1232 if (m->me_idx == entry)
1233 break;
1234
1235 if (m == NULL) {
1236 bam_error(_("no matching entry found\n"));
1237 return (BAM_ERROR);
1238 }
1239 }
1240
1241 return (list_menu_entry(m, setting));
1242 }
1243
1244 /*ARGSUSED*/
1245 static error_t
1246 disable_hyper(struct menu_lst *menu, char *osroot, char *opt)
1247 {
1248 char path[PATH_MAX];
1249
1250 (void) snprintf(path, PATH_MAX, "%s" XEN_CONFIG, bam_root);
1251 (void) unlink(path);
1252 return (BAM_SUCCESS);
1253 }
1254
1255 /*ARGSUSED*/
1256 static error_t
1257 enable_hyper(struct menu_lst *menu, char *osroot, char *opt)
1258 {
1259 ficlVm *vm;
1260 char path[PATH_MAX];
1261 char buf[MAX_INPUT];
1262 char *env;
1263 FILE *fp;
1264 struct mnttab mpref = { 0 };
1265 struct mnttab mp = { 0 };
1266 int ret;
1267
1268 fp = fopen(MNTTAB, "r");
1269 if (fp == NULL)
1270 return (BAM_ERROR);
1271
1272 mpref.mnt_mountp = "/";
1273 if (getmntany(fp, &mp, &mpref) != 0) {
1274 (void) fclose(fp);
1275 return (BAM_ERROR);
1276 }
1277 (void) fclose(fp);
1278
1279 vm = bf_init("", ficlTextOutSilent);
1280 if (vm == NULL) {
1281 bam_error(_("Error setting up forth interpreter\n"));
1282 return (BAM_ERROR);
1283 }
1284
1285 /*
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.
1288 */
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"));
1293 bf_fini();
1294 return (BAM_ERROR);
1295 }
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"));
1300 bf_fini();
1301 return (BAM_ERROR);
1302 }
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"));
1307 bf_fini();
1308 return (BAM_ERROR);
1309 }
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"));
1314 bf_fini();
1315 return (BAM_ERROR);
1316 }
1317 bf_fini();
1318
1319 (void) mkdir(CONF_DIR, 0755);
1320 (void) snprintf(path, PATH_MAX, "%s" XEN_CONFIG, bam_root);
1321 fp = fopen(path, "w");
1322 if (fp == NULL) {
1323 return (BAM_ERROR); /* error, cant write config */
1324 }
1325
1326 errno = 0;
1327 /*
1328 * on write error, remove file to ensure we have bootable config.
1329 * note we dont mind if config exists, it will get updated
1330 */
1331 (void) fprintf(fp, "xen_kernel=\"/boot/${ISADIR}/xen\"\n");
1332 if (errno != 0)
1333 goto error;
1334
1335 /*
1336 * really simple and stupid console conversion.
1337 * it really has to be gone, it belongs to milestone/xvm properties.
1338 */
1339 env = getenv("console");
1340 if (env != NULL) {
1341 if (strcmp(env, "ttya") == 0)
1342 (void) fprintf(fp, "xen_cmdline=\"console=com1 %s\"\n",
1343 opt);
1344 else if (strcmp(env, "ttyb") == 0)
1345 (void) fprintf(fp, "xen_cmdline=\"console=com2 %s\"\n",
1346 opt);
1347 else
1348 (void) fprintf(fp, "xen_cmdline=\"console=vga %s\"\n",
1349 opt);
1350 } else
1351 (void) fprintf(fp, "xen_cmdline=\"%s\"\n", opt);
1352 if (errno != 0)
1353 goto error;
1354
1355 (void) fprintf(fp,
1356 "bootfile=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1357 if (errno != 0)
1358 goto error;
1359
1360 (void) fprintf(fp,
1361 "boot-args=\"/platform/i86xpv/kernel/${ISADIR}/unix\"\n");
1362 if (errno != 0)
1363 goto error;
1364
1365 (void) fclose(fp);
1366 if (errno != 0) {
1367 (void) unlink(path);
1368 return (BAM_ERROR);
1369 }
1370 return (BAM_SUCCESS);
1371 error:
1372 (void) fclose(fp);
1373 (void) unlink(path);
1374 return (BAM_ERROR);
1375 }
|
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Milan Jurik. All rights reserved.
24 */
25
26 /*
27 * Copyright 2018 Nexenta Systems, Inc.
28 * Copyright 2016 Toomas Soome <tsoome@me.com>
29 */
30
31 /*
32 * Loader menu management.
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <wchar.h>
39 #include <errno.h>
40 #include <limits.h>
41 #include <alloca.h>
42 #include <unistd.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <sys/queue.h>
46 #include <libbe.h>
47 #include <ficl.h>
48 #include <ficlplatform/emu.h>
49 #include <ofmt.h>
50
51 #include "bootadm.h"
52
53 extern int bam_rootlen;
54 extern int bam_alt_root;
55 extern char *rootbuf;
56 extern char *bam_root;
57
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
63 typedef struct menu_entry {
64 int me_idx;
65 boolean_t me_active;
66 char *me_title;
67 char *me_type;
68 char *me_bootfs;
69 STAILQ_ENTRY(menu_entry) me_next;
70 } menu_entry_t;
71 STAILQ_HEAD(menu_lst, menu_entry);
72
73 static error_t set_option(struct menu_lst *, char *, char *);
74 static error_t list_entry(struct menu_lst *, char *, char *);
75 static error_t update_entry(struct menu_lst *, char *, char *);
76 static error_t update_temp(struct menu_lst *, char *, char *);
77 static error_t list_setting(struct menu_lst *menu, char *, char *);
78
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 NULL, 0, NULL, 0 /* must be last */
87 };
88
89 #define NUM_COLS (5)
90
91 static boolean_t
92 print_menu_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
93 {
94 menu_entry_t *entry = ofarg->ofmt_cbarg;
95
96 switch (ofarg->ofmt_id) {
97 case 0:
98 (void) snprintf(buf, bufsize, "%d", entry->me_idx);
99 break;
100 case 1:
101 (void) snprintf(buf, bufsize, "%s", entry->me_title);
102 break;
103 case 2:
104 (void) snprintf(buf, bufsize, "%s", entry->me_bootfs);
105 break;
468 if (special != NULL)
469 free(special);
470 return (BAM_ERROR);
471 }
472
473 /*
474 * If listing the menu, display the menu location
475 */
476 if (strcmp(subcmd, "list_entry") == 0)
477 bam_print(_("the location for the active menu is: %s\n"),
478 menu_path);
479
480 /*
481 * We already checked the following case in
482 * check_subcmd_and_suboptions() above. Complete the
483 * final step now.
484 */
485 if (strcmp(subcmd, "set_option") == 0) {
486 assert(largc == 1 && largv[0] && largv[1] == NULL);
487 opt = largv[0];
488 } else if (strcmp(subcmd, "list_setting") != 0) {
489 assert(largc == 0 && largv == NULL);
490 }
491
492 /*
493 * Once the sub-cmd handler has run
494 * only the line field is guaranteed to have valid values
495 */
496 if (strcmp(subcmd, "update_entry") == 0) {
497 ret = f(&menu, menu_root, osdev);
498 } else if (strcmp(subcmd, "upgrade") == 0) {
499 ret = f(&menu, bam_root, menu_root);
500 } else if (strcmp(subcmd, "list_entry") == 0) {
501 ret = f(&menu, menu_path, opt);
502 } else if (strcmp(subcmd, "list_setting") == 0) {
503 ret = f(&menu, ((largc > 0) ? largv[0] : ""),
504 ((largc > 1) ? largv[1] : ""));
505 } else
506 ret = f(&menu, NULL, opt);
507
508 if (ret == BAM_WRITE) {
509 BAM_DPRINTF(("%s: writing menu to clean-menu-root: <%s>\n",
510 fcn, clean_menu_root));
511 /* ret = menu_write(clean_menu_root, menu); */
512 }
513
514 INJECT_ERROR1("POOL_SET", pool = "/pooldata");
515 assert((is_zfs(menu_root)) ^ (pool == NULL));
516 if (pool) {
517 (void) umount_top_dataset(pool, zmnted, zmntpt);
518 free(special);
519 }
520
521 menu_free(&menu);
522 return (ret);
523 }
524
809 }
810
811 }
812 ptr = getenv("console");
813 if (ptr != NULL) {
814 if (*setting == '\0')
815 (void) printf("Console: %s\n", ptr);
816 else if (strcasecmp(setting, "console") == 0) {
817 (void) printf("%s\n", ptr);
818 goto done;
819 }
820 }
821
822 if (*setting == '\0')
823 (void) printf("Bootfs: %s\n", entry->me_bootfs);
824 else if (strcasecmp(setting, "bootfs") == 0) {
825 (void) printf("%s\n", entry->me_bootfs);
826 goto done;
827 }
828
829 ptr = getenv("kernelname");
830 if (ptr != NULL) {
831 if (*setting == '\0') {
832 (void) printf("Kernel: %s\n", ptr);
833 } else if (strcasecmp(setting, "kernel") == 0) {
834 (void) printf("%s\n", ptr);
835 goto done;
836 }
837 }
838
839 ptr = getenv("boot-args");
840 if (ptr != NULL) {
841 if (*setting == '\0') {
842 (void) printf("Boot-args: \"%s\"\n", ptr);
843 } else if (strcasecmp(setting, "boot-args") == 0) {
844 (void) printf("%s\n", ptr);
845 goto done;
846 }
847 }
848
849 if (*setting == '\0' || strcasecmp(setting, "modules") == 0) {
850 (void) printf("\nModules:\n");
851 ficlVmSetTextOut(vm, ficlCallbackDefaultTextOut);
852 (void) snprintf(buf, MAX_INPUT, "show-module-options");
853 ret = ficlVmEvaluate(vm, buf);
854 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
855 bam_error(_("error interpreting boot config\n"));
856 ret = BAM_ERROR;
857 goto done;
958 (void) fprintf(fp, "title %s\n", be_node->be_node_name);
959 (void) fprintf(fp, "bootfs %s\n", be_node->be_root_ds);
960 }
961 }
962
963 be_free_list(be_nodes);
964 (void) fclose(fp);
965 return (BAM_SUCCESS);
966 }
967
968 /*ARGSUSED*/
969 static error_t
970 update_temp(struct menu_lst *menu, char *dummy, char *opt)
971 {
972 error_t ret = BAM_ERROR;
973 char path[PATH_MAX];
974 char buf[MAX_INPUT];
975 struct mnttab mpref = { 0 };
976 struct mnttab mp = { 0 };
977 ficlVm *vm;
978 char *o;
979 FILE *fp;
980
981 (void) snprintf(path, PATH_MAX, "%s" TRANSIENT, bam_root);
982 /*
983 * if opt == NULL, remove transient config
984 */
985 if (opt == NULL) {
986 (void) unlink(path);
987 return (BAM_SUCCESS);
988 }
989
990 fp = fopen(MNTTAB, "r");
991 if (fp == NULL)
992 return (BAM_ERROR);
993
994 mpref.mnt_mountp = "/";
995 if (getmntany(fp, &mp, &mpref) != 0) {
996 (void) fclose(fp);
997 return (BAM_ERROR);
998 }
999 (void) fclose(fp);
1000
1001 vm = bf_init("", ficlTextOutSilent);
1002 if (vm == NULL) {
1003 bam_error(_("Error setting up forth interpreter\n"));
1004 return (ret);
1005 }
1006
1007 /*
1008 * Need to check current boot config, so fire up the ficl.
1009 */
1010 (void) snprintf(buf, MAX_INPUT, "set currdev=zfs:%s:", mp.mnt_special);
1011 ret = ficlVmEvaluate(vm, buf);
1012 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1013 bam_error(_("Error interpreting boot config\n"));
1014 bf_fini();
1015 return (BAM_ERROR);
1016 }
1017 (void) snprintf(buf, MAX_INPUT, "include /boot/forth/loader.4th");
1018 ret = ficlVmEvaluate(vm, buf);
1019 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1020 bam_error(_("Error interpreting boot config\n"));
1021 bf_fini();
1022 return (BAM_ERROR);
1023 }
1024 (void) snprintf(buf, MAX_INPUT, "start");
1025 ret = ficlVmEvaluate(vm, buf);
1026 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1027 bam_error(_("Error interpreting boot config\n"));
1028 bf_fini();
1029 return (BAM_ERROR);
1030 }
1031 (void) snprintf(buf, MAX_INPUT, "boot");
1032 ret = ficlVmEvaluate(vm, buf);
1033 if (ret != FICL_VM_STATUS_OUT_OF_TEXT) {
1034 bam_error(_("Error interpreting boot config\n"));
1035 bf_fini();
1036 return (BAM_ERROR);
1037 }
1038 bf_fini();
1039
1040 if (opt[0] == '-') {
1041 fp = fopen(path, "w");
1042 if (fp == NULL)
1043 return (BAM_ERROR);
1044 (void) fprintf(fp, "boot-args=\"%s\"\n", opt);
1045 (void) fclose(fp);
1046 return (BAM_SUCCESS);
1047 }
1048
1049 /*
1050 * it should be the case with "kernel args"
1051 * so, we split the opt at first space
1052 * and store bootfile= and boot-args=
1053 */
1054 o = strchr(opt, ' ');
1055 if (o == NULL) {
1056 fp = fopen(path, "w");
1057 if (fp == NULL)
1058 return (BAM_ERROR);
1059 (void) fprintf(fp, "bootfile=\"%s;unix\"\n", opt);
1060 (void) fclose(fp);
1061 return (BAM_SUCCESS);
1062 }
1063 *o++ = '\0';
1064 fp = fopen(path, "w");
1065 if (fp == NULL)
1066 return (BAM_ERROR);
1067 (void) fprintf(fp, "bootfile=\"%s;unix\"\n", opt);
1068 (void) fprintf(fp, "boot-args=\"%s\"\n", o);
1069 (void) fflush(fp);
1070 (void) fclose(fp);
1071 return (ret);
1072 }
1073
1074 static error_t
1075 list_setting(struct menu_lst *menu, char *which, char *setting)
1076 {
1077 int entry = -1;
1078 menu_entry_t *m;
1079 be_node_list_t *be_nodes, *be_node = NULL;
1080 int ret;
1081
1082 assert(which);
1083 assert(setting);
1084
1085 /*
1086 * which can be:
1087 * "" - list default entry
1088 * number - use for entry number
1121 be_node->be_active_on_boot == B_TRUE)
1122 break; /* found active node */
1123 }
1124 be_free_list(be_nodes);
1125 if (be_node == NULL) {
1126 bam_error(_("None of BE nodes is marked active\n"));
1127 return (BAM_ERROR);
1128 }
1129 } else {
1130 STAILQ_FOREACH(m, menu, me_next)
1131 if (m->me_idx == entry)
1132 break;
1133
1134 if (m == NULL) {
1135 bam_error(_("no matching entry found\n"));
1136 return (BAM_ERROR);
1137 }
1138 }
1139
1140 return (list_menu_entry(m, setting));
1141 }
|