summaryrefslogtreecommitdiff
path: root/usr/src/lib/libbe/common
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/libbe/common')
-rw-r--r--usr/src/lib/libbe/common/be_activate.c80
-rw-r--r--usr/src/lib/libbe/common/be_utils.c235
-rw-r--r--usr/src/lib/libbe/common/libbe.h6
-rw-r--r--usr/src/lib/libbe/common/libbe_priv.h6
-rw-r--r--usr/src/lib/libbe/common/mapfile-vers3
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;