Reamove grub support.
[unleashed.git] / usr / src / lib / libbe / common / be_activate.c
blob51813ac76d2cbad61320f8297e4c38046f8f1bb0
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.
27 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 * Copyright 2016 Toomas Soome <tsoome@me.com>
31 #include <assert.h>
32 #include <libintl.h>
33 #include <libnvpair.h>
34 #include <libzfs.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <errno.h>
40 #include <sys/mnttab.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <sys/efi_partition.h>
47 #include <libbe.h>
48 #include <libbe_priv.h>
50 char *mnttab = MNTTAB;
53 * Private function prototypes
55 static int set_bootfs(char *boot_rpool, char *be_root_ds);
56 static int set_canmount(be_node_list_t *, char *);
57 static boolean_t be_do_install_mbr(char *, nvlist_t *);
58 static int be_do_installboot_helper(zpool_handle_t *, nvlist_t *, char *,
59 char *, uint16_t);
60 static int be_do_installboot(be_transaction_data_t *, uint16_t);
61 static int be_promote_zone_ds(char *, char *);
62 static int be_promote_ds_callback(zfs_handle_t *, void *);
64 /* ******************************************************************** */
65 /* Public Functions */
66 /* ******************************************************************** */
69 * Function: be_activate
70 * Description: Calls _be_activate which activates the BE named in the
71 * attributes passed in through be_attrs. The process of
72 * activation sets the bootfs property of the root pool, resets
73 * the canmount property to noauto, and sets the default in the
74 * menu to the entry corresponding to the entry for the named BE.
75 * Parameters:
76 * be_attrs - pointer to nvlist_t of attributes being passed in.
77 * The follow attribute values are used by this function:
79 * BE_ATTR_ORIG_BE_NAME *required
80 * Return:
81 * BE_SUCCESS - Success
82 * be_errno_t - Failure
83 * Scope:
84 * Public
86 int
87 be_activate(nvlist_t *be_attrs)
89 int ret = BE_SUCCESS;
90 char *be_name = NULL;
92 /* Initialize libzfs handle */
93 if (!be_zfs_init())
94 return (BE_ERR_INIT);
96 /* Get the BE name to activate */
97 if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
98 != 0) {
99 be_print_err(gettext("be_activate: failed to "
100 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
101 be_zfs_fini();
102 return (BE_ERR_INVAL);
105 /* Validate BE name */
106 if (!be_valid_be_name(be_name)) {
107 be_print_err(gettext("be_activate: invalid BE name %s\n"),
108 be_name);
109 be_zfs_fini();
110 return (BE_ERR_INVAL);
113 ret = _be_activate(be_name);
115 be_zfs_fini();
117 return (ret);
121 * Function: be_installboot
122 * Description: Calls be_do_installboot to install/update bootloader on
123 * pool passed in through be_attrs. The primary consumer is
124 * bootadm command to avoid duplication of the code.
125 * Parameters:
126 * be_attrs - pointer to nvlist_t of attributes being passed in.
127 * The following attribute values are used:
129 * BE_ATTR_ORIG_BE_NAME *required
130 * BE_ATTR_ORIG_BE_POOL *required
131 * BE_ATTR_ORIG_BE_ROOT *required
132 * BE_ATTR_INSTALL_FLAGS optional
134 * Return:
135 * BE_SUCCESS - Success
136 * be_errno_t - Failure
137 * Scope:
138 * Public
141 be_installboot(nvlist_t *be_attrs)
143 int ret = BE_SUCCESS;
144 uint16_t flags = 0;
145 uint16_t verbose;
146 be_transaction_data_t bt = { 0 };
148 /* Get flags */
149 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
150 BE_ATTR_INSTALL_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
151 be_print_err(gettext("be_installboot: failed to lookup "
152 "BE_ATTR_INSTALL_FLAGS attribute\n"));
153 return (BE_ERR_INVAL);
156 /* Set verbose early, so we get all messages */
157 verbose = flags & BE_INSTALLBOOT_FLAG_VERBOSE;
158 if (verbose == BE_INSTALLBOOT_FLAG_VERBOSE)
159 libbe_print_errors(B_TRUE);
161 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
162 &bt.obe_name);
163 if (ret != 0) {
164 be_print_err(gettext("be_installboot: failed to "
165 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
166 return (BE_ERR_INVAL);
169 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_POOL,
170 &bt.obe_zpool);
171 if (ret != 0) {
172 be_print_err(gettext("be_installboot: failed to "
173 "lookup BE_ATTR_ORIG_BE_POOL attribute\n"));
174 return (BE_ERR_INVAL);
177 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_ROOT,
178 &bt.obe_root_ds);
179 if (ret != 0) {
180 be_print_err(gettext("be_installboot: failed to "
181 "lookup BE_ATTR_ORIG_BE_ROOT attribute\n"));
182 return (BE_ERR_INVAL);
185 /* Initialize libzfs handle */
186 if (!be_zfs_init())
187 return (BE_ERR_INIT);
189 ret = be_do_installboot(&bt, flags);
191 be_zfs_fini();
193 return (ret);
196 /* ******************************************************************** */
197 /* Semi Private Functions */
198 /* ******************************************************************** */
201 * Function: _be_activate
202 * Description: This does the actual work described in be_activate.
203 * Parameters:
204 * be_name - pointer to the name of BE to activate.
206 * Return:
207 * BE_SUCCESS - Success
208 * be_errnot_t - Failure
209 * Scope:
210 * Public
213 _be_activate(char *be_name)
215 be_transaction_data_t cb = { 0 };
216 zfs_handle_t *zhp = NULL;
217 char root_ds[MAXPATHLEN];
218 char active_ds[MAXPATHLEN];
219 be_node_list_t *be_nodes = NULL;
220 uuid_t uu = {0};
221 int entry, ret = BE_SUCCESS;
222 int zret = 0;
225 * TODO: The BE needs to be validated to make sure that it is actually
226 * a bootable BE.
229 if (be_name == NULL)
230 return (BE_ERR_INVAL);
232 /* Set obe_name to be_name in the cb structure */
233 cb.obe_name = be_name;
235 /* find which zpool the be is in */
236 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
237 be_print_err(gettext("be_activate: failed to "
238 "find zpool for BE (%s)\n"), cb.obe_name);
239 return (BE_ERR_BE_NOENT);
240 } else if (zret < 0) {
241 be_print_err(gettext("be_activate: "
242 "zpool_iter failed: %s\n"),
243 libzfs_error_description(g_zfs));
244 ret = zfs_err_to_be_err(g_zfs);
245 return (ret);
248 be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
249 cb.obe_root_ds = strdup(root_ds);
251 if (getzoneid() == GLOBAL_ZONEID) {
252 ret = be_do_installboot(&cb, BE_INSTALLBOOT_FLAG_NULL);
253 if (ret != BE_SUCCESS)
254 return (ret);
256 if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
257 if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
258 NULL, NULL, NULL)) != BE_SUCCESS) {
259 be_print_err(gettext("be_activate: Failed to "
260 "add BE (%s) to the menu\n"),
261 cb.obe_name);
262 goto done;
267 if ((ret = _be_list(cb.obe_name, &be_nodes)) != BE_SUCCESS) {
268 return (ret);
271 if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
272 be_print_err(gettext("be_activate: failed to set "
273 "canmount dataset property\n"));
274 goto done;
277 if (getzoneid() == GLOBAL_ZONEID) {
278 if ((ret = set_bootfs(be_nodes->be_rpool,
279 root_ds)) != BE_SUCCESS) {
280 be_print_err(gettext("be_activate: failed to set "
281 "bootfs pool property for %s\n"), root_ds);
282 goto done;
286 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
288 * We don't need to close the zfs handle at this
289 * point because The callback funtion
290 * be_promote_ds_callback() will close it for us.
292 if (be_promote_ds_callback(zhp, NULL) != 0) {
293 be_print_err(gettext("be_activate: "
294 "failed to activate the "
295 "datasets for %s: %s\n"),
296 root_ds,
297 libzfs_error_description(g_zfs));
298 ret = BE_ERR_PROMOTE;
299 goto done;
301 } else {
302 be_print_err(gettext("be_activate: failed to open "
303 "dataset (%s): %s\n"), root_ds,
304 libzfs_error_description(g_zfs));
305 ret = zfs_err_to_be_err(g_zfs);
306 goto done;
309 if (getzoneid() == GLOBAL_ZONEID &&
310 be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
311 (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
312 != BE_SUCCESS) {
313 be_print_err(gettext("be_activate: failed to promote "
314 "the active zonepath datasets for zones in BE %s\n"),
315 cb.obe_name);
318 if (getzoneid() != GLOBAL_ZONEID) {
319 if (!be_zone_compare_uuids(root_ds)) {
320 be_print_err(gettext("be_activate: activating zone "
321 "root dataset from non-active global BE is not "
322 "supported\n"));
323 ret = BE_ERR_NOTSUP;
324 goto done;
326 if ((zhp = zfs_open(g_zfs, root_ds,
327 ZFS_TYPE_FILESYSTEM)) == NULL) {
328 be_print_err(gettext("be_activate: failed to open "
329 "dataset (%s): %s\n"), root_ds,
330 libzfs_error_description(g_zfs));
331 ret = zfs_err_to_be_err(g_zfs);
332 goto done;
334 /* Find current active zone root dataset */
335 if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
336 active_ds, sizeof (active_ds))) != BE_SUCCESS) {
337 be_print_err(gettext("be_activate: failed to find "
338 "active zone root dataset\n"));
339 ZFS_CLOSE(zhp);
340 goto done;
342 /* Do nothing if requested BE is already active */
343 if (strcmp(root_ds, active_ds) == 0) {
344 ret = BE_SUCCESS;
345 ZFS_CLOSE(zhp);
346 goto done;
349 /* Set active property for BE */
350 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
351 be_print_err(gettext("be_activate: failed to set "
352 "active property (%s): %s\n"), root_ds,
353 libzfs_error_description(g_zfs));
354 ret = zfs_err_to_be_err(g_zfs);
355 ZFS_CLOSE(zhp);
356 goto done;
358 ZFS_CLOSE(zhp);
360 /* Unset active property for old active root dataset */
361 if ((zhp = zfs_open(g_zfs, active_ds,
362 ZFS_TYPE_FILESYSTEM)) == NULL) {
363 be_print_err(gettext("be_activate: failed to open "
364 "dataset (%s): %s\n"), active_ds,
365 libzfs_error_description(g_zfs));
366 ret = zfs_err_to_be_err(g_zfs);
367 goto done;
369 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
370 be_print_err(gettext("be_activate: failed to unset "
371 "active property (%s): %s\n"), active_ds,
372 libzfs_error_description(g_zfs));
373 ret = zfs_err_to_be_err(g_zfs);
374 ZFS_CLOSE(zhp);
375 goto done;
377 ZFS_CLOSE(zhp);
379 done:
380 be_free_list(be_nodes);
381 return (ret);
385 * Function: be_activate_current_be
386 * Description: Set the currently "active" BE to be "active on boot"
387 * Paramters:
388 * none
389 * Returns:
390 * BE_SUCCESS - Success
391 * be_errnot_t - Failure
392 * Scope:
393 * Semi-private (library wide use only)
396 be_activate_current_be(void)
398 int ret = BE_SUCCESS;
399 be_transaction_data_t bt = { 0 };
401 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
402 return (ret);
405 if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
406 be_print_err(gettext("be_activate_current_be: failed to "
407 "activate %s\n"), bt.obe_name);
408 return (ret);
411 return (BE_SUCCESS);
415 * Function: be_is_active_on_boot
416 * Description: Checks if the BE name passed in has the "active on boot"
417 * property set to B_TRUE.
418 * Paramters:
419 * be_name - the name of the BE to check
420 * Returns:
421 * B_TRUE - if active on boot.
422 * B_FALSE - if not active on boot.
423 * Scope:
424 * Semi-private (library wide use only)
426 boolean_t
427 be_is_active_on_boot(char *be_name)
429 be_node_list_t *be_node = NULL;
431 if (be_name == NULL) {
432 be_print_err(gettext("be_is_active_on_boot: "
433 "be_name must not be NULL\n"));
434 return (B_FALSE);
437 if (_be_list(be_name, &be_node) != BE_SUCCESS) {
438 return (B_FALSE);
441 if (be_node == NULL) {
442 return (B_FALSE);
445 if (be_node->be_active_on_boot) {
446 be_free_list(be_node);
447 return (B_TRUE);
448 } else {
449 be_free_list(be_node);
450 return (B_FALSE);
454 /* ******************************************************************** */
455 /* Private Functions */
456 /* ******************************************************************** */
459 * Function: set_bootfs
460 * Description: Sets the bootfs property on the boot pool to be the
461 * root dataset of the activated BE.
462 * Parameters:
463 * boot_pool - The pool we're setting bootfs in.
464 * be_root_ds - The main dataset for the BE.
465 * Return:
466 * BE_SUCCESS - Success
467 * be_errno_t - Failure
468 * Scope:
469 * Private
471 static int
472 set_bootfs(char *boot_rpool, char *be_root_ds)
474 zpool_handle_t *zhp;
475 int err = BE_SUCCESS;
477 if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
478 be_print_err(gettext("set_bootfs: failed to open pool "
479 "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
480 err = zfs_err_to_be_err(g_zfs);
481 return (err);
484 err = zpool_set_prop(zhp, "bootfs", be_root_ds);
485 if (err) {
486 be_print_err(gettext("set_bootfs: failed to set "
487 "bootfs property for pool %s: %s\n"), boot_rpool,
488 libzfs_error_description(g_zfs));
489 err = zfs_err_to_be_err(g_zfs);
490 zpool_close(zhp);
491 return (err);
494 zpool_close(zhp);
495 return (BE_SUCCESS);
499 * Function: set_canmount
500 * Description: Sets the canmount property on the datasets of the
501 * activated BE.
502 * Parameters:
503 * be_nodes - The be_node_t returned from be_list
504 * value - The value of canmount we setting, on|off|noauto.
505 * Return:
506 * BE_SUCCESS - Success
507 * be_errno_t - Failure
508 * Scope:
509 * Private
511 static int
512 set_canmount(be_node_list_t *be_nodes, char *value)
514 char ds_path[MAXPATHLEN];
515 zfs_handle_t *zhp = NULL;
516 be_node_list_t *list = be_nodes;
517 int err = BE_SUCCESS;
519 while (list != NULL) {
520 be_dataset_list_t *datasets = list->be_node_datasets;
522 be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
523 sizeof (ds_path));
525 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
526 NULL) {
527 be_print_err(gettext("set_canmount: failed to open "
528 "dataset (%s): %s\n"), ds_path,
529 libzfs_error_description(g_zfs));
530 err = zfs_err_to_be_err(g_zfs);
531 return (err);
533 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
535 * it's already mounted so we can't change the
536 * canmount property anyway.
538 err = BE_SUCCESS;
539 } else {
540 err = zfs_prop_set(zhp,
541 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
542 if (err) {
543 ZFS_CLOSE(zhp);
544 be_print_err(gettext("set_canmount: failed to "
545 "set dataset property (%s): %s\n"),
546 ds_path, libzfs_error_description(g_zfs));
547 err = zfs_err_to_be_err(g_zfs);
548 return (err);
551 ZFS_CLOSE(zhp);
553 while (datasets != NULL) {
554 be_make_root_ds(list->be_rpool,
555 datasets->be_dataset_name, ds_path,
556 sizeof (ds_path));
558 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
559 == NULL) {
560 be_print_err(gettext("set_canmount: failed to "
561 "open dataset %s: %s\n"), ds_path,
562 libzfs_error_description(g_zfs));
563 err = zfs_err_to_be_err(g_zfs);
564 return (err);
566 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
568 * it's already mounted so we can't change the
569 * canmount property anyway.
571 err = BE_SUCCESS;
572 ZFS_CLOSE(zhp);
573 break;
575 err = zfs_prop_set(zhp,
576 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
577 if (err) {
578 ZFS_CLOSE(zhp);
579 be_print_err(gettext("set_canmount: "
580 "Failed to set property value %s "
581 "for dataset %s: %s\n"), value, ds_path,
582 libzfs_error_description(g_zfs));
583 err = zfs_err_to_be_err(g_zfs);
584 return (err);
586 ZFS_CLOSE(zhp);
587 datasets = datasets->be_next_dataset;
589 list = list->be_next_node;
591 return (err);
595 * To be able to boot EFI labeled disks, stage1 needs to be written
596 * into the MBR. We do not do this if we're on disks with a traditional
597 * fdisk partition table only, or if any foreign EFI partitions exist.
598 * In the trivial case of a whole-disk vdev we always write stage1 into
599 * the MBR.
601 static boolean_t
602 be_do_install_mbr(char *diskname, nvlist_t *child)
604 struct uuid allowed_uuids[] = {
605 EFI_UNUSED,
606 EFI_RESV1,
607 EFI_BOOT,
608 EFI_ROOT,
609 EFI_SWAP,
610 EFI_USR,
611 EFI_BACKUP,
612 EFI_RESV2,
613 EFI_VAR,
614 EFI_HOME,
615 EFI_ALTSCTR,
616 EFI_RESERVED,
617 EFI_SYSTEM,
618 EFI_BIOS_BOOT,
619 EFI_SYMC_PUB,
620 EFI_SYMC_CDS
623 uint64_t whole;
624 struct dk_gpt *gpt;
625 struct uuid *u;
626 int fd, npart, i, j;
628 (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK,
629 &whole);
631 if (whole)
632 return (B_TRUE);
634 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0)
635 return (B_FALSE);
637 if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0)
638 return (B_FALSE);
640 for (i = 0; i != npart; i++) {
641 int match = 0;
643 u = &gpt->efi_parts[i].p_guid;
645 for (j = 0;
646 j != sizeof (allowed_uuids) / sizeof (struct uuid);
647 j++)
648 if (bcmp(u, &allowed_uuids[j],
649 sizeof (struct uuid)) == 0)
650 match++;
652 if (match == 0)
653 return (B_FALSE);
656 return (B_TRUE);
659 static int
660 be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1,
661 char *stage2, uint16_t flags)
663 char install_cmd[MAXPATHLEN];
664 char be_run_cmd_errbuf[BUFSIZ];
665 char be_run_cmd_outbuf[BUFSIZ];
666 char diskname[MAXPATHLEN];
667 char *vname;
668 char *path, *dsk_ptr;
669 char *flag = "";
670 int ret;
671 vdev_stat_t *vs;
672 uint_t vsc;
674 if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) {
675 be_print_err(gettext("be_do_installboot: "
676 "failed to get device path\n"));
677 return (BE_ERR_NODEV);
680 if ((nvlist_lookup_uint64_array(child, ZPOOL_CONFIG_VDEV_STATS,
681 (uint64_t **)&vs, &vsc) != 0) ||
682 vs->vs_state < VDEV_STATE_DEGRADED) {
684 * Don't try to run installboot on a vdev that is not ONLINE
685 * or DEGRADED. Try to print a warning for each such vdev.
687 be_print_err(gettext("be_do_installboot: "
688 "vdev %s is %s, can't install boot loader\n"),
689 path, zpool_state_to_name(vs->vs_state, vs->vs_aux));
690 return (BE_SUCCESS);
694 * Modify the vdev path to point to the raw disk.
696 path = strdup(path);
697 if (path == NULL)
698 return (BE_ERR_NOMEM);
700 dsk_ptr = strstr(path, "/dsk/");
701 if (dsk_ptr != NULL) {
702 *dsk_ptr = '\0';
703 dsk_ptr++;
704 } else {
705 dsk_ptr = "";
708 (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
709 free(path);
711 vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE);
712 if (vname == NULL) {
713 be_print_err(gettext("be_do_installboot: "
714 "failed to get device name: %s\n"),
715 libzfs_error_description(g_zfs));
716 return (zfs_err_to_be_err(g_zfs));
719 if (be_is_isa("i386")) {
720 uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE;
721 uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR;
723 if (force == BE_INSTALLBOOT_FLAG_FORCE) {
724 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
725 be_do_install_mbr(diskname, child))
726 flag = "-F -m -f";
727 else
728 flag = "-F";
729 } else {
730 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
731 be_do_install_mbr(diskname, child))
732 flag = "-m -f";
735 (void) snprintf(install_cmd, sizeof (install_cmd),
736 "%s %s %s %s %s", BE_INSTALL_BOOT, flag,
737 stage1, stage2, diskname);
738 } else if (be_is_isa("sparc")) {
739 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) ==
740 BE_INSTALLBOOT_FLAG_FORCE)
741 flag = "-f -F zfs";
742 else
743 flag = "-F zfs";
745 (void) snprintf(install_cmd, sizeof (install_cmd),
746 "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname);
747 } else {
748 be_print_err(gettext("be_do_installboot: unsupported "
749 "architecture.\n"));
750 return (BE_ERR_BOOTFILE_INST);
753 *be_run_cmd_outbuf = '\0';
754 *be_run_cmd_errbuf = '\0';
756 ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ,
757 be_run_cmd_outbuf, BUFSIZ);
759 if (ret != BE_SUCCESS) {
760 be_print_err(gettext("be_do_installboot: install "
761 "failed for device %s.\n"), vname);
762 ret = BE_ERR_BOOTFILE_INST;
765 be_print_err(gettext(" Command: \"%s\"\n"), install_cmd);
766 if (be_run_cmd_outbuf[0] != 0) {
767 be_print_err(gettext(" Output:\n"));
768 be_print_err("%s", be_run_cmd_outbuf);
771 if (be_run_cmd_errbuf[0] != 0) {
772 be_print_err(gettext(" Errors:\n"));
773 be_print_err("%s", be_run_cmd_errbuf);
775 free(vname);
777 return (ret);
781 * Function: be_do_installboot
782 * Description: This function runs installboot using the boot
783 * loader files from the BE we're activating and installing
784 * them on the pool the BE lives in.
786 * Parameters:
787 * bt - The transaction data for the BE we're activating.
788 * flags - flags for bootloader install
789 * Return:
790 * BE_SUCCESS - Success
791 * be_errno_t - Failure
793 * Scope:
794 * Private
796 static int
797 be_do_installboot(be_transaction_data_t *bt, uint16_t flags)
799 zpool_handle_t *zphp = NULL;
800 zfs_handle_t *zhp = NULL;
801 nvlist_t **child, *nv, *config;
802 uint_t c, children = 0;
803 char *tmp_mntpt = NULL;
804 char stage1[MAXPATHLEN];
805 char stage2[MAXPATHLEN];
806 char *vname;
807 int ret = BE_SUCCESS;
808 boolean_t be_mounted = B_FALSE;
809 boolean_t verbose = B_FALSE;
811 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
812 NULL) {
813 be_print_err(gettext("be_do_installboot: failed to "
814 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
815 libzfs_error_description(g_zfs));
816 ret = zfs_err_to_be_err(g_zfs);
817 return (ret);
819 if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
820 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
821 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
822 be_print_err(gettext("be_do_installboot: failed to "
823 "mount BE (%s)\n"), bt->obe_name);
824 ZFS_CLOSE(zhp);
825 return (ret);
827 be_mounted = B_TRUE;
829 ZFS_CLOSE(zhp);
831 if (be_is_isa("i386")) {
832 (void) snprintf(stage1, sizeof (stage1), "%s%s",
833 tmp_mntpt, BE_LOADER_STAGE_1);
834 (void) snprintf(stage2, sizeof (stage2), "%s%s",
835 tmp_mntpt, BE_LOADER_STAGE_2);
836 } else if (be_is_isa("sparc")) {
837 char *platform = be_get_platform();
839 if (platform == NULL) {
840 be_print_err(gettext("be_do_installboot: "
841 "failed to detect system platform name\n"));
842 if (be_mounted)
843 (void) _be_unmount(bt->obe_name, 0);
844 free(tmp_mntpt);
845 return (BE_ERR_BOOTFILE_INST);
847 stage1[0] = '\0'; /* sparc has no stage1 */
848 (void) snprintf(stage2, sizeof (stage2),
849 "%s/usr/platform/%s%s", tmp_mntpt,
850 platform, BE_SPARC_BOOTBLK);
851 } else {
852 be_print_err(gettext("be_do_installboot: unsupported "
853 "architecture.\n"));
854 return (BE_ERR_BOOTFILE_INST);
857 if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
858 be_print_err(gettext("be_do_installboot: failed to open "
859 "pool (%s): %s\n"), bt->obe_zpool,
860 libzfs_error_description(g_zfs));
861 ret = zfs_err_to_be_err(g_zfs);
862 if (be_mounted)
863 (void) _be_unmount(bt->obe_name, 0);
864 free(tmp_mntpt);
865 return (ret);
868 if ((config = zpool_get_config(zphp, NULL)) == NULL) {
869 be_print_err(gettext("be_do_installboot: failed to get zpool "
870 "configuration information. %s\n"),
871 libzfs_error_description(g_zfs));
872 ret = zfs_err_to_be_err(g_zfs);
873 goto done;
877 * Get the vdev tree
879 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
880 be_print_err(gettext("be_do_installboot: failed to get vdev "
881 "tree: %s\n"), libzfs_error_description(g_zfs));
882 ret = zfs_err_to_be_err(g_zfs);
883 goto done;
886 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
887 &children) != 0) {
888 be_print_err(gettext("be_do_installboot: failed to traverse "
889 "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
890 ret = zfs_err_to_be_err(g_zfs);
891 goto done;
893 for (c = 0; c < children; c++) {
894 uint_t i, nchildren = 0;
895 nvlist_t **nvchild;
897 /* ensure update on child status */
898 vname = zpool_vdev_name(g_zfs, zphp, child[c], verbose);
899 if (vname == NULL) {
900 be_print_err(gettext(
901 "be_do_installboot: "
902 "failed to get device name: %s\n"),
903 libzfs_error_description(g_zfs));
904 ret = zfs_err_to_be_err(g_zfs);
905 goto done;
906 } else if (verbose == B_TRUE) {
907 be_print_err(gettext("be_do_installboot: "
908 "device %s\n"), vname);
910 free(vname);
912 ret = nvlist_lookup_nvlist_array(child[c],
913 ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren);
914 if (ret != 0) {
915 if (ret != ENOENT) {
916 be_print_err(gettext("be_do_installboot: "
917 "failed to traverse the vdev tree: %s\n"),
918 libzfs_error_description(g_zfs));
919 ret = zfs_err_to_be_err(g_zfs);
920 goto done;
922 nchildren = 0; /* This is leaf device. */
925 if (nchildren != 0) {
926 for (i = 0; i < nchildren; i++) {
927 /* ensure update on child status */
928 vname = zpool_vdev_name(g_zfs, zphp,
929 nvchild[i], verbose);
930 if (vname == NULL) {
931 be_print_err(gettext(
932 "be_do_installboot: "
933 "failed to get device name: %s\n"),
934 libzfs_error_description(g_zfs));
935 ret = zfs_err_to_be_err(g_zfs);
936 goto done;
937 } else if (verbose == B_TRUE) {
938 be_print_err(gettext(
939 "be_do_installboot: device %s\n"),
940 vname);
942 free(vname);
943 ret = be_do_installboot_helper(zphp, nvchild[i],
944 stage1, stage2, flags);
945 if (ret != BE_SUCCESS)
946 goto done;
948 } else {
949 ret = be_do_installboot_helper(zphp, child[c], stage1,
950 stage2, flags);
951 if (ret != BE_SUCCESS)
952 goto done;
956 done:
957 ZFS_CLOSE(zhp);
958 if (be_mounted)
959 (void) _be_unmount(bt->obe_name, 0);
960 zpool_close(zphp);
961 free(tmp_mntpt);
962 return (ret);
966 * Function: be_promote_zone_ds
967 * Description: This function finds the zones for the BE being activated
968 * and the active zonepath dataset for each zone. Then each
969 * active zonepath dataset is promoted.
971 * Parameters:
972 * be_name - the name of the global zone BE that we need to
973 * find the zones for.
974 * be_root_ds - the root dataset for be_name.
975 * Return:
976 * BE_SUCCESS - Success
977 * be_errno_t - Failure
979 * Scope:
980 * Private
982 static int
983 be_promote_zone_ds(char *be_name, char *be_root_ds)
985 char *zone_ds = NULL;
986 char *temp_mntpt = NULL;
987 char origin[MAXPATHLEN];
988 char zoneroot_ds[MAXPATHLEN];
989 zfs_handle_t *zhp = NULL;
990 zfs_handle_t *z_zhp = NULL;
991 zoneList_t zone_list = NULL;
992 zoneBrandList_t *brands = NULL;
993 boolean_t be_mounted = B_FALSE;
994 int zone_index = 0;
995 int err = BE_SUCCESS;
998 * Get the supported zone brands so we can pass that
999 * to z_get_nonglobal_zone_list_by_brand. Currently
1000 * only the ipkg and labeled brand zones are supported
1003 if ((brands = be_get_supported_brandlist()) == NULL) {
1004 be_print_err(gettext("be_promote_zone_ds: no supported "
1005 "brands\n"));
1006 return (BE_SUCCESS);
1009 if ((zhp = zfs_open(g_zfs, be_root_ds,
1010 ZFS_TYPE_FILESYSTEM)) == NULL) {
1011 be_print_err(gettext("be_promote_zone_ds: Failed to open "
1012 "dataset (%s): %s\n"), be_root_ds,
1013 libzfs_error_description(g_zfs));
1014 err = zfs_err_to_be_err(g_zfs);
1015 z_free_brand_list(brands);
1016 return (err);
1019 if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1020 if ((err = _be_mount(be_name, &temp_mntpt,
1021 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1022 be_print_err(gettext("be_promote_zone_ds: failed to "
1023 "mount the BE for zones procesing.\n"));
1024 ZFS_CLOSE(zhp);
1025 z_free_brand_list(brands);
1026 return (err);
1028 be_mounted = B_TRUE;
1032 * Set the zone root to the temp mount point for the BE we just mounted.
1034 z_set_zone_root(temp_mntpt);
1037 * Get all the zones based on the brands we're looking for. If no zones
1038 * are found that we're interested in unmount the BE and move on.
1040 if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1041 if (be_mounted)
1042 (void) _be_unmount(be_name, 0);
1043 ZFS_CLOSE(zhp);
1044 z_free_brand_list(brands);
1045 free(temp_mntpt);
1046 return (BE_SUCCESS);
1048 for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1049 != NULL; zone_index++) {
1050 char *zone_path = NULL;
1052 /* Skip zones that aren't at least installed */
1053 if (z_zlist_get_current_state(zone_list, zone_index) <
1054 ZONE_STATE_INSTALLED)
1055 continue;
1057 if (((zone_path =
1058 z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1059 ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1060 !be_zone_supported(zone_ds))
1061 continue;
1063 if (be_find_active_zone_root(zhp, zone_ds,
1064 zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1065 be_print_err(gettext("be_promote_zone_ds: "
1066 "Zone does not have an active root "
1067 "dataset, skipping this zone.\n"));
1068 continue;
1071 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1072 ZFS_TYPE_FILESYSTEM)) == NULL) {
1073 be_print_err(gettext("be_promote_zone_ds: "
1074 "Failed to open dataset "
1075 "(%s): %s\n"), zoneroot_ds,
1076 libzfs_error_description(g_zfs));
1077 err = zfs_err_to_be_err(g_zfs);
1078 goto done;
1081 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1082 sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1083 ZFS_CLOSE(z_zhp);
1084 continue;
1088 * We don't need to close the zfs handle at this
1089 * point because the callback funtion
1090 * be_promote_ds_callback() will close it for us.
1092 if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1093 be_print_err(gettext("be_promote_zone_ds: "
1094 "failed to activate the "
1095 "datasets for %s: %s\n"),
1096 zoneroot_ds,
1097 libzfs_error_description(g_zfs));
1098 err = BE_ERR_PROMOTE;
1099 goto done;
1102 done:
1103 if (be_mounted)
1104 (void) _be_unmount(be_name, 0);
1105 ZFS_CLOSE(zhp);
1106 free(temp_mntpt);
1107 z_free_brand_list(brands);
1108 z_free_zone_list(zone_list);
1109 return (err);
1113 * Function: be_promote_ds_callback
1114 * Description: This function is used to promote the datasets for the BE
1115 * being activated as well as the datasets for the zones BE
1116 * being activated.
1118 * Parameters:
1119 * zhp - the zfs handle for zone BE being activated.
1120 * data - not used.
1121 * Return:
1122 * 0 - Success
1123 * be_errno_t - Failure
1125 * Scope:
1126 * Private
1128 static int
1129 /* LINTED */
1130 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1132 char origin[MAXPATHLEN];
1133 char *sub_dataset = NULL;
1134 int ret = 0;
1136 if (zhp != NULL) {
1137 sub_dataset = strdup(zfs_get_name(zhp));
1138 if (sub_dataset == NULL) {
1139 ret = BE_ERR_NOMEM;
1140 goto done;
1142 } else {
1143 be_print_err(gettext("be_promote_ds_callback: "
1144 "Invalid zfs handle passed into function\n"));
1145 ret = BE_ERR_INVAL;
1146 goto done;
1150 * This loop makes sure that we promote the dataset to the
1151 * top of the tree so that it is no longer a decendent of any
1152 * dataset. The ZFS close and then open is used to make sure that
1153 * the promotion is updated before we move on.
1155 while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1156 sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1157 if (zfs_promote(zhp) != 0) {
1158 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1159 be_print_err(gettext("be_promote_ds_callback: "
1160 "promote of %s failed: %s\n"),
1161 zfs_get_name(zhp),
1162 libzfs_error_description(g_zfs));
1163 ret = zfs_err_to_be_err(g_zfs);
1164 goto done;
1165 } else {
1167 * If the call to zfs_promote returns the
1168 * error EZFS_EXISTS we've hit a snapshot name
1169 * collision. This means we're probably
1170 * attemping to promote a zone dataset above a
1171 * parent dataset that belongs to another zone
1172 * which this zone was cloned from.
1174 * TODO: If this is a zone dataset at some
1175 * point we should skip this if the zone
1176 * paths for the dataset and the snapshot
1177 * don't match.
1179 be_print_err(gettext("be_promote_ds_callback: "
1180 "promote of %s failed due to snapshot "
1181 "name collision: %s\n"), zfs_get_name(zhp),
1182 libzfs_error_description(g_zfs));
1183 ret = zfs_err_to_be_err(g_zfs);
1184 goto done;
1187 ZFS_CLOSE(zhp);
1188 if ((zhp = zfs_open(g_zfs, sub_dataset,
1189 ZFS_TYPE_FILESYSTEM)) == NULL) {
1190 be_print_err(gettext("be_promote_ds_callback: "
1191 "Failed to open dataset (%s): %s\n"), sub_dataset,
1192 libzfs_error_description(g_zfs));
1193 ret = zfs_err_to_be_err(g_zfs);
1194 goto done;
1198 /* Iterate down this dataset's children and promote them */
1199 ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1201 done:
1202 free(sub_dataset);
1203 ZFS_CLOSE(zhp);
1204 return (ret);