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.
32 #include <libnvpair.h>
39 #include <sys/mnttab.h>
40 #include <sys/types.h>
44 #include <sys/efi_partition.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 *,
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
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
83 * BE_SUCCESS - Success
84 * be_errno_t - Failure
89 be_activate(nvlist_t
*be_attrs
)
94 /* Initialize libzfs handle */
98 /* Get the BE name to activate */
99 if (nvlist_lookup_string(be_attrs
, BE_ATTR_ORIG_BE_NAME
, &be_name
)
101 be_print_err(gettext("be_activate: failed to "
102 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
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"),
112 return (BE_ERR_INVAL
);
115 ret
= _be_activate(be_name
);
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.
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
137 * BE_SUCCESS - Success
138 * be_errno_t - Failure
143 be_installboot(nvlist_t
*be_attrs
)
145 int ret
= BE_SUCCESS
;
148 be_transaction_data_t bt
= { 0 };
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
,
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
,
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
,
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 */
189 return (BE_ERR_INIT
);
191 ret
= be_do_installboot(&bt
, flags
);
198 /* ******************************************************************** */
199 /* Semi Private Functions */
200 /* ******************************************************************** */
203 * Function: _be_activate
204 * Description: This does the actual work described in be_activate.
206 * be_name - pointer to the name of BE to activate.
209 * BE_SUCCESS - Success
210 * be_errnot_t - Failure
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
;
223 int entry
, ret
= BE_SUCCESS
;
227 * TODO: The BE needs to be validated to make sure that it is actually
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
);
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
)
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"),
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"));
277 if ((ret
= _be_list(cb
.obe_name
, &be_nodes
)) != BE_SUCCESS
) {
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"));
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
);
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"),
307 libzfs_error_description(g_zfs
));
308 ret
= BE_ERR_PROMOTE
;
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
);
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
))
323 be_print_err(gettext("be_activate: failed to promote "
324 "the active zonepath datasets for zones in BE %s\n"),
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 "
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
);
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"));
352 /* Do nothing if requested BE is already active */
353 if (strcmp(root_ds
, active_ds
) == 0) {
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
);
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
);
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
);
390 be_free_list(be_nodes
);
395 * Function: be_activate_current_be
396 * Description: Set the currently "active" BE to be "active on boot"
400 * BE_SUCCESS - Success
401 * be_errnot_t - Failure
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
) {
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
);
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.
429 * be_name - the name of the BE to check
431 * B_TRUE - if active on boot.
432 * B_FALSE - if not active on boot.
434 * Semi-private (library wide use only)
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"));
447 if (_be_list(be_name
, &be_node
) != BE_SUCCESS
) {
451 if (be_node
== NULL
) {
455 if (be_node
->be_active_on_boot
) {
456 be_free_list(be_node
);
459 be_free_list(be_node
);
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.
473 * boot_pool - The pool we're setting bootfs in.
474 * be_root_ds - The main dataset for the BE.
476 * BE_SUCCESS - Success
477 * be_errno_t - Failure
482 set_bootfs(char *boot_rpool
, char *be_root_ds
)
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
);
494 err
= zpool_set_prop(zhp
, "bootfs", be_root_ds
);
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
);
509 * Function: set_canmount
510 * Description: Sets the canmount property on the datasets of the
513 * be_nodes - The be_node_t returned from be_list
514 * value - The value of canmount we setting, on|off|noauto.
516 * BE_SUCCESS - Success
517 * be_errno_t - Failure
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
,
535 if ((zhp
= zfs_open(g_zfs
, ds_path
, ZFS_TYPE_DATASET
)) ==
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
);
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.
550 err
= zfs_prop_set(zhp
,
551 zfs_prop_to_name(ZFS_PROP_CANMOUNT
), value
);
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
);
563 while (datasets
!= NULL
) {
564 be_make_root_ds(list
->be_rpool
,
565 datasets
->be_dataset_name
, ds_path
,
568 if ((zhp
= zfs_open(g_zfs
, ds_path
, ZFS_TYPE_DATASET
))
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
);
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.
585 err
= zfs_prop_set(zhp
,
586 zfs_prop_to_name(ZFS_PROP_CANMOUNT
), value
);
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
);
597 datasets
= datasets
->be_next_dataset
;
599 list
= list
->be_next_node
;
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.
609 * bt - The transaction data for the BE we're getting the grub
611 * cur_vers - used to return the current version of grub from
613 * new_vers - used to return the grub version of the BE we're
616 * BE_SUCCESS - Success
617 * be_errno_t - Failed to find version
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
)) ==
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
);
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
;
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
);
685 if ((ret
= get_ver_from_capfile(cap_file
, cur_vers
)) != BE_SUCCESS
)
688 if ((zhp
= zfs_open(g_zfs
, bt
->obe_root_ds
, ZFS_TYPE_FILESYSTEM
)) ==
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
));
694 ret
= zfs_err_to_be_err(g_zfs
);
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
);
712 * Now get the grub version for the BE being activated.
714 (void) snprintf(cap_file
, sizeof (cap_file
), "%s%s", temp_mntpnt
,
716 ret
= get_ver_from_capfile(cap_file
, new_vers
);
717 if (ret
!= BE_SUCCESS
) {
722 (void) _be_unmount(bt
->obe_name
, 0);
726 int iret
= BE_SUCCESS
;
727 iret
= be_unmount_pool(pool_zhp
, ptmp_mntpnt
, orig_mntpnt
);
728 if (ret
== BE_SUCCESS
)
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.
746 * file - the path to the capability file we want to parse.
747 * vers - the version string that will be passed back.
749 * BE_SUCCESS - Success
750 * be_errno_t - Failed to find version
755 get_ver_from_capfile(char *file
, char **vers
)
760 int err
= BE_SUCCESS
;
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.
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
) {
784 be_print_err(gettext("get_ver_from_capfile: failed to "
785 "open file %s with error %s\n"), file
,
787 err
= errno_to_be_err(err
);
791 while (fgets(line
, BUFSIZ
, fp
)) {
792 char *tok
= strtok_r(line
, "=", &last
);
794 if (tok
== NULL
|| tok
[0] == '#') {
796 } else if (strcmp(tok
, "VERSION") == 0) {
797 *vers
= strdup(last
);
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
815 be_do_install_mbr(char *diskname
, nvlist_t
*child
)
817 struct uuid allowed_uuids
[] = {
841 (void) nvlist_lookup_uint64(child
, ZPOOL_CONFIG_WHOLE_DISK
,
847 if ((fd
= open(diskname
, O_RDONLY
|O_NDELAY
)) < 0)
850 if ((npart
= efi_alloc_and_read(fd
, &gpt
)) <= 0)
853 for (i
= 0; i
!= npart
; i
++) {
856 u
= &gpt
->efi_parts
[i
].p_guid
;
859 j
!= sizeof (allowed_uuids
) / sizeof (struct uuid
);
861 if (bcmp(u
, &allowed_uuids
[j
],
862 sizeof (struct uuid
)) == 0)
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
];
881 char *path
, *dsk_ptr
;
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.
896 return (BE_ERR_NOMEM
);
898 dsk_ptr
= strstr(path
, "/dsk/");
899 if (dsk_ptr
!= NULL
) {
906 (void) snprintf(diskname
, sizeof (diskname
), "%s/r%s", path
, dsk_ptr
);
909 vname
= zpool_vdev_name(g_zfs
, zphp
, child
, B_FALSE
);
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
))
928 if (mbr
== BE_INSTALLBOOT_FLAG_MBR
||
929 be_do_install_mbr(diskname
, child
))
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
)
943 (void) snprintf(install_cmd
, sizeof (install_cmd
),
944 "%s %s %s %s", BE_INSTALL_BOOT
, flag
, stage2
, diskname
);
946 be_print_err(gettext("be_do_installboot: unsupported "
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
);
979 * Function: be_do_copy_grub_cap
980 * Description: This function will copy grub capability file to BE.
983 * bt - The transaction data for the BE we're activating.
985 * BE_SUCCESS - Success
986 * be_errno_t - Failure
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
];
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
;
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
);
1016 be_print_err(gettext("be_do_installboot: zfs_open "
1017 "failed: %s\n"), libzfs_error_description(g_zfs
));
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
);
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
;
1046 (void) snprintf(zpool_cap_file
, sizeof (zpool_cap_file
), "%s%s",
1047 pool_mntpnt
, BE_CAP_FILE
);
1051 if ((zhp
= zfs_open(g_zfs
, bt
->obe_root_ds
, ZFS_TYPE_FILESYSTEM
)) ==
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
);
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
);
1068 be_mounted
= B_TRUE
;
1072 (void) snprintf(cap_file
, sizeof (cap_file
), "%s%s", tmp_mntpnt
,
1076 if ((cap_fp
= fopen(cap_file
, "r")) == NULL
) {
1078 be_print_err(gettext("be_do_installboot: failed to open grub "
1079 "capability file\n"));
1080 ret
= errno_to_be_err(err
);
1083 if ((zpool_cap_fp
= fopen(zpool_cap_file
, "w")) == NULL
) {
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
);
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
);
1101 (void) _be_unmount(bt
->obe_name
, 0);
1105 iret
= be_unmount_pool(zhp
, ptmp_mntpnt
, orig_mntpnt
);
1106 if (ret
== BE_SUCCESS
)
1115 * Function: be_is_install_needed
1116 * Description: Check detached version files to detect if bootloader
1117 * install/update is needed.
1120 * bt - The transaction data for the BE we're activating.
1121 * update - set B_TRUE is update is needed.
1123 * BE_SUCCESS - Success
1124 * be_errno_t - Failure
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
;
1136 assert(update
!= NULL
);
1138 if (!be_has_grub()) {
1140 * no detached versioning, let installboot to manage
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
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"));
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
))
1168 } else if (new_vers
!= NULL
) {
1169 /* we only got new version - update */
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.
1183 * bt - The transaction data for the BE we're activating.
1184 * flags - flags for bootloader install
1186 * BE_SUCCESS - Success
1187 * be_errno_t - Failure
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
];
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
)
1218 if ((zhp
= zfs_open(g_zfs
, bt
->obe_root_ds
, ZFS_TYPE_FILESYSTEM
)) ==
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
);
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
);
1234 be_mounted
= B_TRUE
;
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
);
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"));
1250 (void) _be_unmount(bt
->obe_name
, 0);
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
);
1267 (void) _be_unmount(bt
->obe_name
, 0);
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
);
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
);
1290 if (nvlist_lookup_nvlist_array(nv
, ZPOOL_CONFIG_CHILDREN
, &child
,
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
);
1297 for (c
= 0; c
< children
; c
++) {
1298 uint_t i
, nchildren
= 0;
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
);
1309 if (strcmp(vname
, "mirror") == 0 || vname
[0] != 'c') {
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
);
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
)
1330 ret
= be_do_installboot_helper(zphp
, child
[c
], stage1
,
1332 if (ret
!= BE_SUCCESS
)
1337 if (be_has_grub()) {
1338 ret
= be_do_copy_grub_cap(bt
);
1344 (void) _be_unmount(bt
->obe_name
, 0);
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.
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.
1361 * BE_SUCCESS - Success
1362 * be_errno_t - Failure
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
;
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 "
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
);
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"));
1410 z_free_brand_list(brands
);
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
) {
1427 (void) _be_unmount(be_name
, 0);
1429 z_free_brand_list(brands
);
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
)
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
))
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"));
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
);
1466 if (zfs_prop_get(z_zhp
, ZFS_PROP_ORIGIN
, origin
,
1467 sizeof (origin
), NULL
, NULL
, 0, B_FALSE
) != 0) {
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"),
1482 libzfs_error_description(g_zfs
));
1483 err
= BE_ERR_PROMOTE
;
1489 (void) _be_unmount(be_name
, 0);
1492 z_free_brand_list(brands
);
1493 z_free_zone_list(zone_list
);
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
1504 * zhp - the zfs handle for zone BE being activated.
1508 * be_errno_t - Failure
1515 be_promote_ds_callback(zfs_handle_t
*zhp
, void *data
)
1517 char origin
[MAXPATHLEN
];
1518 char *sub_dataset
= NULL
;
1522 sub_dataset
= strdup(zfs_get_name(zhp
));
1523 if (sub_dataset
== NULL
) {
1528 be_print_err(gettext("be_promote_ds_callback: "
1529 "Invalid zfs handle passed into function\n"));
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"),
1547 libzfs_error_description(g_zfs
));
1548 ret
= zfs_err_to_be_err(g_zfs
);
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
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
);
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
);
1583 /* Iterate down this dataset's children and promote them */
1584 ret
= zfs_iter_filesystems(zhp
, be_promote_ds_callback
, NULL
);