import less(1)
[unleashed/tickless.git] / usr / src / lib / libbe / common / be_activate.c
blob877475031995d64587b4dd5ab75b9bbdf2d4ea4f
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.
26 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
30 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
31 * Copyright 2016 Toomas Soome <tsoome@me.com>
34 #include <assert.h>
35 #include <libintl.h>
36 #include <libnvpair.h>
37 #include <libzfs.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <strings.h>
42 #include <errno.h>
43 #include <sys/mnttab.h>
44 #include <sys/types.h>
45 #include <sys/stat.h>
46 #include <fcntl.h>
47 #include <unistd.h>
48 #include <sys/efi_partition.h>
50 #include <libbe.h>
51 #include <libbe_priv.h>
53 char *mnttab = MNTTAB;
56 * Private function prototypes
58 static int set_bootfs(char *boot_rpool, char *be_root_ds);
59 static int set_canmount(be_node_list_t *, char *);
60 static boolean_t be_do_install_mbr(char *, nvlist_t *);
61 static int be_do_installboot_helper(zpool_handle_t *, nvlist_t *, char *,
62 char *, uint16_t);
63 static int be_do_installboot(be_transaction_data_t *, uint16_t);
64 static int be_promote_zone_ds(char *, char *);
65 static int be_promote_ds_callback(zfs_handle_t *, void *);
67 /* ******************************************************************** */
68 /* Public Functions */
69 /* ******************************************************************** */
72 * Function: be_activate
73 * Description: Calls _be_activate which activates the BE named in the
74 * attributes passed in through be_attrs. The process of
75 * activation sets the bootfs property of the root pool, resets
76 * the canmount property to noauto, and sets the default in the
77 * menu to the entry corresponding to the entry for the named 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;
270 if ((ret = _be_list(cb.obe_name, &be_nodes)) != BE_SUCCESS) {
271 return (ret);
274 if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
275 be_print_err(gettext("be_activate: failed to set "
276 "canmount dataset property\n"));
277 goto done;
280 if (getzoneid() == GLOBAL_ZONEID) {
281 if ((ret = set_bootfs(be_nodes->be_rpool,
282 root_ds)) != BE_SUCCESS) {
283 be_print_err(gettext("be_activate: failed to set "
284 "bootfs pool property for %s\n"), root_ds);
285 goto done;
289 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
291 * We don't need to close the zfs handle at this
292 * point because The callback funtion
293 * be_promote_ds_callback() will close it for us.
295 if (be_promote_ds_callback(zhp, NULL) != 0) {
296 be_print_err(gettext("be_activate: "
297 "failed to activate the "
298 "datasets for %s: %s\n"),
299 root_ds,
300 libzfs_error_description(g_zfs));
301 ret = BE_ERR_PROMOTE;
302 goto done;
304 } else {
305 be_print_err(gettext("be_activate: failed to open "
306 "dataset (%s): %s\n"), root_ds,
307 libzfs_error_description(g_zfs));
308 ret = zfs_err_to_be_err(g_zfs);
309 goto done;
312 if (getzoneid() == GLOBAL_ZONEID &&
313 be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
314 (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
315 != BE_SUCCESS) {
316 be_print_err(gettext("be_activate: failed to promote "
317 "the active zonepath datasets for zones in BE %s\n"),
318 cb.obe_name);
321 if (getzoneid() != GLOBAL_ZONEID) {
322 if (!be_zone_compare_uuids(root_ds)) {
323 be_print_err(gettext("be_activate: activating zone "
324 "root dataset from non-active global BE is not "
325 "supported\n"));
326 ret = BE_ERR_NOTSUP;
327 goto done;
329 if ((zhp = zfs_open(g_zfs, root_ds,
330 ZFS_TYPE_FILESYSTEM)) == NULL) {
331 be_print_err(gettext("be_activate: failed to open "
332 "dataset (%s): %s\n"), root_ds,
333 libzfs_error_description(g_zfs));
334 ret = zfs_err_to_be_err(g_zfs);
335 goto done;
337 /* Find current active zone root dataset */
338 if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
339 active_ds, sizeof (active_ds))) != BE_SUCCESS) {
340 be_print_err(gettext("be_activate: failed to find "
341 "active zone root dataset\n"));
342 ZFS_CLOSE(zhp);
343 goto done;
345 /* Do nothing if requested BE is already active */
346 if (strcmp(root_ds, active_ds) == 0) {
347 ret = BE_SUCCESS;
348 ZFS_CLOSE(zhp);
349 goto done;
352 /* Set active property for BE */
353 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
354 be_print_err(gettext("be_activate: failed to set "
355 "active property (%s): %s\n"), root_ds,
356 libzfs_error_description(g_zfs));
357 ret = zfs_err_to_be_err(g_zfs);
358 ZFS_CLOSE(zhp);
359 goto done;
361 ZFS_CLOSE(zhp);
363 /* Unset active property for old active root dataset */
364 if ((zhp = zfs_open(g_zfs, active_ds,
365 ZFS_TYPE_FILESYSTEM)) == NULL) {
366 be_print_err(gettext("be_activate: failed to open "
367 "dataset (%s): %s\n"), active_ds,
368 libzfs_error_description(g_zfs));
369 ret = zfs_err_to_be_err(g_zfs);
370 goto done;
372 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
373 be_print_err(gettext("be_activate: failed to unset "
374 "active property (%s): %s\n"), active_ds,
375 libzfs_error_description(g_zfs));
376 ret = zfs_err_to_be_err(g_zfs);
377 ZFS_CLOSE(zhp);
378 goto done;
380 ZFS_CLOSE(zhp);
382 done:
383 be_free_list(be_nodes);
384 return (ret);
388 * Function: be_activate_current_be
389 * Description: Set the currently "active" BE to be "active on boot"
390 * Paramters:
391 * none
392 * Returns:
393 * BE_SUCCESS - Success
394 * be_errnot_t - Failure
395 * Scope:
396 * Semi-private (library wide use only)
399 be_activate_current_be(void)
401 int ret = BE_SUCCESS;
402 be_transaction_data_t bt = { 0 };
404 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
405 return (ret);
408 if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
409 be_print_err(gettext("be_activate_current_be: failed to "
410 "activate %s\n"), bt.obe_name);
411 return (ret);
414 return (BE_SUCCESS);
418 * Function: be_is_active_on_boot
419 * Description: Checks if the BE name passed in has the "active on boot"
420 * property set to B_TRUE.
421 * Paramters:
422 * be_name - the name of the BE to check
423 * Returns:
424 * B_TRUE - if active on boot.
425 * B_FALSE - if not active on boot.
426 * Scope:
427 * Semi-private (library wide use only)
429 boolean_t
430 be_is_active_on_boot(char *be_name)
432 be_node_list_t *be_node = NULL;
434 if (be_name == NULL) {
435 be_print_err(gettext("be_is_active_on_boot: "
436 "be_name must not be NULL\n"));
437 return (B_FALSE);
440 if (_be_list(be_name, &be_node) != BE_SUCCESS) {
441 return (B_FALSE);
444 if (be_node == NULL) {
445 return (B_FALSE);
448 if (be_node->be_active_on_boot) {
449 be_free_list(be_node);
450 return (B_TRUE);
451 } else {
452 be_free_list(be_node);
453 return (B_FALSE);
457 /* ******************************************************************** */
458 /* Private Functions */
459 /* ******************************************************************** */
462 * Function: set_bootfs
463 * Description: Sets the bootfs property on the boot pool to be the
464 * root dataset of the activated BE.
465 * Parameters:
466 * boot_pool - The pool we're setting bootfs in.
467 * be_root_ds - The main dataset for the BE.
468 * Return:
469 * BE_SUCCESS - Success
470 * be_errno_t - Failure
471 * Scope:
472 * Private
474 static int
475 set_bootfs(char *boot_rpool, char *be_root_ds)
477 zpool_handle_t *zhp;
478 int err = BE_SUCCESS;
480 if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
481 be_print_err(gettext("set_bootfs: failed to open pool "
482 "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
483 err = zfs_err_to_be_err(g_zfs);
484 return (err);
487 err = zpool_set_prop(zhp, "bootfs", be_root_ds);
488 if (err) {
489 be_print_err(gettext("set_bootfs: failed to set "
490 "bootfs property for pool %s: %s\n"), boot_rpool,
491 libzfs_error_description(g_zfs));
492 err = zfs_err_to_be_err(g_zfs);
493 zpool_close(zhp);
494 return (err);
497 zpool_close(zhp);
498 return (BE_SUCCESS);
502 * Function: set_canmount
503 * Description: Sets the canmount property on the datasets of the
504 * activated BE.
505 * Parameters:
506 * be_nodes - The be_node_t returned from be_list
507 * value - The value of canmount we setting, on|off|noauto.
508 * Return:
509 * BE_SUCCESS - Success
510 * be_errno_t - Failure
511 * Scope:
512 * Private
514 static int
515 set_canmount(be_node_list_t *be_nodes, char *value)
517 char ds_path[MAXPATHLEN];
518 zfs_handle_t *zhp = NULL;
519 be_node_list_t *list = be_nodes;
520 int err = BE_SUCCESS;
522 while (list != NULL) {
523 be_dataset_list_t *datasets = list->be_node_datasets;
525 be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
526 sizeof (ds_path));
528 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
529 NULL) {
530 be_print_err(gettext("set_canmount: failed to open "
531 "dataset (%s): %s\n"), ds_path,
532 libzfs_error_description(g_zfs));
533 err = zfs_err_to_be_err(g_zfs);
534 return (err);
536 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
538 * it's already mounted so we can't change the
539 * canmount property anyway.
541 err = BE_SUCCESS;
542 } else {
543 err = zfs_prop_set(zhp,
544 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
545 if (err) {
546 ZFS_CLOSE(zhp);
547 be_print_err(gettext("set_canmount: failed to "
548 "set dataset property (%s): %s\n"),
549 ds_path, libzfs_error_description(g_zfs));
550 err = zfs_err_to_be_err(g_zfs);
551 return (err);
554 ZFS_CLOSE(zhp);
556 while (datasets != NULL) {
557 be_make_root_ds(list->be_rpool,
558 datasets->be_dataset_name, ds_path,
559 sizeof (ds_path));
561 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
562 == NULL) {
563 be_print_err(gettext("set_canmount: failed to "
564 "open dataset %s: %s\n"), ds_path,
565 libzfs_error_description(g_zfs));
566 err = zfs_err_to_be_err(g_zfs);
567 return (err);
569 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
571 * it's already mounted so we can't change the
572 * canmount property anyway.
574 err = BE_SUCCESS;
575 ZFS_CLOSE(zhp);
576 break;
578 err = zfs_prop_set(zhp,
579 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
580 if (err) {
581 ZFS_CLOSE(zhp);
582 be_print_err(gettext("set_canmount: "
583 "Failed to set property value %s "
584 "for dataset %s: %s\n"), value, ds_path,
585 libzfs_error_description(g_zfs));
586 err = zfs_err_to_be_err(g_zfs);
587 return (err);
589 ZFS_CLOSE(zhp);
590 datasets = datasets->be_next_dataset;
592 list = list->be_next_node;
594 return (err);
598 * To be able to boot EFI labeled disks, stage1 needs to be written
599 * into the MBR. We do not do this if we're on disks with a traditional
600 * fdisk partition table only, or if any foreign EFI partitions exist.
601 * In the trivial case of a whole-disk vdev we always write stage1 into
602 * the MBR.
604 static boolean_t
605 be_do_install_mbr(char *diskname, nvlist_t *child)
607 struct uuid allowed_uuids[] = {
608 EFI_UNUSED,
609 EFI_RESV1,
610 EFI_BOOT,
611 EFI_ROOT,
612 EFI_SWAP,
613 EFI_USR,
614 EFI_BACKUP,
615 EFI_RESV2,
616 EFI_VAR,
617 EFI_HOME,
618 EFI_ALTSCTR,
619 EFI_RESERVED,
620 EFI_SYSTEM,
621 EFI_BIOS_BOOT,
622 EFI_SYMC_PUB,
623 EFI_SYMC_CDS
626 uint64_t whole;
627 struct dk_gpt *gpt;
628 struct uuid *u;
629 int fd, npart, i, j;
631 (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK,
632 &whole);
634 if (whole)
635 return (B_TRUE);
637 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0)
638 return (B_FALSE);
640 if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0)
641 return (B_FALSE);
643 for (i = 0; i != npart; i++) {
644 int match = 0;
646 u = &gpt->efi_parts[i].p_guid;
648 for (j = 0;
649 j != sizeof (allowed_uuids) / sizeof (struct uuid);
650 j++)
651 if (bcmp(u, &allowed_uuids[j],
652 sizeof (struct uuid)) == 0)
653 match++;
655 if (match == 0)
656 return (B_FALSE);
659 return (B_TRUE);
662 static int
663 be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1,
664 char *stage2, uint16_t flags)
666 char install_cmd[MAXPATHLEN];
667 char be_run_cmd_errbuf[BUFSIZ];
668 char be_run_cmd_outbuf[BUFSIZ];
669 char diskname[MAXPATHLEN];
670 char *vname;
671 char *path, *dsk_ptr;
672 char *flag = "";
673 int ret;
674 vdev_stat_t *vs;
675 uint_t vsc;
677 if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) {
678 be_print_err(gettext("be_do_installboot: "
679 "failed to get device path\n"));
680 return (BE_ERR_NODEV);
683 if ((nvlist_lookup_uint64_array(child, ZPOOL_CONFIG_VDEV_STATS,
684 (uint64_t **)&vs, &vsc) != 0) ||
685 vs->vs_state < VDEV_STATE_DEGRADED) {
687 * Don't try to run installboot on a vdev that is not ONLINE
688 * or DEGRADED. Try to print a warning for each such vdev.
690 be_print_err(gettext("be_do_installboot: "
691 "vdev %s is %s, can't install boot loader\n"),
692 path, zpool_state_to_name(vs->vs_state, vs->vs_aux));
693 return (BE_SUCCESS);
697 * Modify the vdev path to point to the raw disk.
699 path = strdup(path);
700 if (path == NULL)
701 return (BE_ERR_NOMEM);
703 dsk_ptr = strstr(path, "/dsk/");
704 if (dsk_ptr != NULL) {
705 *dsk_ptr = '\0';
706 dsk_ptr++;
707 } else {
708 dsk_ptr = "";
711 (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
712 free(path);
714 vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE);
715 if (vname == NULL) {
716 be_print_err(gettext("be_do_installboot: "
717 "failed to get device name: %s\n"),
718 libzfs_error_description(g_zfs));
719 return (zfs_err_to_be_err(g_zfs));
722 if (be_is_isa("i386")) {
723 uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE;
724 uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR;
726 if (force == BE_INSTALLBOOT_FLAG_FORCE) {
727 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
728 be_do_install_mbr(diskname, child))
729 flag = "-F -m -f";
730 else
731 flag = "-F";
732 } else {
733 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
734 be_do_install_mbr(diskname, child))
735 flag = "-m -f";
738 (void) snprintf(install_cmd, sizeof (install_cmd),
739 "%s %s %s %s %s", BE_INSTALL_BOOT, flag,
740 stage1, stage2, diskname);
741 } else if (be_is_isa("sparc")) {
742 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) ==
743 BE_INSTALLBOOT_FLAG_FORCE)
744 flag = "-f -F zfs";
745 else
746 flag = "-F zfs";
748 (void) snprintf(install_cmd, sizeof (install_cmd),
749 "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname);
750 } else {
751 be_print_err(gettext("be_do_installboot: unsupported "
752 "architecture.\n"));
753 return (BE_ERR_BOOTFILE_INST);
756 *be_run_cmd_outbuf = '\0';
757 *be_run_cmd_errbuf = '\0';
759 ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ,
760 be_run_cmd_outbuf, BUFSIZ);
762 if (ret != BE_SUCCESS) {
763 be_print_err(gettext("be_do_installboot: install "
764 "failed for device %s.\n"), vname);
765 ret = BE_ERR_BOOTFILE_INST;
768 be_print_err(gettext(" Command: \"%s\"\n"), install_cmd);
769 if (be_run_cmd_outbuf[0] != 0) {
770 be_print_err(gettext(" Output:\n"));
771 be_print_err("%s", be_run_cmd_outbuf);
774 if (be_run_cmd_errbuf[0] != 0) {
775 be_print_err(gettext(" Errors:\n"));
776 be_print_err("%s", be_run_cmd_errbuf);
778 free(vname);
780 return (ret);
784 * Function: be_do_installboot
785 * Description: This function runs installboot using the boot
786 * loader files from the BE we're activating and installing
787 * them on the pool the BE lives in.
789 * Parameters:
790 * bt - The transaction data for the BE we're activating.
791 * flags - flags for bootloader install
792 * Return:
793 * BE_SUCCESS - Success
794 * be_errno_t - Failure
796 * Scope:
797 * Private
799 static int
800 be_do_installboot(be_transaction_data_t *bt, uint16_t flags)
802 zpool_handle_t *zphp = NULL;
803 zfs_handle_t *zhp = NULL;
804 nvlist_t **child, *nv, *config;
805 uint_t c, children = 0;
806 char *tmp_mntpt = NULL;
807 char stage1[MAXPATHLEN];
808 char stage2[MAXPATHLEN];
809 char *vname;
810 int ret = BE_SUCCESS;
811 boolean_t be_mounted = B_FALSE;
812 boolean_t verbose = B_FALSE;
814 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
815 NULL) {
816 be_print_err(gettext("be_do_installboot: failed to "
817 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
818 libzfs_error_description(g_zfs));
819 ret = zfs_err_to_be_err(g_zfs);
820 return (ret);
822 if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
823 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
824 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
825 be_print_err(gettext("be_do_installboot: failed to "
826 "mount BE (%s)\n"), bt->obe_name);
827 ZFS_CLOSE(zhp);
828 return (ret);
830 be_mounted = B_TRUE;
832 ZFS_CLOSE(zhp);
834 if (be_is_isa("i386")) {
835 (void) snprintf(stage1, sizeof (stage1), "%s%s",
836 tmp_mntpt, BE_LOADER_STAGE_1);
837 (void) snprintf(stage2, sizeof (stage2), "%s%s",
838 tmp_mntpt, BE_LOADER_STAGE_2);
839 } else if (be_is_isa("sparc")) {
840 char *platform = be_get_platform();
842 if (platform == NULL) {
843 be_print_err(gettext("be_do_installboot: "
844 "failed to detect system platform name\n"));
845 if (be_mounted)
846 (void) _be_unmount(bt->obe_name, 0);
847 free(tmp_mntpt);
848 return (BE_ERR_BOOTFILE_INST);
850 stage1[0] = '\0'; /* sparc has no stage1 */
851 (void) snprintf(stage2, sizeof (stage2),
852 "%s/usr/platform/%s%s", tmp_mntpt,
853 platform, BE_SPARC_BOOTBLK);
854 } else {
855 be_print_err(gettext("be_do_installboot: unsupported "
856 "architecture.\n"));
857 return (BE_ERR_BOOTFILE_INST);
860 if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
861 be_print_err(gettext("be_do_installboot: failed to open "
862 "pool (%s): %s\n"), bt->obe_zpool,
863 libzfs_error_description(g_zfs));
864 ret = zfs_err_to_be_err(g_zfs);
865 if (be_mounted)
866 (void) _be_unmount(bt->obe_name, 0);
867 free(tmp_mntpt);
868 return (ret);
871 if ((config = zpool_get_config(zphp, NULL)) == NULL) {
872 be_print_err(gettext("be_do_installboot: failed to get zpool "
873 "configuration information. %s\n"),
874 libzfs_error_description(g_zfs));
875 ret = zfs_err_to_be_err(g_zfs);
876 goto done;
880 * Get the vdev tree
882 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
883 be_print_err(gettext("be_do_installboot: failed to get vdev "
884 "tree: %s\n"), libzfs_error_description(g_zfs));
885 ret = zfs_err_to_be_err(g_zfs);
886 goto done;
889 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
890 &children) != 0) {
891 be_print_err(gettext("be_do_installboot: failed to traverse "
892 "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
893 ret = zfs_err_to_be_err(g_zfs);
894 goto done;
896 for (c = 0; c < children; c++) {
897 uint_t i, nchildren = 0;
898 nvlist_t **nvchild;
900 /* ensure update on child status */
901 vname = zpool_vdev_name(g_zfs, zphp, child[c], verbose);
902 if (vname == NULL) {
903 be_print_err(gettext(
904 "be_do_installboot: "
905 "failed to get device name: %s\n"),
906 libzfs_error_description(g_zfs));
907 ret = zfs_err_to_be_err(g_zfs);
908 goto done;
909 } else if (verbose == B_TRUE) {
910 be_print_err(gettext("be_do_installboot: "
911 "device %s\n"), vname);
913 free(vname);
915 ret = nvlist_lookup_nvlist_array(child[c],
916 ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren);
917 if (ret != 0) {
918 if (ret != ENOENT) {
919 be_print_err(gettext("be_do_installboot: "
920 "failed to traverse the vdev tree: %s\n"),
921 libzfs_error_description(g_zfs));
922 ret = zfs_err_to_be_err(g_zfs);
923 goto done;
925 nchildren = 0; /* This is leaf device. */
928 if (nchildren != 0) {
929 for (i = 0; i < nchildren; i++) {
930 /* ensure update on child status */
931 vname = zpool_vdev_name(g_zfs, zphp,
932 nvchild[i], verbose);
933 if (vname == NULL) {
934 be_print_err(gettext(
935 "be_do_installboot: "
936 "failed to get device name: %s\n"),
937 libzfs_error_description(g_zfs));
938 ret = zfs_err_to_be_err(g_zfs);
939 goto done;
940 } else if (verbose == B_TRUE) {
941 be_print_err(gettext(
942 "be_do_installboot: device %s\n"),
943 vname);
945 free(vname);
946 ret = be_do_installboot_helper(zphp, nvchild[i],
947 stage1, stage2, flags);
948 if (ret != BE_SUCCESS)
949 goto done;
951 } else {
952 ret = be_do_installboot_helper(zphp, child[c], stage1,
953 stage2, flags);
954 if (ret != BE_SUCCESS)
955 goto done;
959 done:
960 ZFS_CLOSE(zhp);
961 if (be_mounted)
962 (void) _be_unmount(bt->obe_name, 0);
963 zpool_close(zphp);
964 free(tmp_mntpt);
965 return (ret);
969 * Function: be_promote_zone_ds
970 * Description: This function finds the zones for the BE being activated
971 * and the active zonepath dataset for each zone. Then each
972 * active zonepath dataset is promoted.
974 * Parameters:
975 * be_name - the name of the global zone BE that we need to
976 * find the zones for.
977 * be_root_ds - the root dataset for be_name.
978 * Return:
979 * BE_SUCCESS - Success
980 * be_errno_t - Failure
982 * Scope:
983 * Private
985 static int
986 be_promote_zone_ds(char *be_name, char *be_root_ds)
988 char *zone_ds = NULL;
989 char *temp_mntpt = NULL;
990 char origin[MAXPATHLEN];
991 char zoneroot_ds[MAXPATHLEN];
992 zfs_handle_t *zhp = NULL;
993 zfs_handle_t *z_zhp = NULL;
994 boolean_t be_mounted = B_FALSE;
995 int err = BE_SUCCESS;
996 FILE *cookie;
997 struct zoneent *ze;
999 if ((zhp = zfs_open(g_zfs, be_root_ds,
1000 ZFS_TYPE_FILESYSTEM)) == NULL) {
1001 be_print_err(gettext("be_promote_zone_ds: Failed to open "
1002 "dataset (%s): %s\n"), be_root_ds,
1003 libzfs_error_description(g_zfs));
1004 err = zfs_err_to_be_err(g_zfs);
1005 return (err);
1008 if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1009 if ((err = _be_mount(be_name, &temp_mntpt,
1010 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1011 be_print_err(gettext("be_promote_zone_ds: failed to "
1012 "mount the BE for zones procesing.\n"));
1013 ZFS_CLOSE(zhp);
1014 return (err);
1016 be_mounted = B_TRUE;
1020 * Set the zone root to the temp mount point for the BE we just mounted.
1022 zonecfg_set_root((const char *)temp_mntpt);
1024 cookie = setzoneent();
1025 while((ze = getzoneent_private(cookie)) != NULL) {
1027 if (strcmp(ze->zone_name, "global") == 0)
1028 continue;
1030 /* Skip zones that aren't at least installed */
1031 if (ze->zone_state < ZONE_STATE_INSTALLED)
1032 continue;
1034 if (((zone_ds = be_get_ds_from_dir(ze->zone_path)) == NULL) ||
1035 !be_zone_supported(zone_ds)) {
1036 free(zone_ds);
1037 free(ze);
1038 continue;
1041 if (be_find_active_zone_root(zhp, zone_ds,
1042 zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1043 be_print_err(gettext("be_promote_zone_ds: "
1044 "Zone does not have an active root "
1045 "dataset, skipping this zone.\n"));
1046 continue;
1049 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1050 ZFS_TYPE_FILESYSTEM)) == NULL) {
1051 be_print_err(gettext("be_promote_zone_ds: "
1052 "Failed to open dataset "
1053 "(%s): %s\n"), zoneroot_ds,
1054 libzfs_error_description(g_zfs));
1055 err = zfs_err_to_be_err(g_zfs);
1056 goto done;
1059 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1060 sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1061 ZFS_CLOSE(z_zhp);
1062 continue;
1066 * We don't need to close the zfs handle at this
1067 * point because the callback funtion
1068 * be_promote_ds_callback() will close it for us.
1070 if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1071 be_print_err(gettext("be_promote_zone_ds: "
1072 "failed to activate the "
1073 "datasets for %s: %s\n"),
1074 zoneroot_ds,
1075 libzfs_error_description(g_zfs));
1076 err = BE_ERR_PROMOTE;
1077 goto done;
1079 free(ze);
1081 endzoneent(cookie);
1083 done:
1084 if (be_mounted)
1085 (void) _be_unmount(be_name, 0);
1086 ZFS_CLOSE(zhp);
1087 free(temp_mntpt);
1088 return (err);
1092 * Function: be_promote_ds_callback
1093 * Description: This function is used to promote the datasets for the BE
1094 * being activated as well as the datasets for the zones BE
1095 * being activated.
1097 * Parameters:
1098 * zhp - the zfs handle for zone BE being activated.
1099 * data - not used.
1100 * Return:
1101 * 0 - Success
1102 * be_errno_t - Failure
1104 * Scope:
1105 * Private
1107 static int
1108 /* LINTED */
1109 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1111 char origin[MAXPATHLEN];
1112 char *sub_dataset = NULL;
1113 int ret = 0;
1115 if (zhp != NULL) {
1116 sub_dataset = strdup(zfs_get_name(zhp));
1117 if (sub_dataset == NULL) {
1118 ret = BE_ERR_NOMEM;
1119 goto done;
1121 } else {
1122 be_print_err(gettext("be_promote_ds_callback: "
1123 "Invalid zfs handle passed into function\n"));
1124 ret = BE_ERR_INVAL;
1125 goto done;
1129 * This loop makes sure that we promote the dataset to the
1130 * top of the tree so that it is no longer a decendent of any
1131 * dataset. The ZFS close and then open is used to make sure that
1132 * the promotion is updated before we move on.
1134 while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1135 sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1136 if (zfs_promote(zhp) != 0) {
1137 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1138 be_print_err(gettext("be_promote_ds_callback: "
1139 "promote of %s failed: %s\n"),
1140 zfs_get_name(zhp),
1141 libzfs_error_description(g_zfs));
1142 ret = zfs_err_to_be_err(g_zfs);
1143 goto done;
1144 } else {
1146 * If the call to zfs_promote returns the
1147 * error EZFS_EXISTS we've hit a snapshot name
1148 * collision. This means we're probably
1149 * attemping to promote a zone dataset above a
1150 * parent dataset that belongs to another zone
1151 * which this zone was cloned from.
1153 * TODO: If this is a zone dataset at some
1154 * point we should skip this if the zone
1155 * paths for the dataset and the snapshot
1156 * don't match.
1158 be_print_err(gettext("be_promote_ds_callback: "
1159 "promote of %s failed due to snapshot "
1160 "name collision: %s\n"), zfs_get_name(zhp),
1161 libzfs_error_description(g_zfs));
1162 ret = zfs_err_to_be_err(g_zfs);
1163 goto done;
1166 ZFS_CLOSE(zhp);
1167 if ((zhp = zfs_open(g_zfs, sub_dataset,
1168 ZFS_TYPE_FILESYSTEM)) == NULL) {
1169 be_print_err(gettext("be_promote_ds_callback: "
1170 "Failed to open dataset (%s): %s\n"), sub_dataset,
1171 libzfs_error_description(g_zfs));
1172 ret = zfs_err_to_be_err(g_zfs);
1173 goto done;
1177 /* Iterate down this dataset's children and promote them */
1178 ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1180 done:
1181 free(sub_dataset);
1182 ZFS_CLOSE(zhp);
1183 return (ret);