6159 libbe should proactively handle future architectures
[unleashed.git] / usr / src / lib / libbe / common / be_activate.c
blobfeb6fc46b592ab27740285ad72a35bdfa7c883b6
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;
885 if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) {
886 be_print_err(gettext("be_do_installboot: "
887 "failed to get device path\n"));
888 return (BE_ERR_NODEV);
892 * Modify the vdev path to point to the raw disk.
894 path = strdup(path);
895 if (path == NULL)
896 return (BE_ERR_NOMEM);
898 dsk_ptr = strstr(path, "/dsk/");
899 if (dsk_ptr != NULL) {
900 *dsk_ptr = '\0';
901 dsk_ptr++;
902 } else {
903 dsk_ptr = "";
906 (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
907 free(path);
909 vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE);
910 if (vname == NULL) {
911 be_print_err(gettext("be_do_installboot: "
912 "failed to get device name: %s\n"),
913 libzfs_error_description(g_zfs));
914 return (zfs_err_to_be_err(g_zfs));
917 if (be_is_isa("i386")) {
918 uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE;
919 uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR;
921 if (force == BE_INSTALLBOOT_FLAG_FORCE) {
922 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
923 be_do_install_mbr(diskname, child))
924 flag = "-F -m -f";
925 else
926 flag = "-F";
927 } else {
928 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
929 be_do_install_mbr(diskname, child))
930 flag = "-m -f";
933 (void) snprintf(install_cmd, sizeof (install_cmd),
934 "%s %s %s %s %s", BE_INSTALL_GRUB, flag,
935 stage1, stage2, diskname);
936 } else if (be_is_isa("sparc")) {
937 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) ==
938 BE_INSTALLBOOT_FLAG_FORCE)
939 flag = "-f -F zfs";
940 else
941 flag = "-F zfs";
943 (void) snprintf(install_cmd, sizeof (install_cmd),
944 "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname);
945 } else {
946 be_print_err(gettext("be_do_installboot: unsupported "
947 "architecture.\n"));
948 return (BE_ERR_BOOTFILE_INST);
951 *be_run_cmd_outbuf = '\0';
952 *be_run_cmd_errbuf = '\0';
954 ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ,
955 be_run_cmd_outbuf, BUFSIZ);
957 if (ret != BE_SUCCESS) {
958 be_print_err(gettext("be_do_installboot: install "
959 "failed for device %s.\n"), vname);
960 ret = BE_ERR_BOOTFILE_INST;
963 be_print_err(gettext(" Command: \"%s\"\n"), install_cmd);
964 if (be_run_cmd_outbuf[0] != 0) {
965 be_print_err(gettext(" Output:\n"));
966 be_print_err("%s", be_run_cmd_outbuf);
969 if (be_run_cmd_errbuf[0] != 0) {
970 be_print_err(gettext(" Errors:\n"));
971 be_print_err("%s", be_run_cmd_errbuf);
973 free(vname);
975 return (ret);
979 * Function: be_do_copy_grub_cap
980 * Description: This function will copy grub capability file to BE.
982 * Parameters:
983 * bt - The transaction data for the BE we're activating.
984 * Return:
985 * BE_SUCCESS - Success
986 * be_errno_t - Failure
988 * Scope:
989 * Private
991 static int
992 be_do_copy_grub_cap(be_transaction_data_t *bt)
994 zpool_handle_t *zphp = NULL;
995 zfs_handle_t *zhp = NULL;
996 char cap_file[MAXPATHLEN];
997 char zpool_cap_file[MAXPATHLEN];
998 char line[BUFSIZ];
999 char *tmp_mntpnt = NULL;
1000 char *orig_mntpnt = NULL;
1001 char *pool_mntpnt = NULL;
1002 char *ptmp_mntpnt = NULL;
1003 FILE *cap_fp = NULL;
1004 FILE *zpool_cap_fp = NULL;
1005 int err = 0;
1006 int ret = BE_SUCCESS;
1007 boolean_t pool_mounted = B_FALSE;
1008 boolean_t be_mounted = B_FALSE;
1011 * Copy the grub capability file from the BE we're activating
1012 * into the root pool.
1014 zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM);
1015 if (zhp == NULL) {
1016 be_print_err(gettext("be_do_installboot: zfs_open "
1017 "failed: %s\n"), libzfs_error_description(g_zfs));
1018 zpool_close(zphp);
1019 return (zfs_err_to_be_err(g_zfs));
1023 * Check to see if the pool's dataset is mounted. If it isn't we'll
1024 * attempt to mount it.
1026 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt,
1027 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
1028 be_print_err(gettext("be_do_installboot: pool dataset "
1029 "(%s) could not be mounted\n"), bt->obe_zpool);
1030 ZFS_CLOSE(zhp);
1031 zpool_close(zphp);
1032 return (ret);
1036 * Get the mountpoint for the root pool dataset.
1038 if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1039 be_print_err(gettext("be_do_installboot: pool "
1040 "dataset (%s) is not mounted. Can't check the grub "
1041 "version from the grub capability file.\n"), bt->obe_zpool);
1042 ret = BE_ERR_NO_MENU;
1043 goto done;
1046 (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
1047 pool_mntpnt, BE_CAP_FILE);
1049 free(pool_mntpnt);
1051 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1052 NULL) {
1053 be_print_err(gettext("be_do_installboot: failed to "
1054 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1055 libzfs_error_description(g_zfs));
1056 ret = zfs_err_to_be_err(g_zfs);
1057 goto done;
1060 if (!zfs_is_mounted(zhp, &tmp_mntpnt)) {
1061 if ((ret = _be_mount(bt->obe_name, &tmp_mntpnt,
1062 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1063 be_print_err(gettext("be_do_installboot: failed to "
1064 "mount BE (%s)\n"), bt->obe_name);
1065 ZFS_CLOSE(zhp);
1066 goto done;
1068 be_mounted = B_TRUE;
1070 ZFS_CLOSE(zhp);
1072 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpnt,
1073 BE_CAP_FILE);
1074 free(tmp_mntpnt);
1076 if ((cap_fp = fopen(cap_file, "r")) == NULL) {
1077 err = errno;
1078 be_print_err(gettext("be_do_installboot: failed to open grub "
1079 "capability file\n"));
1080 ret = errno_to_be_err(err);
1081 goto done;
1083 if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
1084 err = errno;
1085 be_print_err(gettext("be_do_installboot: failed to open new "
1086 "grub capability file\n"));
1087 ret = errno_to_be_err(err);
1088 (void) fclose(cap_fp);
1089 goto done;
1092 while (fgets(line, BUFSIZ, cap_fp)) {
1093 (void) fputs(line, zpool_cap_fp);
1096 (void) fclose(zpool_cap_fp);
1097 (void) fclose(cap_fp);
1099 done:
1100 if (be_mounted)
1101 (void) _be_unmount(bt->obe_name, 0);
1103 if (pool_mounted) {
1104 int iret = 0;
1105 iret = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
1106 if (ret == BE_SUCCESS)
1107 ret = iret;
1108 free(orig_mntpnt);
1109 free(ptmp_mntpnt);
1111 return (ret);
1115 * Function: be_is_install_needed
1116 * Description: Check detached version files to detect if bootloader
1117 * install/update is needed.
1119 * Parameters:
1120 * bt - The transaction data for the BE we're activating.
1121 * update - set B_TRUE is update is needed.
1122 * Return:
1123 * BE_SUCCESS - Success
1124 * be_errno_t - Failure
1126 * Scope:
1127 * Private
1129 static int
1130 be_is_install_needed(be_transaction_data_t *bt, boolean_t *update)
1132 int ret = BE_SUCCESS;
1133 char *cur_vers = NULL, *new_vers = NULL;
1135 assert(bt != NULL);
1136 assert(update != NULL);
1138 if (!be_has_grub()) {
1140 * no detached versioning, let installboot to manage
1141 * versioning.
1143 *update = B_TRUE;
1144 return (ret);
1147 *update = B_FALSE; /* set default */
1150 * We need to check to see if the version number from
1151 * the BE being activated is greater than the current
1152 * one.
1154 ret = be_get_grub_vers(bt, &cur_vers, &new_vers);
1155 if (ret != BE_SUCCESS) {
1156 be_print_err(gettext("be_activate: failed to get grub "
1157 "versions from capability files.\n"));
1158 return (ret);
1160 /* update if we have both versions and can compare */
1161 if (cur_vers != NULL) {
1162 if (new_vers != NULL) {
1163 if (atof(cur_vers) < atof(new_vers))
1164 *update = B_TRUE;
1165 free(new_vers);
1167 free(cur_vers);
1168 } else if (new_vers != NULL) {
1169 /* we only got new version - update */
1170 *update = B_TRUE;
1171 free(new_vers);
1173 return (ret);
1177 * Function: be_do_installboot
1178 * Description: This function runs installgrub/installboot using the boot
1179 * loader files from the BE we're activating and installing
1180 * them on the pool the BE lives in.
1182 * Parameters:
1183 * bt - The transaction data for the BE we're activating.
1184 * flags - flags for bootloader install
1185 * Return:
1186 * BE_SUCCESS - Success
1187 * be_errno_t - Failure
1189 * Scope:
1190 * Private
1192 static int
1193 be_do_installboot(be_transaction_data_t *bt, uint16_t flags)
1195 zpool_handle_t *zphp = NULL;
1196 zfs_handle_t *zhp = NULL;
1197 nvlist_t **child, *nv, *config;
1198 uint_t c, children = 0;
1199 char *tmp_mntpt = NULL;
1200 char stage1[MAXPATHLEN];
1201 char stage2[MAXPATHLEN];
1202 char *vname;
1203 int ret = BE_SUCCESS;
1204 boolean_t be_mounted = B_FALSE;
1205 boolean_t update = B_FALSE;
1208 * check versions. This call is to support detached
1209 * version implementation like grub. Embedded versioning is
1210 * checked by actual installer.
1212 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) != BE_INSTALLBOOT_FLAG_FORCE) {
1213 ret = be_is_install_needed(bt, &update);
1214 if (ret != BE_SUCCESS || update == B_FALSE)
1215 return (ret);
1218 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1219 NULL) {
1220 be_print_err(gettext("be_do_installboot: failed to "
1221 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1222 libzfs_error_description(g_zfs));
1223 ret = zfs_err_to_be_err(g_zfs);
1224 return (ret);
1226 if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
1227 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
1228 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1229 be_print_err(gettext("be_do_installboot: failed to "
1230 "mount BE (%s)\n"), bt->obe_name);
1231 ZFS_CLOSE(zhp);
1232 return (ret);
1234 be_mounted = B_TRUE;
1236 ZFS_CLOSE(zhp);
1238 if (be_has_grub()) {
1239 (void) snprintf(stage1, sizeof (stage1), "%s%s",
1240 tmp_mntpt, BE_GRUB_STAGE_1);
1241 (void) snprintf(stage2, sizeof (stage2), "%s%s",
1242 tmp_mntpt, BE_GRUB_STAGE_2);
1243 } else {
1244 char *platform = be_get_platform();
1246 if (platform == NULL) {
1247 be_print_err(gettext("be_do_installboot: failed to "
1248 "detect system platform name\n"));
1249 if (be_mounted)
1250 (void) _be_unmount(bt->obe_name, 0);
1251 free(tmp_mntpt);
1252 return (BE_ERR_BOOTFILE_INST);
1255 stage1[0] = '\0'; /* sparc has no stage1 */
1256 (void) snprintf(stage2, sizeof (stage2),
1257 "%s/usr/platform/%s%s", tmp_mntpt,
1258 platform, BE_SPARC_BOOTBLK);
1261 if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
1262 be_print_err(gettext("be_do_installboot: failed to open "
1263 "pool (%s): %s\n"), bt->obe_zpool,
1264 libzfs_error_description(g_zfs));
1265 ret = zfs_err_to_be_err(g_zfs);
1266 if (be_mounted)
1267 (void) _be_unmount(bt->obe_name, 0);
1268 free(tmp_mntpt);
1269 return (ret);
1272 if ((config = zpool_get_config(zphp, NULL)) == NULL) {
1273 be_print_err(gettext("be_do_installboot: failed to get zpool "
1274 "configuration information. %s\n"),
1275 libzfs_error_description(g_zfs));
1276 ret = zfs_err_to_be_err(g_zfs);
1277 goto done;
1281 * Get the vdev tree
1283 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
1284 be_print_err(gettext("be_do_installboot: failed to get vdev "
1285 "tree: %s\n"), libzfs_error_description(g_zfs));
1286 ret = zfs_err_to_be_err(g_zfs);
1287 goto done;
1290 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1291 &children) != 0) {
1292 be_print_err(gettext("be_do_installboot: failed to traverse "
1293 "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
1294 ret = zfs_err_to_be_err(g_zfs);
1295 goto done;
1297 for (c = 0; c < children; c++) {
1298 uint_t i, nchildren = 0;
1299 nvlist_t **nvchild;
1300 vname = zpool_vdev_name(g_zfs, zphp, child[c], B_FALSE);
1301 if (vname == NULL) {
1302 be_print_err(gettext(
1303 "be_do_installboot: "
1304 "failed to get device name: %s\n"),
1305 libzfs_error_description(g_zfs));
1306 ret = zfs_err_to_be_err(g_zfs);
1307 goto done;
1309 if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') {
1310 free(vname);
1312 if (nvlist_lookup_nvlist_array(child[c],
1313 ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) {
1314 be_print_err(gettext("be_do_installboot: "
1315 "failed to traverse the vdev tree: %s\n"),
1316 libzfs_error_description(g_zfs));
1317 ret = zfs_err_to_be_err(g_zfs);
1318 goto done;
1321 for (i = 0; i < nchildren; i++) {
1322 ret = be_do_installboot_helper(zphp, nvchild[i],
1323 stage1, stage2, flags);
1324 if (ret != BE_SUCCESS)
1325 goto done;
1327 } else {
1328 free(vname);
1330 ret = be_do_installboot_helper(zphp, child[c], stage1,
1331 stage2, flags);
1332 if (ret != BE_SUCCESS)
1333 goto done;
1337 if (be_has_grub()) {
1338 ret = be_do_copy_grub_cap(bt);
1341 done:
1342 ZFS_CLOSE(zhp);
1343 if (be_mounted)
1344 (void) _be_unmount(bt->obe_name, 0);
1345 zpool_close(zphp);
1346 free(tmp_mntpt);
1347 return (ret);
1351 * Function: be_promote_zone_ds
1352 * Description: This function finds the zones for the BE being activated
1353 * and the active zonepath dataset for each zone. Then each
1354 * active zonepath dataset is promoted.
1356 * Parameters:
1357 * be_name - the name of the global zone BE that we need to
1358 * find the zones for.
1359 * be_root_ds - the root dataset for be_name.
1360 * Return:
1361 * BE_SUCCESS - Success
1362 * be_errno_t - Failure
1364 * Scope:
1365 * Private
1367 static int
1368 be_promote_zone_ds(char *be_name, char *be_root_ds)
1370 char *zone_ds = NULL;
1371 char *temp_mntpt = NULL;
1372 char origin[MAXPATHLEN];
1373 char zoneroot_ds[MAXPATHLEN];
1374 zfs_handle_t *zhp = NULL;
1375 zfs_handle_t *z_zhp = NULL;
1376 zoneList_t zone_list = NULL;
1377 zoneBrandList_t *brands = NULL;
1378 boolean_t be_mounted = B_FALSE;
1379 int zone_index = 0;
1380 int err = BE_SUCCESS;
1383 * Get the supported zone brands so we can pass that
1384 * to z_get_nonglobal_zone_list_by_brand. Currently
1385 * only the ipkg and labeled brand zones are supported
1388 if ((brands = be_get_supported_brandlist()) == NULL) {
1389 be_print_err(gettext("be_promote_zone_ds: no supported "
1390 "brands\n"));
1391 return (BE_SUCCESS);
1394 if ((zhp = zfs_open(g_zfs, be_root_ds,
1395 ZFS_TYPE_FILESYSTEM)) == NULL) {
1396 be_print_err(gettext("be_promote_zone_ds: Failed to open "
1397 "dataset (%s): %s\n"), be_root_ds,
1398 libzfs_error_description(g_zfs));
1399 err = zfs_err_to_be_err(g_zfs);
1400 z_free_brand_list(brands);
1401 return (err);
1404 if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1405 if ((err = _be_mount(be_name, &temp_mntpt,
1406 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1407 be_print_err(gettext("be_promote_zone_ds: failed to "
1408 "mount the BE for zones procesing.\n"));
1409 ZFS_CLOSE(zhp);
1410 z_free_brand_list(brands);
1411 return (err);
1413 be_mounted = B_TRUE;
1417 * Set the zone root to the temp mount point for the BE we just mounted.
1419 z_set_zone_root(temp_mntpt);
1422 * Get all the zones based on the brands we're looking for. If no zones
1423 * are found that we're interested in unmount the BE and move on.
1425 if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1426 if (be_mounted)
1427 (void) _be_unmount(be_name, 0);
1428 ZFS_CLOSE(zhp);
1429 z_free_brand_list(brands);
1430 free(temp_mntpt);
1431 return (BE_SUCCESS);
1433 for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1434 != NULL; zone_index++) {
1435 char *zone_path = NULL;
1437 /* Skip zones that aren't at least installed */
1438 if (z_zlist_get_current_state(zone_list, zone_index) <
1439 ZONE_STATE_INSTALLED)
1440 continue;
1442 if (((zone_path =
1443 z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1444 ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1445 !be_zone_supported(zone_ds))
1446 continue;
1448 if (be_find_active_zone_root(zhp, zone_ds,
1449 zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1450 be_print_err(gettext("be_promote_zone_ds: "
1451 "Zone does not have an active root "
1452 "dataset, skipping this zone.\n"));
1453 continue;
1456 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1457 ZFS_TYPE_FILESYSTEM)) == NULL) {
1458 be_print_err(gettext("be_promote_zone_ds: "
1459 "Failed to open dataset "
1460 "(%s): %s\n"), zoneroot_ds,
1461 libzfs_error_description(g_zfs));
1462 err = zfs_err_to_be_err(g_zfs);
1463 goto done;
1466 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1467 sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1468 ZFS_CLOSE(z_zhp);
1469 continue;
1473 * We don't need to close the zfs handle at this
1474 * point because the callback funtion
1475 * be_promote_ds_callback() will close it for us.
1477 if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1478 be_print_err(gettext("be_promote_zone_ds: "
1479 "failed to activate the "
1480 "datasets for %s: %s\n"),
1481 zoneroot_ds,
1482 libzfs_error_description(g_zfs));
1483 err = BE_ERR_PROMOTE;
1484 goto done;
1487 done:
1488 if (be_mounted)
1489 (void) _be_unmount(be_name, 0);
1490 ZFS_CLOSE(zhp);
1491 free(temp_mntpt);
1492 z_free_brand_list(brands);
1493 z_free_zone_list(zone_list);
1494 return (err);
1498 * Function: be_promote_ds_callback
1499 * Description: This function is used to promote the datasets for the BE
1500 * being activated as well as the datasets for the zones BE
1501 * being activated.
1503 * Parameters:
1504 * zhp - the zfs handle for zone BE being activated.
1505 * data - not used.
1506 * Return:
1507 * 0 - Success
1508 * be_errno_t - Failure
1510 * Scope:
1511 * Private
1513 static int
1514 /* LINTED */
1515 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1517 char origin[MAXPATHLEN];
1518 char *sub_dataset = NULL;
1519 int ret = 0;
1521 if (zhp != NULL) {
1522 sub_dataset = strdup(zfs_get_name(zhp));
1523 if (sub_dataset == NULL) {
1524 ret = BE_ERR_NOMEM;
1525 goto done;
1527 } else {
1528 be_print_err(gettext("be_promote_ds_callback: "
1529 "Invalid zfs handle passed into function\n"));
1530 ret = BE_ERR_INVAL;
1531 goto done;
1535 * This loop makes sure that we promote the dataset to the
1536 * top of the tree so that it is no longer a decendent of any
1537 * dataset. The ZFS close and then open is used to make sure that
1538 * the promotion is updated before we move on.
1540 while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1541 sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1542 if (zfs_promote(zhp) != 0) {
1543 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1544 be_print_err(gettext("be_promote_ds_callback: "
1545 "promote of %s failed: %s\n"),
1546 zfs_get_name(zhp),
1547 libzfs_error_description(g_zfs));
1548 ret = zfs_err_to_be_err(g_zfs);
1549 goto done;
1550 } else {
1552 * If the call to zfs_promote returns the
1553 * error EZFS_EXISTS we've hit a snapshot name
1554 * collision. This means we're probably
1555 * attemping to promote a zone dataset above a
1556 * parent dataset that belongs to another zone
1557 * which this zone was cloned from.
1559 * TODO: If this is a zone dataset at some
1560 * point we should skip this if the zone
1561 * paths for the dataset and the snapshot
1562 * don't match.
1564 be_print_err(gettext("be_promote_ds_callback: "
1565 "promote of %s failed due to snapshot "
1566 "name collision: %s\n"), zfs_get_name(zhp),
1567 libzfs_error_description(g_zfs));
1568 ret = zfs_err_to_be_err(g_zfs);
1569 goto done;
1572 ZFS_CLOSE(zhp);
1573 if ((zhp = zfs_open(g_zfs, sub_dataset,
1574 ZFS_TYPE_FILESYSTEM)) == NULL) {
1575 be_print_err(gettext("be_promote_ds_callback: "
1576 "Failed to open dataset (%s): %s\n"), sub_dataset,
1577 libzfs_error_description(g_zfs));
1578 ret = zfs_err_to_be_err(g_zfs);
1579 goto done;
1583 /* Iterate down this dataset's children and promote them */
1584 ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1586 done:
1587 free(sub_dataset);
1588 ZFS_CLOSE(zhp);
1589 return (ret);