diff options
Diffstat (limited to 'usr/src/lib/libbe/common')
| -rw-r--r-- | usr/src/lib/libbe/common/be_activate.c | 80 | ||||
| -rw-r--r-- | usr/src/lib/libbe/common/be_utils.c | 235 | ||||
| -rw-r--r-- | usr/src/lib/libbe/common/libbe.h | 6 | ||||
| -rw-r--r-- | usr/src/lib/libbe/common/libbe_priv.h | 6 | ||||
| -rw-r--r-- | usr/src/lib/libbe/common/mapfile-vers | 3 |
5 files changed, 300 insertions, 30 deletions
diff --git a/usr/src/lib/libbe/common/be_activate.c b/usr/src/lib/libbe/common/be_activate.c index 4843be623b..9602333a56 100644 --- a/usr/src/lib/libbe/common/be_activate.c +++ b/usr/src/lib/libbe/common/be_activate.c @@ -25,6 +25,7 @@ /* * Copyright 2015 Nexenta Systems, Inc. All rights reserved. + * Copyright 2016 Toomas Soome <tsoome@me.com> */ #include <assert.h> @@ -945,9 +946,15 @@ be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1, flag = "-m -f"; } - (void) snprintf(install_cmd, sizeof (install_cmd), - "%s %s %s %s %s", BE_INSTALL_GRUB, flag, - stage1, stage2, diskname); + if (be_has_grub()) { + (void) snprintf(install_cmd, sizeof (install_cmd), + "%s %s %s %s %s", BE_INSTALL_GRUB, flag, + stage1, stage2, diskname); + } else { + (void) snprintf(install_cmd, sizeof (install_cmd), + "%s %s %s %s %s", BE_INSTALL_BOOT, flag, + stage1, stage2, diskname); + } } else if (be_is_isa("sparc")) { if ((flags & BE_INSTALLBOOT_FLAG_FORCE) == BE_INSTALLBOOT_FLAG_FORCE) @@ -1215,6 +1222,7 @@ be_do_installboot(be_transaction_data_t *bt, uint16_t flags) int ret = BE_SUCCESS; boolean_t be_mounted = B_FALSE; boolean_t update = B_FALSE; + boolean_t verbose = B_FALSE; /* * check versions. This call is to support detached @@ -1226,6 +1234,7 @@ be_do_installboot(be_transaction_data_t *bt, uint16_t flags) if (ret != BE_SUCCESS || update == B_FALSE) return (ret); } + verbose = do_print; if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) == NULL) { @@ -1247,27 +1256,37 @@ be_do_installboot(be_transaction_data_t *bt, uint16_t flags) } ZFS_CLOSE(zhp); - if (be_has_grub()) { - (void) snprintf(stage1, sizeof (stage1), "%s%s", - tmp_mntpt, BE_GRUB_STAGE_1); - (void) snprintf(stage2, sizeof (stage2), "%s%s", - tmp_mntpt, BE_GRUB_STAGE_2); - } else { + if (be_is_isa("i386")) { + if (be_has_grub()) { + (void) snprintf(stage1, sizeof (stage1), "%s%s", + tmp_mntpt, BE_GRUB_STAGE_1); + (void) snprintf(stage2, sizeof (stage2), "%s%s", + tmp_mntpt, BE_GRUB_STAGE_2); + } else { + (void) snprintf(stage1, sizeof (stage1), "%s%s", + tmp_mntpt, BE_LOADER_STAGE_1); + (void) snprintf(stage2, sizeof (stage2), "%s%s", + tmp_mntpt, BE_LOADER_STAGE_2); + } + } else if (be_is_isa("sparc")) { char *platform = be_get_platform(); if (platform == NULL) { - be_print_err(gettext("be_do_installboot: failed to " - "detect system platform name\n")); + be_print_err(gettext("be_do_installboot: " + "failed to detect system platform name\n")); if (be_mounted) (void) _be_unmount(bt->obe_name, 0); free(tmp_mntpt); return (BE_ERR_BOOTFILE_INST); } - stage1[0] = '\0'; /* sparc has no stage1 */ (void) snprintf(stage2, sizeof (stage2), "%s/usr/platform/%s%s", tmp_mntpt, platform, BE_SPARC_BOOTBLK); + } else { + be_print_err(gettext("be_do_installboot: unsupported " + "architecture.\n")); + return (BE_ERR_BOOTFILE_INST); } if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) { @@ -1309,7 +1328,9 @@ be_do_installboot(be_transaction_data_t *bt, uint16_t flags) for (c = 0; c < children; c++) { uint_t i, nchildren = 0; nvlist_t **nvchild; - vname = zpool_vdev_name(g_zfs, zphp, child[c], B_FALSE); + + /* ensure update on child status */ + vname = zpool_vdev_name(g_zfs, zphp, child[c], verbose); if (vname == NULL) { be_print_err(gettext( "be_do_installboot: " @@ -1317,28 +1338,49 @@ be_do_installboot(be_transaction_data_t *bt, uint16_t flags) libzfs_error_description(g_zfs)); ret = zfs_err_to_be_err(g_zfs); goto done; + } else if (verbose == B_TRUE) { + be_print_err(gettext("be_do_installboot: " + "device %s\n"), vname); } - if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') { - free(vname); + free(vname); - if (nvlist_lookup_nvlist_array(child[c], - ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) { + ret = nvlist_lookup_nvlist_array(child[c], + ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren); + if (ret != 0) { + if (ret != ENOENT) { be_print_err(gettext("be_do_installboot: " "failed to traverse the vdev tree: %s\n"), libzfs_error_description(g_zfs)); ret = zfs_err_to_be_err(g_zfs); goto done; } + nchildren = 0; /* This is leaf device. */ + } + if (nchildren != 0) { for (i = 0; i < nchildren; i++) { + /* ensure update on child status */ + vname = zpool_vdev_name(g_zfs, zphp, + nvchild[i], verbose); + if (vname == NULL) { + be_print_err(gettext( + "be_do_installboot: " + "failed to get device name: %s\n"), + libzfs_error_description(g_zfs)); + ret = zfs_err_to_be_err(g_zfs); + goto done; + } else if (verbose == B_TRUE) { + be_print_err(gettext( + "be_do_installboot: device %s\n"), + vname); + } + free(vname); ret = be_do_installboot_helper(zphp, nvchild[i], stage1, stage2, flags); if (ret != BE_SUCCESS) goto done; } } else { - free(vname); - ret = be_do_installboot_helper(zphp, child[c], stage1, stage2, flags); if (ret != BE_SUCCESS) diff --git a/usr/src/lib/libbe/common/be_utils.c b/usr/src/lib/libbe/common/be_utils.c index b92c32e527..1d79c51a4f 100644 --- a/usr/src/lib/libbe/common/be_utils.c +++ b/usr/src/lib/libbe/common/be_utils.c @@ -22,7 +22,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2013 Nexenta Systems, Inc. All rights reserved. - * Copyright 2015 Toomas Soome <tsoome@me.com> + * Copyright 2016 Toomas Soome <tsoome@me.com> * Copyright (c) 2015 by Delphix. All rights reserved. */ @@ -57,6 +57,8 @@ #include <libbe.h> #include <libbe_priv.h> #include <boot_utils.h> +#include <ficl.h> +#include <ficlplatform/emu.h> /* Private function prototypes */ static int update_dataset(char *, int, char *, char *, char *); @@ -83,6 +85,212 @@ typedef struct zone_be_name_cb_data { /* ******************************************************************** */ /* + * Callback for ficl to suppress all output from ficl, as we do not + * want to confuse user with messages from ficl, and we are only + * checking results from function calls. + */ +/*ARGSUSED*/ +static void +ficlSuppressTextOutput(ficlCallback *cb, char *text) +{ + /* This function is intentionally doing nothing. */ +} + +/* + * Function: be_get_boot_args + * Description: Returns the fast boot argument string for enumerated BE. + * Parameters: + * fbarg - pointer to argument string. + * entry - index of BE. + * Returns: + * fast boot argument string. + * Scope: + * Public + */ +int +be_get_boot_args(char **fbarg, int entry) +{ + be_node_list_t *node, *be_nodes = NULL; + be_transaction_data_t bt = {0}; + char *mountpoint = NULL; + boolean_t be_mounted = B_FALSE; + int ret = BE_SUCCESS; + int index; + ficlVm *vm; + + *fbarg = NULL; + if (!be_zfs_init()) + return (BE_ERR_INIT); + + /* + * need pool name, menu.lst has entries from our pool only + */ + ret = be_find_current_be(&bt); + if (ret != BE_SUCCESS) { + be_zfs_fini(); + return (ret); + } + + /* + * be_get_boot_args() is for loader, fail with grub will trigger + * normal boot. + */ + if (be_has_grub()) { + ret = BE_ERR_INIT; + goto done; + } + + ret = _be_list(NULL, &be_nodes); + if (ret != BE_SUCCESS) + goto done; + + /* + * iterate through be_nodes, + * if entry == -1, stop if be_active_on_boot, + * else stop if index == entry. + */ + index = 0; + for (node = be_nodes; node != NULL; node = node->be_next_node) { + if (strcmp(node->be_rpool, bt.obe_zpool) != 0) + continue; + if (entry == BE_ENTRY_DEFAULT && + node->be_active_on_boot == B_TRUE) + break; + if (index == entry) + break; + index++; + } + if (node == NULL) { + be_free_list(be_nodes); + ret = BE_ERR_NOENT; + goto done; + } + + /* try to mount inactive be */ + if (node->be_active == B_FALSE) { + ret = _be_mount(node->be_node_name, &mountpoint, + BE_MOUNT_FLAG_NO_ZONES); + if (ret != BE_SUCCESS && ret != BE_ERR_MOUNTED) { + be_free_list(be_nodes); + goto done; + } else + be_mounted = B_TRUE; + } + + vm = bf_init("", ficlSuppressTextOutput); + if (vm != NULL) { + /* + * zfs MAXNAMELEN is 256, so we need to pick buf large enough + * to contain such names. + */ + char buf[MAXNAMELEN * 2]; + char *kernel_options = NULL; + char *kernel = NULL; + char *tmp; + zpool_handle_t *zph; + + /* + * just try to interpret following words. on error + * we will be missing kernelname, and will get out. + */ + (void) snprintf(buf, sizeof (buf), "set currdev=zfs:%s:", + node->be_root_ds); + ret = ficlVmEvaluate(vm, buf); + if (ret != FICL_VM_STATUS_OUT_OF_TEXT) { + be_print_err(gettext("be_get_boot_args: error " + "interpreting boot config: %d\n"), ret); + bf_fini(); + ret = BE_ERR_NO_MENU; + goto cleanup; + } + (void) snprintf(buf, sizeof (buf), + "include /boot/forth/loader.4th"); + ret = ficlVmEvaluate(vm, buf); + if (ret != FICL_VM_STATUS_OUT_OF_TEXT) { + be_print_err(gettext("be_get_boot_args: error " + "interpreting boot config: %d\n"), ret); + bf_fini(); + ret = BE_ERR_NO_MENU; + goto cleanup; + } + (void) snprintf(buf, sizeof (buf), "start"); + ret = ficlVmEvaluate(vm, buf); + if (ret != FICL_VM_STATUS_OUT_OF_TEXT) { + be_print_err(gettext("be_get_boot_args: error " + "interpreting boot config: %d\n"), ret); + bf_fini(); + ret = BE_ERR_NO_MENU; + goto cleanup; + } + (void) snprintf(buf, sizeof (buf), "boot"); + ret = ficlVmEvaluate(vm, buf); + bf_fini(); + if (ret != FICL_VM_STATUS_OUT_OF_TEXT) { + be_print_err(gettext("be_get_boot_args: error " + "interpreting boot config: %d\n"), ret); + ret = BE_ERR_NO_MENU; + goto cleanup; + } + + kernel_options = getenv("boot-args"); + kernel = getenv("kernelname"); + + if (kernel == NULL) { + be_print_err(gettext("be_get_boot_args: no kernel\n")); + ret = BE_ERR_NOENT; + goto cleanup; + } + + if ((zph = zpool_open(g_zfs, node->be_rpool)) == NULL) { + be_print_err(gettext("be_get_boot_args: failed to " + "open root pool (%s): %s\n"), node->be_rpool, + libzfs_error_description(g_zfs)); + ret = zfs_err_to_be_err(g_zfs); + goto cleanup; + } + ret = zpool_get_physpath(zph, buf, sizeof (buf)); + zpool_close(zph); + if (ret != 0) { + be_print_err(gettext("be_get_boot_args: failed to " + "get physpath\n")); + goto cleanup; + } + + /* zpool_get_physpath() can return space separated list */ + tmp = buf; + tmp = strsep(&tmp, " "); + + if (kernel_options == NULL || *kernel_options == '\0') + (void) asprintf(fbarg, "/ %s " + "-B zfs-bootfs=%s,bootpath=\"%s\"\n", kernel, + node->be_root_ds, tmp); + else + (void) asprintf(fbarg, "/ %s %s " + "-B zfs-bootfs=%s,bootpath=\"%s\"\n", kernel, + kernel_options, node->be_root_ds, tmp); + + if (fbarg == NULL) + ret = BE_ERR_NOMEM; + else + ret = 0; + } else + ret = BE_ERR_NOMEM; +cleanup: + if (be_mounted == B_TRUE) + (void) _be_unmount(node->be_node_name, BE_UNMOUNT_FLAG_FORCE); + be_free_list(be_nodes); +done: + free(mountpoint); + free(bt.obe_name); + free(bt.obe_root_ds); + free(bt.obe_zpool); + free(bt.obe_snap_name); + free(bt.obe_altroot); + be_zfs_fini(); + return (ret); +} + +/* * Function: be_max_avail * Description: Returns the available size for the zfs dataset passed in. * Parameters: @@ -197,16 +405,24 @@ be_get_defaults(struct be_defaults *defaults) { void *defp; + defaults->be_deflt_grub = B_FALSE; defaults->be_deflt_rpool_container = B_FALSE; defaults->be_deflt_bename_starts_with[0] = '\0'; if ((defp = defopen_r(BE_DEFAULTS)) != NULL) { const char *res = defread_r(BE_DFLT_BENAME_STARTS, defp); - if (res != NULL && res[0] != NULL) { + if (res != NULL && res[0] != '\0') { (void) strlcpy(defaults->be_deflt_bename_starts_with, res, ZFS_MAX_DATASET_NAME_LEN); defaults->be_deflt_rpool_container = B_TRUE; } + if (be_is_isa("i386")) { + res = defread_r(BE_DFLT_BE_HAS_GRUB, defp); + if (res != NULL && res[0] != '\0') { + if (strcasecmp(res, "true") == 0) + defaults->be_deflt_grub = B_TRUE; + } + } defclose_r(defp); } } @@ -2908,11 +3124,16 @@ be_err_to_str(int err) boolean_t be_has_grub(void) { - /* - * TODO: This will need to be expanded to check for the existence of - * grub if and when there is grub support for SPARC. - */ - return (be_is_isa("i386")); + static struct be_defaults be_defaults; + static boolean_t be_deflts_set = B_FALSE; + + /* Cache the defaults, because be_has_grub is used often. */ + if (be_deflts_set == B_FALSE) { + be_get_defaults(&be_defaults); + be_deflts_set = B_TRUE; + } + + return (be_defaults.be_deflt_grub); } /* diff --git a/usr/src/lib/libbe/common/libbe.h b/usr/src/lib/libbe/common/libbe.h index 994bc881ac..a78f7a62f8 100644 --- a/usr/src/lib/libbe/common/libbe.h +++ b/usr/src/lib/libbe/common/libbe.h @@ -25,7 +25,7 @@ /* * Copyright 2013 Nexenta Systems, Inc. All rights reserved. - * Copyright 2015 Toomas Soome <tsoome@me.com> + * Copyright 2016 Toomas Soome <tsoome@me.com> * Copyright 2015 Gary Mills */ @@ -224,6 +224,8 @@ typedef enum { BE_SORT_SPACE_REV } be_sort_t; +/* for fastboot arguments */ +#define BE_ENTRY_DEFAULT (-1) /* * BE functions */ @@ -250,7 +252,7 @@ void be_free_list(be_node_list_t *); int be_max_avail(char *, uint64_t *); char *be_err_to_str(int); int be_sort(be_node_list_t **, int); - +int be_get_boot_args(char **, int); /* * Installboot support */ diff --git a/usr/src/lib/libbe/common/libbe_priv.h b/usr/src/lib/libbe/common/libbe_priv.h index 2e99204f22..d9cb964c25 100644 --- a/usr/src/lib/libbe/common/libbe_priv.h +++ b/usr/src/lib/libbe/common/libbe_priv.h @@ -22,7 +22,7 @@ /* * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2013 Nexenta Systems, Inc. All rights reserved. - * Copyright 2015 Toomas Soome <tsoome@me.com> + * Copyright 2016 Toomas Soome <tsoome@me.com> * Copyright (c) 2015 by Delphix. All rights reserved. */ @@ -42,6 +42,7 @@ extern "C" { #define BE_AUTO_NAME_DELIM '-' #define BE_DEFAULTS "/etc/default/be" #define BE_DFLT_BENAME_STARTS "BENAME_STARTS_WITH=" +#define BE_DFLT_BE_HAS_GRUB "BE_HAS_GRUB=" #define BE_CONTAINER_DS_NAME "ROOT" #define BE_DEFAULT_CONSOLE "text" #define BE_POLICY_PROPERTY "org.opensolaris.libbe:policy" @@ -61,6 +62,8 @@ extern "C" { #define BE_GRUB_STAGE_1 "/boot/grub/stage1" #define BE_GRUB_STAGE_2 "/boot/grub/stage2" #define BE_INSTALL_BOOT "/usr/sbin/installboot" +#define BE_LOADER_STAGE_1 "/boot/pmbr" +#define BE_LOADER_STAGE_2 "/boot/gptzfsboot" #define BE_SPARC_BOOTBLK "/lib/fs/zfs/bootblk" #define ZFS_CLOSE(_zhp) \ @@ -135,6 +138,7 @@ typedef struct be_plcy_list { struct be_defaults { boolean_t be_deflt_rpool_container; + boolean_t be_deflt_grub; char be_deflt_bename_starts_with[ZFS_MAX_DATASET_NAME_LEN]; }; diff --git a/usr/src/lib/libbe/common/mapfile-vers b/usr/src/lib/libbe/common/mapfile-vers index 0602bd7de3..eb461d4130 100644 --- a/usr/src/lib/libbe/common/mapfile-vers +++ b/usr/src/lib/libbe/common/mapfile-vers @@ -20,7 +20,7 @@ # # # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. -# Copyright (c) 2015, Toomas Soome <tsoome@me.com> +# Copyright 2016 Toomas Soome <tsoome@me.com> # # @@ -48,6 +48,7 @@ SYMBOL_VERSION SUNWprivate_1.1 { be_destroy_snapshot; be_err_to_str; be_free_list; + be_get_boot_args; be_init; be_installboot; be_list; |
