6646 libbe be_do_copy_grub_cap() is broken when pool root dataset is not mounted
[unleashed.git] / usr / src / lib / libbe / common / be_activate.c
blob416ceef7e22f62840a8d9229eabffdfcff97dfc9
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.
30 #include <assert.h>
31 #include <libintl.h>
32 #include <libnvpair.h>
33 #include <libzfs.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <errno.h>
39 #include <sys/mnttab.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 #include <sys/efi_partition.h>
46 #include <libbe.h>
47 #include <libbe_priv.h>
49 char *mnttab = MNTTAB;
52 * Private function prototypes
54 static int set_bootfs(char *boot_rpool, char *be_root_ds);
55 static int set_canmount(be_node_list_t *, char *);
56 static boolean_t be_do_install_mbr(char *, nvlist_t *);
57 static int be_do_installboot_helper(zpool_handle_t *, nvlist_t *, char *,
58 char *, uint16_t);
59 static int be_do_installboot(be_transaction_data_t *, uint16_t);
60 static int be_get_grub_vers(be_transaction_data_t *, char **, char **);
61 static int get_ver_from_capfile(char *, char **);
62 static int be_promote_zone_ds(char *, char *);
63 static int be_promote_ds_callback(zfs_handle_t *, void *);
65 /* ******************************************************************** */
66 /* Public Functions */
67 /* ******************************************************************** */
70 * Function: be_activate
71 * Description: Calls _be_activate which activates the BE named in the
72 * attributes passed in through be_attrs. The process of
73 * activation sets the bootfs property of the root pool, resets
74 * the canmount property to noauto, and sets the default in the
75 * grub menu to the entry corresponding to the entry for the named
76 * BE.
77 * Parameters:
78 * be_attrs - pointer to nvlist_t of attributes being passed in.
79 * The follow attribute values are used by this function:
81 * BE_ATTR_ORIG_BE_NAME *required
82 * Return:
83 * BE_SUCCESS - Success
84 * be_errno_t - Failure
85 * Scope:
86 * Public
88 int
89 be_activate(nvlist_t *be_attrs)
91 int ret = BE_SUCCESS;
92 char *be_name = NULL;
94 /* Initialize libzfs handle */
95 if (!be_zfs_init())
96 return (BE_ERR_INIT);
98 /* Get the BE name to activate */
99 if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
100 != 0) {
101 be_print_err(gettext("be_activate: failed to "
102 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
103 be_zfs_fini();
104 return (BE_ERR_INVAL);
107 /* Validate BE name */
108 if (!be_valid_be_name(be_name)) {
109 be_print_err(gettext("be_activate: invalid BE name %s\n"),
110 be_name);
111 be_zfs_fini();
112 return (BE_ERR_INVAL);
115 ret = _be_activate(be_name);
117 be_zfs_fini();
119 return (ret);
123 * Function: be_installboot
124 * Description: Calls be_do_installboot to install/update bootloader on
125 * pool passed in through be_attrs. The primary consumer is
126 * bootadm command to avoid duplication of the code.
127 * Parameters:
128 * be_attrs - pointer to nvlist_t of attributes being passed in.
129 * The following attribute values are used:
131 * BE_ATTR_ORIG_BE_NAME *required
132 * BE_ATTR_ORIG_BE_POOL *required
133 * BE_ATTR_ORIG_BE_ROOT *required
134 * BE_ATTR_INSTALL_FLAGS optional
136 * Return:
137 * BE_SUCCESS - Success
138 * be_errno_t - Failure
139 * Scope:
140 * Public
143 be_installboot(nvlist_t *be_attrs)
145 int ret = BE_SUCCESS;
146 uint16_t flags = 0;
147 uint16_t verbose;
148 be_transaction_data_t bt = { 0 };
150 /* Get flags */
151 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
152 BE_ATTR_INSTALL_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
153 be_print_err(gettext("be_installboot: failed to lookup "
154 "BE_ATTR_INSTALL_FLAGS attribute\n"));
155 return (BE_ERR_INVAL);
158 /* Set verbose early, so we get all messages */
159 verbose = flags & BE_INSTALLBOOT_FLAG_VERBOSE;
160 if (verbose == BE_INSTALLBOOT_FLAG_VERBOSE)
161 libbe_print_errors(B_TRUE);
163 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
164 &bt.obe_name);
165 if (ret != 0) {
166 be_print_err(gettext("be_installboot: failed to "
167 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
168 return (BE_ERR_INVAL);
171 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_POOL,
172 &bt.obe_zpool);
173 if (ret != 0) {
174 be_print_err(gettext("be_installboot: failed to "
175 "lookup BE_ATTR_ORIG_BE_POOL attribute\n"));
176 return (BE_ERR_INVAL);
179 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_ROOT,
180 &bt.obe_root_ds);
181 if (ret != 0) {
182 be_print_err(gettext("be_installboot: failed to "
183 "lookup BE_ATTR_ORIG_BE_ROOT attribute\n"));
184 return (BE_ERR_INVAL);
187 /* Initialize libzfs handle */
188 if (!be_zfs_init())
189 return (BE_ERR_INIT);
191 ret = be_do_installboot(&bt, flags);
193 be_zfs_fini();
195 return (ret);
198 /* ******************************************************************** */
199 /* Semi Private Functions */
200 /* ******************************************************************** */
203 * Function: _be_activate
204 * Description: This does the actual work described in be_activate.
205 * Parameters:
206 * be_name - pointer to the name of BE to activate.
208 * Return:
209 * BE_SUCCESS - Success
210 * be_errnot_t - Failure
211 * Scope:
212 * Public
215 _be_activate(char *be_name)
217 be_transaction_data_t cb = { 0 };
218 zfs_handle_t *zhp = NULL;
219 char root_ds[MAXPATHLEN];
220 char active_ds[MAXPATHLEN];
221 be_node_list_t *be_nodes = NULL;
222 uuid_t uu = {0};
223 int entry, ret = BE_SUCCESS;
224 int zret = 0;
227 * TODO: The BE needs to be validated to make sure that it is actually
228 * a bootable BE.
231 if (be_name == NULL)
232 return (BE_ERR_INVAL);
234 /* Set obe_name to be_name in the cb structure */
235 cb.obe_name = be_name;
237 /* find which zpool the be is in */
238 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
239 be_print_err(gettext("be_activate: failed to "
240 "find zpool for BE (%s)\n"), cb.obe_name);
241 return (BE_ERR_BE_NOENT);
242 } else if (zret < 0) {
243 be_print_err(gettext("be_activate: "
244 "zpool_iter failed: %s\n"),
245 libzfs_error_description(g_zfs));
246 ret = zfs_err_to_be_err(g_zfs);
247 return (ret);
250 be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
251 cb.obe_root_ds = strdup(root_ds);
253 if (getzoneid() == GLOBAL_ZONEID) {
254 ret = be_do_installboot(&cb, BE_INSTALLBOOT_FLAG_NULL);
255 if (ret != BE_SUCCESS)
256 return (ret);
258 if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
259 if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
260 NULL, NULL, NULL)) != BE_SUCCESS) {
261 be_print_err(gettext("be_activate: Failed to "
262 "add BE (%s) to the menu\n"),
263 cb.obe_name);
264 goto done;
267 if (be_has_grub()) {
268 if ((ret = be_change_grub_default(cb.obe_name,
269 cb.obe_zpool)) != BE_SUCCESS) {
270 be_print_err(gettext("be_activate: failed to "
271 "change the default entry in menu.lst\n"));
272 goto done;
277 if ((ret = _be_list(cb.obe_name, &be_nodes)) != BE_SUCCESS) {
278 return (ret);
281 if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
282 be_print_err(gettext("be_activate: failed to set "
283 "canmount dataset property\n"));
284 goto done;
287 if (getzoneid() == GLOBAL_ZONEID) {
288 if ((ret = set_bootfs(be_nodes->be_rpool,
289 root_ds)) != BE_SUCCESS) {
290 be_print_err(gettext("be_activate: failed to set "
291 "bootfs pool property for %s\n"), root_ds);
292 goto done;
296 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
298 * We don't need to close the zfs handle at this
299 * point because The callback funtion
300 * be_promote_ds_callback() will close it for us.
302 if (be_promote_ds_callback(zhp, NULL) != 0) {
303 be_print_err(gettext("be_activate: "
304 "failed to activate the "
305 "datasets for %s: %s\n"),
306 root_ds,
307 libzfs_error_description(g_zfs));
308 ret = BE_ERR_PROMOTE;
309 goto done;
311 } else {
312 be_print_err(gettext("be_activate: failed to open "
313 "dataset (%s): %s\n"), root_ds,
314 libzfs_error_description(g_zfs));
315 ret = zfs_err_to_be_err(g_zfs);
316 goto done;
319 if (getzoneid() == GLOBAL_ZONEID &&
320 be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
321 (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
322 != BE_SUCCESS) {
323 be_print_err(gettext("be_activate: failed to promote "
324 "the active zonepath datasets for zones in BE %s\n"),
325 cb.obe_name);
328 if (getzoneid() != GLOBAL_ZONEID) {
329 if (!be_zone_compare_uuids(root_ds)) {
330 be_print_err(gettext("be_activate: activating zone "
331 "root dataset from non-active global BE is not "
332 "supported\n"));
333 ret = BE_ERR_NOTSUP;
334 goto done;
336 if ((zhp = zfs_open(g_zfs, root_ds,
337 ZFS_TYPE_FILESYSTEM)) == NULL) {
338 be_print_err(gettext("be_activate: failed to open "
339 "dataset (%s): %s\n"), root_ds,
340 libzfs_error_description(g_zfs));
341 ret = zfs_err_to_be_err(g_zfs);
342 goto done;
344 /* Find current active zone root dataset */
345 if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
346 active_ds, sizeof (active_ds))) != BE_SUCCESS) {
347 be_print_err(gettext("be_activate: failed to find "
348 "active zone root dataset\n"));
349 ZFS_CLOSE(zhp);
350 goto done;
352 /* Do nothing if requested BE is already active */
353 if (strcmp(root_ds, active_ds) == 0) {
354 ret = BE_SUCCESS;
355 ZFS_CLOSE(zhp);
356 goto done;
359 /* Set active property for BE */
360 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
361 be_print_err(gettext("be_activate: failed to set "
362 "active property (%s): %s\n"), root_ds,
363 libzfs_error_description(g_zfs));
364 ret = zfs_err_to_be_err(g_zfs);
365 ZFS_CLOSE(zhp);
366 goto done;
368 ZFS_CLOSE(zhp);
370 /* Unset active property for old active root dataset */
371 if ((zhp = zfs_open(g_zfs, active_ds,
372 ZFS_TYPE_FILESYSTEM)) == NULL) {
373 be_print_err(gettext("be_activate: failed to open "
374 "dataset (%s): %s\n"), active_ds,
375 libzfs_error_description(g_zfs));
376 ret = zfs_err_to_be_err(g_zfs);
377 goto done;
379 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
380 be_print_err(gettext("be_activate: failed to unset "
381 "active property (%s): %s\n"), active_ds,
382 libzfs_error_description(g_zfs));
383 ret = zfs_err_to_be_err(g_zfs);
384 ZFS_CLOSE(zhp);
385 goto done;
387 ZFS_CLOSE(zhp);
389 done:
390 be_free_list(be_nodes);
391 return (ret);
395 * Function: be_activate_current_be
396 * Description: Set the currently "active" BE to be "active on boot"
397 * Paramters:
398 * none
399 * Returns:
400 * BE_SUCCESS - Success
401 * be_errnot_t - Failure
402 * Scope:
403 * Semi-private (library wide use only)
406 be_activate_current_be(void)
408 int ret = BE_SUCCESS;
409 be_transaction_data_t bt = { 0 };
411 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
412 return (ret);
415 if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
416 be_print_err(gettext("be_activate_current_be: failed to "
417 "activate %s\n"), bt.obe_name);
418 return (ret);
421 return (BE_SUCCESS);
425 * Function: be_is_active_on_boot
426 * Description: Checks if the BE name passed in has the "active on boot"
427 * property set to B_TRUE.
428 * Paramters:
429 * be_name - the name of the BE to check
430 * Returns:
431 * B_TRUE - if active on boot.
432 * B_FALSE - if not active on boot.
433 * Scope:
434 * Semi-private (library wide use only)
436 boolean_t
437 be_is_active_on_boot(char *be_name)
439 be_node_list_t *be_node = NULL;
441 if (be_name == NULL) {
442 be_print_err(gettext("be_is_active_on_boot: "
443 "be_name must not be NULL\n"));
444 return (B_FALSE);
447 if (_be_list(be_name, &be_node) != BE_SUCCESS) {
448 return (B_FALSE);
451 if (be_node == NULL) {
452 return (B_FALSE);
455 if (be_node->be_active_on_boot) {
456 be_free_list(be_node);
457 return (B_TRUE);
458 } else {
459 be_free_list(be_node);
460 return (B_FALSE);
464 /* ******************************************************************** */
465 /* Private Functions */
466 /* ******************************************************************** */
469 * Function: set_bootfs
470 * Description: Sets the bootfs property on the boot pool to be the
471 * root dataset of the activated BE.
472 * Parameters:
473 * boot_pool - The pool we're setting bootfs in.
474 * be_root_ds - The main dataset for the BE.
475 * Return:
476 * BE_SUCCESS - Success
477 * be_errno_t - Failure
478 * Scope:
479 * Private
481 static int
482 set_bootfs(char *boot_rpool, char *be_root_ds)
484 zpool_handle_t *zhp;
485 int err = BE_SUCCESS;
487 if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
488 be_print_err(gettext("set_bootfs: failed to open pool "
489 "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
490 err = zfs_err_to_be_err(g_zfs);
491 return (err);
494 err = zpool_set_prop(zhp, "bootfs", be_root_ds);
495 if (err) {
496 be_print_err(gettext("set_bootfs: failed to set "
497 "bootfs property for pool %s: %s\n"), boot_rpool,
498 libzfs_error_description(g_zfs));
499 err = zfs_err_to_be_err(g_zfs);
500 zpool_close(zhp);
501 return (err);
504 zpool_close(zhp);
505 return (BE_SUCCESS);
509 * Function: set_canmount
510 * Description: Sets the canmount property on the datasets of the
511 * activated BE.
512 * Parameters:
513 * be_nodes - The be_node_t returned from be_list
514 * value - The value of canmount we setting, on|off|noauto.
515 * Return:
516 * BE_SUCCESS - Success
517 * be_errno_t - Failure
518 * Scope:
519 * Private
521 static int
522 set_canmount(be_node_list_t *be_nodes, char *value)
524 char ds_path[MAXPATHLEN];
525 zfs_handle_t *zhp = NULL;
526 be_node_list_t *list = be_nodes;
527 int err = BE_SUCCESS;
529 while (list != NULL) {
530 be_dataset_list_t *datasets = list->be_node_datasets;
532 be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
533 sizeof (ds_path));
535 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
536 NULL) {
537 be_print_err(gettext("set_canmount: failed to open "
538 "dataset (%s): %s\n"), ds_path,
539 libzfs_error_description(g_zfs));
540 err = zfs_err_to_be_err(g_zfs);
541 return (err);
543 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
545 * it's already mounted so we can't change the
546 * canmount property anyway.
548 err = BE_SUCCESS;
549 } else {
550 err = zfs_prop_set(zhp,
551 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
552 if (err) {
553 ZFS_CLOSE(zhp);
554 be_print_err(gettext("set_canmount: failed to "
555 "set dataset property (%s): %s\n"),
556 ds_path, libzfs_error_description(g_zfs));
557 err = zfs_err_to_be_err(g_zfs);
558 return (err);
561 ZFS_CLOSE(zhp);
563 while (datasets != NULL) {
564 be_make_root_ds(list->be_rpool,
565 datasets->be_dataset_name, ds_path,
566 sizeof (ds_path));
568 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
569 == NULL) {
570 be_print_err(gettext("set_canmount: failed to "
571 "open dataset %s: %s\n"), ds_path,
572 libzfs_error_description(g_zfs));
573 err = zfs_err_to_be_err(g_zfs);
574 return (err);
576 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
578 * it's already mounted so we can't change the
579 * canmount property anyway.
581 err = BE_SUCCESS;
582 ZFS_CLOSE(zhp);
583 break;
585 err = zfs_prop_set(zhp,
586 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
587 if (err) {
588 ZFS_CLOSE(zhp);
589 be_print_err(gettext("set_canmount: "
590 "Failed to set property value %s "
591 "for dataset %s: %s\n"), value, ds_path,
592 libzfs_error_description(g_zfs));
593 err = zfs_err_to_be_err(g_zfs);
594 return (err);
596 ZFS_CLOSE(zhp);
597 datasets = datasets->be_next_dataset;
599 list = list->be_next_node;
601 return (err);
605 * Function: be_get_grub_vers
606 * Description: Gets the grub version number from /boot/grub/capability. If
607 * capability file doesn't exist NULL is returned.
608 * Parameters:
609 * bt - The transaction data for the BE we're getting the grub
610 * version for.
611 * cur_vers - used to return the current version of grub from
612 * the root pool.
613 * new_vers - used to return the grub version of the BE we're
614 * activating.
615 * Return:
616 * BE_SUCCESS - Success
617 * be_errno_t - Failed to find version
618 * Scope:
619 * Private
621 static int
622 be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
624 zfs_handle_t *zhp = NULL;
625 zfs_handle_t *pool_zhp = NULL;
626 int ret = BE_SUCCESS;
627 char cap_file[MAXPATHLEN];
628 char *temp_mntpnt = NULL;
629 char *zpool_mntpt = NULL;
630 char *ptmp_mntpnt = NULL;
631 char *orig_mntpnt = NULL;
632 boolean_t be_mounted = B_FALSE;
633 boolean_t pool_mounted = B_FALSE;
635 if (!be_has_grub()) {
636 be_print_err(gettext("be_get_grub_vers: Not supported on "
637 "this architecture\n"));
638 return (BE_ERR_NOTSUP);
641 if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL ||
642 bt->obe_root_ds == NULL) {
643 be_print_err(gettext("be_get_grub_vers: Invalid BE\n"));
644 return (BE_ERR_INVAL);
647 if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
648 NULL) {
649 be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"),
650 libzfs_error_description(g_zfs));
651 return (zfs_err_to_be_err(g_zfs));
655 * Check to see if the pool's dataset is mounted. If it isn't we'll
656 * attempt to mount it.
658 if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt,
659 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
660 be_print_err(gettext("be_get_grub_vers: pool dataset "
661 "(%s) could not be mounted\n"), bt->obe_zpool);
662 ZFS_CLOSE(pool_zhp);
663 return (ret);
667 * Get the mountpoint for the root pool dataset.
669 if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) {
670 be_print_err(gettext("be_get_grub_vers: pool "
671 "dataset (%s) is not mounted. Can't read the "
672 "grub capability file.\n"), bt->obe_zpool);
673 ret = BE_ERR_NO_MENU;
674 goto cleanup;
678 * get the version of the most recent grub update.
680 (void) snprintf(cap_file, sizeof (cap_file), "%s%s",
681 zpool_mntpt, BE_CAP_FILE);
682 free(zpool_mntpt);
683 zpool_mntpt = NULL;
685 if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
686 goto cleanup;
688 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
689 NULL) {
690 be_print_err(gettext("be_get_grub_vers: failed to "
691 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
692 libzfs_error_description(g_zfs));
693 free(cur_vers);
694 ret = zfs_err_to_be_err(g_zfs);
695 goto cleanup;
697 if (!zfs_is_mounted(zhp, &temp_mntpnt)) {
698 if ((ret = _be_mount(bt->obe_name, &temp_mntpnt,
699 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
700 be_print_err(gettext("be_get_grub_vers: failed to "
701 "mount BE (%s)\n"), bt->obe_name);
702 free(*cur_vers);
703 *cur_vers = NULL;
704 ZFS_CLOSE(zhp);
705 goto cleanup;
707 be_mounted = B_TRUE;
709 ZFS_CLOSE(zhp);
712 * Now get the grub version for the BE being activated.
714 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt,
715 BE_CAP_FILE);
716 ret = get_ver_from_capfile(cap_file, new_vers);
717 if (ret != BE_SUCCESS) {
718 free(*cur_vers);
719 *cur_vers = NULL;
721 if (be_mounted)
722 (void) _be_unmount(bt->obe_name, 0);
724 cleanup:
725 if (pool_mounted) {
726 int iret = BE_SUCCESS;
727 iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt);
728 if (ret == BE_SUCCESS)
729 ret = iret;
730 free(orig_mntpnt);
731 free(ptmp_mntpnt);
733 ZFS_CLOSE(pool_zhp);
735 free(temp_mntpnt);
736 return (ret);
740 * Function: get_ver_from_capfile
741 * Description: Parses the capability file passed in looking for the VERSION
742 * line. If found the version is returned in vers, if not then
743 * NULL is returned in vers.
745 * Parameters:
746 * file - the path to the capability file we want to parse.
747 * vers - the version string that will be passed back.
748 * Return:
749 * BE_SUCCESS - Success
750 * be_errno_t - Failed to find version
751 * Scope:
752 * Private
754 static int
755 get_ver_from_capfile(char *file, char **vers)
757 FILE *fp = NULL;
758 char line[BUFSIZ];
759 char *last = NULL;
760 int err = BE_SUCCESS;
761 errno = 0;
763 if (!be_has_grub()) {
764 be_print_err(gettext("get_ver_from_capfile: Not supported "
765 "on this architecture\n"));
766 return (BE_ERR_NOTSUP);
770 * Set version string to NULL; the only case this shouldn't be set
771 * to be NULL is when we've actually found a version in the capability
772 * file, which is set below.
774 *vers = NULL;
777 * If the capability file doesn't exist, we're returning success
778 * because on older releases, the capability file did not exist
779 * so this is a valid scenario.
781 if (access(file, F_OK) == 0) {
782 if ((fp = fopen(file, "r")) == NULL) {
783 err = errno;
784 be_print_err(gettext("get_ver_from_capfile: failed to "
785 "open file %s with error %s\n"), file,
786 strerror(err));
787 err = errno_to_be_err(err);
788 return (err);
791 while (fgets(line, BUFSIZ, fp)) {
792 char *tok = strtok_r(line, "=", &last);
794 if (tok == NULL || tok[0] == '#') {
795 continue;
796 } else if (strcmp(tok, "VERSION") == 0) {
797 *vers = strdup(last);
798 break;
801 (void) fclose(fp);
804 return (BE_SUCCESS);
808 * To be able to boot EFI labeled disks, stage1 needs to be written
809 * into the MBR. We do not do this if we're on disks with a traditional
810 * fdisk partition table only, or if any foreign EFI partitions exist.
811 * In the trivial case of a whole-disk vdev we always write stage1 into
812 * the MBR.
814 static boolean_t
815 be_do_install_mbr(char *diskname, nvlist_t *child)
817 struct uuid allowed_uuids[] = {
818 EFI_UNUSED,
819 EFI_RESV1,
820 EFI_BOOT,
821 EFI_ROOT,
822 EFI_SWAP,
823 EFI_USR,
824 EFI_BACKUP,
825 EFI_RESV2,
826 EFI_VAR,
827 EFI_HOME,
828 EFI_ALTSCTR,
829 EFI_RESERVED,
830 EFI_SYSTEM,
831 EFI_BIOS_BOOT,
832 EFI_SYMC_PUB,
833 EFI_SYMC_CDS
836 uint64_t whole;
837 struct dk_gpt *gpt;
838 struct uuid *u;
839 int fd, npart, i, j;
841 (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK,
842 &whole);
844 if (whole)
845 return (B_TRUE);
847 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0)
848 return (B_FALSE);
850 if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0)
851 return (B_FALSE);
853 for (i = 0; i != npart; i++) {
854 int match = 0;
856 u = &gpt->efi_parts[i].p_guid;
858 for (j = 0;
859 j != sizeof (allowed_uuids) / sizeof (struct uuid);
860 j++)
861 if (bcmp(u, &allowed_uuids[j],
862 sizeof (struct uuid)) == 0)
863 match++;
865 if (match == 0)
866 return (B_FALSE);
869 return (B_TRUE);
872 static int
873 be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1,
874 char *stage2, uint16_t flags)
876 char install_cmd[MAXPATHLEN];
877 char be_run_cmd_errbuf[BUFSIZ];
878 char be_run_cmd_outbuf[BUFSIZ];
879 char diskname[MAXPATHLEN];
880 char *vname;
881 char *path, *dsk_ptr;
882 char *flag = "";
883 int ret;
884 vdev_stat_t *vs;
885 uint_t vsc;
887 if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) {
888 be_print_err(gettext("be_do_installboot: "
889 "failed to get device path\n"));
890 return (BE_ERR_NODEV);
893 if ((nvlist_lookup_uint64_array(child, ZPOOL_CONFIG_VDEV_STATS,
894 (uint64_t **)&vs, &vsc) != 0) ||
895 vs->vs_state < VDEV_STATE_DEGRADED) {
897 * Don't try to run installgrub on a vdev that is not ONLINE
898 * or DEGRADED. Try to print a warning for each such vdev.
900 be_print_err(gettext("be_do_installboot: "
901 "vdev %s is %s, can't install boot loader\n"),
902 path, zpool_state_to_name(vs->vs_state, vs->vs_aux));
903 free(path);
904 return (BE_SUCCESS);
908 * Modify the vdev path to point to the raw disk.
910 path = strdup(path);
911 if (path == NULL)
912 return (BE_ERR_NOMEM);
914 dsk_ptr = strstr(path, "/dsk/");
915 if (dsk_ptr != NULL) {
916 *dsk_ptr = '\0';
917 dsk_ptr++;
918 } else {
919 dsk_ptr = "";
922 (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
923 free(path);
925 vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE);
926 if (vname == NULL) {
927 be_print_err(gettext("be_do_installboot: "
928 "failed to get device name: %s\n"),
929 libzfs_error_description(g_zfs));
930 return (zfs_err_to_be_err(g_zfs));
933 if (be_is_isa("i386")) {
934 uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE;
935 uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR;
937 if (force == BE_INSTALLBOOT_FLAG_FORCE) {
938 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
939 be_do_install_mbr(diskname, child))
940 flag = "-F -m -f";
941 else
942 flag = "-F";
943 } else {
944 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
945 be_do_install_mbr(diskname, child))
946 flag = "-m -f";
949 (void) snprintf(install_cmd, sizeof (install_cmd),
950 "%s %s %s %s %s", BE_INSTALL_GRUB, flag,
951 stage1, stage2, diskname);
952 } else if (be_is_isa("sparc")) {
953 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) ==
954 BE_INSTALLBOOT_FLAG_FORCE)
955 flag = "-f -F zfs";
956 else
957 flag = "-F zfs";
959 (void) snprintf(install_cmd, sizeof (install_cmd),
960 "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname);
961 } else {
962 be_print_err(gettext("be_do_installboot: unsupported "
963 "architecture.\n"));
964 return (BE_ERR_BOOTFILE_INST);
967 *be_run_cmd_outbuf = '\0';
968 *be_run_cmd_errbuf = '\0';
970 ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ,
971 be_run_cmd_outbuf, BUFSIZ);
973 if (ret != BE_SUCCESS) {
974 be_print_err(gettext("be_do_installboot: install "
975 "failed for device %s.\n"), vname);
976 ret = BE_ERR_BOOTFILE_INST;
979 be_print_err(gettext(" Command: \"%s\"\n"), install_cmd);
980 if (be_run_cmd_outbuf[0] != 0) {
981 be_print_err(gettext(" Output:\n"));
982 be_print_err("%s", be_run_cmd_outbuf);
985 if (be_run_cmd_errbuf[0] != 0) {
986 be_print_err(gettext(" Errors:\n"));
987 be_print_err("%s", be_run_cmd_errbuf);
989 free(vname);
991 return (ret);
995 * Function: be_do_copy_grub_cap
996 * Description: This function will copy grub capability file to BE.
998 * Parameters:
999 * bt - The transaction data for the BE we're activating.
1000 * Return:
1001 * BE_SUCCESS - Success
1002 * be_errno_t - Failure
1004 * Scope:
1005 * Private
1007 static int
1008 be_do_copy_grub_cap(be_transaction_data_t *bt)
1010 zfs_handle_t *zhp = NULL;
1011 char cap_file[MAXPATHLEN];
1012 char zpool_cap_file[MAXPATHLEN];
1013 char line[BUFSIZ];
1014 char *tmp_mntpnt = NULL;
1015 char *orig_mntpnt = NULL;
1016 char *pool_mntpnt = NULL;
1017 FILE *cap_fp = NULL;
1018 FILE *zpool_cap_fp = NULL;
1019 int err = 0;
1020 int ret = BE_SUCCESS;
1021 boolean_t pool_mounted = B_FALSE;
1022 boolean_t be_mounted = B_FALSE;
1025 * first get BE dataset mountpoint, we can free all the resources
1026 * once cap_file is built, leaving only be unmount to be done.
1028 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1029 NULL) {
1030 be_print_err(gettext("be_do_copy_grub_cap: failed to "
1031 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1032 libzfs_error_description(g_zfs));
1033 return (zfs_err_to_be_err(g_zfs));
1036 if (!zfs_is_mounted(zhp, &tmp_mntpnt)) {
1037 if ((ret = _be_mount(bt->obe_name, &tmp_mntpnt,
1038 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1039 be_print_err(gettext("be_do_copy_grub_cap: failed to "
1040 "mount BE (%s)\n"), bt->obe_name);
1041 ZFS_CLOSE(zhp);
1042 goto done;
1044 be_mounted = B_TRUE;
1046 ZFS_CLOSE(zhp); /* BE dataset handle is not needed any more */
1048 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpnt,
1049 BE_CAP_FILE);
1050 free(tmp_mntpnt);
1052 /* get pool root dataset mountpoint */
1053 zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM);
1054 if (zhp == NULL) {
1055 be_print_err(gettext("be_do_copy_grub_cap: zfs_open "
1056 "failed: %s\n"), libzfs_error_description(g_zfs));
1057 ret = zfs_err_to_be_err(g_zfs);
1058 goto done;
1062 * Check to see if the pool's dataset is mounted. If it isn't we'll
1063 * attempt to mount it.
1065 if ((ret = be_mount_pool(zhp, &tmp_mntpnt,
1066 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
1067 be_print_err(gettext("be_do_copy_grub_cap: pool dataset "
1068 "(%s) could not be mounted\n"), bt->obe_zpool);
1069 ZFS_CLOSE(zhp);
1070 goto done;
1074 * Get the mountpoint for the root pool dataset.
1075 * NOTE: zhp must be kept for _be_unmount_pool()
1077 if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1078 be_print_err(gettext("be_do_copy_grub_cap: pool "
1079 "dataset (%s) is not mounted. Can't check the grub "
1080 "version from the grub capability file.\n"), bt->obe_zpool);
1081 ret = BE_ERR_NO_MENU;
1082 goto done;
1085 (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
1086 pool_mntpnt, BE_CAP_FILE);
1087 free(pool_mntpnt);
1089 if ((cap_fp = fopen(cap_file, "r")) == NULL) {
1090 err = errno;
1091 be_print_err(gettext("be_do_copy_grub_cap: failed to open grub "
1092 "capability file\n"));
1093 ret = errno_to_be_err(err);
1094 goto done;
1096 if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
1097 err = errno;
1098 be_print_err(gettext("be_do_copy_grub_cap: failed to open new "
1099 "grub capability file\n"));
1100 ret = errno_to_be_err(err);
1101 (void) fclose(cap_fp);
1102 goto done;
1105 while (fgets(line, BUFSIZ, cap_fp)) {
1106 (void) fputs(line, zpool_cap_fp);
1109 (void) fclose(zpool_cap_fp);
1110 (void) fclose(cap_fp);
1112 done:
1113 if (be_mounted)
1114 (void) _be_unmount(bt->obe_name, 0);
1116 if (pool_mounted) {
1117 err = be_unmount_pool(zhp, tmp_mntpnt, orig_mntpnt);
1118 if (ret == BE_SUCCESS)
1119 ret = err;
1120 free(orig_mntpnt);
1121 free(tmp_mntpnt);
1122 zfs_close(zhp);
1124 return (ret);
1128 * Function: be_is_install_needed
1129 * Description: Check detached version files to detect if bootloader
1130 * install/update is needed.
1132 * Parameters:
1133 * bt - The transaction data for the BE we're activating.
1134 * update - set B_TRUE is update is needed.
1135 * Return:
1136 * BE_SUCCESS - Success
1137 * be_errno_t - Failure
1139 * Scope:
1140 * Private
1142 static int
1143 be_is_install_needed(be_transaction_data_t *bt, boolean_t *update)
1145 int ret = BE_SUCCESS;
1146 char *cur_vers = NULL, *new_vers = NULL;
1148 assert(bt != NULL);
1149 assert(update != NULL);
1151 if (!be_has_grub()) {
1153 * no detached versioning, let installboot to manage
1154 * versioning.
1156 *update = B_TRUE;
1157 return (ret);
1160 *update = B_FALSE; /* set default */
1163 * We need to check to see if the version number from
1164 * the BE being activated is greater than the current
1165 * one.
1167 ret = be_get_grub_vers(bt, &cur_vers, &new_vers);
1168 if (ret != BE_SUCCESS) {
1169 be_print_err(gettext("be_activate: failed to get grub "
1170 "versions from capability files.\n"));
1171 return (ret);
1173 /* update if we have both versions and can compare */
1174 if (cur_vers != NULL) {
1175 if (new_vers != NULL) {
1176 if (atof(cur_vers) < atof(new_vers))
1177 *update = B_TRUE;
1178 free(new_vers);
1180 free(cur_vers);
1181 } else if (new_vers != NULL) {
1182 /* we only got new version - update */
1183 *update = B_TRUE;
1184 free(new_vers);
1186 return (ret);
1190 * Function: be_do_installboot
1191 * Description: This function runs installgrub/installboot using the boot
1192 * loader files from the BE we're activating and installing
1193 * them on the pool the BE lives in.
1195 * Parameters:
1196 * bt - The transaction data for the BE we're activating.
1197 * flags - flags for bootloader install
1198 * Return:
1199 * BE_SUCCESS - Success
1200 * be_errno_t - Failure
1202 * Scope:
1203 * Private
1205 static int
1206 be_do_installboot(be_transaction_data_t *bt, uint16_t flags)
1208 zpool_handle_t *zphp = NULL;
1209 zfs_handle_t *zhp = NULL;
1210 nvlist_t **child, *nv, *config;
1211 uint_t c, children = 0;
1212 char *tmp_mntpt = NULL;
1213 char stage1[MAXPATHLEN];
1214 char stage2[MAXPATHLEN];
1215 char *vname;
1216 int ret = BE_SUCCESS;
1217 boolean_t be_mounted = B_FALSE;
1218 boolean_t update = B_FALSE;
1221 * check versions. This call is to support detached
1222 * version implementation like grub. Embedded versioning is
1223 * checked by actual installer.
1225 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) != BE_INSTALLBOOT_FLAG_FORCE) {
1226 ret = be_is_install_needed(bt, &update);
1227 if (ret != BE_SUCCESS || update == B_FALSE)
1228 return (ret);
1231 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1232 NULL) {
1233 be_print_err(gettext("be_do_installboot: failed to "
1234 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1235 libzfs_error_description(g_zfs));
1236 ret = zfs_err_to_be_err(g_zfs);
1237 return (ret);
1239 if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
1240 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
1241 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1242 be_print_err(gettext("be_do_installboot: failed to "
1243 "mount BE (%s)\n"), bt->obe_name);
1244 ZFS_CLOSE(zhp);
1245 return (ret);
1247 be_mounted = B_TRUE;
1249 ZFS_CLOSE(zhp);
1251 if (be_has_grub()) {
1252 (void) snprintf(stage1, sizeof (stage1), "%s%s",
1253 tmp_mntpt, BE_GRUB_STAGE_1);
1254 (void) snprintf(stage2, sizeof (stage2), "%s%s",
1255 tmp_mntpt, BE_GRUB_STAGE_2);
1256 } else {
1257 char *platform = be_get_platform();
1259 if (platform == NULL) {
1260 be_print_err(gettext("be_do_installboot: failed to "
1261 "detect system platform name\n"));
1262 if (be_mounted)
1263 (void) _be_unmount(bt->obe_name, 0);
1264 free(tmp_mntpt);
1265 return (BE_ERR_BOOTFILE_INST);
1268 stage1[0] = '\0'; /* sparc has no stage1 */
1269 (void) snprintf(stage2, sizeof (stage2),
1270 "%s/usr/platform/%s%s", tmp_mntpt,
1271 platform, BE_SPARC_BOOTBLK);
1274 if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
1275 be_print_err(gettext("be_do_installboot: failed to open "
1276 "pool (%s): %s\n"), bt->obe_zpool,
1277 libzfs_error_description(g_zfs));
1278 ret = zfs_err_to_be_err(g_zfs);
1279 if (be_mounted)
1280 (void) _be_unmount(bt->obe_name, 0);
1281 free(tmp_mntpt);
1282 return (ret);
1285 if ((config = zpool_get_config(zphp, NULL)) == NULL) {
1286 be_print_err(gettext("be_do_installboot: failed to get zpool "
1287 "configuration information. %s\n"),
1288 libzfs_error_description(g_zfs));
1289 ret = zfs_err_to_be_err(g_zfs);
1290 goto done;
1294 * Get the vdev tree
1296 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
1297 be_print_err(gettext("be_do_installboot: failed to get vdev "
1298 "tree: %s\n"), libzfs_error_description(g_zfs));
1299 ret = zfs_err_to_be_err(g_zfs);
1300 goto done;
1303 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1304 &children) != 0) {
1305 be_print_err(gettext("be_do_installboot: failed to traverse "
1306 "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
1307 ret = zfs_err_to_be_err(g_zfs);
1308 goto done;
1310 for (c = 0; c < children; c++) {
1311 uint_t i, nchildren = 0;
1312 nvlist_t **nvchild;
1313 vname = zpool_vdev_name(g_zfs, zphp, child[c], B_FALSE);
1314 if (vname == NULL) {
1315 be_print_err(gettext(
1316 "be_do_installboot: "
1317 "failed to get device name: %s\n"),
1318 libzfs_error_description(g_zfs));
1319 ret = zfs_err_to_be_err(g_zfs);
1320 goto done;
1322 if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') {
1323 free(vname);
1325 if (nvlist_lookup_nvlist_array(child[c],
1326 ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) {
1327 be_print_err(gettext("be_do_installboot: "
1328 "failed to traverse the vdev tree: %s\n"),
1329 libzfs_error_description(g_zfs));
1330 ret = zfs_err_to_be_err(g_zfs);
1331 goto done;
1334 for (i = 0; i < nchildren; i++) {
1335 ret = be_do_installboot_helper(zphp, nvchild[i],
1336 stage1, stage2, flags);
1337 if (ret != BE_SUCCESS)
1338 goto done;
1340 } else {
1341 free(vname);
1343 ret = be_do_installboot_helper(zphp, child[c], stage1,
1344 stage2, flags);
1345 if (ret != BE_SUCCESS)
1346 goto done;
1350 if (be_has_grub()) {
1351 ret = be_do_copy_grub_cap(bt);
1354 done:
1355 ZFS_CLOSE(zhp);
1356 if (be_mounted)
1357 (void) _be_unmount(bt->obe_name, 0);
1358 zpool_close(zphp);
1359 free(tmp_mntpt);
1360 return (ret);
1364 * Function: be_promote_zone_ds
1365 * Description: This function finds the zones for the BE being activated
1366 * and the active zonepath dataset for each zone. Then each
1367 * active zonepath dataset is promoted.
1369 * Parameters:
1370 * be_name - the name of the global zone BE that we need to
1371 * find the zones for.
1372 * be_root_ds - the root dataset for be_name.
1373 * Return:
1374 * BE_SUCCESS - Success
1375 * be_errno_t - Failure
1377 * Scope:
1378 * Private
1380 static int
1381 be_promote_zone_ds(char *be_name, char *be_root_ds)
1383 char *zone_ds = NULL;
1384 char *temp_mntpt = NULL;
1385 char origin[MAXPATHLEN];
1386 char zoneroot_ds[MAXPATHLEN];
1387 zfs_handle_t *zhp = NULL;
1388 zfs_handle_t *z_zhp = NULL;
1389 zoneList_t zone_list = NULL;
1390 zoneBrandList_t *brands = NULL;
1391 boolean_t be_mounted = B_FALSE;
1392 int zone_index = 0;
1393 int err = BE_SUCCESS;
1396 * Get the supported zone brands so we can pass that
1397 * to z_get_nonglobal_zone_list_by_brand. Currently
1398 * only the ipkg and labeled brand zones are supported
1401 if ((brands = be_get_supported_brandlist()) == NULL) {
1402 be_print_err(gettext("be_promote_zone_ds: no supported "
1403 "brands\n"));
1404 return (BE_SUCCESS);
1407 if ((zhp = zfs_open(g_zfs, be_root_ds,
1408 ZFS_TYPE_FILESYSTEM)) == NULL) {
1409 be_print_err(gettext("be_promote_zone_ds: Failed to open "
1410 "dataset (%s): %s\n"), be_root_ds,
1411 libzfs_error_description(g_zfs));
1412 err = zfs_err_to_be_err(g_zfs);
1413 z_free_brand_list(brands);
1414 return (err);
1417 if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1418 if ((err = _be_mount(be_name, &temp_mntpt,
1419 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1420 be_print_err(gettext("be_promote_zone_ds: failed to "
1421 "mount the BE for zones procesing.\n"));
1422 ZFS_CLOSE(zhp);
1423 z_free_brand_list(brands);
1424 return (err);
1426 be_mounted = B_TRUE;
1430 * Set the zone root to the temp mount point for the BE we just mounted.
1432 z_set_zone_root(temp_mntpt);
1435 * Get all the zones based on the brands we're looking for. If no zones
1436 * are found that we're interested in unmount the BE and move on.
1438 if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1439 if (be_mounted)
1440 (void) _be_unmount(be_name, 0);
1441 ZFS_CLOSE(zhp);
1442 z_free_brand_list(brands);
1443 free(temp_mntpt);
1444 return (BE_SUCCESS);
1446 for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1447 != NULL; zone_index++) {
1448 char *zone_path = NULL;
1450 /* Skip zones that aren't at least installed */
1451 if (z_zlist_get_current_state(zone_list, zone_index) <
1452 ZONE_STATE_INSTALLED)
1453 continue;
1455 if (((zone_path =
1456 z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1457 ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1458 !be_zone_supported(zone_ds))
1459 continue;
1461 if (be_find_active_zone_root(zhp, zone_ds,
1462 zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1463 be_print_err(gettext("be_promote_zone_ds: "
1464 "Zone does not have an active root "
1465 "dataset, skipping this zone.\n"));
1466 continue;
1469 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1470 ZFS_TYPE_FILESYSTEM)) == NULL) {
1471 be_print_err(gettext("be_promote_zone_ds: "
1472 "Failed to open dataset "
1473 "(%s): %s\n"), zoneroot_ds,
1474 libzfs_error_description(g_zfs));
1475 err = zfs_err_to_be_err(g_zfs);
1476 goto done;
1479 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1480 sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1481 ZFS_CLOSE(z_zhp);
1482 continue;
1486 * We don't need to close the zfs handle at this
1487 * point because the callback funtion
1488 * be_promote_ds_callback() will close it for us.
1490 if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1491 be_print_err(gettext("be_promote_zone_ds: "
1492 "failed to activate the "
1493 "datasets for %s: %s\n"),
1494 zoneroot_ds,
1495 libzfs_error_description(g_zfs));
1496 err = BE_ERR_PROMOTE;
1497 goto done;
1500 done:
1501 if (be_mounted)
1502 (void) _be_unmount(be_name, 0);
1503 ZFS_CLOSE(zhp);
1504 free(temp_mntpt);
1505 z_free_brand_list(brands);
1506 z_free_zone_list(zone_list);
1507 return (err);
1511 * Function: be_promote_ds_callback
1512 * Description: This function is used to promote the datasets for the BE
1513 * being activated as well as the datasets for the zones BE
1514 * being activated.
1516 * Parameters:
1517 * zhp - the zfs handle for zone BE being activated.
1518 * data - not used.
1519 * Return:
1520 * 0 - Success
1521 * be_errno_t - Failure
1523 * Scope:
1524 * Private
1526 static int
1527 /* LINTED */
1528 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1530 char origin[MAXPATHLEN];
1531 char *sub_dataset = NULL;
1532 int ret = 0;
1534 if (zhp != NULL) {
1535 sub_dataset = strdup(zfs_get_name(zhp));
1536 if (sub_dataset == NULL) {
1537 ret = BE_ERR_NOMEM;
1538 goto done;
1540 } else {
1541 be_print_err(gettext("be_promote_ds_callback: "
1542 "Invalid zfs handle passed into function\n"));
1543 ret = BE_ERR_INVAL;
1544 goto done;
1548 * This loop makes sure that we promote the dataset to the
1549 * top of the tree so that it is no longer a decendent of any
1550 * dataset. The ZFS close and then open is used to make sure that
1551 * the promotion is updated before we move on.
1553 while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1554 sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1555 if (zfs_promote(zhp) != 0) {
1556 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1557 be_print_err(gettext("be_promote_ds_callback: "
1558 "promote of %s failed: %s\n"),
1559 zfs_get_name(zhp),
1560 libzfs_error_description(g_zfs));
1561 ret = zfs_err_to_be_err(g_zfs);
1562 goto done;
1563 } else {
1565 * If the call to zfs_promote returns the
1566 * error EZFS_EXISTS we've hit a snapshot name
1567 * collision. This means we're probably
1568 * attemping to promote a zone dataset above a
1569 * parent dataset that belongs to another zone
1570 * which this zone was cloned from.
1572 * TODO: If this is a zone dataset at some
1573 * point we should skip this if the zone
1574 * paths for the dataset and the snapshot
1575 * don't match.
1577 be_print_err(gettext("be_promote_ds_callback: "
1578 "promote of %s failed due to snapshot "
1579 "name collision: %s\n"), zfs_get_name(zhp),
1580 libzfs_error_description(g_zfs));
1581 ret = zfs_err_to_be_err(g_zfs);
1582 goto done;
1585 ZFS_CLOSE(zhp);
1586 if ((zhp = zfs_open(g_zfs, sub_dataset,
1587 ZFS_TYPE_FILESYSTEM)) == NULL) {
1588 be_print_err(gettext("be_promote_ds_callback: "
1589 "Failed to open dataset (%s): %s\n"), sub_dataset,
1590 libzfs_error_description(g_zfs));
1591 ret = zfs_err_to_be_err(g_zfs);
1592 goto done;
1596 /* Iterate down this dataset's children and promote them */
1597 ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1599 done:
1600 free(sub_dataset);
1601 ZFS_CLOSE(zhp);
1602 return (ret);