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]
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>
33 #include <libnvpair.h>
40 #include <sys/mnttab.h>
41 #include <sys/types.h>
45 #include <sys/efi_partition.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 *,
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
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
84 * BE_SUCCESS - Success
85 * be_errno_t - Failure
90 be_activate(nvlist_t
*be_attrs
)
95 /* Initialize libzfs handle */
99 /* Get the BE name to activate */
100 if (nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, &be_name
)
102 be_print_err(gettext("be_activate: failed to "
103 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
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"),
113 return (BE_ERR_INVAL
);
116 ret
= _be_activate(be_name
);
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.
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
138 * BE_SUCCESS - Success
139 * be_errno_t - Failure
144 be_installboot(nvlist_t
*be_attrs
)
146 int ret
= BE_SUCCESS
;
149 be_transaction_data_t bt
= { 0 };
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
,
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
,
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
,
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 */
190 return (BE_ERR_INIT
);
192 ret
= be_do_installboot(&bt
, flags
);
199 /* ******************************************************************** */
200 /* Semi Private Functions */
201 /* ******************************************************************** */
204 * Function: _be_activate
205 * Description: This does the actual work described in be_activate.
207 * be_name - pointer to the name of BE to activate.
210 * BE_SUCCESS - Success
211 * be_errnot_t - Failure
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
;
224 int entry
, ret
= BE_SUCCESS
;
228 * TODO: The BE needs to be validated to make sure that it is actually
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
);
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
)
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"),
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"));
278 if ((ret
= _be_list(cb
.obe_name
, &be_nodes
)) != BE_SUCCESS
) {
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"));
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
);
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"),
308 libzfs_error_description(g_zfs
));
309 ret
= BE_ERR_PROMOTE
;
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
);
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
))
324 be_print_err(gettext("be_activate: failed to promote "
325 "the active zonepath datasets for zones in BE %s\n"),
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 "
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
);
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"));
353 /* Do nothing if requested BE is already active */
354 if (strcmp(root_ds
, active_ds
) == 0) {
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
);
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
);
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
);
391 be_free_list(be_nodes
);
396 * Function: be_activate_current_be
397 * Description: Set the currently "active" BE to be "active on boot"
401 * BE_SUCCESS - Success
402 * be_errnot_t - Failure
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
) {
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
);
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.
430 * be_name - the name of the BE to check
432 * B_TRUE - if active on boot.
433 * B_FALSE - if not active on boot.
435 * Semi-private (library wide use only)
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"));
448 if (_be_list(be_name
, &be_node
) != BE_SUCCESS
) {
452 if (be_node
== NULL
) {
456 if (be_node
->be_active_on_boot
) {
457 be_free_list(be_node
);
460 be_free_list(be_node
);
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.
474 * boot_pool - The pool we're setting bootfs in.
475 * be_root_ds - The main dataset for the BE.
477 * BE_SUCCESS - Success
478 * be_errno_t - Failure
483 set_bootfs(char *boot_rpool
, char *be_root_ds
)
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
);
495 err
= zpool_set_prop(zhp
, "bootfs", be_root_ds
);
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
);
510 * Function: set_canmount
511 * Description: Sets the canmount property on the datasets of the
514 * be_nodes - The be_node_t returned from be_list
515 * value - The value of canmount we setting, on|off|noauto.
517 * BE_SUCCESS - Success
518 * be_errno_t - Failure
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
,
536 if ((zhp
= zfs_open(g_zfs
, ds_path
, ZFS_TYPE_DATASET
)) ==
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
);
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.
551 err
= zfs_prop_set(zhp
,
552 zfs_prop_to_name(ZFS_PROP_CANMOUNT
), value
);
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
);
564 while (datasets
!= NULL
) {
565 be_make_root_ds(list
->be_rpool
,
566 datasets
->be_dataset_name
, ds_path
,
569 if ((zhp
= zfs_open(g_zfs
, ds_path
, ZFS_TYPE_DATASET
))
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
);
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.
586 err
= zfs_prop_set(zhp
,
587 zfs_prop_to_name(ZFS_PROP_CANMOUNT
), value
);
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
);
598 datasets
= datasets
->be_next_dataset
;
600 list
= list
->be_next_node
;
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.
610 * bt - The transaction data for the BE we're getting the grub
612 * cur_vers - used to return the current version of grub from
614 * new_vers - used to return the grub version of the BE we're
617 * BE_SUCCESS - Success
618 * be_errno_t - Failed to find version
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
)) ==
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
);
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
;
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
);
686 if ((ret
= get_ver_from_capfile(cap_file
, cur_vers
)) != BE_SUCCESS
)
689 if ((zhp
= zfs_open(g_zfs
, bt
->obe_root_ds
, ZFS_TYPE_FILESYSTEM
)) ==
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
));
695 ret
= zfs_err_to_be_err(g_zfs
);
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
);
713 * Now get the grub version for the BE being activated.
715 (void) snprintf(cap_file
, sizeof (cap_file
), "%s%s", temp_mntpnt
,
717 ret
= get_ver_from_capfile(cap_file
, new_vers
);
718 if (ret
!= BE_SUCCESS
) {
723 (void) _be_unmount(bt
->obe_name
, 0);
727 int iret
= BE_SUCCESS
;
728 iret
= be_unmount_pool(pool_zhp
, ptmp_mntpnt
, orig_mntpnt
);
729 if (ret
== BE_SUCCESS
)
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.
747 * file - the path to the capability file we want to parse.
748 * vers - the version string that will be passed back.
750 * BE_SUCCESS - Success
751 * be_errno_t - Failed to find version
756 get_ver_from_capfile(char *file
, char **vers
)
761 int err
= BE_SUCCESS
;
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.
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
) {
785 be_print_err(gettext("get_ver_from_capfile: failed to "
786 "open file %s with error %s\n"), file
,
788 err
= errno_to_be_err(err
);
792 while (fgets(line
, BUFSIZ
, fp
)) {
793 char *tok
= strtok_r(line
, "=", &last
);
795 if (tok
== NULL
|| tok
[0] == '#') {
797 } else if (strcmp(tok
, "VERSION") == 0) {
798 *vers
= strdup(last
);
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
816 be_do_install_mbr(char *diskname
, nvlist_t
*child
)
818 struct uuid allowed_uuids
[] = {
842 (void) nvlist_lookup_uint64(child
, ZPOOL_CONFIG_WHOLE_DISK
,
848 if ((fd
= open(diskname
, O_RDONLY
|O_NDELAY
)) < 0)
851 if ((npart
= efi_alloc_and_read(fd
, &gpt
)) <= 0)
854 for (i
= 0; i
!= npart
; i
++) {
857 u
= &gpt
->efi_parts
[i
].p_guid
;
860 j
!= sizeof (allowed_uuids
) / sizeof (struct uuid
);
862 if (bcmp(u
, &allowed_uuids
[j
],
863 sizeof (struct uuid
)) == 0)
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
];
882 char *path
, *dsk_ptr
;
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
));
908 * Modify the vdev path to point to the raw disk.
912 return (BE_ERR_NOMEM
);
914 dsk_ptr
= strstr(path
, "/dsk/");
915 if (dsk_ptr
!= NULL
) {
922 (void) snprintf(diskname
, sizeof (diskname
), "%s/r%s", path
, dsk_ptr
);
925 vname
= zpool_vdev_name(g_zfs
, zphp
, child
, B_FALSE
);
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
))
944 if (mbr
== BE_INSTALLBOOT_FLAG_MBR
||
945 be_do_install_mbr(diskname
, child
))
950 (void) snprintf(install_cmd
, sizeof (install_cmd
),
951 "%s %s %s %s %s", BE_INSTALL_GRUB
, flag
,
952 stage1
, stage2
, diskname
);
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
)
965 (void) snprintf(install_cmd
, sizeof (install_cmd
),
966 "%s %s %s %s", BE_INSTALL_BOOT
, flag
, stage2
, diskname
);
968 be_print_err(gettext("be_do_installboot: unsupported "
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
);
1001 * Function: be_do_copy_grub_cap
1002 * Description: This function will copy grub capability file to BE.
1005 * bt - The transaction data for the BE we're activating.
1007 * BE_SUCCESS - Success
1008 * be_errno_t - Failure
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
];
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
;
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
)) ==
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
);
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
,
1058 /* get pool root dataset mountpoint */
1059 zhp
= zfs_open(g_zfs
, bt
->obe_zpool
, ZFS_TYPE_FILESYSTEM
);
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
);
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
);
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
;
1091 (void) snprintf(zpool_cap_file
, sizeof (zpool_cap_file
), "%s%s",
1092 pool_mntpnt
, BE_CAP_FILE
);
1095 if ((cap_fp
= fopen(cap_file
, "r")) == NULL
) {
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
);
1102 if ((zpool_cap_fp
= fopen(zpool_cap_file
, "w")) == NULL
) {
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
);
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
);
1120 (void) _be_unmount(bt
->obe_name
, 0);
1123 err
= be_unmount_pool(zhp
, tmp_mntpnt
, orig_mntpnt
);
1124 if (ret
== BE_SUCCESS
)
1134 * Function: be_is_install_needed
1135 * Description: Check detached version files to detect if bootloader
1136 * install/update is needed.
1139 * bt - The transaction data for the BE we're activating.
1140 * update - set B_TRUE is update is needed.
1142 * BE_SUCCESS - Success
1143 * be_errno_t - Failure
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
;
1155 assert(update
!= NULL
);
1157 if (!be_has_grub()) {
1159 * no detached versioning, let installboot to manage
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
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"));
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
))
1187 } else if (new_vers
!= NULL
) {
1188 /* we only got new version - update */
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.
1202 * bt - The transaction data for the BE we're activating.
1203 * flags - flags for bootloader install
1205 * BE_SUCCESS - Success
1206 * be_errno_t - Failure
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
];
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
)
1239 if ((zhp
= zfs_open(g_zfs
, bt
->obe_root_ds
, ZFS_TYPE_FILESYSTEM
)) ==
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
);
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
);
1255 be_mounted
= B_TRUE
;
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
);
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"));
1278 (void) _be_unmount(bt
->obe_name
, 0);
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
);
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
);
1298 (void) _be_unmount(bt
->obe_name
, 0);
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
);
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
);
1321 if (nvlist_lookup_nvlist_array(nv
, ZPOOL_CONFIG_CHILDREN
, &child
,
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
);
1328 for (c
= 0; c
< children
; c
++) {
1329 uint_t i
, nchildren
= 0;
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
);
1341 } else if (verbose
== B_TRUE
) {
1342 be_print_err(gettext("be_do_installboot: "
1343 "device %s\n"), vname
);
1347 ret
= nvlist_lookup_nvlist_array(child
[c
],
1348 ZPOOL_CONFIG_CHILDREN
, &nvchild
, &nchildren
);
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
);
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
);
1372 } else if (verbose
== B_TRUE
) {
1373 be_print_err(gettext(
1374 "be_do_installboot: device %s\n"),
1378 ret
= be_do_installboot_helper(zphp
, nvchild
[i
],
1379 stage1
, stage2
, flags
);
1380 if (ret
!= BE_SUCCESS
)
1384 ret
= be_do_installboot_helper(zphp
, child
[c
], stage1
,
1386 if (ret
!= BE_SUCCESS
)
1391 if (be_has_grub()) {
1392 ret
= be_do_copy_grub_cap(bt
);
1398 (void) _be_unmount(bt
->obe_name
, 0);
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.
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.
1415 * BE_SUCCESS - Success
1416 * be_errno_t - Failure
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
;
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 "
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
);
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"));
1464 z_free_brand_list(brands
);
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
) {
1481 (void) _be_unmount(be_name
, 0);
1483 z_free_brand_list(brands
);
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
)
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
))
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"));
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
);
1520 if (zfs_prop_get(z_zhp
, ZFS_PROP_ORIGIN
, origin
,
1521 sizeof (origin
), NULL
, NULL
, 0, B_FALSE
) != 0) {
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"),
1536 libzfs_error_description(g_zfs
));
1537 err
= BE_ERR_PROMOTE
;
1543 (void) _be_unmount(be_name
, 0);
1546 z_free_brand_list(brands
);
1547 z_free_zone_list(zone_list
);
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
1558 * zhp - the zfs handle for zone BE being activated.
1562 * be_errno_t - Failure
1569 be_promote_ds_callback(zfs_handle_t
*zhp
, void *data
)
1571 char origin
[MAXPATHLEN
];
1572 char *sub_dataset
= NULL
;
1576 sub_dataset
= strdup(zfs_get_name(zhp
));
1577 if (sub_dataset
== NULL
) {
1582 be_print_err(gettext("be_promote_ds_callback: "
1583 "Invalid zfs handle passed into function\n"));
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"),
1601 libzfs_error_description(g_zfs
));
1602 ret
= zfs_err_to_be_err(g_zfs
);
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
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
);
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
);
1637 /* Iterate down this dataset's children and promote them */
1638 ret
= zfs_iter_filesystems(zhp
, be_promote_ds_callback
, NULL
);