9892 Most consumers of be_list() do not need snapshots
[unleashed.git] / usr / src / lib / libbe / common / be_activate.c
blobf59cb88ea938d9497cd434b7d0746af349031577
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
30 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
31 * Copyright 2016 Toomas Soome <tsoome@me.com>
32 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
35 #include <assert.h>
36 #include <libintl.h>
37 #include <libnvpair.h>
38 #include <libzfs.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <strings.h>
43 #include <errno.h>
44 #include <sys/mnttab.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #include <unistd.h>
49 #include <sys/efi_partition.h>
51 #include <libbe.h>
52 #include <libbe_priv.h>
54 char *mnttab = MNTTAB;
57 * Private function prototypes
59 static int set_bootfs(char *boot_rpool, char *be_root_ds);
60 static int set_canmount(be_node_list_t *, char *);
61 static boolean_t be_do_install_mbr(char *, nvlist_t *);
62 static int be_do_installboot_helper(zpool_handle_t *, nvlist_t *, char *,
63 char *, uint16_t);
64 static int be_do_installboot(be_transaction_data_t *, uint16_t);
65 static int be_promote_zone_ds(char *, char *);
66 static int be_promote_ds_callback(zfs_handle_t *, void *);
68 /* ******************************************************************** */
69 /* Public Functions */
70 /* ******************************************************************** */
73 * Function: be_activate
74 * Description: Calls _be_activate which activates the BE named in the
75 * attributes passed in through be_attrs. The process of
76 * activation sets the bootfs property of the root pool, resets
77 * the canmount property to noauto, and sets the default in the
78 * menu to the entry corresponding to the entry for the named BE.
79 * Parameters:
80 * be_attrs - pointer to nvlist_t of attributes being passed in.
81 * The follow attribute values are used by this function:
83 * BE_ATTR_ORIG_BE_NAME *required
84 * Return:
85 * BE_SUCCESS - Success
86 * be_errno_t - Failure
87 * Scope:
88 * Public
90 int
91 be_activate(nvlist_t *be_attrs)
93 int ret = BE_SUCCESS;
94 char *be_name = NULL;
96 /* Initialize libzfs handle */
97 if (!be_zfs_init())
98 return (BE_ERR_INIT);
100 /* Get the BE name to activate */
101 if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
102 != 0) {
103 be_print_err(gettext("be_activate: failed to "
104 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
105 be_zfs_fini();
106 return (BE_ERR_INVAL);
109 /* Validate BE name */
110 if (!be_valid_be_name(be_name)) {
111 be_print_err(gettext("be_activate: invalid BE name %s\n"),
112 be_name);
113 be_zfs_fini();
114 return (BE_ERR_INVAL);
117 ret = _be_activate(be_name);
119 be_zfs_fini();
121 return (ret);
125 * Function: be_installboot
126 * Description: Calls be_do_installboot to install/update bootloader on
127 * pool passed in through be_attrs. The primary consumer is
128 * bootadm command to avoid duplication of the code.
129 * Parameters:
130 * be_attrs - pointer to nvlist_t of attributes being passed in.
131 * The following attribute values are used:
133 * BE_ATTR_ORIG_BE_NAME *required
134 * BE_ATTR_ORIG_BE_POOL *required
135 * BE_ATTR_ORIG_BE_ROOT *required
136 * BE_ATTR_INSTALL_FLAGS optional
138 * Return:
139 * BE_SUCCESS - Success
140 * be_errno_t - Failure
141 * Scope:
142 * Public
145 be_installboot(nvlist_t *be_attrs)
147 int ret = BE_SUCCESS;
148 uint16_t flags = 0;
149 uint16_t verbose;
150 be_transaction_data_t bt = { 0 };
152 /* Get flags */
153 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
154 BE_ATTR_INSTALL_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
155 be_print_err(gettext("be_installboot: failed to lookup "
156 "BE_ATTR_INSTALL_FLAGS attribute\n"));
157 return (BE_ERR_INVAL);
160 /* Set verbose early, so we get all messages */
161 verbose = flags & BE_INSTALLBOOT_FLAG_VERBOSE;
162 if (verbose == BE_INSTALLBOOT_FLAG_VERBOSE)
163 libbe_print_errors(B_TRUE);
165 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
166 &bt.obe_name);
167 if (ret != 0) {
168 be_print_err(gettext("be_installboot: failed to "
169 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
170 return (BE_ERR_INVAL);
173 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_POOL,
174 &bt.obe_zpool);
175 if (ret != 0) {
176 be_print_err(gettext("be_installboot: failed to "
177 "lookup BE_ATTR_ORIG_BE_POOL attribute\n"));
178 return (BE_ERR_INVAL);
181 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_ROOT,
182 &bt.obe_root_ds);
183 if (ret != 0) {
184 be_print_err(gettext("be_installboot: failed to "
185 "lookup BE_ATTR_ORIG_BE_ROOT attribute\n"));
186 return (BE_ERR_INVAL);
189 /* Initialize libzfs handle */
190 if (!be_zfs_init())
191 return (BE_ERR_INIT);
193 ret = be_do_installboot(&bt, flags);
195 be_zfs_fini();
197 return (ret);
200 /* ******************************************************************** */
201 /* Semi Private Functions */
202 /* ******************************************************************** */
205 * Function: _be_activate
206 * Description: This does the actual work described in be_activate.
207 * Parameters:
208 * be_name - pointer to the name of BE to activate.
210 * Return:
211 * BE_SUCCESS - Success
212 * be_errnot_t - Failure
213 * Scope:
214 * Public
217 _be_activate(char *be_name)
219 be_transaction_data_t cb = { 0 };
220 zfs_handle_t *zhp = NULL;
221 char root_ds[MAXPATHLEN];
222 char active_ds[MAXPATHLEN];
223 be_node_list_t *be_nodes = NULL;
224 uuid_t uu = {0};
225 int entry, ret = BE_SUCCESS;
226 int zret = 0;
229 * TODO: The BE needs to be validated to make sure that it is actually
230 * a bootable BE.
233 if (be_name == NULL)
234 return (BE_ERR_INVAL);
236 /* Set obe_name to be_name in the cb structure */
237 cb.obe_name = be_name;
239 /* find which zpool the be is in */
240 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
241 be_print_err(gettext("be_activate: failed to "
242 "find zpool for BE (%s)\n"), cb.obe_name);
243 return (BE_ERR_BE_NOENT);
244 } else if (zret < 0) {
245 be_print_err(gettext("be_activate: "
246 "zpool_iter failed: %s\n"),
247 libzfs_error_description(g_zfs));
248 ret = zfs_err_to_be_err(g_zfs);
249 return (ret);
252 be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
253 cb.obe_root_ds = strdup(root_ds);
255 if (getzoneid() == GLOBAL_ZONEID) {
256 ret = be_do_installboot(&cb, BE_INSTALLBOOT_FLAG_NULL);
257 if (ret != BE_SUCCESS)
258 return (ret);
260 if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
261 if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
262 NULL, NULL, NULL)) != BE_SUCCESS) {
263 be_print_err(gettext("be_activate: Failed to "
264 "add BE (%s) to the menu\n"),
265 cb.obe_name);
266 goto done;
271 if ((ret = _be_list(cb.obe_name, &be_nodes, BE_LIST_DEFAULT))
272 != BE_SUCCESS) {
273 return (ret);
276 if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
277 be_print_err(gettext("be_activate: failed to set "
278 "canmount dataset property\n"));
279 goto done;
282 if (getzoneid() == GLOBAL_ZONEID) {
283 if ((ret = set_bootfs(be_nodes->be_rpool,
284 root_ds)) != BE_SUCCESS) {
285 be_print_err(gettext("be_activate: failed to set "
286 "bootfs pool property for %s\n"), root_ds);
287 goto done;
291 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
293 * We don't need to close the zfs handle at this
294 * point because The callback funtion
295 * be_promote_ds_callback() will close it for us.
297 if (be_promote_ds_callback(zhp, NULL) != 0) {
298 be_print_err(gettext("be_activate: "
299 "failed to activate the "
300 "datasets for %s: %s\n"),
301 root_ds,
302 libzfs_error_description(g_zfs));
303 ret = BE_ERR_PROMOTE;
304 goto done;
306 } else {
307 be_print_err(gettext("be_activate: failed to open "
308 "dataset (%s): %s\n"), root_ds,
309 libzfs_error_description(g_zfs));
310 ret = zfs_err_to_be_err(g_zfs);
311 goto done;
314 if (getzoneid() == GLOBAL_ZONEID &&
315 be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
316 (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
317 != BE_SUCCESS) {
318 be_print_err(gettext("be_activate: failed to promote "
319 "the active zonepath datasets for zones in BE %s\n"),
320 cb.obe_name);
323 if (getzoneid() != GLOBAL_ZONEID) {
324 if (!be_zone_compare_uuids(root_ds)) {
325 be_print_err(gettext("be_activate: activating zone "
326 "root dataset from non-active global BE is not "
327 "supported\n"));
328 ret = BE_ERR_NOTSUP;
329 goto done;
331 if ((zhp = zfs_open(g_zfs, root_ds,
332 ZFS_TYPE_FILESYSTEM)) == NULL) {
333 be_print_err(gettext("be_activate: failed to open "
334 "dataset (%s): %s\n"), root_ds,
335 libzfs_error_description(g_zfs));
336 ret = zfs_err_to_be_err(g_zfs);
337 goto done;
339 /* Find current active zone root dataset */
340 if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
341 active_ds, sizeof (active_ds))) != BE_SUCCESS) {
342 be_print_err(gettext("be_activate: failed to find "
343 "active zone root dataset\n"));
344 ZFS_CLOSE(zhp);
345 goto done;
347 /* Do nothing if requested BE is already active */
348 if (strcmp(root_ds, active_ds) == 0) {
349 ret = BE_SUCCESS;
350 ZFS_CLOSE(zhp);
351 goto done;
354 /* Set active property for BE */
355 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
356 be_print_err(gettext("be_activate: failed to set "
357 "active property (%s): %s\n"), root_ds,
358 libzfs_error_description(g_zfs));
359 ret = zfs_err_to_be_err(g_zfs);
360 ZFS_CLOSE(zhp);
361 goto done;
363 ZFS_CLOSE(zhp);
365 /* Unset active property for old active root dataset */
366 if ((zhp = zfs_open(g_zfs, active_ds,
367 ZFS_TYPE_FILESYSTEM)) == NULL) {
368 be_print_err(gettext("be_activate: failed to open "
369 "dataset (%s): %s\n"), active_ds,
370 libzfs_error_description(g_zfs));
371 ret = zfs_err_to_be_err(g_zfs);
372 goto done;
374 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
375 be_print_err(gettext("be_activate: failed to unset "
376 "active property (%s): %s\n"), active_ds,
377 libzfs_error_description(g_zfs));
378 ret = zfs_err_to_be_err(g_zfs);
379 ZFS_CLOSE(zhp);
380 goto done;
382 ZFS_CLOSE(zhp);
384 done:
385 be_free_list(be_nodes);
386 return (ret);
390 * Function: be_activate_current_be
391 * Description: Set the currently "active" BE to be "active on boot"
392 * Paramters:
393 * none
394 * Returns:
395 * BE_SUCCESS - Success
396 * be_errnot_t - Failure
397 * Scope:
398 * Semi-private (library wide use only)
401 be_activate_current_be(void)
403 int ret = BE_SUCCESS;
404 be_transaction_data_t bt = { 0 };
406 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
407 return (ret);
410 if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
411 be_print_err(gettext("be_activate_current_be: failed to "
412 "activate %s\n"), bt.obe_name);
413 return (ret);
416 return (BE_SUCCESS);
420 * Function: be_is_active_on_boot
421 * Description: Checks if the BE name passed in has the "active on boot"
422 * property set to B_TRUE.
423 * Paramters:
424 * be_name - the name of the BE to check
425 * Returns:
426 * B_TRUE - if active on boot.
427 * B_FALSE - if not active on boot.
428 * Scope:
429 * Semi-private (library wide use only)
431 boolean_t
432 be_is_active_on_boot(char *be_name)
434 be_node_list_t *be_node = NULL;
436 if (be_name == NULL) {
437 be_print_err(gettext("be_is_active_on_boot: "
438 "be_name must not be NULL\n"));
439 return (B_FALSE);
442 if (_be_list(be_name, &be_node, BE_LIST_DEFAULT) != BE_SUCCESS) {
443 return (B_FALSE);
446 if (be_node == NULL) {
447 return (B_FALSE);
450 if (be_node->be_active_on_boot) {
451 be_free_list(be_node);
452 return (B_TRUE);
453 } else {
454 be_free_list(be_node);
455 return (B_FALSE);
459 /* ******************************************************************** */
460 /* Private Functions */
461 /* ******************************************************************** */
464 * Function: set_bootfs
465 * Description: Sets the bootfs property on the boot pool to be the
466 * root dataset of the activated BE.
467 * Parameters:
468 * boot_pool - The pool we're setting bootfs in.
469 * be_root_ds - The main dataset for the BE.
470 * Return:
471 * BE_SUCCESS - Success
472 * be_errno_t - Failure
473 * Scope:
474 * Private
476 static int
477 set_bootfs(char *boot_rpool, char *be_root_ds)
479 zpool_handle_t *zhp;
480 int err = BE_SUCCESS;
482 if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
483 be_print_err(gettext("set_bootfs: failed to open pool "
484 "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
485 err = zfs_err_to_be_err(g_zfs);
486 return (err);
489 err = zpool_set_prop(zhp, "bootfs", be_root_ds);
490 if (err) {
491 be_print_err(gettext("set_bootfs: failed to set "
492 "bootfs property for pool %s: %s\n"), boot_rpool,
493 libzfs_error_description(g_zfs));
494 err = zfs_err_to_be_err(g_zfs);
495 zpool_close(zhp);
496 return (err);
499 zpool_close(zhp);
500 return (BE_SUCCESS);
504 * Function: set_canmount
505 * Description: Sets the canmount property on the datasets of the
506 * activated BE.
507 * Parameters:
508 * be_nodes - The be_node_t returned from be_list
509 * value - The value of canmount we setting, on|off|noauto.
510 * Return:
511 * BE_SUCCESS - Success
512 * be_errno_t - Failure
513 * Scope:
514 * Private
516 static int
517 set_canmount(be_node_list_t *be_nodes, char *value)
519 char ds_path[MAXPATHLEN];
520 zfs_handle_t *zhp = NULL;
521 be_node_list_t *list = be_nodes;
522 int err = BE_SUCCESS;
524 while (list != NULL) {
525 be_dataset_list_t *datasets = list->be_node_datasets;
527 be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
528 sizeof (ds_path));
530 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
531 NULL) {
532 be_print_err(gettext("set_canmount: failed to open "
533 "dataset (%s): %s\n"), ds_path,
534 libzfs_error_description(g_zfs));
535 err = zfs_err_to_be_err(g_zfs);
536 return (err);
538 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
540 * it's already mounted so we can't change the
541 * canmount property anyway.
543 err = BE_SUCCESS;
544 } else {
545 err = zfs_prop_set(zhp,
546 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
547 if (err) {
548 ZFS_CLOSE(zhp);
549 be_print_err(gettext("set_canmount: failed to "
550 "set dataset property (%s): %s\n"),
551 ds_path, libzfs_error_description(g_zfs));
552 err = zfs_err_to_be_err(g_zfs);
553 return (err);
556 ZFS_CLOSE(zhp);
558 while (datasets != NULL) {
559 be_make_root_ds(list->be_rpool,
560 datasets->be_dataset_name, ds_path,
561 sizeof (ds_path));
563 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
564 == NULL) {
565 be_print_err(gettext("set_canmount: failed to "
566 "open dataset %s: %s\n"), ds_path,
567 libzfs_error_description(g_zfs));
568 err = zfs_err_to_be_err(g_zfs);
569 return (err);
571 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
573 * it's already mounted so we can't change the
574 * canmount property anyway.
576 err = BE_SUCCESS;
577 ZFS_CLOSE(zhp);
578 break;
580 err = zfs_prop_set(zhp,
581 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
582 if (err) {
583 ZFS_CLOSE(zhp);
584 be_print_err(gettext("set_canmount: "
585 "Failed to set property value %s "
586 "for dataset %s: %s\n"), value, ds_path,
587 libzfs_error_description(g_zfs));
588 err = zfs_err_to_be_err(g_zfs);
589 return (err);
591 ZFS_CLOSE(zhp);
592 datasets = datasets->be_next_dataset;
594 list = list->be_next_node;
596 return (err);
600 * To be able to boot EFI labeled disks, stage1 needs to be written
601 * into the MBR. We do not do this if we're on disks with a traditional
602 * fdisk partition table only, or if any foreign EFI partitions exist.
603 * In the trivial case of a whole-disk vdev we always write stage1 into
604 * the MBR.
606 static boolean_t
607 be_do_install_mbr(char *diskname, nvlist_t *child)
609 struct uuid allowed_uuids[] = {
610 EFI_UNUSED,
611 EFI_RESV1,
612 EFI_BOOT,
613 EFI_ROOT,
614 EFI_SWAP,
615 EFI_USR,
616 EFI_BACKUP,
617 EFI_RESV2,
618 EFI_VAR,
619 EFI_HOME,
620 EFI_ALTSCTR,
621 EFI_RESERVED,
622 EFI_SYSTEM,
623 EFI_BIOS_BOOT,
624 EFI_SYMC_PUB,
625 EFI_SYMC_CDS
628 uint64_t whole;
629 struct dk_gpt *gpt;
630 struct uuid *u;
631 int fd, npart, i, j;
633 (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK,
634 &whole);
636 if (whole)
637 return (B_TRUE);
639 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0)
640 return (B_FALSE);
642 if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0)
643 return (B_FALSE);
645 for (i = 0; i != npart; i++) {
646 int match = 0;
648 u = &gpt->efi_parts[i].p_guid;
650 for (j = 0;
651 j != sizeof (allowed_uuids) / sizeof (struct uuid);
652 j++)
653 if (bcmp(u, &allowed_uuids[j],
654 sizeof (struct uuid)) == 0)
655 match++;
657 if (match == 0)
658 return (B_FALSE);
661 return (B_TRUE);
664 static int
665 be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1,
666 char *stage2, uint16_t flags)
668 char install_cmd[MAXPATHLEN];
669 char be_run_cmd_errbuf[BUFSIZ];
670 char be_run_cmd_outbuf[BUFSIZ];
671 char diskname[MAXPATHLEN];
672 char *vname;
673 char *path, *type, *dsk_ptr;
674 char *flag = "";
675 int ret;
676 vdev_stat_t *vs;
677 uint_t vsc;
679 if (nvlist_lookup_string(child, ZPOOL_CONFIG_TYPE, &type) != 0) {
680 be_print_err(gettext("%s: failed to get device type\n"),
681 __func__);
682 return (BE_ERR_NODEV);
684 /* Skip indirect devices. */
685 if (strcmp(type, VDEV_TYPE_INDIRECT) == 0)
686 return (BE_ERR_NOTSUP);
688 if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) {
689 be_print_err(gettext("%s: failed to get device path\n"),
690 __func__);
691 return (BE_ERR_NODEV);
694 if ((nvlist_lookup_uint64_array(child, ZPOOL_CONFIG_VDEV_STATS,
695 (uint64_t **)&vs, &vsc) != 0) ||
696 vs->vs_state < VDEV_STATE_DEGRADED) {
698 * Don't try to run installboot on a vdev that is not ONLINE
699 * or DEGRADED. Try to print a warning for each such vdev.
701 be_print_err(gettext("%s: vdev %s is %s, can't install "
702 "boot loader\n"), __func__, path,
703 zpool_state_to_name(vs->vs_state, vs->vs_aux));
704 return (BE_SUCCESS);
708 * Modify the vdev path to point to the raw disk.
710 path = strdup(path);
711 if (path == NULL)
712 return (BE_ERR_NOMEM);
714 dsk_ptr = strstr(path, "/dsk/");
715 if (dsk_ptr != NULL) {
716 *dsk_ptr = '\0';
717 dsk_ptr++;
718 } else {
719 dsk_ptr = "";
722 (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
723 free(path);
725 vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE);
726 if (vname == NULL) {
727 be_print_err(gettext("%s: failed to get device name: %s\n"),
728 __func__, libzfs_error_description(g_zfs));
729 return (zfs_err_to_be_err(g_zfs));
732 if (be_is_isa("i386")) {
733 uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE;
734 uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR;
736 if (force == BE_INSTALLBOOT_FLAG_FORCE) {
737 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
738 be_do_install_mbr(diskname, child))
739 flag = "-F -m -f";
740 else
741 flag = "-F";
742 } else {
743 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
744 be_do_install_mbr(diskname, child))
745 flag = "-m -f";
748 (void) snprintf(install_cmd, sizeof (install_cmd),
749 "%s %s %s %s %s", BE_INSTALL_BOOT, flag,
750 stage1, stage2, diskname);
751 } else if (be_is_isa("sparc")) {
752 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) ==
753 BE_INSTALLBOOT_FLAG_FORCE)
754 flag = "-f -F zfs";
755 else
756 flag = "-F zfs";
758 (void) snprintf(install_cmd, sizeof (install_cmd),
759 "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname);
760 } else {
761 be_print_err(gettext("%s: unsupported architecture.\n"),
762 __func__);
763 return (BE_ERR_BOOTFILE_INST);
766 *be_run_cmd_outbuf = '\0';
767 *be_run_cmd_errbuf = '\0';
769 ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ,
770 be_run_cmd_outbuf, BUFSIZ);
772 if (ret != BE_SUCCESS) {
773 be_print_err(gettext("%s: install failed for device %s.\n"),
774 __func__, vname);
775 ret = BE_ERR_BOOTFILE_INST;
778 be_print_err(gettext(" Command: \"%s\"\n"), install_cmd);
779 if (be_run_cmd_outbuf[0] != 0) {
780 be_print_err(gettext(" Output:\n"));
781 be_print_err("%s", be_run_cmd_outbuf);
784 if (be_run_cmd_errbuf[0] != 0) {
785 be_print_err(gettext(" Errors:\n"));
786 be_print_err("%s", be_run_cmd_errbuf);
788 free(vname);
790 return (ret);
793 static int
794 be_do_installboot_walk(zpool_handle_t *zphp, nvlist_t *nv, char *stage1,
795 char *stage2, uint16_t flags)
797 boolean_t verbose = do_print;
798 nvlist_t **child;
799 uint_t children = 0;
800 int ret = -1;
802 /* It is OK to have no children. */
803 (void) nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
804 &children);
806 for (int c = 0; c < children; c++) {
807 char *vname;
808 int rv;
810 /* ensure update on child status */
811 vname = zpool_vdev_name(g_zfs, zphp, child[c], verbose);
812 if (vname == NULL) {
813 be_print_err(gettext("%s: "
814 "failed to get device name: %s\n"), __func__,
815 libzfs_error_description(g_zfs));
816 return (zfs_err_to_be_err(g_zfs));
817 } else {
818 be_print_err(gettext("%s: child %d of %d device %s\n"),
819 __func__, c, children, vname);
822 rv = be_do_installboot_walk(zphp, child[c], stage1, stage2,
823 flags);
824 switch (rv) {
825 case BE_ERR_NOTSUP:
826 /* ignore unsupported devices */
827 be_print_err(
828 gettext("%s: device %s is not supported\n"),
829 __func__, vname);
830 break;
831 case BE_SUCCESS:
832 /* catch at least one success */
833 ret = rv;
834 break;
835 default:
836 if (ret == -1)
837 ret = rv;
838 break;
840 free(vname);
843 if (children > 0)
844 return (ret == -1? BE_ERR_NOTSUP : ret);
845 return (be_do_installboot_helper(zphp, nv, stage1, stage2, flags));
849 * Function: be_do_installboot
850 * Description: This function runs installboot using the boot
851 * loader files from the BE we're activating and installing
852 * them on the pool the BE lives in.
854 * Parameters:
855 * bt - The transaction data for the BE we're activating.
856 * flags - flags for bootloader install
857 * Return:
858 * BE_SUCCESS - Success
859 * be_errno_t - Failure
861 * Scope:
862 * Private
864 static int
865 be_do_installboot(be_transaction_data_t *bt, uint16_t flags)
867 zpool_handle_t *zphp = NULL;
868 zfs_handle_t *zhp = NULL;
869 nvlist_t *nv, *config;
870 char *tmp_mntpt = NULL;
871 char stage1[MAXPATHLEN];
872 char stage2[MAXPATHLEN];
873 int ret = BE_SUCCESS;
874 boolean_t be_mounted = B_FALSE;
876 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
877 NULL) {
878 be_print_err(gettext("%s: failed to "
879 "open BE root dataset (%s): %s\n"), __func__,
880 bt->obe_root_ds, libzfs_error_description(g_zfs));
881 ret = zfs_err_to_be_err(g_zfs);
882 return (ret);
884 if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
885 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
886 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
887 be_print_err(gettext("%s: failed to "
888 "mount BE (%s)\n"), __func__, bt->obe_name);
889 ZFS_CLOSE(zhp);
890 return (ret);
892 be_mounted = B_TRUE;
894 ZFS_CLOSE(zhp);
896 if (be_is_isa("i386")) {
897 (void) snprintf(stage1, sizeof (stage1), "%s%s",
898 tmp_mntpt, BE_LOADER_STAGE_1);
899 (void) snprintf(stage2, sizeof (stage2), "%s%s",
900 tmp_mntpt, BE_LOADER_STAGE_2);
901 } else if (be_is_isa("sparc")) {
902 char *platform = be_get_platform();
904 if (platform == NULL) {
905 be_print_err(gettext("%s: failed to detect system "
906 "platform name\n"), __func__);
907 if (be_mounted)
908 (void) _be_unmount(bt->obe_name, 0);
909 free(tmp_mntpt);
910 return (BE_ERR_BOOTFILE_INST);
912 stage1[0] = '\0'; /* sparc has no stage1 */
913 (void) snprintf(stage2, sizeof (stage2),
914 "%s/usr/platform/%s%s", tmp_mntpt,
915 platform, BE_SPARC_BOOTBLK);
916 } else {
917 be_print_err(gettext("%s: unsupported architecture.\n"),
918 __func__);
919 return (BE_ERR_BOOTFILE_INST);
922 if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
923 be_print_err(gettext("%s: failed to open "
924 "pool (%s): %s\n"), __func__, bt->obe_zpool,
925 libzfs_error_description(g_zfs));
926 ret = zfs_err_to_be_err(g_zfs);
927 if (be_mounted)
928 (void) _be_unmount(bt->obe_name, 0);
929 free(tmp_mntpt);
930 return (ret);
933 if ((config = zpool_get_config(zphp, NULL)) == NULL) {
934 be_print_err(gettext("%s: failed to get zpool "
935 "configuration information. %s\n"), __func__,
936 libzfs_error_description(g_zfs));
937 ret = zfs_err_to_be_err(g_zfs);
938 goto done;
942 * Get the vdev tree
944 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
945 be_print_err(gettext("%s: failed to get vdev "
946 "tree: %s\n"), __func__, libzfs_error_description(g_zfs));
947 ret = zfs_err_to_be_err(g_zfs);
948 goto done;
951 ret = be_do_installboot_walk(zphp, nv, stage1, stage2, flags);
953 done:
954 ZFS_CLOSE(zhp);
955 if (be_mounted)
956 (void) _be_unmount(bt->obe_name, 0);
957 zpool_close(zphp);
958 free(tmp_mntpt);
959 return (ret);
963 * Function: be_promote_zone_ds
964 * Description: This function finds the zones for the BE being activated
965 * and the active zonepath dataset for each zone. Then each
966 * active zonepath dataset is promoted.
968 * Parameters:
969 * be_name - the name of the global zone BE that we need to
970 * find the zones for.
971 * be_root_ds - the root dataset for be_name.
972 * Return:
973 * BE_SUCCESS - Success
974 * be_errno_t - Failure
976 * Scope:
977 * Private
979 static int
980 be_promote_zone_ds(char *be_name, char *be_root_ds)
982 char *zone_ds = NULL;
983 char *temp_mntpt = NULL;
984 char origin[MAXPATHLEN];
985 char zoneroot_ds[MAXPATHLEN];
986 zfs_handle_t *zhp = NULL;
987 zfs_handle_t *z_zhp = NULL;
988 boolean_t be_mounted = B_FALSE;
989 int err = BE_SUCCESS;
990 FILE *cookie;
991 struct zoneent *ze;
993 if ((zhp = zfs_open(g_zfs, be_root_ds,
994 ZFS_TYPE_FILESYSTEM)) == NULL) {
995 be_print_err(gettext("be_promote_zone_ds: Failed to open "
996 "dataset (%s): %s\n"), be_root_ds,
997 libzfs_error_description(g_zfs));
998 err = zfs_err_to_be_err(g_zfs);
999 return (err);
1002 if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1003 if ((err = _be_mount(be_name, &temp_mntpt,
1004 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1005 be_print_err(gettext("be_promote_zone_ds: failed to "
1006 "mount the BE for zones procesing.\n"));
1007 ZFS_CLOSE(zhp);
1008 return (err);
1010 be_mounted = B_TRUE;
1014 * Set the zone root to the temp mount point for the BE we just mounted.
1016 zonecfg_set_root((const char *)temp_mntpt);
1018 cookie = setzoneent();
1019 while((ze = getzoneent_private(cookie)) != NULL) {
1021 if (strcmp(ze->zone_name, "global") == 0)
1022 continue;
1024 /* Skip zones that aren't at least installed */
1025 if (ze->zone_state < ZONE_STATE_INSTALLED)
1026 continue;
1028 if (((zone_ds = be_get_ds_from_dir(ze->zone_path)) == NULL) ||
1029 !be_zone_supported(zone_ds)) {
1030 free(zone_ds);
1031 free(ze);
1032 continue;
1035 if (be_find_active_zone_root(zhp, zone_ds,
1036 zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1037 be_print_err(gettext("be_promote_zone_ds: "
1038 "Zone does not have an active root "
1039 "dataset, skipping this zone.\n"));
1040 continue;
1043 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1044 ZFS_TYPE_FILESYSTEM)) == NULL) {
1045 be_print_err(gettext("be_promote_zone_ds: "
1046 "Failed to open dataset "
1047 "(%s): %s\n"), zoneroot_ds,
1048 libzfs_error_description(g_zfs));
1049 err = zfs_err_to_be_err(g_zfs);
1050 goto done;
1053 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1054 sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1055 ZFS_CLOSE(z_zhp);
1056 continue;
1060 * We don't need to close the zfs handle at this
1061 * point because the callback funtion
1062 * be_promote_ds_callback() will close it for us.
1064 if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1065 be_print_err(gettext("be_promote_zone_ds: "
1066 "failed to activate the "
1067 "datasets for %s: %s\n"),
1068 zoneroot_ds,
1069 libzfs_error_description(g_zfs));
1070 err = BE_ERR_PROMOTE;
1071 goto done;
1073 free(ze);
1075 endzoneent(cookie);
1077 done:
1078 if (be_mounted)
1079 (void) _be_unmount(be_name, 0);
1080 ZFS_CLOSE(zhp);
1081 free(temp_mntpt);
1082 return (err);
1086 * Function: be_promote_ds_callback
1087 * Description: This function is used to promote the datasets for the BE
1088 * being activated as well as the datasets for the zones BE
1089 * being activated.
1091 * Parameters:
1092 * zhp - the zfs handle for zone BE being activated.
1093 * data - not used.
1094 * Return:
1095 * 0 - Success
1096 * be_errno_t - Failure
1098 * Scope:
1099 * Private
1101 static int
1102 /* LINTED */
1103 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1105 char origin[MAXPATHLEN];
1106 char *sub_dataset = NULL;
1107 int ret = 0;
1109 if (zhp != NULL) {
1110 sub_dataset = strdup(zfs_get_name(zhp));
1111 if (sub_dataset == NULL) {
1112 ret = BE_ERR_NOMEM;
1113 goto done;
1115 } else {
1116 be_print_err(gettext("be_promote_ds_callback: "
1117 "Invalid zfs handle passed into function\n"));
1118 ret = BE_ERR_INVAL;
1119 goto done;
1123 * This loop makes sure that we promote the dataset to the
1124 * top of the tree so that it is no longer a decendent of any
1125 * dataset. The ZFS close and then open is used to make sure that
1126 * the promotion is updated before we move on.
1128 while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1129 sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1130 if (zfs_promote(zhp) != 0) {
1131 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1132 be_print_err(gettext("be_promote_ds_callback: "
1133 "promote of %s failed: %s\n"),
1134 zfs_get_name(zhp),
1135 libzfs_error_description(g_zfs));
1136 ret = zfs_err_to_be_err(g_zfs);
1137 goto done;
1138 } else {
1140 * If the call to zfs_promote returns the
1141 * error EZFS_EXISTS we've hit a snapshot name
1142 * collision. This means we're probably
1143 * attemping to promote a zone dataset above a
1144 * parent dataset that belongs to another zone
1145 * which this zone was cloned from.
1147 * TODO: If this is a zone dataset at some
1148 * point we should skip this if the zone
1149 * paths for the dataset and the snapshot
1150 * don't match.
1152 be_print_err(gettext("be_promote_ds_callback: "
1153 "promote of %s failed due to snapshot "
1154 "name collision: %s\n"), zfs_get_name(zhp),
1155 libzfs_error_description(g_zfs));
1156 ret = zfs_err_to_be_err(g_zfs);
1157 goto done;
1160 ZFS_CLOSE(zhp);
1161 if ((zhp = zfs_open(g_zfs, sub_dataset,
1162 ZFS_TYPE_FILESYSTEM)) == NULL) {
1163 be_print_err(gettext("be_promote_ds_callback: "
1164 "Failed to open dataset (%s): %s\n"), sub_dataset,
1165 libzfs_error_description(g_zfs));
1166 ret = zfs_err_to_be_err(g_zfs);
1167 goto done;
1171 /* Iterate down this dataset's children and promote them */
1172 ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1174 done:
1175 free(sub_dataset);
1176 ZFS_CLOSE(zhp);
1177 return (ret);