8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / lib / libbe / common / be_activate.c
blob9602333a56539c57f008333bef8caa2801983eca
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 * Copyright 2016 Toomas Soome <tsoome@me.com>
31 #include <assert.h>
32 #include <libintl.h>
33 #include <libnvpair.h>
34 #include <libzfs.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <errno.h>
40 #include <sys/mnttab.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <unistd.h>
45 #include <sys/efi_partition.h>
47 #include <libbe.h>
48 #include <libbe_priv.h>
50 char *mnttab = MNTTAB;
53 * Private function prototypes
55 static int set_bootfs(char *boot_rpool, char *be_root_ds);
56 static int set_canmount(be_node_list_t *, char *);
57 static boolean_t be_do_install_mbr(char *, nvlist_t *);
58 static int be_do_installboot_helper(zpool_handle_t *, nvlist_t *, char *,
59 char *, uint16_t);
60 static int be_do_installboot(be_transaction_data_t *, uint16_t);
61 static int be_get_grub_vers(be_transaction_data_t *, char **, char **);
62 static int get_ver_from_capfile(char *, char **);
63 static int be_promote_zone_ds(char *, char *);
64 static int be_promote_ds_callback(zfs_handle_t *, void *);
66 /* ******************************************************************** */
67 /* Public Functions */
68 /* ******************************************************************** */
71 * Function: be_activate
72 * Description: Calls _be_activate which activates the BE named in the
73 * attributes passed in through be_attrs. The process of
74 * activation sets the bootfs property of the root pool, resets
75 * the canmount property to noauto, and sets the default in the
76 * grub menu to the entry corresponding to the entry for the named
77 * BE.
78 * Parameters:
79 * be_attrs - pointer to nvlist_t of attributes being passed in.
80 * The follow attribute values are used by this function:
82 * BE_ATTR_ORIG_BE_NAME *required
83 * Return:
84 * BE_SUCCESS - Success
85 * be_errno_t - Failure
86 * Scope:
87 * Public
89 int
90 be_activate(nvlist_t *be_attrs)
92 int ret = BE_SUCCESS;
93 char *be_name = NULL;
95 /* Initialize libzfs handle */
96 if (!be_zfs_init())
97 return (BE_ERR_INIT);
99 /* Get the BE name to activate */
100 if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
101 != 0) {
102 be_print_err(gettext("be_activate: failed to "
103 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
104 be_zfs_fini();
105 return (BE_ERR_INVAL);
108 /* Validate BE name */
109 if (!be_valid_be_name(be_name)) {
110 be_print_err(gettext("be_activate: invalid BE name %s\n"),
111 be_name);
112 be_zfs_fini();
113 return (BE_ERR_INVAL);
116 ret = _be_activate(be_name);
118 be_zfs_fini();
120 return (ret);
124 * Function: be_installboot
125 * Description: Calls be_do_installboot to install/update bootloader on
126 * pool passed in through be_attrs. The primary consumer is
127 * bootadm command to avoid duplication of the code.
128 * Parameters:
129 * be_attrs - pointer to nvlist_t of attributes being passed in.
130 * The following attribute values are used:
132 * BE_ATTR_ORIG_BE_NAME *required
133 * BE_ATTR_ORIG_BE_POOL *required
134 * BE_ATTR_ORIG_BE_ROOT *required
135 * BE_ATTR_INSTALL_FLAGS optional
137 * Return:
138 * BE_SUCCESS - Success
139 * be_errno_t - Failure
140 * Scope:
141 * Public
144 be_installboot(nvlist_t *be_attrs)
146 int ret = BE_SUCCESS;
147 uint16_t flags = 0;
148 uint16_t verbose;
149 be_transaction_data_t bt = { 0 };
151 /* Get flags */
152 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
153 BE_ATTR_INSTALL_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
154 be_print_err(gettext("be_installboot: failed to lookup "
155 "BE_ATTR_INSTALL_FLAGS attribute\n"));
156 return (BE_ERR_INVAL);
159 /* Set verbose early, so we get all messages */
160 verbose = flags & BE_INSTALLBOOT_FLAG_VERBOSE;
161 if (verbose == BE_INSTALLBOOT_FLAG_VERBOSE)
162 libbe_print_errors(B_TRUE);
164 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
165 &bt.obe_name);
166 if (ret != 0) {
167 be_print_err(gettext("be_installboot: failed to "
168 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
169 return (BE_ERR_INVAL);
172 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_POOL,
173 &bt.obe_zpool);
174 if (ret != 0) {
175 be_print_err(gettext("be_installboot: failed to "
176 "lookup BE_ATTR_ORIG_BE_POOL attribute\n"));
177 return (BE_ERR_INVAL);
180 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_ROOT,
181 &bt.obe_root_ds);
182 if (ret != 0) {
183 be_print_err(gettext("be_installboot: failed to "
184 "lookup BE_ATTR_ORIG_BE_ROOT attribute\n"));
185 return (BE_ERR_INVAL);
188 /* Initialize libzfs handle */
189 if (!be_zfs_init())
190 return (BE_ERR_INIT);
192 ret = be_do_installboot(&bt, flags);
194 be_zfs_fini();
196 return (ret);
199 /* ******************************************************************** */
200 /* Semi Private Functions */
201 /* ******************************************************************** */
204 * Function: _be_activate
205 * Description: This does the actual work described in be_activate.
206 * Parameters:
207 * be_name - pointer to the name of BE to activate.
209 * Return:
210 * BE_SUCCESS - Success
211 * be_errnot_t - Failure
212 * Scope:
213 * Public
216 _be_activate(char *be_name)
218 be_transaction_data_t cb = { 0 };
219 zfs_handle_t *zhp = NULL;
220 char root_ds[MAXPATHLEN];
221 char active_ds[MAXPATHLEN];
222 be_node_list_t *be_nodes = NULL;
223 uuid_t uu = {0};
224 int entry, ret = BE_SUCCESS;
225 int zret = 0;
228 * TODO: The BE needs to be validated to make sure that it is actually
229 * a bootable BE.
232 if (be_name == NULL)
233 return (BE_ERR_INVAL);
235 /* Set obe_name to be_name in the cb structure */
236 cb.obe_name = be_name;
238 /* find which zpool the be is in */
239 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
240 be_print_err(gettext("be_activate: failed to "
241 "find zpool for BE (%s)\n"), cb.obe_name);
242 return (BE_ERR_BE_NOENT);
243 } else if (zret < 0) {
244 be_print_err(gettext("be_activate: "
245 "zpool_iter failed: %s\n"),
246 libzfs_error_description(g_zfs));
247 ret = zfs_err_to_be_err(g_zfs);
248 return (ret);
251 be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
252 cb.obe_root_ds = strdup(root_ds);
254 if (getzoneid() == GLOBAL_ZONEID) {
255 ret = be_do_installboot(&cb, BE_INSTALLBOOT_FLAG_NULL);
256 if (ret != BE_SUCCESS)
257 return (ret);
259 if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
260 if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
261 NULL, NULL, NULL)) != BE_SUCCESS) {
262 be_print_err(gettext("be_activate: Failed to "
263 "add BE (%s) to the menu\n"),
264 cb.obe_name);
265 goto done;
268 if (be_has_grub()) {
269 if ((ret = be_change_grub_default(cb.obe_name,
270 cb.obe_zpool)) != BE_SUCCESS) {
271 be_print_err(gettext("be_activate: failed to "
272 "change the default entry in menu.lst\n"));
273 goto done;
278 if ((ret = _be_list(cb.obe_name, &be_nodes)) != BE_SUCCESS) {
279 return (ret);
282 if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
283 be_print_err(gettext("be_activate: failed to set "
284 "canmount dataset property\n"));
285 goto done;
288 if (getzoneid() == GLOBAL_ZONEID) {
289 if ((ret = set_bootfs(be_nodes->be_rpool,
290 root_ds)) != BE_SUCCESS) {
291 be_print_err(gettext("be_activate: failed to set "
292 "bootfs pool property for %s\n"), root_ds);
293 goto done;
297 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
299 * We don't need to close the zfs handle at this
300 * point because The callback funtion
301 * be_promote_ds_callback() will close it for us.
303 if (be_promote_ds_callback(zhp, NULL) != 0) {
304 be_print_err(gettext("be_activate: "
305 "failed to activate the "
306 "datasets for %s: %s\n"),
307 root_ds,
308 libzfs_error_description(g_zfs));
309 ret = BE_ERR_PROMOTE;
310 goto done;
312 } else {
313 be_print_err(gettext("be_activate: failed to open "
314 "dataset (%s): %s\n"), root_ds,
315 libzfs_error_description(g_zfs));
316 ret = zfs_err_to_be_err(g_zfs);
317 goto done;
320 if (getzoneid() == GLOBAL_ZONEID &&
321 be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
322 (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
323 != BE_SUCCESS) {
324 be_print_err(gettext("be_activate: failed to promote "
325 "the active zonepath datasets for zones in BE %s\n"),
326 cb.obe_name);
329 if (getzoneid() != GLOBAL_ZONEID) {
330 if (!be_zone_compare_uuids(root_ds)) {
331 be_print_err(gettext("be_activate: activating zone "
332 "root dataset from non-active global BE is not "
333 "supported\n"));
334 ret = BE_ERR_NOTSUP;
335 goto done;
337 if ((zhp = zfs_open(g_zfs, root_ds,
338 ZFS_TYPE_FILESYSTEM)) == NULL) {
339 be_print_err(gettext("be_activate: failed to open "
340 "dataset (%s): %s\n"), root_ds,
341 libzfs_error_description(g_zfs));
342 ret = zfs_err_to_be_err(g_zfs);
343 goto done;
345 /* Find current active zone root dataset */
346 if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
347 active_ds, sizeof (active_ds))) != BE_SUCCESS) {
348 be_print_err(gettext("be_activate: failed to find "
349 "active zone root dataset\n"));
350 ZFS_CLOSE(zhp);
351 goto done;
353 /* Do nothing if requested BE is already active */
354 if (strcmp(root_ds, active_ds) == 0) {
355 ret = BE_SUCCESS;
356 ZFS_CLOSE(zhp);
357 goto done;
360 /* Set active property for BE */
361 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
362 be_print_err(gettext("be_activate: failed to set "
363 "active property (%s): %s\n"), root_ds,
364 libzfs_error_description(g_zfs));
365 ret = zfs_err_to_be_err(g_zfs);
366 ZFS_CLOSE(zhp);
367 goto done;
369 ZFS_CLOSE(zhp);
371 /* Unset active property for old active root dataset */
372 if ((zhp = zfs_open(g_zfs, active_ds,
373 ZFS_TYPE_FILESYSTEM)) == NULL) {
374 be_print_err(gettext("be_activate: failed to open "
375 "dataset (%s): %s\n"), active_ds,
376 libzfs_error_description(g_zfs));
377 ret = zfs_err_to_be_err(g_zfs);
378 goto done;
380 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
381 be_print_err(gettext("be_activate: failed to unset "
382 "active property (%s): %s\n"), active_ds,
383 libzfs_error_description(g_zfs));
384 ret = zfs_err_to_be_err(g_zfs);
385 ZFS_CLOSE(zhp);
386 goto done;
388 ZFS_CLOSE(zhp);
390 done:
391 be_free_list(be_nodes);
392 return (ret);
396 * Function: be_activate_current_be
397 * Description: Set the currently "active" BE to be "active on boot"
398 * Paramters:
399 * none
400 * Returns:
401 * BE_SUCCESS - Success
402 * be_errnot_t - Failure
403 * Scope:
404 * Semi-private (library wide use only)
407 be_activate_current_be(void)
409 int ret = BE_SUCCESS;
410 be_transaction_data_t bt = { 0 };
412 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
413 return (ret);
416 if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
417 be_print_err(gettext("be_activate_current_be: failed to "
418 "activate %s\n"), bt.obe_name);
419 return (ret);
422 return (BE_SUCCESS);
426 * Function: be_is_active_on_boot
427 * Description: Checks if the BE name passed in has the "active on boot"
428 * property set to B_TRUE.
429 * Paramters:
430 * be_name - the name of the BE to check
431 * Returns:
432 * B_TRUE - if active on boot.
433 * B_FALSE - if not active on boot.
434 * Scope:
435 * Semi-private (library wide use only)
437 boolean_t
438 be_is_active_on_boot(char *be_name)
440 be_node_list_t *be_node = NULL;
442 if (be_name == NULL) {
443 be_print_err(gettext("be_is_active_on_boot: "
444 "be_name must not be NULL\n"));
445 return (B_FALSE);
448 if (_be_list(be_name, &be_node) != BE_SUCCESS) {
449 return (B_FALSE);
452 if (be_node == NULL) {
453 return (B_FALSE);
456 if (be_node->be_active_on_boot) {
457 be_free_list(be_node);
458 return (B_TRUE);
459 } else {
460 be_free_list(be_node);
461 return (B_FALSE);
465 /* ******************************************************************** */
466 /* Private Functions */
467 /* ******************************************************************** */
470 * Function: set_bootfs
471 * Description: Sets the bootfs property on the boot pool to be the
472 * root dataset of the activated BE.
473 * Parameters:
474 * boot_pool - The pool we're setting bootfs in.
475 * be_root_ds - The main dataset for the BE.
476 * Return:
477 * BE_SUCCESS - Success
478 * be_errno_t - Failure
479 * Scope:
480 * Private
482 static int
483 set_bootfs(char *boot_rpool, char *be_root_ds)
485 zpool_handle_t *zhp;
486 int err = BE_SUCCESS;
488 if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
489 be_print_err(gettext("set_bootfs: failed to open pool "
490 "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
491 err = zfs_err_to_be_err(g_zfs);
492 return (err);
495 err = zpool_set_prop(zhp, "bootfs", be_root_ds);
496 if (err) {
497 be_print_err(gettext("set_bootfs: failed to set "
498 "bootfs property for pool %s: %s\n"), boot_rpool,
499 libzfs_error_description(g_zfs));
500 err = zfs_err_to_be_err(g_zfs);
501 zpool_close(zhp);
502 return (err);
505 zpool_close(zhp);
506 return (BE_SUCCESS);
510 * Function: set_canmount
511 * Description: Sets the canmount property on the datasets of the
512 * activated BE.
513 * Parameters:
514 * be_nodes - The be_node_t returned from be_list
515 * value - The value of canmount we setting, on|off|noauto.
516 * Return:
517 * BE_SUCCESS - Success
518 * be_errno_t - Failure
519 * Scope:
520 * Private
522 static int
523 set_canmount(be_node_list_t *be_nodes, char *value)
525 char ds_path[MAXPATHLEN];
526 zfs_handle_t *zhp = NULL;
527 be_node_list_t *list = be_nodes;
528 int err = BE_SUCCESS;
530 while (list != NULL) {
531 be_dataset_list_t *datasets = list->be_node_datasets;
533 be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
534 sizeof (ds_path));
536 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
537 NULL) {
538 be_print_err(gettext("set_canmount: failed to open "
539 "dataset (%s): %s\n"), ds_path,
540 libzfs_error_description(g_zfs));
541 err = zfs_err_to_be_err(g_zfs);
542 return (err);
544 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
546 * it's already mounted so we can't change the
547 * canmount property anyway.
549 err = BE_SUCCESS;
550 } else {
551 err = zfs_prop_set(zhp,
552 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
553 if (err) {
554 ZFS_CLOSE(zhp);
555 be_print_err(gettext("set_canmount: failed to "
556 "set dataset property (%s): %s\n"),
557 ds_path, libzfs_error_description(g_zfs));
558 err = zfs_err_to_be_err(g_zfs);
559 return (err);
562 ZFS_CLOSE(zhp);
564 while (datasets != NULL) {
565 be_make_root_ds(list->be_rpool,
566 datasets->be_dataset_name, ds_path,
567 sizeof (ds_path));
569 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
570 == NULL) {
571 be_print_err(gettext("set_canmount: failed to "
572 "open dataset %s: %s\n"), ds_path,
573 libzfs_error_description(g_zfs));
574 err = zfs_err_to_be_err(g_zfs);
575 return (err);
577 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
579 * it's already mounted so we can't change the
580 * canmount property anyway.
582 err = BE_SUCCESS;
583 ZFS_CLOSE(zhp);
584 break;
586 err = zfs_prop_set(zhp,
587 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
588 if (err) {
589 ZFS_CLOSE(zhp);
590 be_print_err(gettext("set_canmount: "
591 "Failed to set property value %s "
592 "for dataset %s: %s\n"), value, ds_path,
593 libzfs_error_description(g_zfs));
594 err = zfs_err_to_be_err(g_zfs);
595 return (err);
597 ZFS_CLOSE(zhp);
598 datasets = datasets->be_next_dataset;
600 list = list->be_next_node;
602 return (err);
606 * Function: be_get_grub_vers
607 * Description: Gets the grub version number from /boot/grub/capability. If
608 * capability file doesn't exist NULL is returned.
609 * Parameters:
610 * bt - The transaction data for the BE we're getting the grub
611 * version for.
612 * cur_vers - used to return the current version of grub from
613 * the root pool.
614 * new_vers - used to return the grub version of the BE we're
615 * activating.
616 * Return:
617 * BE_SUCCESS - Success
618 * be_errno_t - Failed to find version
619 * Scope:
620 * Private
622 static int
623 be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
625 zfs_handle_t *zhp = NULL;
626 zfs_handle_t *pool_zhp = NULL;
627 int ret = BE_SUCCESS;
628 char cap_file[MAXPATHLEN];
629 char *temp_mntpnt = NULL;
630 char *zpool_mntpt = NULL;
631 char *ptmp_mntpnt = NULL;
632 char *orig_mntpnt = NULL;
633 boolean_t be_mounted = B_FALSE;
634 boolean_t pool_mounted = B_FALSE;
636 if (!be_has_grub()) {
637 be_print_err(gettext("be_get_grub_vers: Not supported on "
638 "this architecture\n"));
639 return (BE_ERR_NOTSUP);
642 if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL ||
643 bt->obe_root_ds == NULL) {
644 be_print_err(gettext("be_get_grub_vers: Invalid BE\n"));
645 return (BE_ERR_INVAL);
648 if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
649 NULL) {
650 be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"),
651 libzfs_error_description(g_zfs));
652 return (zfs_err_to_be_err(g_zfs));
656 * Check to see if the pool's dataset is mounted. If it isn't we'll
657 * attempt to mount it.
659 if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt,
660 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
661 be_print_err(gettext("be_get_grub_vers: pool dataset "
662 "(%s) could not be mounted\n"), bt->obe_zpool);
663 ZFS_CLOSE(pool_zhp);
664 return (ret);
668 * Get the mountpoint for the root pool dataset.
670 if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) {
671 be_print_err(gettext("be_get_grub_vers: pool "
672 "dataset (%s) is not mounted. Can't read the "
673 "grub capability file.\n"), bt->obe_zpool);
674 ret = BE_ERR_NO_MENU;
675 goto cleanup;
679 * get the version of the most recent grub update.
681 (void) snprintf(cap_file, sizeof (cap_file), "%s%s",
682 zpool_mntpt, BE_CAP_FILE);
683 free(zpool_mntpt);
684 zpool_mntpt = NULL;
686 if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
687 goto cleanup;
689 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
690 NULL) {
691 be_print_err(gettext("be_get_grub_vers: failed to "
692 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
693 libzfs_error_description(g_zfs));
694 free(cur_vers);
695 ret = zfs_err_to_be_err(g_zfs);
696 goto cleanup;
698 if (!zfs_is_mounted(zhp, &temp_mntpnt)) {
699 if ((ret = _be_mount(bt->obe_name, &temp_mntpnt,
700 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
701 be_print_err(gettext("be_get_grub_vers: failed to "
702 "mount BE (%s)\n"), bt->obe_name);
703 free(*cur_vers);
704 *cur_vers = NULL;
705 ZFS_CLOSE(zhp);
706 goto cleanup;
708 be_mounted = B_TRUE;
710 ZFS_CLOSE(zhp);
713 * Now get the grub version for the BE being activated.
715 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt,
716 BE_CAP_FILE);
717 ret = get_ver_from_capfile(cap_file, new_vers);
718 if (ret != BE_SUCCESS) {
719 free(*cur_vers);
720 *cur_vers = NULL;
722 if (be_mounted)
723 (void) _be_unmount(bt->obe_name, 0);
725 cleanup:
726 if (pool_mounted) {
727 int iret = BE_SUCCESS;
728 iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt);
729 if (ret == BE_SUCCESS)
730 ret = iret;
731 free(orig_mntpnt);
732 free(ptmp_mntpnt);
734 ZFS_CLOSE(pool_zhp);
736 free(temp_mntpnt);
737 return (ret);
741 * Function: get_ver_from_capfile
742 * Description: Parses the capability file passed in looking for the VERSION
743 * line. If found the version is returned in vers, if not then
744 * NULL is returned in vers.
746 * Parameters:
747 * file - the path to the capability file we want to parse.
748 * vers - the version string that will be passed back.
749 * Return:
750 * BE_SUCCESS - Success
751 * be_errno_t - Failed to find version
752 * Scope:
753 * Private
755 static int
756 get_ver_from_capfile(char *file, char **vers)
758 FILE *fp = NULL;
759 char line[BUFSIZ];
760 char *last = NULL;
761 int err = BE_SUCCESS;
762 errno = 0;
764 if (!be_has_grub()) {
765 be_print_err(gettext("get_ver_from_capfile: Not supported "
766 "on this architecture\n"));
767 return (BE_ERR_NOTSUP);
771 * Set version string to NULL; the only case this shouldn't be set
772 * to be NULL is when we've actually found a version in the capability
773 * file, which is set below.
775 *vers = NULL;
778 * If the capability file doesn't exist, we're returning success
779 * because on older releases, the capability file did not exist
780 * so this is a valid scenario.
782 if (access(file, F_OK) == 0) {
783 if ((fp = fopen(file, "r")) == NULL) {
784 err = errno;
785 be_print_err(gettext("get_ver_from_capfile: failed to "
786 "open file %s with error %s\n"), file,
787 strerror(err));
788 err = errno_to_be_err(err);
789 return (err);
792 while (fgets(line, BUFSIZ, fp)) {
793 char *tok = strtok_r(line, "=", &last);
795 if (tok == NULL || tok[0] == '#') {
796 continue;
797 } else if (strcmp(tok, "VERSION") == 0) {
798 *vers = strdup(last);
799 break;
802 (void) fclose(fp);
805 return (BE_SUCCESS);
809 * To be able to boot EFI labeled disks, stage1 needs to be written
810 * into the MBR. We do not do this if we're on disks with a traditional
811 * fdisk partition table only, or if any foreign EFI partitions exist.
812 * In the trivial case of a whole-disk vdev we always write stage1 into
813 * the MBR.
815 static boolean_t
816 be_do_install_mbr(char *diskname, nvlist_t *child)
818 struct uuid allowed_uuids[] = {
819 EFI_UNUSED,
820 EFI_RESV1,
821 EFI_BOOT,
822 EFI_ROOT,
823 EFI_SWAP,
824 EFI_USR,
825 EFI_BACKUP,
826 EFI_RESV2,
827 EFI_VAR,
828 EFI_HOME,
829 EFI_ALTSCTR,
830 EFI_RESERVED,
831 EFI_SYSTEM,
832 EFI_BIOS_BOOT,
833 EFI_SYMC_PUB,
834 EFI_SYMC_CDS
837 uint64_t whole;
838 struct dk_gpt *gpt;
839 struct uuid *u;
840 int fd, npart, i, j;
842 (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK,
843 &whole);
845 if (whole)
846 return (B_TRUE);
848 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0)
849 return (B_FALSE);
851 if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0)
852 return (B_FALSE);
854 for (i = 0; i != npart; i++) {
855 int match = 0;
857 u = &gpt->efi_parts[i].p_guid;
859 for (j = 0;
860 j != sizeof (allowed_uuids) / sizeof (struct uuid);
861 j++)
862 if (bcmp(u, &allowed_uuids[j],
863 sizeof (struct uuid)) == 0)
864 match++;
866 if (match == 0)
867 return (B_FALSE);
870 return (B_TRUE);
873 static int
874 be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1,
875 char *stage2, uint16_t flags)
877 char install_cmd[MAXPATHLEN];
878 char be_run_cmd_errbuf[BUFSIZ];
879 char be_run_cmd_outbuf[BUFSIZ];
880 char diskname[MAXPATHLEN];
881 char *vname;
882 char *path, *dsk_ptr;
883 char *flag = "";
884 int ret;
885 vdev_stat_t *vs;
886 uint_t vsc;
888 if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) {
889 be_print_err(gettext("be_do_installboot: "
890 "failed to get device path\n"));
891 return (BE_ERR_NODEV);
894 if ((nvlist_lookup_uint64_array(child, ZPOOL_CONFIG_VDEV_STATS,
895 (uint64_t **)&vs, &vsc) != 0) ||
896 vs->vs_state < VDEV_STATE_DEGRADED) {
898 * Don't try to run installgrub on a vdev that is not ONLINE
899 * or DEGRADED. Try to print a warning for each such vdev.
901 be_print_err(gettext("be_do_installboot: "
902 "vdev %s is %s, can't install boot loader\n"),
903 path, zpool_state_to_name(vs->vs_state, vs->vs_aux));
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 if (be_has_grub()) {
950 (void) snprintf(install_cmd, sizeof (install_cmd),
951 "%s %s %s %s %s", BE_INSTALL_GRUB, flag,
952 stage1, stage2, diskname);
953 } else {
954 (void) snprintf(install_cmd, sizeof (install_cmd),
955 "%s %s %s %s %s", BE_INSTALL_BOOT, flag,
956 stage1, stage2, diskname);
958 } else if (be_is_isa("sparc")) {
959 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) ==
960 BE_INSTALLBOOT_FLAG_FORCE)
961 flag = "-f -F zfs";
962 else
963 flag = "-F zfs";
965 (void) snprintf(install_cmd, sizeof (install_cmd),
966 "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname);
967 } else {
968 be_print_err(gettext("be_do_installboot: unsupported "
969 "architecture.\n"));
970 return (BE_ERR_BOOTFILE_INST);
973 *be_run_cmd_outbuf = '\0';
974 *be_run_cmd_errbuf = '\0';
976 ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ,
977 be_run_cmd_outbuf, BUFSIZ);
979 if (ret != BE_SUCCESS) {
980 be_print_err(gettext("be_do_installboot: install "
981 "failed for device %s.\n"), vname);
982 ret = BE_ERR_BOOTFILE_INST;
985 be_print_err(gettext(" Command: \"%s\"\n"), install_cmd);
986 if (be_run_cmd_outbuf[0] != 0) {
987 be_print_err(gettext(" Output:\n"));
988 be_print_err("%s", be_run_cmd_outbuf);
991 if (be_run_cmd_errbuf[0] != 0) {
992 be_print_err(gettext(" Errors:\n"));
993 be_print_err("%s", be_run_cmd_errbuf);
995 free(vname);
997 return (ret);
1001 * Function: be_do_copy_grub_cap
1002 * Description: This function will copy grub capability file to BE.
1004 * Parameters:
1005 * bt - The transaction data for the BE we're activating.
1006 * Return:
1007 * BE_SUCCESS - Success
1008 * be_errno_t - Failure
1010 * Scope:
1011 * Private
1013 static int
1014 be_do_copy_grub_cap(be_transaction_data_t *bt)
1016 zfs_handle_t *zhp = NULL;
1017 char cap_file[MAXPATHLEN];
1018 char zpool_cap_file[MAXPATHLEN];
1019 char line[BUFSIZ];
1020 char *tmp_mntpnt = NULL;
1021 char *orig_mntpnt = NULL;
1022 char *pool_mntpnt = NULL;
1023 FILE *cap_fp = NULL;
1024 FILE *zpool_cap_fp = NULL;
1025 int err = 0;
1026 int ret = BE_SUCCESS;
1027 boolean_t pool_mounted = B_FALSE;
1028 boolean_t be_mounted = B_FALSE;
1031 * first get BE dataset mountpoint, we can free all the resources
1032 * once cap_file is built, leaving only be unmount to be done.
1034 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1035 NULL) {
1036 be_print_err(gettext("be_do_copy_grub_cap: failed to "
1037 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1038 libzfs_error_description(g_zfs));
1039 return (zfs_err_to_be_err(g_zfs));
1042 if (!zfs_is_mounted(zhp, &tmp_mntpnt)) {
1043 if ((ret = _be_mount(bt->obe_name, &tmp_mntpnt,
1044 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1045 be_print_err(gettext("be_do_copy_grub_cap: failed to "
1046 "mount BE (%s)\n"), bt->obe_name);
1047 ZFS_CLOSE(zhp);
1048 goto done;
1050 be_mounted = B_TRUE;
1052 ZFS_CLOSE(zhp); /* BE dataset handle is not needed any more */
1054 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpnt,
1055 BE_CAP_FILE);
1056 free(tmp_mntpnt);
1058 /* get pool root dataset mountpoint */
1059 zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM);
1060 if (zhp == NULL) {
1061 be_print_err(gettext("be_do_copy_grub_cap: zfs_open "
1062 "failed: %s\n"), libzfs_error_description(g_zfs));
1063 ret = zfs_err_to_be_err(g_zfs);
1064 goto done;
1068 * Check to see if the pool's dataset is mounted. If it isn't we'll
1069 * attempt to mount it.
1071 if ((ret = be_mount_pool(zhp, &tmp_mntpnt,
1072 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
1073 be_print_err(gettext("be_do_copy_grub_cap: pool dataset "
1074 "(%s) could not be mounted\n"), bt->obe_zpool);
1075 ZFS_CLOSE(zhp);
1076 goto done;
1080 * Get the mountpoint for the root pool dataset.
1081 * NOTE: zhp must be kept for _be_unmount_pool()
1083 if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1084 be_print_err(gettext("be_do_copy_grub_cap: pool "
1085 "dataset (%s) is not mounted. Can't check the grub "
1086 "version from the grub capability file.\n"), bt->obe_zpool);
1087 ret = BE_ERR_NO_MENU;
1088 goto done;
1091 (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
1092 pool_mntpnt, BE_CAP_FILE);
1093 free(pool_mntpnt);
1095 if ((cap_fp = fopen(cap_file, "r")) == NULL) {
1096 err = errno;
1097 be_print_err(gettext("be_do_copy_grub_cap: failed to open grub "
1098 "capability file\n"));
1099 ret = errno_to_be_err(err);
1100 goto done;
1102 if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
1103 err = errno;
1104 be_print_err(gettext("be_do_copy_grub_cap: failed to open new "
1105 "grub capability file\n"));
1106 ret = errno_to_be_err(err);
1107 (void) fclose(cap_fp);
1108 goto done;
1111 while (fgets(line, BUFSIZ, cap_fp)) {
1112 (void) fputs(line, zpool_cap_fp);
1115 (void) fclose(zpool_cap_fp);
1116 (void) fclose(cap_fp);
1118 done:
1119 if (be_mounted)
1120 (void) _be_unmount(bt->obe_name, 0);
1122 if (pool_mounted) {
1123 err = be_unmount_pool(zhp, tmp_mntpnt, orig_mntpnt);
1124 if (ret == BE_SUCCESS)
1125 ret = err;
1126 free(orig_mntpnt);
1127 free(tmp_mntpnt);
1128 zfs_close(zhp);
1130 return (ret);
1134 * Function: be_is_install_needed
1135 * Description: Check detached version files to detect if bootloader
1136 * install/update is needed.
1138 * Parameters:
1139 * bt - The transaction data for the BE we're activating.
1140 * update - set B_TRUE is update is needed.
1141 * Return:
1142 * BE_SUCCESS - Success
1143 * be_errno_t - Failure
1145 * Scope:
1146 * Private
1148 static int
1149 be_is_install_needed(be_transaction_data_t *bt, boolean_t *update)
1151 int ret = BE_SUCCESS;
1152 char *cur_vers = NULL, *new_vers = NULL;
1154 assert(bt != NULL);
1155 assert(update != NULL);
1157 if (!be_has_grub()) {
1159 * no detached versioning, let installboot to manage
1160 * versioning.
1162 *update = B_TRUE;
1163 return (ret);
1166 *update = B_FALSE; /* set default */
1169 * We need to check to see if the version number from
1170 * the BE being activated is greater than the current
1171 * one.
1173 ret = be_get_grub_vers(bt, &cur_vers, &new_vers);
1174 if (ret != BE_SUCCESS) {
1175 be_print_err(gettext("be_activate: failed to get grub "
1176 "versions from capability files.\n"));
1177 return (ret);
1179 /* update if we have both versions and can compare */
1180 if (cur_vers != NULL) {
1181 if (new_vers != NULL) {
1182 if (atof(cur_vers) < atof(new_vers))
1183 *update = B_TRUE;
1184 free(new_vers);
1186 free(cur_vers);
1187 } else if (new_vers != NULL) {
1188 /* we only got new version - update */
1189 *update = B_TRUE;
1190 free(new_vers);
1192 return (ret);
1196 * Function: be_do_installboot
1197 * Description: This function runs installgrub/installboot using the boot
1198 * loader files from the BE we're activating and installing
1199 * them on the pool the BE lives in.
1201 * Parameters:
1202 * bt - The transaction data for the BE we're activating.
1203 * flags - flags for bootloader install
1204 * Return:
1205 * BE_SUCCESS - Success
1206 * be_errno_t - Failure
1208 * Scope:
1209 * Private
1211 static int
1212 be_do_installboot(be_transaction_data_t *bt, uint16_t flags)
1214 zpool_handle_t *zphp = NULL;
1215 zfs_handle_t *zhp = NULL;
1216 nvlist_t **child, *nv, *config;
1217 uint_t c, children = 0;
1218 char *tmp_mntpt = NULL;
1219 char stage1[MAXPATHLEN];
1220 char stage2[MAXPATHLEN];
1221 char *vname;
1222 int ret = BE_SUCCESS;
1223 boolean_t be_mounted = B_FALSE;
1224 boolean_t update = B_FALSE;
1225 boolean_t verbose = B_FALSE;
1228 * check versions. This call is to support detached
1229 * version implementation like grub. Embedded versioning is
1230 * checked by actual installer.
1232 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) != BE_INSTALLBOOT_FLAG_FORCE) {
1233 ret = be_is_install_needed(bt, &update);
1234 if (ret != BE_SUCCESS || update == B_FALSE)
1235 return (ret);
1237 verbose = do_print;
1239 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1240 NULL) {
1241 be_print_err(gettext("be_do_installboot: failed to "
1242 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1243 libzfs_error_description(g_zfs));
1244 ret = zfs_err_to_be_err(g_zfs);
1245 return (ret);
1247 if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
1248 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
1249 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1250 be_print_err(gettext("be_do_installboot: failed to "
1251 "mount BE (%s)\n"), bt->obe_name);
1252 ZFS_CLOSE(zhp);
1253 return (ret);
1255 be_mounted = B_TRUE;
1257 ZFS_CLOSE(zhp);
1259 if (be_is_isa("i386")) {
1260 if (be_has_grub()) {
1261 (void) snprintf(stage1, sizeof (stage1), "%s%s",
1262 tmp_mntpt, BE_GRUB_STAGE_1);
1263 (void) snprintf(stage2, sizeof (stage2), "%s%s",
1264 tmp_mntpt, BE_GRUB_STAGE_2);
1265 } else {
1266 (void) snprintf(stage1, sizeof (stage1), "%s%s",
1267 tmp_mntpt, BE_LOADER_STAGE_1);
1268 (void) snprintf(stage2, sizeof (stage2), "%s%s",
1269 tmp_mntpt, BE_LOADER_STAGE_2);
1271 } else if (be_is_isa("sparc")) {
1272 char *platform = be_get_platform();
1274 if (platform == NULL) {
1275 be_print_err(gettext("be_do_installboot: "
1276 "failed to detect system platform name\n"));
1277 if (be_mounted)
1278 (void) _be_unmount(bt->obe_name, 0);
1279 free(tmp_mntpt);
1280 return (BE_ERR_BOOTFILE_INST);
1282 stage1[0] = '\0'; /* sparc has no stage1 */
1283 (void) snprintf(stage2, sizeof (stage2),
1284 "%s/usr/platform/%s%s", tmp_mntpt,
1285 platform, BE_SPARC_BOOTBLK);
1286 } else {
1287 be_print_err(gettext("be_do_installboot: unsupported "
1288 "architecture.\n"));
1289 return (BE_ERR_BOOTFILE_INST);
1292 if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
1293 be_print_err(gettext("be_do_installboot: failed to open "
1294 "pool (%s): %s\n"), bt->obe_zpool,
1295 libzfs_error_description(g_zfs));
1296 ret = zfs_err_to_be_err(g_zfs);
1297 if (be_mounted)
1298 (void) _be_unmount(bt->obe_name, 0);
1299 free(tmp_mntpt);
1300 return (ret);
1303 if ((config = zpool_get_config(zphp, NULL)) == NULL) {
1304 be_print_err(gettext("be_do_installboot: failed to get zpool "
1305 "configuration information. %s\n"),
1306 libzfs_error_description(g_zfs));
1307 ret = zfs_err_to_be_err(g_zfs);
1308 goto done;
1312 * Get the vdev tree
1314 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
1315 be_print_err(gettext("be_do_installboot: failed to get vdev "
1316 "tree: %s\n"), libzfs_error_description(g_zfs));
1317 ret = zfs_err_to_be_err(g_zfs);
1318 goto done;
1321 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1322 &children) != 0) {
1323 be_print_err(gettext("be_do_installboot: failed to traverse "
1324 "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
1325 ret = zfs_err_to_be_err(g_zfs);
1326 goto done;
1328 for (c = 0; c < children; c++) {
1329 uint_t i, nchildren = 0;
1330 nvlist_t **nvchild;
1332 /* ensure update on child status */
1333 vname = zpool_vdev_name(g_zfs, zphp, child[c], verbose);
1334 if (vname == NULL) {
1335 be_print_err(gettext(
1336 "be_do_installboot: "
1337 "failed to get device name: %s\n"),
1338 libzfs_error_description(g_zfs));
1339 ret = zfs_err_to_be_err(g_zfs);
1340 goto done;
1341 } else if (verbose == B_TRUE) {
1342 be_print_err(gettext("be_do_installboot: "
1343 "device %s\n"), vname);
1345 free(vname);
1347 ret = nvlist_lookup_nvlist_array(child[c],
1348 ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren);
1349 if (ret != 0) {
1350 if (ret != ENOENT) {
1351 be_print_err(gettext("be_do_installboot: "
1352 "failed to traverse the vdev tree: %s\n"),
1353 libzfs_error_description(g_zfs));
1354 ret = zfs_err_to_be_err(g_zfs);
1355 goto done;
1357 nchildren = 0; /* This is leaf device. */
1360 if (nchildren != 0) {
1361 for (i = 0; i < nchildren; i++) {
1362 /* ensure update on child status */
1363 vname = zpool_vdev_name(g_zfs, zphp,
1364 nvchild[i], verbose);
1365 if (vname == NULL) {
1366 be_print_err(gettext(
1367 "be_do_installboot: "
1368 "failed to get device name: %s\n"),
1369 libzfs_error_description(g_zfs));
1370 ret = zfs_err_to_be_err(g_zfs);
1371 goto done;
1372 } else if (verbose == B_TRUE) {
1373 be_print_err(gettext(
1374 "be_do_installboot: device %s\n"),
1375 vname);
1377 free(vname);
1378 ret = be_do_installboot_helper(zphp, nvchild[i],
1379 stage1, stage2, flags);
1380 if (ret != BE_SUCCESS)
1381 goto done;
1383 } else {
1384 ret = be_do_installboot_helper(zphp, child[c], stage1,
1385 stage2, flags);
1386 if (ret != BE_SUCCESS)
1387 goto done;
1391 if (be_has_grub()) {
1392 ret = be_do_copy_grub_cap(bt);
1395 done:
1396 ZFS_CLOSE(zhp);
1397 if (be_mounted)
1398 (void) _be_unmount(bt->obe_name, 0);
1399 zpool_close(zphp);
1400 free(tmp_mntpt);
1401 return (ret);
1405 * Function: be_promote_zone_ds
1406 * Description: This function finds the zones for the BE being activated
1407 * and the active zonepath dataset for each zone. Then each
1408 * active zonepath dataset is promoted.
1410 * Parameters:
1411 * be_name - the name of the global zone BE that we need to
1412 * find the zones for.
1413 * be_root_ds - the root dataset for be_name.
1414 * Return:
1415 * BE_SUCCESS - Success
1416 * be_errno_t - Failure
1418 * Scope:
1419 * Private
1421 static int
1422 be_promote_zone_ds(char *be_name, char *be_root_ds)
1424 char *zone_ds = NULL;
1425 char *temp_mntpt = NULL;
1426 char origin[MAXPATHLEN];
1427 char zoneroot_ds[MAXPATHLEN];
1428 zfs_handle_t *zhp = NULL;
1429 zfs_handle_t *z_zhp = NULL;
1430 zoneList_t zone_list = NULL;
1431 zoneBrandList_t *brands = NULL;
1432 boolean_t be_mounted = B_FALSE;
1433 int zone_index = 0;
1434 int err = BE_SUCCESS;
1437 * Get the supported zone brands so we can pass that
1438 * to z_get_nonglobal_zone_list_by_brand. Currently
1439 * only the ipkg and labeled brand zones are supported
1442 if ((brands = be_get_supported_brandlist()) == NULL) {
1443 be_print_err(gettext("be_promote_zone_ds: no supported "
1444 "brands\n"));
1445 return (BE_SUCCESS);
1448 if ((zhp = zfs_open(g_zfs, be_root_ds,
1449 ZFS_TYPE_FILESYSTEM)) == NULL) {
1450 be_print_err(gettext("be_promote_zone_ds: Failed to open "
1451 "dataset (%s): %s\n"), be_root_ds,
1452 libzfs_error_description(g_zfs));
1453 err = zfs_err_to_be_err(g_zfs);
1454 z_free_brand_list(brands);
1455 return (err);
1458 if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1459 if ((err = _be_mount(be_name, &temp_mntpt,
1460 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1461 be_print_err(gettext("be_promote_zone_ds: failed to "
1462 "mount the BE for zones procesing.\n"));
1463 ZFS_CLOSE(zhp);
1464 z_free_brand_list(brands);
1465 return (err);
1467 be_mounted = B_TRUE;
1471 * Set the zone root to the temp mount point for the BE we just mounted.
1473 z_set_zone_root(temp_mntpt);
1476 * Get all the zones based on the brands we're looking for. If no zones
1477 * are found that we're interested in unmount the BE and move on.
1479 if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1480 if (be_mounted)
1481 (void) _be_unmount(be_name, 0);
1482 ZFS_CLOSE(zhp);
1483 z_free_brand_list(brands);
1484 free(temp_mntpt);
1485 return (BE_SUCCESS);
1487 for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1488 != NULL; zone_index++) {
1489 char *zone_path = NULL;
1491 /* Skip zones that aren't at least installed */
1492 if (z_zlist_get_current_state(zone_list, zone_index) <
1493 ZONE_STATE_INSTALLED)
1494 continue;
1496 if (((zone_path =
1497 z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1498 ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1499 !be_zone_supported(zone_ds))
1500 continue;
1502 if (be_find_active_zone_root(zhp, zone_ds,
1503 zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1504 be_print_err(gettext("be_promote_zone_ds: "
1505 "Zone does not have an active root "
1506 "dataset, skipping this zone.\n"));
1507 continue;
1510 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1511 ZFS_TYPE_FILESYSTEM)) == NULL) {
1512 be_print_err(gettext("be_promote_zone_ds: "
1513 "Failed to open dataset "
1514 "(%s): %s\n"), zoneroot_ds,
1515 libzfs_error_description(g_zfs));
1516 err = zfs_err_to_be_err(g_zfs);
1517 goto done;
1520 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1521 sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1522 ZFS_CLOSE(z_zhp);
1523 continue;
1527 * We don't need to close the zfs handle at this
1528 * point because the callback funtion
1529 * be_promote_ds_callback() will close it for us.
1531 if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1532 be_print_err(gettext("be_promote_zone_ds: "
1533 "failed to activate the "
1534 "datasets for %s: %s\n"),
1535 zoneroot_ds,
1536 libzfs_error_description(g_zfs));
1537 err = BE_ERR_PROMOTE;
1538 goto done;
1541 done:
1542 if (be_mounted)
1543 (void) _be_unmount(be_name, 0);
1544 ZFS_CLOSE(zhp);
1545 free(temp_mntpt);
1546 z_free_brand_list(brands);
1547 z_free_zone_list(zone_list);
1548 return (err);
1552 * Function: be_promote_ds_callback
1553 * Description: This function is used to promote the datasets for the BE
1554 * being activated as well as the datasets for the zones BE
1555 * being activated.
1557 * Parameters:
1558 * zhp - the zfs handle for zone BE being activated.
1559 * data - not used.
1560 * Return:
1561 * 0 - Success
1562 * be_errno_t - Failure
1564 * Scope:
1565 * Private
1567 static int
1568 /* LINTED */
1569 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1571 char origin[MAXPATHLEN];
1572 char *sub_dataset = NULL;
1573 int ret = 0;
1575 if (zhp != NULL) {
1576 sub_dataset = strdup(zfs_get_name(zhp));
1577 if (sub_dataset == NULL) {
1578 ret = BE_ERR_NOMEM;
1579 goto done;
1581 } else {
1582 be_print_err(gettext("be_promote_ds_callback: "
1583 "Invalid zfs handle passed into function\n"));
1584 ret = BE_ERR_INVAL;
1585 goto done;
1589 * This loop makes sure that we promote the dataset to the
1590 * top of the tree so that it is no longer a decendent of any
1591 * dataset. The ZFS close and then open is used to make sure that
1592 * the promotion is updated before we move on.
1594 while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1595 sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1596 if (zfs_promote(zhp) != 0) {
1597 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1598 be_print_err(gettext("be_promote_ds_callback: "
1599 "promote of %s failed: %s\n"),
1600 zfs_get_name(zhp),
1601 libzfs_error_description(g_zfs));
1602 ret = zfs_err_to_be_err(g_zfs);
1603 goto done;
1604 } else {
1606 * If the call to zfs_promote returns the
1607 * error EZFS_EXISTS we've hit a snapshot name
1608 * collision. This means we're probably
1609 * attemping to promote a zone dataset above a
1610 * parent dataset that belongs to another zone
1611 * which this zone was cloned from.
1613 * TODO: If this is a zone dataset at some
1614 * point we should skip this if the zone
1615 * paths for the dataset and the snapshot
1616 * don't match.
1618 be_print_err(gettext("be_promote_ds_callback: "
1619 "promote of %s failed due to snapshot "
1620 "name collision: %s\n"), zfs_get_name(zhp),
1621 libzfs_error_description(g_zfs));
1622 ret = zfs_err_to_be_err(g_zfs);
1623 goto done;
1626 ZFS_CLOSE(zhp);
1627 if ((zhp = zfs_open(g_zfs, sub_dataset,
1628 ZFS_TYPE_FILESYSTEM)) == NULL) {
1629 be_print_err(gettext("be_promote_ds_callback: "
1630 "Failed to open dataset (%s): %s\n"), sub_dataset,
1631 libzfs_error_description(g_zfs));
1632 ret = zfs_err_to_be_err(g_zfs);
1633 goto done;
1637 /* Iterate down this dataset's children and promote them */
1638 ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1640 done:
1641 free(sub_dataset);
1642 ZFS_CLOSE(zhp);
1643 return (ret);