16702 CCM wide mode bit moved from DF::CCMConfig4 to DF::CCDEnable in DFv4D2
[illumos-gate.git] / usr / src / lib / libbe / common / be_activate.c
blob581ddc41c2c275d718d15c9783d87e5abef8f436
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>
29 * Copyright 2022 OmniOS Community Edition (OmniOSce) Association.
32 #include <assert.h>
33 #include <libintl.h>
34 #include <libnvpair.h>
35 #include <libzfs.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <strings.h>
40 #include <errno.h>
41 #include <sys/mnttab.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <unistd.h>
46 #include <sys/efi_partition.h>
48 #include <libbe.h>
49 #include <libbe_priv.h>
50 #include <libzfsbootenv.h>
52 char *mnttab = MNTTAB;
55 * Private function prototypes
57 static int set_bootfs(char *boot_rpool, char *be_root_ds);
58 static int set_canmount(be_node_list_t *, char *);
59 static boolean_t be_do_install_mbr(char *, nvlist_t *);
60 static int be_do_installboot_helper(zpool_handle_t *, nvlist_t *, char *,
61 char *, uint16_t);
62 static int be_do_installboot(be_transaction_data_t *, uint16_t);
63 static int be_get_grub_vers(be_transaction_data_t *, char **, char **);
64 static int get_ver_from_capfile(char *, char **);
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 * grub menu to the entry corresponding to the entry for the named
79 * BE.
80 * Parameters:
81 * be_attrs - pointer to nvlist_t of attributes being passed in.
82 * The follow attribute values are used by this function:
84 * BE_ATTR_ORIG_BE_NAME *required
85 * Return:
86 * BE_SUCCESS - Success
87 * be_errno_t - Failure
88 * Scope:
89 * Public
91 int
92 be_activate(nvlist_t *be_attrs)
94 int ret = BE_SUCCESS;
95 char *be_name = NULL;
96 be_nextboot_state_t nextboot;
97 boolean_t next_boot;
99 /* Initialize libzfs handle */
100 if (!be_zfs_init())
101 return (BE_ERR_INIT);
103 /* Get the BE name to activate */
104 if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
105 != 0) {
106 be_print_err(gettext("be_activate: failed to "
107 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
108 be_zfs_fini();
109 return (BE_ERR_INVAL);
112 /* Validate BE name */
113 if (!be_valid_be_name(be_name)) {
114 be_print_err(gettext("be_activate: invalid BE name %s\n"),
115 be_name);
116 be_zfs_fini();
117 return (BE_ERR_INVAL);
120 if (nvlist_lookup_boolean_value(be_attrs, BE_ATTR_ACTIVE_NEXTBOOT,
121 &next_boot) == 0) {
122 if (next_boot)
123 nextboot = BE_NEXTBOOT_SET;
124 else
125 nextboot = BE_NEXTBOOT_UNSET;
126 } else {
127 nextboot = BE_NEXTBOOT_IGNORE;
130 ret = _be_activate(be_name, nextboot);
132 be_zfs_fini();
134 return (ret);
138 * Function: be_installboot
139 * Description: Calls be_do_installboot to install/update bootloader on
140 * pool passed in through be_attrs. The primary consumer is
141 * bootadm command to avoid duplication of the code.
142 * Parameters:
143 * be_attrs - pointer to nvlist_t of attributes being passed in.
144 * The following attribute values are used:
146 * BE_ATTR_ORIG_BE_NAME *required
147 * BE_ATTR_ORIG_BE_POOL *required
148 * BE_ATTR_ORIG_BE_ROOT *required
149 * BE_ATTR_INSTALL_FLAGS optional
151 * Return:
152 * BE_SUCCESS - Success
153 * be_errno_t - Failure
154 * Scope:
155 * Public
158 be_installboot(nvlist_t *be_attrs)
160 int ret = BE_SUCCESS;
161 uint16_t flags = 0;
162 uint16_t verbose;
163 be_transaction_data_t bt = { 0 };
165 /* Get flags */
166 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
167 BE_ATTR_INSTALL_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
168 be_print_err(gettext("be_installboot: failed to lookup "
169 "BE_ATTR_INSTALL_FLAGS attribute\n"));
170 return (BE_ERR_INVAL);
173 /* Set verbose early, so we get all messages */
174 verbose = flags & BE_INSTALLBOOT_FLAG_VERBOSE;
175 if (verbose == BE_INSTALLBOOT_FLAG_VERBOSE)
176 libbe_print_errors(B_TRUE);
178 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
179 &bt.obe_name);
180 if (ret != 0) {
181 be_print_err(gettext("be_installboot: failed to "
182 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
183 return (BE_ERR_INVAL);
186 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_POOL,
187 &bt.obe_zpool);
188 if (ret != 0) {
189 be_print_err(gettext("be_installboot: failed to "
190 "lookup BE_ATTR_ORIG_BE_POOL attribute\n"));
191 return (BE_ERR_INVAL);
194 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_ROOT,
195 &bt.obe_root_ds);
196 if (ret != 0) {
197 be_print_err(gettext("be_installboot: failed to "
198 "lookup BE_ATTR_ORIG_BE_ROOT attribute\n"));
199 return (BE_ERR_INVAL);
202 /* Initialize libzfs handle */
203 if (!be_zfs_init())
204 return (BE_ERR_INIT);
206 ret = be_do_installboot(&bt, flags);
208 be_zfs_fini();
210 return (ret);
213 /* ******************************************************************** */
214 /* Semi Private Functions */
215 /* ******************************************************************** */
218 * Function: _be_activate
219 * Description: This does the actual work described in be_activate.
220 * Parameters:
221 * be_name - pointer to the name of BE to activate.
222 * nextboot - flag to ignore, set or unset nextboot
224 * Return:
225 * BE_SUCCESS - Success
226 * be_errnot_t - Failure
227 * Scope:
228 * Public
231 _be_activate(char *be_name, be_nextboot_state_t nextboot)
233 be_transaction_data_t cb = { 0 };
234 zfs_handle_t *zhp = NULL;
235 char root_ds[MAXPATHLEN];
236 char active_ds[MAXPATHLEN];
237 be_node_list_t *be_nodes = NULL;
238 uuid_t uu = {0};
239 int entry, ret = BE_SUCCESS;
240 int zret = 0;
243 * TODO: The BE needs to be validated to make sure that it is actually
244 * a bootable BE.
247 if (be_name == NULL)
248 return (BE_ERR_INVAL);
250 if (nextboot == BE_NEXTBOOT_SET && getzoneid() != GLOBAL_ZONEID)
251 return (BE_ERR_INVAL);
253 /* Set obe_name to be_name in the cb structure */
254 cb.obe_name = be_name;
256 /* find which zpool the be is in */
257 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
258 be_print_err(gettext("be_activate: failed to "
259 "find zpool for BE (%s)\n"), cb.obe_name);
260 return (BE_ERR_BE_NOENT);
261 } else if (zret < 0) {
262 be_print_err(gettext("be_activate: "
263 "zpool_iter failed: %s\n"),
264 libzfs_error_description(g_zfs));
265 ret = zfs_err_to_be_err(g_zfs);
266 return (ret);
269 if ((ret = be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds,
270 sizeof (root_ds))) != BE_SUCCESS) {
271 be_print_err(gettext("%s: failed to get BE container dataset "
272 "for %s/%s\n"), __func__, cb.obe_zpool, cb.obe_name);
273 return (ret);
275 cb.obe_root_ds = strdup(root_ds);
277 if (getzoneid() == GLOBAL_ZONEID) {
278 ret = be_do_installboot(&cb, BE_INSTALLBOOT_FLAG_NULL);
279 if (ret != BE_SUCCESS)
280 return (ret);
282 if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
283 if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
284 NULL, NULL, NULL)) != BE_SUCCESS) {
285 be_print_err(gettext("be_activate: Failed to "
286 "add BE (%s) to the menu\n"),
287 cb.obe_name);
288 goto done;
291 if (be_has_grub()) {
292 if ((ret = be_change_grub_default(cb.obe_name,
293 cb.obe_zpool)) != BE_SUCCESS) {
294 be_print_err(gettext("be_activate: failed to "
295 "change the default entry in menu.lst\n"));
296 goto done;
301 if ((ret = _be_list(cb.obe_name, &be_nodes, BE_LIST_DEFAULT))
302 != BE_SUCCESS) {
303 return (ret);
306 if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
307 be_print_err(gettext("be_activate: failed to set "
308 "canmount dataset property\n"));
309 goto done;
312 if (getzoneid() == GLOBAL_ZONEID) {
313 switch (nextboot) {
314 case BE_NEXTBOOT_SET:
315 if ((ret = lzbe_set_boot_device(be_nodes->be_rpool,
316 lzbe_add, root_ds)) != 0) {
317 be_print_err(gettext("be_activate: failed to "
318 "set nextboot for %s\n"), root_ds);
319 goto done;
321 break;
322 case BE_NEXTBOOT_UNSET:
323 if ((ret = lzbe_set_boot_device(be_nodes->be_rpool,
324 lzbe_add, "")) != 0) {
325 be_print_err(gettext("be_activate: failed to "
326 "clear nextboot for %s\n"), root_ds);
327 goto done;
329 break;
330 default:
331 if ((ret = set_bootfs(be_nodes->be_rpool,
332 root_ds)) != BE_SUCCESS) {
333 be_print_err(gettext("be_activate: failed to "
334 "set bootfs pool property for %s\n"),
335 root_ds);
336 goto done;
341 if (nextboot == BE_NEXTBOOT_IGNORE) {
342 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) !=
343 NULL) {
345 * We don't need to close the zfs handle at this
346 * point because The callback funtion
347 * be_promote_ds_callback() will close it for us.
349 if (be_promote_ds_callback(zhp, NULL) != 0) {
350 be_print_err(gettext("be_activate: "
351 "failed to activate the "
352 "datasets for %s: %s\n"),
353 root_ds,
354 libzfs_error_description(g_zfs));
355 ret = BE_ERR_PROMOTE;
356 goto done;
358 } else {
359 be_print_err(gettext("be_activate: failed to open "
360 "dataset (%s): %s\n"), root_ds,
361 libzfs_error_description(g_zfs));
362 ret = zfs_err_to_be_err(g_zfs);
363 goto done;
366 if (getzoneid() == GLOBAL_ZONEID &&
367 be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
368 (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
369 != BE_SUCCESS) {
370 be_print_err(gettext("be_activate: failed to promote "
371 "the active zonepath datasets for zones in BE "
372 "%s\n"), cb.obe_name);
376 if (getzoneid() != GLOBAL_ZONEID) {
377 if (!be_zone_compare_uuids(root_ds)) {
378 be_print_err(gettext("be_activate: activating zone "
379 "root dataset from non-active global BE is not "
380 "supported\n"));
381 ret = BE_ERR_NOTSUP;
382 goto done;
384 if ((zhp = zfs_open(g_zfs, root_ds,
385 ZFS_TYPE_FILESYSTEM)) == NULL) {
386 be_print_err(gettext("be_activate: failed to open "
387 "dataset (%s): %s\n"), root_ds,
388 libzfs_error_description(g_zfs));
389 ret = zfs_err_to_be_err(g_zfs);
390 goto done;
392 /* Find current active zone root dataset */
393 if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
394 active_ds, sizeof (active_ds))) != BE_SUCCESS) {
395 be_print_err(gettext("be_activate: failed to find "
396 "active zone root dataset\n"));
397 ZFS_CLOSE(zhp);
398 goto done;
400 /* Do nothing if requested BE is already active */
401 if (strcmp(root_ds, active_ds) == 0) {
402 ret = BE_SUCCESS;
403 ZFS_CLOSE(zhp);
404 goto done;
407 /* Set active property for BE */
408 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
409 be_print_err(gettext("be_activate: failed to set "
410 "active property (%s): %s\n"), root_ds,
411 libzfs_error_description(g_zfs));
412 ret = zfs_err_to_be_err(g_zfs);
413 ZFS_CLOSE(zhp);
414 goto done;
416 ZFS_CLOSE(zhp);
418 /* Unset active property for old active root dataset */
419 if ((zhp = zfs_open(g_zfs, active_ds,
420 ZFS_TYPE_FILESYSTEM)) == NULL) {
421 be_print_err(gettext("be_activate: failed to open "
422 "dataset (%s): %s\n"), active_ds,
423 libzfs_error_description(g_zfs));
424 ret = zfs_err_to_be_err(g_zfs);
425 goto done;
427 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
428 be_print_err(gettext("be_activate: failed to unset "
429 "active property (%s): %s\n"), active_ds,
430 libzfs_error_description(g_zfs));
431 ret = zfs_err_to_be_err(g_zfs);
432 ZFS_CLOSE(zhp);
433 goto done;
435 ZFS_CLOSE(zhp);
437 done:
438 be_free_list(be_nodes);
439 return (ret);
443 * Function: be_activate_current_be
444 * Description: Set the currently "active" BE to be "active on boot"
445 * Paramters:
446 * none
447 * Returns:
448 * BE_SUCCESS - Success
449 * be_errnot_t - Failure
450 * Scope:
451 * Semi-private (library wide use only)
454 be_activate_current_be(void)
456 int ret = BE_SUCCESS;
457 be_transaction_data_t bt = { 0 };
459 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
460 return (ret);
463 ret = _be_activate(bt.obe_name, BE_NEXTBOOT_IGNORE);
464 if (ret != BE_SUCCESS) {
465 be_print_err(gettext("be_activate_current_be: failed to "
466 "activate %s\n"), bt.obe_name);
467 return (ret);
470 return (BE_SUCCESS);
474 * Function: be_is_active_on_boot
475 * Description: Checks if the BE name passed in has the "active on boot"
476 * property set to B_TRUE.
477 * Paramters:
478 * be_name - the name of the BE to check
479 * Returns:
480 * B_TRUE - if active on boot.
481 * B_FALSE - if not active on boot.
482 * Scope:
483 * Semi-private (library wide use only)
485 boolean_t
486 be_is_active_on_boot(char *be_name)
488 be_node_list_t *be_node = NULL;
490 if (be_name == NULL) {
491 be_print_err(gettext("be_is_active_on_boot: "
492 "be_name must not be NULL\n"));
493 return (B_FALSE);
496 if (_be_list(be_name, &be_node, BE_LIST_DEFAULT) != BE_SUCCESS) {
497 return (B_FALSE);
500 if (be_node == NULL) {
501 return (B_FALSE);
504 if (be_node->be_active_on_boot) {
505 be_free_list(be_node);
506 return (B_TRUE);
507 } else {
508 be_free_list(be_node);
509 return (B_FALSE);
513 /* ******************************************************************** */
514 /* Private Functions */
515 /* ******************************************************************** */
518 * Function: set_bootfs
519 * Description: Sets the bootfs property on the boot pool to be the
520 * root dataset of the activated BE.
521 * Parameters:
522 * boot_pool - The pool we're setting bootfs in.
523 * be_root_ds - The main dataset for the BE.
524 * Return:
525 * BE_SUCCESS - Success
526 * be_errno_t - Failure
527 * Scope:
528 * Private
530 static int
531 set_bootfs(char *boot_rpool, char *be_root_ds)
533 zpool_handle_t *zhp;
534 int err = BE_SUCCESS;
536 if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
537 be_print_err(gettext("set_bootfs: failed to open pool "
538 "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
539 err = zfs_err_to_be_err(g_zfs);
540 return (err);
543 err = zpool_set_prop(zhp, "bootfs", be_root_ds);
544 if (err) {
545 be_print_err(gettext("set_bootfs: failed to set "
546 "bootfs property for pool %s: %s\n"), boot_rpool,
547 libzfs_error_description(g_zfs));
548 err = zfs_err_to_be_err(g_zfs);
549 zpool_close(zhp);
550 return (err);
553 zpool_close(zhp);
554 return (BE_SUCCESS);
558 * Function: set_canmount
559 * Description: Sets the canmount property on the datasets of the
560 * activated BE.
561 * Parameters:
562 * be_nodes - The be_node_t returned from be_list
563 * value - The value of canmount we setting, on|off|noauto.
564 * Return:
565 * BE_SUCCESS - Success
566 * be_errno_t - Failure
567 * Scope:
568 * Private
570 static int
571 set_canmount(be_node_list_t *be_nodes, char *value)
573 char ds_path[MAXPATHLEN];
574 zfs_handle_t *zhp = NULL;
575 be_node_list_t *list = be_nodes;
576 int err = BE_SUCCESS;
578 while (list != NULL) {
579 be_dataset_list_t *datasets = list->be_node_datasets;
581 if ((err = be_make_root_ds(list->be_rpool, list->be_node_name,
582 ds_path, sizeof (ds_path))) != BE_SUCCESS) {
583 be_print_err(gettext("%s: failed to get BE container "
584 "dataset for %s/%s\n"), __func__,
585 list->be_rpool, list->be_node_name);
586 return (err);
589 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
590 NULL) {
591 be_print_err(gettext("set_canmount: failed to open "
592 "dataset (%s): %s\n"), ds_path,
593 libzfs_error_description(g_zfs));
594 err = zfs_err_to_be_err(g_zfs);
595 return (err);
597 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
599 * it's already mounted so we can't change the
600 * canmount property anyway.
602 err = BE_SUCCESS;
603 } else {
604 err = zfs_prop_set(zhp,
605 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
606 if (err) {
607 ZFS_CLOSE(zhp);
608 be_print_err(gettext("set_canmount: failed to "
609 "set dataset property (%s): %s\n"),
610 ds_path, libzfs_error_description(g_zfs));
611 err = zfs_err_to_be_err(g_zfs);
612 return (err);
615 ZFS_CLOSE(zhp);
617 while (datasets != NULL) {
618 if ((err = be_make_root_ds(list->be_rpool,
619 datasets->be_dataset_name, ds_path,
620 sizeof (ds_path))) != BE_SUCCESS) {
621 be_print_err(gettext("%s: failed to get BE "
622 "container dataset for %s/%s\n"), __func__,
623 list->be_rpool, datasets->be_dataset_name);
624 return (err);
627 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
628 == NULL) {
629 be_print_err(gettext("set_canmount: failed to "
630 "open dataset %s: %s\n"), ds_path,
631 libzfs_error_description(g_zfs));
632 err = zfs_err_to_be_err(g_zfs);
633 return (err);
635 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
637 * it's already mounted so we can't change the
638 * canmount property anyway.
640 err = BE_SUCCESS;
641 ZFS_CLOSE(zhp);
642 break;
644 err = zfs_prop_set(zhp,
645 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
646 if (err) {
647 ZFS_CLOSE(zhp);
648 be_print_err(gettext("set_canmount: "
649 "Failed to set property value %s "
650 "for dataset %s: %s\n"), value, ds_path,
651 libzfs_error_description(g_zfs));
652 err = zfs_err_to_be_err(g_zfs);
653 return (err);
655 ZFS_CLOSE(zhp);
656 datasets = datasets->be_next_dataset;
658 list = list->be_next_node;
660 return (err);
664 * Function: be_get_grub_vers
665 * Description: Gets the grub version number from /boot/grub/capability. If
666 * capability file doesn't exist NULL is returned.
667 * Parameters:
668 * bt - The transaction data for the BE we're getting the grub
669 * version for.
670 * cur_vers - used to return the current version of grub from
671 * the root pool.
672 * new_vers - used to return the grub version of the BE we're
673 * activating.
674 * Return:
675 * BE_SUCCESS - Success
676 * be_errno_t - Failed to find version
677 * Scope:
678 * Private
680 static int
681 be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
683 zfs_handle_t *zhp = NULL;
684 zfs_handle_t *pool_zhp = NULL;
685 int ret = BE_SUCCESS;
686 char cap_file[MAXPATHLEN];
687 char *temp_mntpnt = NULL;
688 char *zpool_mntpt = NULL;
689 char *ptmp_mntpnt = NULL;
690 char *orig_mntpnt = NULL;
691 boolean_t be_mounted = B_FALSE;
692 boolean_t pool_mounted = B_FALSE;
694 if (!be_has_grub()) {
695 be_print_err(gettext("be_get_grub_vers: Not supported on "
696 "this architecture\n"));
697 return (BE_ERR_NOTSUP);
700 if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL ||
701 bt->obe_root_ds == NULL) {
702 be_print_err(gettext("be_get_grub_vers: Invalid BE\n"));
703 return (BE_ERR_INVAL);
706 if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
707 NULL) {
708 be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"),
709 libzfs_error_description(g_zfs));
710 return (zfs_err_to_be_err(g_zfs));
714 * Check to see if the pool's dataset is mounted. If it isn't we'll
715 * attempt to mount it.
717 if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt,
718 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
719 be_print_err(gettext("be_get_grub_vers: pool dataset "
720 "(%s) could not be mounted\n"), bt->obe_zpool);
721 ZFS_CLOSE(pool_zhp);
722 return (ret);
726 * Get the mountpoint for the root pool dataset.
728 if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) {
729 be_print_err(gettext("be_get_grub_vers: pool "
730 "dataset (%s) is not mounted. Can't read the "
731 "grub capability file.\n"), bt->obe_zpool);
732 ret = BE_ERR_NO_MENU;
733 goto cleanup;
737 * get the version of the most recent grub update.
739 (void) snprintf(cap_file, sizeof (cap_file), "%s%s",
740 zpool_mntpt, BE_CAP_FILE);
741 free(zpool_mntpt);
742 zpool_mntpt = NULL;
744 if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
745 goto cleanup;
747 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
748 NULL) {
749 be_print_err(gettext("be_get_grub_vers: failed to "
750 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
751 libzfs_error_description(g_zfs));
752 free(cur_vers);
753 ret = zfs_err_to_be_err(g_zfs);
754 goto cleanup;
756 if (!zfs_is_mounted(zhp, &temp_mntpnt)) {
757 if ((ret = _be_mount(bt->obe_name, &temp_mntpnt,
758 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
759 be_print_err(gettext("be_get_grub_vers: failed to "
760 "mount BE (%s)\n"), bt->obe_name);
761 free(*cur_vers);
762 *cur_vers = NULL;
763 ZFS_CLOSE(zhp);
764 goto cleanup;
766 be_mounted = B_TRUE;
768 ZFS_CLOSE(zhp);
771 * Now get the grub version for the BE being activated.
773 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt,
774 BE_CAP_FILE);
775 ret = get_ver_from_capfile(cap_file, new_vers);
776 if (ret != BE_SUCCESS) {
777 free(*cur_vers);
778 *cur_vers = NULL;
780 if (be_mounted)
781 (void) _be_unmount(bt->obe_name, 0);
783 cleanup:
784 if (pool_mounted) {
785 int iret = BE_SUCCESS;
786 iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt);
787 if (ret == BE_SUCCESS)
788 ret = iret;
789 free(orig_mntpnt);
790 free(ptmp_mntpnt);
792 ZFS_CLOSE(pool_zhp);
794 free(temp_mntpnt);
795 return (ret);
799 * Function: get_ver_from_capfile
800 * Description: Parses the capability file passed in looking for the VERSION
801 * line. If found the version is returned in vers, if not then
802 * NULL is returned in vers.
804 * Parameters:
805 * file - the path to the capability file we want to parse.
806 * vers - the version string that will be passed back.
807 * Return:
808 * BE_SUCCESS - Success
809 * be_errno_t - Failed to find version
810 * Scope:
811 * Private
813 static int
814 get_ver_from_capfile(char *file, char **vers)
816 FILE *fp = NULL;
817 char line[BUFSIZ];
818 char *last = NULL;
819 int err = BE_SUCCESS;
820 errno = 0;
822 if (!be_has_grub()) {
823 be_print_err(gettext("get_ver_from_capfile: Not supported "
824 "on this architecture\n"));
825 return (BE_ERR_NOTSUP);
829 * Set version string to NULL; the only case this shouldn't be set
830 * to be NULL is when we've actually found a version in the capability
831 * file, which is set below.
833 *vers = NULL;
836 * If the capability file doesn't exist, we're returning success
837 * because on older releases, the capability file did not exist
838 * so this is a valid scenario.
840 if (access(file, F_OK) == 0) {
841 if ((fp = fopen(file, "r")) == NULL) {
842 err = errno;
843 be_print_err(gettext("get_ver_from_capfile: failed to "
844 "open file %s with error %s\n"), file,
845 strerror(err));
846 err = errno_to_be_err(err);
847 return (err);
850 while (fgets(line, BUFSIZ, fp)) {
851 char *tok = strtok_r(line, "=", &last);
853 if (tok == NULL || tok[0] == '#') {
854 continue;
855 } else if (strcmp(tok, "VERSION") == 0) {
856 *vers = strdup(last);
857 break;
860 (void) fclose(fp);
863 return (BE_SUCCESS);
867 * To be able to boot EFI labeled disks, stage1 needs to be written
868 * into the MBR. We do not do this if we're on disks with a traditional
869 * fdisk partition table only, or if any foreign EFI partitions exist.
870 * In the trivial case of a whole-disk vdev we always write stage1 into
871 * the MBR.
873 static boolean_t
874 be_do_install_mbr(char *diskname, nvlist_t *child)
876 struct uuid allowed_uuids[] = {
877 EFI_UNUSED,
878 EFI_RESV1,
879 EFI_BOOT,
880 EFI_ROOT,
881 EFI_SWAP,
882 EFI_USR,
883 EFI_BACKUP,
884 EFI_RESV2,
885 EFI_VAR,
886 EFI_HOME,
887 EFI_ALTSCTR,
888 EFI_RESERVED,
889 EFI_SYSTEM,
890 EFI_BIOS_BOOT,
891 EFI_SYMC_PUB,
892 EFI_SYMC_CDS
895 uint64_t whole;
896 struct dk_gpt *gpt;
897 struct uuid *u;
898 int fd, npart, i, j;
900 (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK,
901 &whole);
903 if (whole)
904 return (B_TRUE);
906 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0)
907 return (B_FALSE);
909 if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0)
910 return (B_FALSE);
912 for (i = 0; i != npart; i++) {
913 int match = 0;
915 u = &gpt->efi_parts[i].p_guid;
917 for (j = 0;
918 j != sizeof (allowed_uuids) / sizeof (struct uuid);
919 j++)
920 if (bcmp(u, &allowed_uuids[j],
921 sizeof (struct uuid)) == 0)
922 match++;
924 if (match == 0)
925 return (B_FALSE);
928 return (B_TRUE);
931 static int
932 be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1,
933 char *stage2, uint16_t flags)
935 char install_cmd[MAXPATHLEN];
936 char be_run_cmd_errbuf[BUFSIZ];
937 char be_run_cmd_outbuf[BUFSIZ];
938 char diskname[MAXPATHLEN];
939 char *vname;
940 char *path, *type, *dsk_ptr;
941 char *flag = "";
942 int ret;
943 vdev_stat_t *vs;
944 uint_t vsc;
946 if (nvlist_lookup_string(child, ZPOOL_CONFIG_TYPE, &type) != 0) {
947 be_print_err(gettext("%s: failed to get device type\n"),
948 __func__);
949 return (BE_ERR_NODEV);
951 /* Skip indirect devices. */
952 if (strcmp(type, VDEV_TYPE_INDIRECT) == 0)
953 return (BE_ERR_NOTSUP);
955 if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) {
956 be_print_err(gettext("%s: failed to get device path\n"),
957 __func__);
958 return (BE_ERR_NODEV);
961 if ((nvlist_lookup_uint64_array(child, ZPOOL_CONFIG_VDEV_STATS,
962 (uint64_t **)&vs, &vsc) != 0) ||
963 vs->vs_state < VDEV_STATE_DEGRADED) {
965 * Don't try to run installgrub on a vdev that is not ONLINE
966 * or DEGRADED. Try to print a warning for each such vdev.
968 be_print_err(gettext("%s: vdev %s is %s, can't install "
969 "boot loader\n"), __func__, path,
970 zpool_state_to_name(vs->vs_state, vs->vs_aux));
971 return (BE_SUCCESS);
975 * Modify the vdev path to point to the raw disk.
977 path = strdup(path);
978 if (path == NULL)
979 return (BE_ERR_NOMEM);
981 dsk_ptr = strstr(path, "/dsk/");
982 if (dsk_ptr != NULL) {
983 *dsk_ptr = '\0';
984 dsk_ptr++;
985 } else {
986 dsk_ptr = "";
989 (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
990 free(path);
992 vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE);
993 if (vname == NULL) {
994 be_print_err(gettext("%s: failed to get device name: %s\n"),
995 __func__, libzfs_error_description(g_zfs));
996 return (zfs_err_to_be_err(g_zfs));
999 if (be_is_isa("i386")) {
1000 uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE;
1001 uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR;
1003 if (force == BE_INSTALLBOOT_FLAG_FORCE) {
1004 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
1005 be_do_install_mbr(diskname, child))
1006 flag = "-F -m -f";
1007 else
1008 flag = "-F";
1009 } else {
1010 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
1011 be_do_install_mbr(diskname, child))
1012 flag = "-m -f";
1015 if (be_has_grub()) {
1016 (void) snprintf(install_cmd, sizeof (install_cmd),
1017 "%s %s %s %s %s", BE_INSTALL_GRUB, flag,
1018 stage1, stage2, diskname);
1019 } else {
1021 * With updated installboot, we only need boot
1022 * directory.
1024 (void) snprintf(install_cmd, sizeof (install_cmd),
1025 "%s %s -b %s %s", BE_INSTALL_BOOT, flag,
1026 stage1, diskname);
1028 } else if (be_is_isa("sparc")) {
1029 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) ==
1030 BE_INSTALLBOOT_FLAG_FORCE)
1031 flag = "-f -F zfs";
1032 else
1033 flag = "-F zfs";
1035 (void) snprintf(install_cmd, sizeof (install_cmd),
1036 "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname);
1037 } else {
1038 be_print_err(gettext("%s: unsupported architecture.\n"),
1039 __func__);
1040 return (BE_ERR_BOOTFILE_INST);
1043 *be_run_cmd_outbuf = '\0';
1044 *be_run_cmd_errbuf = '\0';
1046 ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ,
1047 be_run_cmd_outbuf, BUFSIZ);
1049 if (ret != BE_SUCCESS) {
1050 be_print_err(gettext("%s: install failed for device %s.\n"),
1051 __func__, vname);
1052 ret = BE_ERR_BOOTFILE_INST;
1055 be_print_err(gettext(" Command: \"%s\"\n"), install_cmd);
1056 if (be_run_cmd_outbuf[0] != 0) {
1057 be_print_err(gettext(" Output:\n"));
1058 be_print_err("%s", be_run_cmd_outbuf);
1061 if (be_run_cmd_errbuf[0] != 0) {
1062 be_print_err(gettext(" Errors:\n"));
1063 be_print_err("%s", be_run_cmd_errbuf);
1065 free(vname);
1067 return (ret);
1071 * Function: be_do_copy_grub_cap
1072 * Description: This function will copy grub capability file to BE.
1074 * Parameters:
1075 * bt - The transaction data for the BE we're activating.
1076 * Return:
1077 * BE_SUCCESS - Success
1078 * be_errno_t - Failure
1080 * Scope:
1081 * Private
1083 static int
1084 be_do_copy_grub_cap(be_transaction_data_t *bt)
1086 zfs_handle_t *zhp = NULL;
1087 char cap_file[MAXPATHLEN];
1088 char zpool_cap_file[MAXPATHLEN];
1089 char line[BUFSIZ];
1090 char *tmp_mntpnt = NULL;
1091 char *orig_mntpnt = NULL;
1092 char *pool_mntpnt = NULL;
1093 FILE *cap_fp = NULL;
1094 FILE *zpool_cap_fp = NULL;
1095 int err = 0;
1096 int ret = BE_SUCCESS;
1097 boolean_t pool_mounted = B_FALSE;
1098 boolean_t be_mounted = B_FALSE;
1101 * first get BE dataset mountpoint, we can free all the resources
1102 * once cap_file is built, leaving only be unmount to be done.
1104 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1105 NULL) {
1106 be_print_err(gettext("%s: failed to "
1107 "open BE root dataset (%s): %s\n"), __func__,
1108 bt->obe_root_ds, libzfs_error_description(g_zfs));
1109 return (zfs_err_to_be_err(g_zfs));
1112 if (!zfs_is_mounted(zhp, &tmp_mntpnt)) {
1113 if ((ret = _be_mount(bt->obe_name, &tmp_mntpnt,
1114 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1115 be_print_err(gettext("%s: failed to "
1116 "mount BE (%s)\n"), __func__, bt->obe_name);
1117 ZFS_CLOSE(zhp);
1118 goto done;
1120 be_mounted = B_TRUE;
1122 ZFS_CLOSE(zhp); /* BE dataset handle is not needed any more */
1124 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpnt,
1125 BE_CAP_FILE);
1126 free(tmp_mntpnt);
1128 /* get pool root dataset mountpoint */
1129 zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM);
1130 if (zhp == NULL) {
1131 be_print_err(gettext("%s: zfs_open failed: %s\n"),
1132 __func__, libzfs_error_description(g_zfs));
1133 ret = zfs_err_to_be_err(g_zfs);
1134 goto done;
1138 * Check to see if the pool's dataset is mounted. If it isn't we'll
1139 * attempt to mount it.
1141 if ((ret = be_mount_pool(zhp, &tmp_mntpnt,
1142 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
1143 be_print_err(gettext("%s: pool dataset "
1144 "(%s) could not be mounted\n"), __func__, bt->obe_zpool);
1145 ZFS_CLOSE(zhp);
1146 goto done;
1150 * Get the mountpoint for the root pool dataset.
1151 * NOTE: zhp must be kept for _be_unmount_pool()
1153 if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1154 be_print_err(gettext("%s: pool "
1155 "dataset (%s) is not mounted. Can't check the grub "
1156 "version from the grub capability file.\n"), __func__,
1157 bt->obe_zpool);
1158 ret = BE_ERR_NO_MENU;
1159 goto done;
1162 (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
1163 pool_mntpnt, BE_CAP_FILE);
1164 free(pool_mntpnt);
1166 if ((cap_fp = fopen(cap_file, "r")) == NULL) {
1167 err = errno;
1168 be_print_err(gettext("%s: failed to open grub "
1169 "capability file\n"), __func__);
1170 ret = errno_to_be_err(err);
1171 goto done;
1173 if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
1174 err = errno;
1175 be_print_err(gettext("%s: failed to open new "
1176 "grub capability file\n"), __func__);
1177 ret = errno_to_be_err(err);
1178 (void) fclose(cap_fp);
1179 goto done;
1182 while (fgets(line, BUFSIZ, cap_fp)) {
1183 (void) fputs(line, zpool_cap_fp);
1186 (void) fclose(zpool_cap_fp);
1187 (void) fclose(cap_fp);
1189 done:
1190 if (be_mounted)
1191 (void) _be_unmount(bt->obe_name, 0);
1193 if (pool_mounted) {
1194 err = be_unmount_pool(zhp, tmp_mntpnt, orig_mntpnt);
1195 if (ret == BE_SUCCESS)
1196 ret = err;
1197 free(orig_mntpnt);
1198 free(tmp_mntpnt);
1199 zfs_close(zhp);
1201 return (ret);
1205 * Function: be_is_install_needed
1206 * Description: Check detached version files to detect if bootloader
1207 * install/update is needed.
1209 * Parameters:
1210 * bt - The transaction data for the BE we're activating.
1211 * update - set B_TRUE is update is needed.
1212 * Return:
1213 * BE_SUCCESS - Success
1214 * be_errno_t - Failure
1216 * Scope:
1217 * Private
1219 static int
1220 be_is_install_needed(be_transaction_data_t *bt, boolean_t *update)
1222 int ret = BE_SUCCESS;
1223 char *cur_vers = NULL, *new_vers = NULL;
1225 assert(bt != NULL);
1226 assert(update != NULL);
1228 if (!be_has_grub()) {
1230 * no detached versioning, let installboot to manage
1231 * versioning.
1233 *update = B_TRUE;
1234 return (ret);
1237 *update = B_FALSE; /* set default */
1240 * We need to check to see if the version number from
1241 * the BE being activated is greater than the current
1242 * one.
1244 ret = be_get_grub_vers(bt, &cur_vers, &new_vers);
1245 if (ret != BE_SUCCESS) {
1246 be_print_err(gettext("be_activate: failed to get grub "
1247 "versions from capability files.\n"));
1248 return (ret);
1250 /* update if we have both versions and can compare */
1251 if (cur_vers != NULL) {
1252 if (new_vers != NULL) {
1253 if (atof(cur_vers) < atof(new_vers))
1254 *update = B_TRUE;
1255 free(new_vers);
1257 free(cur_vers);
1258 } else if (new_vers != NULL) {
1259 /* we only got new version - update */
1260 *update = B_TRUE;
1261 free(new_vers);
1263 return (ret);
1266 static int
1267 be_do_installboot_walk(zpool_handle_t *zphp, nvlist_t *nv, char *stage1,
1268 char *stage2, uint16_t flags)
1270 boolean_t verbose = do_print;
1271 nvlist_t **child;
1272 uint_t children = 0;
1273 int ret = -1;
1275 /* It is OK to have no children. */
1276 (void) nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1277 &children);
1279 for (int c = 0; c < children; c++) {
1280 char *vname;
1281 int rv;
1283 /* ensure update on child status */
1284 vname = zpool_vdev_name(g_zfs, zphp, child[c], verbose);
1285 if (vname == NULL) {
1286 be_print_err(gettext("%s: "
1287 "failed to get device name: %s\n"), __func__,
1288 libzfs_error_description(g_zfs));
1289 return (zfs_err_to_be_err(g_zfs));
1290 } else {
1291 be_print_err(gettext("%s: child %d of %d device %s\n"),
1292 __func__, c, children, vname);
1295 rv = be_do_installboot_walk(zphp, child[c], stage1, stage2,
1296 flags);
1297 switch (rv) {
1298 case BE_ERR_NOTSUP:
1299 /* ignore unsupported devices */
1300 be_print_err(
1301 gettext("%s: device %s is not supported\n"),
1302 __func__, vname);
1303 break;
1304 case BE_SUCCESS:
1305 /* catch at least one success */
1306 ret = rv;
1307 break;
1308 default:
1309 if (ret == -1)
1310 ret = rv;
1311 break;
1313 free(vname);
1316 if (children > 0)
1317 return (ret == -1? BE_ERR_NOTSUP : ret);
1318 return (be_do_installboot_helper(zphp, nv, stage1, stage2, flags));
1322 * Function: be_do_installboot
1323 * Description: This function runs installgrub/installboot using the boot
1324 * loader files from the BE we're activating and installing
1325 * them on the pool the BE lives in.
1327 * Parameters:
1328 * bt - The transaction data for the BE we're activating.
1329 * flags - flags for bootloader install
1330 * Return:
1331 * BE_SUCCESS - Success
1332 * be_errno_t - Failure
1334 * Scope:
1335 * Private
1337 static int
1338 be_do_installboot(be_transaction_data_t *bt, uint16_t flags)
1340 zpool_handle_t *zphp = NULL;
1341 zfs_handle_t *zhp = NULL;
1342 nvlist_t *nv, *config;
1343 char *tmp_mntpt = NULL;
1344 char stage1[MAXPATHLEN];
1345 char stage2[MAXPATHLEN];
1346 int ret = BE_SUCCESS;
1347 boolean_t be_mounted = B_FALSE;
1348 boolean_t update = B_FALSE;
1351 * check versions. This call is to support detached
1352 * version implementation like grub. Embedded versioning is
1353 * checked by actual installer.
1355 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) != BE_INSTALLBOOT_FLAG_FORCE) {
1356 ret = be_is_install_needed(bt, &update);
1357 if (ret != BE_SUCCESS || update == B_FALSE)
1358 return (ret);
1361 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1362 NULL) {
1363 be_print_err(gettext("%s: failed to "
1364 "open BE root dataset (%s): %s\n"), __func__,
1365 bt->obe_root_ds, libzfs_error_description(g_zfs));
1366 ret = zfs_err_to_be_err(g_zfs);
1367 return (ret);
1369 if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
1370 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
1371 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1372 be_print_err(gettext("%s: failed to "
1373 "mount BE (%s)\n"), __func__, bt->obe_name);
1374 ZFS_CLOSE(zhp);
1375 return (ret);
1377 be_mounted = B_TRUE;
1379 ZFS_CLOSE(zhp);
1381 if (be_is_isa("i386")) {
1382 if (be_has_grub()) {
1383 (void) snprintf(stage1, sizeof (stage1), "%s%s",
1384 tmp_mntpt, BE_GRUB_STAGE_1);
1385 (void) snprintf(stage2, sizeof (stage2), "%s%s",
1386 tmp_mntpt, BE_GRUB_STAGE_2);
1387 } else {
1388 (void) snprintf(stage1, sizeof (stage1), "%s%s",
1389 tmp_mntpt, BE_LOADER_STAGES);
1390 /* Skip stage2 */
1392 } else if (be_is_isa("sparc")) {
1393 char *platform = be_get_platform();
1395 if (platform == NULL) {
1396 be_print_err(gettext("%s: failed to detect system "
1397 "platform name\n"), __func__);
1398 if (be_mounted)
1399 (void) _be_unmount(bt->obe_name, 0);
1400 free(tmp_mntpt);
1401 return (BE_ERR_BOOTFILE_INST);
1403 stage1[0] = '\0'; /* sparc has no stage1 */
1404 (void) snprintf(stage2, sizeof (stage2),
1405 "%s/usr/platform/%s%s", tmp_mntpt,
1406 platform, BE_SPARC_BOOTBLK);
1407 } else {
1408 be_print_err(gettext("%s: unsupported architecture.\n"),
1409 __func__);
1410 return (BE_ERR_BOOTFILE_INST);
1413 if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
1414 be_print_err(gettext("%s: failed to open "
1415 "pool (%s): %s\n"), __func__, bt->obe_zpool,
1416 libzfs_error_description(g_zfs));
1417 ret = zfs_err_to_be_err(g_zfs);
1418 if (be_mounted)
1419 (void) _be_unmount(bt->obe_name, 0);
1420 free(tmp_mntpt);
1421 return (ret);
1424 if ((config = zpool_get_config(zphp, NULL)) == NULL) {
1425 be_print_err(gettext("%s: failed to get zpool "
1426 "configuration information. %s\n"), __func__,
1427 libzfs_error_description(g_zfs));
1428 ret = zfs_err_to_be_err(g_zfs);
1429 goto done;
1433 * Get the vdev tree
1435 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
1436 be_print_err(gettext("%s: failed to get vdev "
1437 "tree: %s\n"), __func__, libzfs_error_description(g_zfs));
1438 ret = zfs_err_to_be_err(g_zfs);
1439 goto done;
1442 ret = be_do_installboot_walk(zphp, nv, stage1, stage2, flags);
1444 if (be_has_grub()) {
1445 ret = be_do_copy_grub_cap(bt);
1448 done:
1449 ZFS_CLOSE(zhp);
1450 if (be_mounted)
1451 (void) _be_unmount(bt->obe_name, 0);
1452 zpool_close(zphp);
1453 free(tmp_mntpt);
1454 return (ret);
1458 * Function: be_promote_zone_ds
1459 * Description: This function finds the zones for the BE being activated
1460 * and the active zonepath dataset for each zone. Then each
1461 * active zonepath dataset is promoted.
1463 * Parameters:
1464 * be_name - the name of the global zone BE that we need to
1465 * find the zones for.
1466 * be_root_ds - the root dataset for be_name.
1467 * Return:
1468 * BE_SUCCESS - Success
1469 * be_errno_t - Failure
1471 * Scope:
1472 * Private
1474 static int
1475 be_promote_zone_ds(char *be_name, char *be_root_ds)
1477 char *zone_ds = NULL;
1478 char *temp_mntpt = NULL;
1479 char origin[MAXPATHLEN];
1480 char zoneroot_ds[MAXPATHLEN];
1481 zfs_handle_t *zhp = NULL;
1482 zfs_handle_t *z_zhp = NULL;
1483 zoneList_t zone_list = NULL;
1484 zoneBrandList_t *brands = NULL;
1485 boolean_t be_mounted = B_FALSE;
1486 int zone_index = 0;
1487 int err = BE_SUCCESS;
1490 * Get the supported zone brands so we can pass that
1491 * to z_get_nonglobal_zone_list_by_brand. Currently
1492 * only the ipkg and labeled brand zones are supported
1495 if ((brands = be_get_supported_brandlist()) == NULL) {
1496 be_print_err(gettext("be_promote_zone_ds: no supported "
1497 "brands\n"));
1498 return (BE_SUCCESS);
1501 if ((zhp = zfs_open(g_zfs, be_root_ds,
1502 ZFS_TYPE_FILESYSTEM)) == NULL) {
1503 be_print_err(gettext("be_promote_zone_ds: Failed to open "
1504 "dataset (%s): %s\n"), be_root_ds,
1505 libzfs_error_description(g_zfs));
1506 err = zfs_err_to_be_err(g_zfs);
1507 z_free_brand_list(brands);
1508 return (err);
1511 if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1512 if ((err = _be_mount(be_name, &temp_mntpt,
1513 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1514 be_print_err(gettext("be_promote_zone_ds: failed to "
1515 "mount the BE for zones procesing.\n"));
1516 ZFS_CLOSE(zhp);
1517 z_free_brand_list(brands);
1518 return (err);
1520 be_mounted = B_TRUE;
1524 * Set the zone root to the temp mount point for the BE we just mounted.
1526 z_set_zone_root(temp_mntpt);
1529 * Get all the zones based on the brands we're looking for. If no zones
1530 * are found that we're interested in unmount the BE and move on.
1532 if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1533 if (be_mounted)
1534 (void) _be_unmount(be_name, 0);
1535 ZFS_CLOSE(zhp);
1536 z_free_brand_list(brands);
1537 free(temp_mntpt);
1538 return (BE_SUCCESS);
1540 for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1541 != NULL; zone_index++) {
1542 char *zone_path = NULL;
1544 /* Skip zones that aren't at least installed */
1545 if (z_zlist_get_current_state(zone_list, zone_index) <
1546 ZONE_STATE_INSTALLED)
1547 continue;
1549 if (((zone_path =
1550 z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1551 ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1552 !be_zone_supported(zone_ds))
1553 continue;
1555 if (be_find_active_zone_root(zhp, zone_ds,
1556 zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1557 be_print_err(gettext("be_promote_zone_ds: "
1558 "Zone does not have an active root "
1559 "dataset, skipping this zone.\n"));
1560 continue;
1563 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1564 ZFS_TYPE_FILESYSTEM)) == NULL) {
1565 be_print_err(gettext("be_promote_zone_ds: "
1566 "Failed to open dataset "
1567 "(%s): %s\n"), zoneroot_ds,
1568 libzfs_error_description(g_zfs));
1569 err = zfs_err_to_be_err(g_zfs);
1570 goto done;
1573 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1574 sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1575 ZFS_CLOSE(z_zhp);
1576 continue;
1580 * We don't need to close the zfs handle at this
1581 * point because the callback funtion
1582 * be_promote_ds_callback() will close it for us.
1584 if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1585 be_print_err(gettext("be_promote_zone_ds: "
1586 "failed to activate the "
1587 "datasets for %s: %s\n"),
1588 zoneroot_ds,
1589 libzfs_error_description(g_zfs));
1590 err = BE_ERR_PROMOTE;
1591 goto done;
1594 done:
1595 if (be_mounted)
1596 (void) _be_unmount(be_name, 0);
1597 ZFS_CLOSE(zhp);
1598 free(temp_mntpt);
1599 z_free_brand_list(brands);
1600 z_free_zone_list(zone_list);
1601 return (err);
1605 * Function: be_promote_ds_callback
1606 * Description: This function is used to promote the datasets for the BE
1607 * being activated as well as the datasets for the zones BE
1608 * being activated.
1610 * Parameters:
1611 * zhp - the zfs handle for zone BE being activated.
1612 * data - not used.
1613 * Return:
1614 * 0 - Success
1615 * be_errno_t - Failure
1617 * Scope:
1618 * Private
1620 static int
1621 /* LINTED */
1622 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1624 char origin[MAXPATHLEN];
1625 char *sub_dataset = NULL;
1626 int ret = 0;
1628 if (zhp != NULL) {
1629 sub_dataset = strdup(zfs_get_name(zhp));
1630 if (sub_dataset == NULL) {
1631 ret = BE_ERR_NOMEM;
1632 goto done;
1634 } else {
1635 be_print_err(gettext("be_promote_ds_callback: "
1636 "Invalid zfs handle passed into function\n"));
1637 ret = BE_ERR_INVAL;
1638 goto done;
1642 * This loop makes sure that we promote the dataset to the
1643 * top of the tree so that it is no longer a decendent of any
1644 * dataset. The ZFS close and then open is used to make sure that
1645 * the promotion is updated before we move on.
1647 while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1648 sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1649 if (zfs_promote(zhp) != 0) {
1650 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1651 be_print_err(gettext("be_promote_ds_callback: "
1652 "promote of %s failed: %s\n"),
1653 zfs_get_name(zhp),
1654 libzfs_error_description(g_zfs));
1655 ret = zfs_err_to_be_err(g_zfs);
1656 goto done;
1657 } else {
1659 * If the call to zfs_promote returns the
1660 * error EZFS_EXISTS we've hit a snapshot name
1661 * collision. This means we're probably
1662 * attemping to promote a zone dataset above a
1663 * parent dataset that belongs to another zone
1664 * which this zone was cloned from.
1666 * TODO: If this is a zone dataset at some
1667 * point we should skip this if the zone
1668 * paths for the dataset and the snapshot
1669 * don't match.
1671 be_print_err(gettext("be_promote_ds_callback: "
1672 "promote of %s failed due to snapshot "
1673 "name collision: %s\n"), zfs_get_name(zhp),
1674 libzfs_error_description(g_zfs));
1675 ret = zfs_err_to_be_err(g_zfs);
1676 goto done;
1679 ZFS_CLOSE(zhp);
1680 if ((zhp = zfs_open(g_zfs, sub_dataset,
1681 ZFS_TYPE_FILESYSTEM)) == NULL) {
1682 be_print_err(gettext("be_promote_ds_callback: "
1683 "Failed to open dataset (%s): %s\n"), sub_dataset,
1684 libzfs_error_description(g_zfs));
1685 ret = zfs_err_to_be_err(g_zfs);
1686 goto done;
1690 /* Iterate down this dataset's children and promote them */
1691 ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1693 done:
1694 free(sub_dataset);
1695 ZFS_CLOSE(zhp);
1696 return (ret);