Print this page
9250 remove xpv related code from bootadm


   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 }