1f169c0eaSGlenn Lagasse /*
2f169c0eaSGlenn Lagasse * CDDL HEADER START
3f169c0eaSGlenn Lagasse *
4f169c0eaSGlenn Lagasse * The contents of this file are subject to the terms of the
5f169c0eaSGlenn Lagasse * Common Development and Distribution License (the "License").
6f169c0eaSGlenn Lagasse * You may not use this file except in compliance with the License.
7f169c0eaSGlenn Lagasse *
8f169c0eaSGlenn Lagasse * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9f169c0eaSGlenn Lagasse * or http://www.opensolaris.org/os/licensing.
10f169c0eaSGlenn Lagasse * See the License for the specific language governing permissions
11f169c0eaSGlenn Lagasse * and limitations under the License.
12f169c0eaSGlenn Lagasse *
13f169c0eaSGlenn Lagasse * When distributing Covered Code, include this CDDL HEADER in each
14f169c0eaSGlenn Lagasse * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15f169c0eaSGlenn Lagasse * If applicable, add the following below this CDDL HEADER, with the
16f169c0eaSGlenn Lagasse * fields enclosed by brackets "[]" replaced with your own identifying
17f169c0eaSGlenn Lagasse * information: Portions Copyright [yyyy] [name of copyright owner]
18f169c0eaSGlenn Lagasse *
19f169c0eaSGlenn Lagasse * CDDL HEADER END
20f169c0eaSGlenn Lagasse */
21f169c0eaSGlenn Lagasse
22f169c0eaSGlenn Lagasse /*
23f169c0eaSGlenn Lagasse * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24f169c0eaSGlenn Lagasse */
25f169c0eaSGlenn Lagasse
267e0e2549SAlexander Eremin /*
271a902ef8SHans Rosenfeld * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
281a47de4eSToomas Soome * Copyright 2016 Toomas Soome <tsoome@me.com>
29*71668a2fSAndy Fiddaman * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
307e0e2549SAlexander Eremin */
317e0e2549SAlexander Eremin
32f169c0eaSGlenn Lagasse #include <assert.h>
33f169c0eaSGlenn Lagasse #include <libintl.h>
34f169c0eaSGlenn Lagasse #include <libnvpair.h>
35f169c0eaSGlenn Lagasse #include <libzfs.h>
36f169c0eaSGlenn Lagasse #include <stdio.h>
37f169c0eaSGlenn Lagasse #include <stdlib.h>
38f169c0eaSGlenn Lagasse #include <string.h>
391a902ef8SHans Rosenfeld #include <strings.h>
40f169c0eaSGlenn Lagasse #include <errno.h>
41f169c0eaSGlenn Lagasse #include <sys/mnttab.h>
42f169c0eaSGlenn Lagasse #include <sys/types.h>
43f169c0eaSGlenn Lagasse #include <sys/stat.h>
441a902ef8SHans Rosenfeld #include <fcntl.h>
45f169c0eaSGlenn Lagasse #include <unistd.h>
461a902ef8SHans Rosenfeld #include <sys/efi_partition.h>
47f169c0eaSGlenn Lagasse
48f169c0eaSGlenn Lagasse #include <libbe.h>
49f169c0eaSGlenn Lagasse #include <libbe_priv.h>
50f169c0eaSGlenn Lagasse
51f169c0eaSGlenn Lagasse char *mnttab = MNTTAB;
52f169c0eaSGlenn Lagasse
53f169c0eaSGlenn Lagasse /*
54f169c0eaSGlenn Lagasse * Private function prototypes
55f169c0eaSGlenn Lagasse */
56f169c0eaSGlenn Lagasse static int set_bootfs(char *boot_rpool, char *be_root_ds);
57f169c0eaSGlenn Lagasse static int set_canmount(be_node_list_t *, char *);
58a63c99a2SToomas Soome static boolean_t be_do_install_mbr(char *, nvlist_t *);
59a63c99a2SToomas Soome static int be_do_installboot_helper(zpool_handle_t *, nvlist_t *, char *,
60c7c0ceafSToomas Soome char *, uint16_t);
61c7c0ceafSToomas Soome static int be_do_installboot(be_transaction_data_t *, uint16_t);
62f169c0eaSGlenn Lagasse static int be_get_grub_vers(be_transaction_data_t *, char **, char **);
63f169c0eaSGlenn Lagasse static int get_ver_from_capfile(char *, char **);
64f169c0eaSGlenn Lagasse static int be_promote_zone_ds(char *, char *);
65f169c0eaSGlenn Lagasse static int be_promote_ds_callback(zfs_handle_t *, void *);
66f169c0eaSGlenn Lagasse
67f169c0eaSGlenn Lagasse /* ******************************************************************** */
68f169c0eaSGlenn Lagasse /* Public Functions */
69f169c0eaSGlenn Lagasse /* ******************************************************************** */
70f169c0eaSGlenn Lagasse
71f169c0eaSGlenn Lagasse /*
72f169c0eaSGlenn Lagasse * Function: be_activate
73f169c0eaSGlenn Lagasse * Description: Calls _be_activate which activates the BE named in the
74f169c0eaSGlenn Lagasse * attributes passed in through be_attrs. The process of
75f169c0eaSGlenn Lagasse * activation sets the bootfs property of the root pool, resets
76f169c0eaSGlenn Lagasse * the canmount property to noauto, and sets the default in the
77f169c0eaSGlenn Lagasse * grub menu to the entry corresponding to the entry for the named
78f169c0eaSGlenn Lagasse * BE.
79f169c0eaSGlenn Lagasse * Parameters:
80f169c0eaSGlenn Lagasse * be_attrs - pointer to nvlist_t of attributes being passed in.
81f169c0eaSGlenn Lagasse * The follow attribute values are used by this function:
82f169c0eaSGlenn Lagasse *
83f169c0eaSGlenn Lagasse * BE_ATTR_ORIG_BE_NAME *required
84f169c0eaSGlenn Lagasse * Return:
85f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
86f169c0eaSGlenn Lagasse * be_errno_t - Failure
87f169c0eaSGlenn Lagasse * Scope:
88f169c0eaSGlenn Lagasse * Public
89f169c0eaSGlenn Lagasse */
90f169c0eaSGlenn Lagasse int
be_activate(nvlist_t * be_attrs)91f169c0eaSGlenn Lagasse be_activate(nvlist_t *be_attrs)
92f169c0eaSGlenn Lagasse {
93f169c0eaSGlenn Lagasse int ret = BE_SUCCESS;
94f169c0eaSGlenn Lagasse char *be_name = NULL;
95f169c0eaSGlenn Lagasse
96f169c0eaSGlenn Lagasse /* Initialize libzfs handle */
97f169c0eaSGlenn Lagasse if (!be_zfs_init())
98f169c0eaSGlenn Lagasse return (BE_ERR_INIT);
99f169c0eaSGlenn Lagasse
100f169c0eaSGlenn Lagasse /* Get the BE name to activate */
101f169c0eaSGlenn Lagasse if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
102f169c0eaSGlenn Lagasse != 0) {
103f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to "
104f169c0eaSGlenn Lagasse "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
105f169c0eaSGlenn Lagasse be_zfs_fini();
106f169c0eaSGlenn Lagasse return (BE_ERR_INVAL);
107f169c0eaSGlenn Lagasse }
108f169c0eaSGlenn Lagasse
109f169c0eaSGlenn Lagasse /* Validate BE name */
110f169c0eaSGlenn Lagasse if (!be_valid_be_name(be_name)) {
111f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: invalid BE name %s\n"),
112f169c0eaSGlenn Lagasse be_name);
113f169c0eaSGlenn Lagasse be_zfs_fini();
114f169c0eaSGlenn Lagasse return (BE_ERR_INVAL);
115f169c0eaSGlenn Lagasse }
116f169c0eaSGlenn Lagasse
117f169c0eaSGlenn Lagasse ret = _be_activate(be_name);
118f169c0eaSGlenn Lagasse
119f169c0eaSGlenn Lagasse be_zfs_fini();
120f169c0eaSGlenn Lagasse
121f169c0eaSGlenn Lagasse return (ret);
122f169c0eaSGlenn Lagasse }
123f169c0eaSGlenn Lagasse
124c7c0ceafSToomas Soome /*
125c7c0ceafSToomas Soome * Function: be_installboot
126c7c0ceafSToomas Soome * Description: Calls be_do_installboot to install/update bootloader on
127c7c0ceafSToomas Soome * pool passed in through be_attrs. The primary consumer is
128c7c0ceafSToomas Soome * bootadm command to avoid duplication of the code.
129c7c0ceafSToomas Soome * Parameters:
130c7c0ceafSToomas Soome * be_attrs - pointer to nvlist_t of attributes being passed in.
131c7c0ceafSToomas Soome * The following attribute values are used:
132c7c0ceafSToomas Soome *
133c7c0ceafSToomas Soome * BE_ATTR_ORIG_BE_NAME *required
134c7c0ceafSToomas Soome * BE_ATTR_ORIG_BE_POOL *required
135c7c0ceafSToomas Soome * BE_ATTR_ORIG_BE_ROOT *required
136c7c0ceafSToomas Soome * BE_ATTR_INSTALL_FLAGS optional
137c7c0ceafSToomas Soome *
138c7c0ceafSToomas Soome * Return:
139c7c0ceafSToomas Soome * BE_SUCCESS - Success
140c7c0ceafSToomas Soome * be_errno_t - Failure
141c7c0ceafSToomas Soome * Scope:
142c7c0ceafSToomas Soome * Public
143c7c0ceafSToomas Soome */
144c7c0ceafSToomas Soome int
be_installboot(nvlist_t * be_attrs)145c7c0ceafSToomas Soome be_installboot(nvlist_t *be_attrs)
146c7c0ceafSToomas Soome {
147c7c0ceafSToomas Soome int ret = BE_SUCCESS;
148c7c0ceafSToomas Soome uint16_t flags = 0;
149c7c0ceafSToomas Soome uint16_t verbose;
150c7c0ceafSToomas Soome be_transaction_data_t bt = { 0 };
151c7c0ceafSToomas Soome
152c7c0ceafSToomas Soome /* Get flags */
153c7c0ceafSToomas Soome if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
154c7c0ceafSToomas Soome BE_ATTR_INSTALL_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
155c7c0ceafSToomas Soome be_print_err(gettext("be_installboot: failed to lookup "
156c7c0ceafSToomas Soome "BE_ATTR_INSTALL_FLAGS attribute\n"));
157c7c0ceafSToomas Soome return (BE_ERR_INVAL);
158c7c0ceafSToomas Soome }
159c7c0ceafSToomas Soome
160c7c0ceafSToomas Soome /* Set verbose early, so we get all messages */
161c7c0ceafSToomas Soome verbose = flags & BE_INSTALLBOOT_FLAG_VERBOSE;
162c7c0ceafSToomas Soome if (verbose == BE_INSTALLBOOT_FLAG_VERBOSE)
163c7c0ceafSToomas Soome libbe_print_errors(B_TRUE);
164c7c0ceafSToomas Soome
165c7c0ceafSToomas Soome ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
166c7c0ceafSToomas Soome &bt.obe_name);
167c7c0ceafSToomas Soome if (ret != 0) {
168c7c0ceafSToomas Soome be_print_err(gettext("be_installboot: failed to "
169c7c0ceafSToomas Soome "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
170c7c0ceafSToomas Soome return (BE_ERR_INVAL);
171c7c0ceafSToomas Soome }
172c7c0ceafSToomas Soome
173c7c0ceafSToomas Soome ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_POOL,
174c7c0ceafSToomas Soome &bt.obe_zpool);
175c7c0ceafSToomas Soome if (ret != 0) {
176c7c0ceafSToomas Soome be_print_err(gettext("be_installboot: failed to "
177c7c0ceafSToomas Soome "lookup BE_ATTR_ORIG_BE_POOL attribute\n"));
178c7c0ceafSToomas Soome return (BE_ERR_INVAL);
179c7c0ceafSToomas Soome }
180c7c0ceafSToomas Soome
181c7c0ceafSToomas Soome ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_ROOT,
182c7c0ceafSToomas Soome &bt.obe_root_ds);
183c7c0ceafSToomas Soome if (ret != 0) {
184c7c0ceafSToomas Soome be_print_err(gettext("be_installboot: failed to "
185c7c0ceafSToomas Soome "lookup BE_ATTR_ORIG_BE_ROOT attribute\n"));
186c7c0ceafSToomas Soome return (BE_ERR_INVAL);
187c7c0ceafSToomas Soome }
188c7c0ceafSToomas Soome
189c7c0ceafSToomas Soome /* Initialize libzfs handle */
190c7c0ceafSToomas Soome if (!be_zfs_init())
191c7c0ceafSToomas Soome return (BE_ERR_INIT);
192c7c0ceafSToomas Soome
193c7c0ceafSToomas Soome ret = be_do_installboot(&bt, flags);
194c7c0ceafSToomas Soome
195c7c0ceafSToomas Soome be_zfs_fini();
196c7c0ceafSToomas Soome
197c7c0ceafSToomas Soome return (ret);
198c7c0ceafSToomas Soome }
199c7c0ceafSToomas Soome
200f169c0eaSGlenn Lagasse /* ******************************************************************** */
201f169c0eaSGlenn Lagasse /* Semi Private Functions */
202f169c0eaSGlenn Lagasse /* ******************************************************************** */
203f169c0eaSGlenn Lagasse
204f169c0eaSGlenn Lagasse /*
205f169c0eaSGlenn Lagasse * Function: _be_activate
206f169c0eaSGlenn Lagasse * Description: This does the actual work described in be_activate.
207f169c0eaSGlenn Lagasse * Parameters:
208f169c0eaSGlenn Lagasse * be_name - pointer to the name of BE to activate.
209f169c0eaSGlenn Lagasse *
210f169c0eaSGlenn Lagasse * Return:
211f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
212f169c0eaSGlenn Lagasse * be_errnot_t - Failure
213f169c0eaSGlenn Lagasse * Scope:
214f169c0eaSGlenn Lagasse * Public
215f169c0eaSGlenn Lagasse */
216f169c0eaSGlenn Lagasse int
_be_activate(char * be_name)217f169c0eaSGlenn Lagasse _be_activate(char *be_name)
218f169c0eaSGlenn Lagasse {
219f169c0eaSGlenn Lagasse be_transaction_data_t cb = { 0 };
220f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
221f169c0eaSGlenn Lagasse char root_ds[MAXPATHLEN];
2227e0e2549SAlexander Eremin char active_ds[MAXPATHLEN];
223f169c0eaSGlenn Lagasse be_node_list_t *be_nodes = NULL;
224f169c0eaSGlenn Lagasse uuid_t uu = {0};
225f169c0eaSGlenn Lagasse int entry, ret = BE_SUCCESS;
226f169c0eaSGlenn Lagasse int zret = 0;
227f169c0eaSGlenn Lagasse
228f169c0eaSGlenn Lagasse /*
229f169c0eaSGlenn Lagasse * TODO: The BE needs to be validated to make sure that it is actually
230f169c0eaSGlenn Lagasse * a bootable BE.
231f169c0eaSGlenn Lagasse */
232f169c0eaSGlenn Lagasse
233f169c0eaSGlenn Lagasse if (be_name == NULL)
234f169c0eaSGlenn Lagasse return (BE_ERR_INVAL);
235f169c0eaSGlenn Lagasse
236f169c0eaSGlenn Lagasse /* Set obe_name to be_name in the cb structure */
237f169c0eaSGlenn Lagasse cb.obe_name = be_name;
238f169c0eaSGlenn Lagasse
239f169c0eaSGlenn Lagasse /* find which zpool the be is in */
240f169c0eaSGlenn Lagasse if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
241f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to "
242f169c0eaSGlenn Lagasse "find zpool for BE (%s)\n"), cb.obe_name);
243f169c0eaSGlenn Lagasse return (BE_ERR_BE_NOENT);
244f169c0eaSGlenn Lagasse } else if (zret < 0) {
245f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: "
246f169c0eaSGlenn Lagasse "zpool_iter failed: %s\n"),
247f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
248f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs);
249f169c0eaSGlenn Lagasse return (ret);
250f169c0eaSGlenn Lagasse }
251f169c0eaSGlenn Lagasse
252f169c0eaSGlenn Lagasse be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
253f169c0eaSGlenn Lagasse cb.obe_root_ds = strdup(root_ds);
254f169c0eaSGlenn Lagasse
255f169c0eaSGlenn Lagasse if (getzoneid() == GLOBAL_ZONEID) {
256c7c0ceafSToomas Soome ret = be_do_installboot(&cb, BE_INSTALLBOOT_FLAG_NULL);
257c7c0ceafSToomas Soome if (ret != BE_SUCCESS)
258f169c0eaSGlenn Lagasse return (ret);
259a63c99a2SToomas Soome
260f169c0eaSGlenn Lagasse if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
261f169c0eaSGlenn Lagasse if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
262f169c0eaSGlenn Lagasse NULL, NULL, NULL)) != BE_SUCCESS) {
263f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: Failed to "
264a63c99a2SToomas Soome "add BE (%s) to the menu\n"),
265f169c0eaSGlenn Lagasse cb.obe_name);
266f169c0eaSGlenn Lagasse goto done;
267f169c0eaSGlenn Lagasse }
268f169c0eaSGlenn Lagasse }
269f169c0eaSGlenn Lagasse if (be_has_grub()) {
270f169c0eaSGlenn Lagasse if ((ret = be_change_grub_default(cb.obe_name,
271f169c0eaSGlenn Lagasse cb.obe_zpool)) != BE_SUCCESS) {
272f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to "
273f169c0eaSGlenn Lagasse "change the default entry in menu.lst\n"));
274f169c0eaSGlenn Lagasse goto done;
275f169c0eaSGlenn Lagasse }
276f169c0eaSGlenn Lagasse }
277f169c0eaSGlenn Lagasse }
278f169c0eaSGlenn Lagasse
279*71668a2fSAndy Fiddaman if ((ret = _be_list(cb.obe_name, &be_nodes, BE_LIST_DEFAULT))
280*71668a2fSAndy Fiddaman != BE_SUCCESS) {
281f169c0eaSGlenn Lagasse return (ret);
282f169c0eaSGlenn Lagasse }
283f169c0eaSGlenn Lagasse
284f169c0eaSGlenn Lagasse if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
285f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to set "
286f169c0eaSGlenn Lagasse "canmount dataset property\n"));
287f169c0eaSGlenn Lagasse goto done;
288f169c0eaSGlenn Lagasse }
289f169c0eaSGlenn Lagasse
2907e0e2549SAlexander Eremin if (getzoneid() == GLOBAL_ZONEID) {
2917e0e2549SAlexander Eremin if ((ret = set_bootfs(be_nodes->be_rpool,
2927e0e2549SAlexander Eremin root_ds)) != BE_SUCCESS) {
293f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to set "
294f169c0eaSGlenn Lagasse "bootfs pool property for %s\n"), root_ds);
295f169c0eaSGlenn Lagasse goto done;
296f169c0eaSGlenn Lagasse }
2977e0e2549SAlexander Eremin }
298f169c0eaSGlenn Lagasse
299f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
300f169c0eaSGlenn Lagasse /*
301f169c0eaSGlenn Lagasse * We don't need to close the zfs handle at this
302f169c0eaSGlenn Lagasse * point because The callback funtion
303f169c0eaSGlenn Lagasse * be_promote_ds_callback() will close it for us.
304f169c0eaSGlenn Lagasse */
305f169c0eaSGlenn Lagasse if (be_promote_ds_callback(zhp, NULL) != 0) {
306f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: "
307f169c0eaSGlenn Lagasse "failed to activate the "
308f169c0eaSGlenn Lagasse "datasets for %s: %s\n"),
309f169c0eaSGlenn Lagasse root_ds,
310f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
311f169c0eaSGlenn Lagasse ret = BE_ERR_PROMOTE;
312f169c0eaSGlenn Lagasse goto done;
313f169c0eaSGlenn Lagasse }
314f169c0eaSGlenn Lagasse } else {
3157e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to open "
316f169c0eaSGlenn Lagasse "dataset (%s): %s\n"), root_ds,
317f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
318f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs);
319f169c0eaSGlenn Lagasse goto done;
320f169c0eaSGlenn Lagasse }
321f169c0eaSGlenn Lagasse
322f169c0eaSGlenn Lagasse if (getzoneid() == GLOBAL_ZONEID &&
323f169c0eaSGlenn Lagasse be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
324f169c0eaSGlenn Lagasse (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
325f169c0eaSGlenn Lagasse != BE_SUCCESS) {
326f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate: failed to promote "
327f169c0eaSGlenn Lagasse "the active zonepath datasets for zones in BE %s\n"),
328f169c0eaSGlenn Lagasse cb.obe_name);
329f169c0eaSGlenn Lagasse }
330f169c0eaSGlenn Lagasse
3317e0e2549SAlexander Eremin if (getzoneid() != GLOBAL_ZONEID) {
3327e0e2549SAlexander Eremin if (!be_zone_compare_uuids(root_ds)) {
3337e0e2549SAlexander Eremin be_print_err(gettext("be_activate: activating zone "
3347e0e2549SAlexander Eremin "root dataset from non-active global BE is not "
3357e0e2549SAlexander Eremin "supported\n"));
3367e0e2549SAlexander Eremin ret = BE_ERR_NOTSUP;
3377e0e2549SAlexander Eremin goto done;
3387e0e2549SAlexander Eremin }
3397e0e2549SAlexander Eremin if ((zhp = zfs_open(g_zfs, root_ds,
3407e0e2549SAlexander Eremin ZFS_TYPE_FILESYSTEM)) == NULL) {
3417e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to open "
3427e0e2549SAlexander Eremin "dataset (%s): %s\n"), root_ds,
3437e0e2549SAlexander Eremin libzfs_error_description(g_zfs));
3447e0e2549SAlexander Eremin ret = zfs_err_to_be_err(g_zfs);
3457e0e2549SAlexander Eremin goto done;
3467e0e2549SAlexander Eremin }
3477e0e2549SAlexander Eremin /* Find current active zone root dataset */
3487e0e2549SAlexander Eremin if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
3497e0e2549SAlexander Eremin active_ds, sizeof (active_ds))) != BE_SUCCESS) {
3507e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to find "
3517e0e2549SAlexander Eremin "active zone root dataset\n"));
3527e0e2549SAlexander Eremin ZFS_CLOSE(zhp);
3537e0e2549SAlexander Eremin goto done;
3547e0e2549SAlexander Eremin }
3557e0e2549SAlexander Eremin /* Do nothing if requested BE is already active */
3567e0e2549SAlexander Eremin if (strcmp(root_ds, active_ds) == 0) {
3577e0e2549SAlexander Eremin ret = BE_SUCCESS;
3587e0e2549SAlexander Eremin ZFS_CLOSE(zhp);
3597e0e2549SAlexander Eremin goto done;
3607e0e2549SAlexander Eremin }
3617e0e2549SAlexander Eremin
3627e0e2549SAlexander Eremin /* Set active property for BE */
3637e0e2549SAlexander Eremin if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
3647e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to set "
3657e0e2549SAlexander Eremin "active property (%s): %s\n"), root_ds,
3667e0e2549SAlexander Eremin libzfs_error_description(g_zfs));
3677e0e2549SAlexander Eremin ret = zfs_err_to_be_err(g_zfs);
3687e0e2549SAlexander Eremin ZFS_CLOSE(zhp);
3697e0e2549SAlexander Eremin goto done;
3707e0e2549SAlexander Eremin }
3717e0e2549SAlexander Eremin ZFS_CLOSE(zhp);
3727e0e2549SAlexander Eremin
3737e0e2549SAlexander Eremin /* Unset active property for old active root dataset */
3747e0e2549SAlexander Eremin if ((zhp = zfs_open(g_zfs, active_ds,
3757e0e2549SAlexander Eremin ZFS_TYPE_FILESYSTEM)) == NULL) {
3767e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to open "
3777e0e2549SAlexander Eremin "dataset (%s): %s\n"), active_ds,
3787e0e2549SAlexander Eremin libzfs_error_description(g_zfs));
3797e0e2549SAlexander Eremin ret = zfs_err_to_be_err(g_zfs);
3807e0e2549SAlexander Eremin goto done;
3817e0e2549SAlexander Eremin }
3827e0e2549SAlexander Eremin if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
3837e0e2549SAlexander Eremin be_print_err(gettext("be_activate: failed to unset "
3847e0e2549SAlexander Eremin "active property (%s): %s\n"), active_ds,
3857e0e2549SAlexander Eremin libzfs_error_description(g_zfs));
3867e0e2549SAlexander Eremin ret = zfs_err_to_be_err(g_zfs);
3877e0e2549SAlexander Eremin ZFS_CLOSE(zhp);
3887e0e2549SAlexander Eremin goto done;
3897e0e2549SAlexander Eremin }
3907e0e2549SAlexander Eremin ZFS_CLOSE(zhp);
3917e0e2549SAlexander Eremin }
392f169c0eaSGlenn Lagasse done:
393f169c0eaSGlenn Lagasse be_free_list(be_nodes);
394f169c0eaSGlenn Lagasse return (ret);
395f169c0eaSGlenn Lagasse }
396f169c0eaSGlenn Lagasse
397f169c0eaSGlenn Lagasse /*
398f169c0eaSGlenn Lagasse * Function: be_activate_current_be
399f169c0eaSGlenn Lagasse * Description: Set the currently "active" BE to be "active on boot"
400f169c0eaSGlenn Lagasse * Paramters:
401f169c0eaSGlenn Lagasse * none
402f169c0eaSGlenn Lagasse * Returns:
403f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
404f169c0eaSGlenn Lagasse * be_errnot_t - Failure
405f169c0eaSGlenn Lagasse * Scope:
406f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
407f169c0eaSGlenn Lagasse */
408f169c0eaSGlenn Lagasse int
be_activate_current_be(void)409f169c0eaSGlenn Lagasse be_activate_current_be(void)
410f169c0eaSGlenn Lagasse {
411f169c0eaSGlenn Lagasse int ret = BE_SUCCESS;
412f169c0eaSGlenn Lagasse be_transaction_data_t bt = { 0 };
413f169c0eaSGlenn Lagasse
414f169c0eaSGlenn Lagasse if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
415f169c0eaSGlenn Lagasse return (ret);
416f169c0eaSGlenn Lagasse }
417f169c0eaSGlenn Lagasse
418f169c0eaSGlenn Lagasse if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
419f169c0eaSGlenn Lagasse be_print_err(gettext("be_activate_current_be: failed to "
420f169c0eaSGlenn Lagasse "activate %s\n"), bt.obe_name);
421f169c0eaSGlenn Lagasse return (ret);
422f169c0eaSGlenn Lagasse }
423f169c0eaSGlenn Lagasse
424f169c0eaSGlenn Lagasse return (BE_SUCCESS);
425f169c0eaSGlenn Lagasse }
426f169c0eaSGlenn Lagasse
427f169c0eaSGlenn Lagasse /*
428f169c0eaSGlenn Lagasse * Function: be_is_active_on_boot
429f169c0eaSGlenn Lagasse * Description: Checks if the BE name passed in has the "active on boot"
430f169c0eaSGlenn Lagasse * property set to B_TRUE.
431f169c0eaSGlenn Lagasse * Paramters:
432f169c0eaSGlenn Lagasse * be_name - the name of the BE to check
433f169c0eaSGlenn Lagasse * Returns:
434f169c0eaSGlenn Lagasse * B_TRUE - if active on boot.
435f169c0eaSGlenn Lagasse * B_FALSE - if not active on boot.
436f169c0eaSGlenn Lagasse * Scope:
437f169c0eaSGlenn Lagasse * Semi-private (library wide use only)
438f169c0eaSGlenn Lagasse */
439f169c0eaSGlenn Lagasse boolean_t
be_is_active_on_boot(char * be_name)440f169c0eaSGlenn Lagasse be_is_active_on_boot(char *be_name)
441f169c0eaSGlenn Lagasse {
442f169c0eaSGlenn Lagasse be_node_list_t *be_node = NULL;
443f169c0eaSGlenn Lagasse
444f169c0eaSGlenn Lagasse if (be_name == NULL) {
445f169c0eaSGlenn Lagasse be_print_err(gettext("be_is_active_on_boot: "
446f169c0eaSGlenn Lagasse "be_name must not be NULL\n"));
447f169c0eaSGlenn Lagasse return (B_FALSE);
448f169c0eaSGlenn Lagasse }
449f169c0eaSGlenn Lagasse
450*71668a2fSAndy Fiddaman if (_be_list(be_name, &be_node, BE_LIST_DEFAULT) != BE_SUCCESS) {
451f169c0eaSGlenn Lagasse return (B_FALSE);
452f169c0eaSGlenn Lagasse }
453f169c0eaSGlenn Lagasse
454f169c0eaSGlenn Lagasse if (be_node == NULL) {
455f169c0eaSGlenn Lagasse return (B_FALSE);
456f169c0eaSGlenn Lagasse }
457f169c0eaSGlenn Lagasse
458f169c0eaSGlenn Lagasse if (be_node->be_active_on_boot) {
459f169c0eaSGlenn Lagasse be_free_list(be_node);
460f169c0eaSGlenn Lagasse return (B_TRUE);
461f169c0eaSGlenn Lagasse } else {
462f169c0eaSGlenn Lagasse be_free_list(be_node);
463f169c0eaSGlenn Lagasse return (B_FALSE);
464f169c0eaSGlenn Lagasse }
465f169c0eaSGlenn Lagasse }
466f169c0eaSGlenn Lagasse
467f169c0eaSGlenn Lagasse /* ******************************************************************** */
468f169c0eaSGlenn Lagasse /* Private Functions */
469f169c0eaSGlenn Lagasse /* ******************************************************************** */
470f169c0eaSGlenn Lagasse
471f169c0eaSGlenn Lagasse /*
472f169c0eaSGlenn Lagasse * Function: set_bootfs
473f169c0eaSGlenn Lagasse * Description: Sets the bootfs property on the boot pool to be the
474f169c0eaSGlenn Lagasse * root dataset of the activated BE.
475f169c0eaSGlenn Lagasse * Parameters:
476f169c0eaSGlenn Lagasse * boot_pool - The pool we're setting bootfs in.
477f169c0eaSGlenn Lagasse * be_root_ds - The main dataset for the BE.
478f169c0eaSGlenn Lagasse * Return:
479f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
480f169c0eaSGlenn Lagasse * be_errno_t - Failure
481f169c0eaSGlenn Lagasse * Scope:
482f169c0eaSGlenn Lagasse * Private
483f169c0eaSGlenn Lagasse */
484f169c0eaSGlenn Lagasse static int
set_bootfs(char * boot_rpool,char * be_root_ds)485f169c0eaSGlenn Lagasse set_bootfs(char *boot_rpool, char *be_root_ds)
486f169c0eaSGlenn Lagasse {
487f169c0eaSGlenn Lagasse zpool_handle_t *zhp;
488f169c0eaSGlenn Lagasse int err = BE_SUCCESS;
489f169c0eaSGlenn Lagasse
490f169c0eaSGlenn Lagasse if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
491f169c0eaSGlenn Lagasse be_print_err(gettext("set_bootfs: failed to open pool "
492f169c0eaSGlenn Lagasse "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
493f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs);
494f169c0eaSGlenn Lagasse return (err);
495f169c0eaSGlenn Lagasse }
496f169c0eaSGlenn Lagasse
497f169c0eaSGlenn Lagasse err = zpool_set_prop(zhp, "bootfs", be_root_ds);
498f169c0eaSGlenn Lagasse if (err) {
499f169c0eaSGlenn Lagasse be_print_err(gettext("set_bootfs: failed to set "
500f169c0eaSGlenn Lagasse "bootfs property for pool %s: %s\n"), boot_rpool,
501f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
502f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs);
503f169c0eaSGlenn Lagasse zpool_close(zhp);
504f169c0eaSGlenn Lagasse return (err);
505f169c0eaSGlenn Lagasse }
506f169c0eaSGlenn Lagasse
507f169c0eaSGlenn Lagasse zpool_close(zhp);
508f169c0eaSGlenn Lagasse return (BE_SUCCESS);
509f169c0eaSGlenn Lagasse }
510f169c0eaSGlenn Lagasse
511f169c0eaSGlenn Lagasse /*
512f169c0eaSGlenn Lagasse * Function: set_canmount
513f169c0eaSGlenn Lagasse * Description: Sets the canmount property on the datasets of the
514f169c0eaSGlenn Lagasse * activated BE.
515f169c0eaSGlenn Lagasse * Parameters:
516f169c0eaSGlenn Lagasse * be_nodes - The be_node_t returned from be_list
517f169c0eaSGlenn Lagasse * value - The value of canmount we setting, on|off|noauto.
518f169c0eaSGlenn Lagasse * Return:
519f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
520f169c0eaSGlenn Lagasse * be_errno_t - Failure
521f169c0eaSGlenn Lagasse * Scope:
522f169c0eaSGlenn Lagasse * Private
523f169c0eaSGlenn Lagasse */
524f169c0eaSGlenn Lagasse static int
set_canmount(be_node_list_t * be_nodes,char * value)525f169c0eaSGlenn Lagasse set_canmount(be_node_list_t *be_nodes, char *value)
526f169c0eaSGlenn Lagasse {
527f169c0eaSGlenn Lagasse char ds_path[MAXPATHLEN];
528f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
529f169c0eaSGlenn Lagasse be_node_list_t *list = be_nodes;
530f169c0eaSGlenn Lagasse int err = BE_SUCCESS;
531f169c0eaSGlenn Lagasse
532f169c0eaSGlenn Lagasse while (list != NULL) {
533f169c0eaSGlenn Lagasse be_dataset_list_t *datasets = list->be_node_datasets;
534f169c0eaSGlenn Lagasse
535f169c0eaSGlenn Lagasse be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
536f169c0eaSGlenn Lagasse sizeof (ds_path));
537f169c0eaSGlenn Lagasse
538f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
539f169c0eaSGlenn Lagasse NULL) {
540f169c0eaSGlenn Lagasse be_print_err(gettext("set_canmount: failed to open "
541f169c0eaSGlenn Lagasse "dataset (%s): %s\n"), ds_path,
542f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
543f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs);
544f169c0eaSGlenn Lagasse return (err);
545f169c0eaSGlenn Lagasse }
546f169c0eaSGlenn Lagasse if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
547f169c0eaSGlenn Lagasse /*
548f169c0eaSGlenn Lagasse * it's already mounted so we can't change the
549f169c0eaSGlenn Lagasse * canmount property anyway.
550f169c0eaSGlenn Lagasse */
551f169c0eaSGlenn Lagasse err = BE_SUCCESS;
552f169c0eaSGlenn Lagasse } else {
553f169c0eaSGlenn Lagasse err = zfs_prop_set(zhp,
554f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
555f169c0eaSGlenn Lagasse if (err) {
556f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
557f169c0eaSGlenn Lagasse be_print_err(gettext("set_canmount: failed to "
558f169c0eaSGlenn Lagasse "set dataset property (%s): %s\n"),
559f169c0eaSGlenn Lagasse ds_path, libzfs_error_description(g_zfs));
560f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs);
561f169c0eaSGlenn Lagasse return (err);
562f169c0eaSGlenn Lagasse }
563f169c0eaSGlenn Lagasse }
564f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
565f169c0eaSGlenn Lagasse
566f169c0eaSGlenn Lagasse while (datasets != NULL) {
567f169c0eaSGlenn Lagasse be_make_root_ds(list->be_rpool,
568f169c0eaSGlenn Lagasse datasets->be_dataset_name, ds_path,
569f169c0eaSGlenn Lagasse sizeof (ds_path));
570f169c0eaSGlenn Lagasse
571f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
572f169c0eaSGlenn Lagasse == NULL) {
573f169c0eaSGlenn Lagasse be_print_err(gettext("set_canmount: failed to "
574f169c0eaSGlenn Lagasse "open dataset %s: %s\n"), ds_path,
575f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
576f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs);
577f169c0eaSGlenn Lagasse return (err);
578f169c0eaSGlenn Lagasse }
579f169c0eaSGlenn Lagasse if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
580f169c0eaSGlenn Lagasse /*
581f169c0eaSGlenn Lagasse * it's already mounted so we can't change the
582f169c0eaSGlenn Lagasse * canmount property anyway.
583f169c0eaSGlenn Lagasse */
584f169c0eaSGlenn Lagasse err = BE_SUCCESS;
585f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
586f169c0eaSGlenn Lagasse break;
587f169c0eaSGlenn Lagasse }
588f169c0eaSGlenn Lagasse err = zfs_prop_set(zhp,
589f169c0eaSGlenn Lagasse zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
590f169c0eaSGlenn Lagasse if (err) {
591f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
592f169c0eaSGlenn Lagasse be_print_err(gettext("set_canmount: "
593f169c0eaSGlenn Lagasse "Failed to set property value %s "
594f169c0eaSGlenn Lagasse "for dataset %s: %s\n"), value, ds_path,
595f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
596f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs);
597f169c0eaSGlenn Lagasse return (err);
598f169c0eaSGlenn Lagasse }
599f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
600f169c0eaSGlenn Lagasse datasets = datasets->be_next_dataset;
601f169c0eaSGlenn Lagasse }
602f169c0eaSGlenn Lagasse list = list->be_next_node;
603f169c0eaSGlenn Lagasse }
604f169c0eaSGlenn Lagasse return (err);
605f169c0eaSGlenn Lagasse }
606f169c0eaSGlenn Lagasse
607f169c0eaSGlenn Lagasse /*
608f169c0eaSGlenn Lagasse * Function: be_get_grub_vers
609f169c0eaSGlenn Lagasse * Description: Gets the grub version number from /boot/grub/capability. If
610f169c0eaSGlenn Lagasse * capability file doesn't exist NULL is returned.
611f169c0eaSGlenn Lagasse * Parameters:
612f169c0eaSGlenn Lagasse * bt - The transaction data for the BE we're getting the grub
613f169c0eaSGlenn Lagasse * version for.
614f169c0eaSGlenn Lagasse * cur_vers - used to return the current version of grub from
615f169c0eaSGlenn Lagasse * the root pool.
616f169c0eaSGlenn Lagasse * new_vers - used to return the grub version of the BE we're
617f169c0eaSGlenn Lagasse * activating.
618f169c0eaSGlenn Lagasse * Return:
619f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
620f169c0eaSGlenn Lagasse * be_errno_t - Failed to find version
621f169c0eaSGlenn Lagasse * Scope:
622f169c0eaSGlenn Lagasse * Private
623f169c0eaSGlenn Lagasse */
624f169c0eaSGlenn Lagasse static int
be_get_grub_vers(be_transaction_data_t * bt,char ** cur_vers,char ** new_vers)625f169c0eaSGlenn Lagasse be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
626f169c0eaSGlenn Lagasse {
627f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
628f169c0eaSGlenn Lagasse zfs_handle_t *pool_zhp = NULL;
629f169c0eaSGlenn Lagasse int ret = BE_SUCCESS;
630f169c0eaSGlenn Lagasse char cap_file[MAXPATHLEN];
631f169c0eaSGlenn Lagasse char *temp_mntpnt = NULL;
632f169c0eaSGlenn Lagasse char *zpool_mntpt = NULL;
633f169c0eaSGlenn Lagasse char *ptmp_mntpnt = NULL;
634f169c0eaSGlenn Lagasse char *orig_mntpnt = NULL;
635f169c0eaSGlenn Lagasse boolean_t be_mounted = B_FALSE;
636f169c0eaSGlenn Lagasse boolean_t pool_mounted = B_FALSE;
637f169c0eaSGlenn Lagasse
638f169c0eaSGlenn Lagasse if (!be_has_grub()) {
639f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: Not supported on "
640f169c0eaSGlenn Lagasse "this architecture\n"));
641f169c0eaSGlenn Lagasse return (BE_ERR_NOTSUP);
642f169c0eaSGlenn Lagasse }
643f169c0eaSGlenn Lagasse
644f169c0eaSGlenn Lagasse if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL ||
645f169c0eaSGlenn Lagasse bt->obe_root_ds == NULL) {
646f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: Invalid BE\n"));
647f169c0eaSGlenn Lagasse return (BE_ERR_INVAL);
648f169c0eaSGlenn Lagasse }
649f169c0eaSGlenn Lagasse
650f169c0eaSGlenn Lagasse if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
651f169c0eaSGlenn Lagasse NULL) {
652f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"),
653f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
654f169c0eaSGlenn Lagasse return (zfs_err_to_be_err(g_zfs));
655f169c0eaSGlenn Lagasse }
656f169c0eaSGlenn Lagasse
657f169c0eaSGlenn Lagasse /*
658f169c0eaSGlenn Lagasse * Check to see if the pool's dataset is mounted. If it isn't we'll
659f169c0eaSGlenn Lagasse * attempt to mount it.
660f169c0eaSGlenn Lagasse */
661f169c0eaSGlenn Lagasse if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt,
662f169c0eaSGlenn Lagasse &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
663f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: pool dataset "
664f169c0eaSGlenn Lagasse "(%s) could not be mounted\n"), bt->obe_zpool);
665f169c0eaSGlenn Lagasse ZFS_CLOSE(pool_zhp);
666f169c0eaSGlenn Lagasse return (ret);
667f169c0eaSGlenn Lagasse }
668f169c0eaSGlenn Lagasse
669f169c0eaSGlenn Lagasse /*
670f169c0eaSGlenn Lagasse * Get the mountpoint for the root pool dataset.
671f169c0eaSGlenn Lagasse */
672f169c0eaSGlenn Lagasse if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) {
673f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: pool "
674a63c99a2SToomas Soome "dataset (%s) is not mounted. Can't read the "
675a63c99a2SToomas Soome "grub capability file.\n"), bt->obe_zpool);
676f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
677f169c0eaSGlenn Lagasse goto cleanup;
678f169c0eaSGlenn Lagasse }
679f169c0eaSGlenn Lagasse
680f169c0eaSGlenn Lagasse /*
681f169c0eaSGlenn Lagasse * get the version of the most recent grub update.
682f169c0eaSGlenn Lagasse */
683f169c0eaSGlenn Lagasse (void) snprintf(cap_file, sizeof (cap_file), "%s%s",
684f169c0eaSGlenn Lagasse zpool_mntpt, BE_CAP_FILE);
685f169c0eaSGlenn Lagasse free(zpool_mntpt);
686f169c0eaSGlenn Lagasse zpool_mntpt = NULL;
687f169c0eaSGlenn Lagasse
688f169c0eaSGlenn Lagasse if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
689f169c0eaSGlenn Lagasse goto cleanup;
690f169c0eaSGlenn Lagasse
691f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
692f169c0eaSGlenn Lagasse NULL) {
693f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: failed to "
694f169c0eaSGlenn Lagasse "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
695f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
696f169c0eaSGlenn Lagasse free(cur_vers);
697f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs);
698f169c0eaSGlenn Lagasse goto cleanup;
699f169c0eaSGlenn Lagasse }
700f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &temp_mntpnt)) {
701f169c0eaSGlenn Lagasse if ((ret = _be_mount(bt->obe_name, &temp_mntpnt,
702f169c0eaSGlenn Lagasse BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
703f169c0eaSGlenn Lagasse be_print_err(gettext("be_get_grub_vers: failed to "
704f169c0eaSGlenn Lagasse "mount BE (%s)\n"), bt->obe_name);
705f169c0eaSGlenn Lagasse free(*cur_vers);
706f169c0eaSGlenn Lagasse *cur_vers = NULL;
707f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
708f169c0eaSGlenn Lagasse goto cleanup;
709f169c0eaSGlenn Lagasse }
710f169c0eaSGlenn Lagasse be_mounted = B_TRUE;
711f169c0eaSGlenn Lagasse }
712f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
713f169c0eaSGlenn Lagasse
714f169c0eaSGlenn Lagasse /*
715f169c0eaSGlenn Lagasse * Now get the grub version for the BE being activated.
716f169c0eaSGlenn Lagasse */
717f169c0eaSGlenn Lagasse (void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt,
718f169c0eaSGlenn Lagasse BE_CAP_FILE);
719f169c0eaSGlenn Lagasse ret = get_ver_from_capfile(cap_file, new_vers);
720f169c0eaSGlenn Lagasse if (ret != BE_SUCCESS) {
721f169c0eaSGlenn Lagasse free(*cur_vers);
722f169c0eaSGlenn Lagasse *cur_vers = NULL;
723f169c0eaSGlenn Lagasse }
724f169c0eaSGlenn Lagasse if (be_mounted)
725f169c0eaSGlenn Lagasse (void) _be_unmount(bt->obe_name, 0);
726f169c0eaSGlenn Lagasse
727f169c0eaSGlenn Lagasse cleanup:
728f169c0eaSGlenn Lagasse if (pool_mounted) {
729f169c0eaSGlenn Lagasse int iret = BE_SUCCESS;
730f169c0eaSGlenn Lagasse iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt);
731f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS)
732f169c0eaSGlenn Lagasse ret = iret;
733f169c0eaSGlenn Lagasse free(orig_mntpnt);
734f169c0eaSGlenn Lagasse free(ptmp_mntpnt);
735f169c0eaSGlenn Lagasse }
736f169c0eaSGlenn Lagasse ZFS_CLOSE(pool_zhp);
737f169c0eaSGlenn Lagasse
738f169c0eaSGlenn Lagasse free(temp_mntpnt);
739f169c0eaSGlenn Lagasse return (ret);
740f169c0eaSGlenn Lagasse }
741f169c0eaSGlenn Lagasse
742f169c0eaSGlenn Lagasse /*
743f169c0eaSGlenn Lagasse * Function: get_ver_from_capfile
744f169c0eaSGlenn Lagasse * Description: Parses the capability file passed in looking for the VERSION
745f169c0eaSGlenn Lagasse * line. If found the version is returned in vers, if not then
746f169c0eaSGlenn Lagasse * NULL is returned in vers.
747f169c0eaSGlenn Lagasse *
748f169c0eaSGlenn Lagasse * Parameters:
749f169c0eaSGlenn Lagasse * file - the path to the capability file we want to parse.
750f169c0eaSGlenn Lagasse * vers - the version string that will be passed back.
751f169c0eaSGlenn Lagasse * Return:
752f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
753f169c0eaSGlenn Lagasse * be_errno_t - Failed to find version
754f169c0eaSGlenn Lagasse * Scope:
755f169c0eaSGlenn Lagasse * Private
756f169c0eaSGlenn Lagasse */
757f169c0eaSGlenn Lagasse static int
get_ver_from_capfile(char * file,char ** vers)758f169c0eaSGlenn Lagasse get_ver_from_capfile(char *file, char **vers)
759f169c0eaSGlenn Lagasse {
760f169c0eaSGlenn Lagasse FILE *fp = NULL;
761f169c0eaSGlenn Lagasse char line[BUFSIZ];
762f169c0eaSGlenn Lagasse char *last = NULL;
763f169c0eaSGlenn Lagasse int err = BE_SUCCESS;
764f169c0eaSGlenn Lagasse errno = 0;
765f169c0eaSGlenn Lagasse
766f169c0eaSGlenn Lagasse if (!be_has_grub()) {
767f169c0eaSGlenn Lagasse be_print_err(gettext("get_ver_from_capfile: Not supported "
768f169c0eaSGlenn Lagasse "on this architecture\n"));
769f169c0eaSGlenn Lagasse return (BE_ERR_NOTSUP);
770f169c0eaSGlenn Lagasse }
771f169c0eaSGlenn Lagasse
772f169c0eaSGlenn Lagasse /*
773f169c0eaSGlenn Lagasse * Set version string to NULL; the only case this shouldn't be set
774f169c0eaSGlenn Lagasse * to be NULL is when we've actually found a version in the capability
775f169c0eaSGlenn Lagasse * file, which is set below.
776f169c0eaSGlenn Lagasse */
777f169c0eaSGlenn Lagasse *vers = NULL;
778f169c0eaSGlenn Lagasse
779f169c0eaSGlenn Lagasse /*
780f169c0eaSGlenn Lagasse * If the capability file doesn't exist, we're returning success
781f169c0eaSGlenn Lagasse * because on older releases, the capability file did not exist
782f169c0eaSGlenn Lagasse * so this is a valid scenario.
783f169c0eaSGlenn Lagasse */
784f169c0eaSGlenn Lagasse if (access(file, F_OK) == 0) {
785f169c0eaSGlenn Lagasse if ((fp = fopen(file, "r")) == NULL) {
786f169c0eaSGlenn Lagasse err = errno;
787f169c0eaSGlenn Lagasse be_print_err(gettext("get_ver_from_capfile: failed to "
788f169c0eaSGlenn Lagasse "open file %s with error %s\n"), file,
789f169c0eaSGlenn Lagasse strerror(err));
790f169c0eaSGlenn Lagasse err = errno_to_be_err(err);
791f169c0eaSGlenn Lagasse return (err);
792f169c0eaSGlenn Lagasse }
793f169c0eaSGlenn Lagasse
794f169c0eaSGlenn Lagasse while (fgets(line, BUFSIZ, fp)) {
795f169c0eaSGlenn Lagasse char *tok = strtok_r(line, "=", &last);
796f169c0eaSGlenn Lagasse
797f169c0eaSGlenn Lagasse if (tok == NULL || tok[0] == '#') {
798f169c0eaSGlenn Lagasse continue;
799f169c0eaSGlenn Lagasse } else if (strcmp(tok, "VERSION") == 0) {
800f169c0eaSGlenn Lagasse *vers = strdup(last);
801f169c0eaSGlenn Lagasse break;
802f169c0eaSGlenn Lagasse }
803f169c0eaSGlenn Lagasse }
804f169c0eaSGlenn Lagasse (void) fclose(fp);
805f169c0eaSGlenn Lagasse }
806f169c0eaSGlenn Lagasse
807f169c0eaSGlenn Lagasse return (BE_SUCCESS);
808f169c0eaSGlenn Lagasse }
809f169c0eaSGlenn Lagasse
810f169c0eaSGlenn Lagasse /*
811a63c99a2SToomas Soome * To be able to boot EFI labeled disks, stage1 needs to be written
8121a902ef8SHans Rosenfeld * into the MBR. We do not do this if we're on disks with a traditional
8131a902ef8SHans Rosenfeld * fdisk partition table only, or if any foreign EFI partitions exist.
8141a902ef8SHans Rosenfeld * In the trivial case of a whole-disk vdev we always write stage1 into
8151a902ef8SHans Rosenfeld * the MBR.
8161a902ef8SHans Rosenfeld */
8171a902ef8SHans Rosenfeld static boolean_t
be_do_install_mbr(char * diskname,nvlist_t * child)818a63c99a2SToomas Soome be_do_install_mbr(char *diskname, nvlist_t *child)
8191a902ef8SHans Rosenfeld {
8201a902ef8SHans Rosenfeld struct uuid allowed_uuids[] = {
8211a902ef8SHans Rosenfeld EFI_UNUSED,
8221a902ef8SHans Rosenfeld EFI_RESV1,
8231a902ef8SHans Rosenfeld EFI_BOOT,
8241a902ef8SHans Rosenfeld EFI_ROOT,
8251a902ef8SHans Rosenfeld EFI_SWAP,
8261a902ef8SHans Rosenfeld EFI_USR,
8271a902ef8SHans Rosenfeld EFI_BACKUP,
8281a902ef8SHans Rosenfeld EFI_RESV2,
8291a902ef8SHans Rosenfeld EFI_VAR,
8301a902ef8SHans Rosenfeld EFI_HOME,
8311a902ef8SHans Rosenfeld EFI_ALTSCTR,
8321a902ef8SHans Rosenfeld EFI_RESERVED,
8331a902ef8SHans Rosenfeld EFI_SYSTEM,
8341a902ef8SHans Rosenfeld EFI_BIOS_BOOT,
8351a902ef8SHans Rosenfeld EFI_SYMC_PUB,
8361a902ef8SHans Rosenfeld EFI_SYMC_CDS
8371a902ef8SHans Rosenfeld };
8381a902ef8SHans Rosenfeld
8391a902ef8SHans Rosenfeld uint64_t whole;
8401a902ef8SHans Rosenfeld struct dk_gpt *gpt;
8411a902ef8SHans Rosenfeld struct uuid *u;
8421a902ef8SHans Rosenfeld int fd, npart, i, j;
8431a902ef8SHans Rosenfeld
8441a902ef8SHans Rosenfeld (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK,
8451a902ef8SHans Rosenfeld &whole);
8461a902ef8SHans Rosenfeld
8471a902ef8SHans Rosenfeld if (whole)
8481a902ef8SHans Rosenfeld return (B_TRUE);
8491a902ef8SHans Rosenfeld
8501a902ef8SHans Rosenfeld if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0)
8511a902ef8SHans Rosenfeld return (B_FALSE);
8521a902ef8SHans Rosenfeld
8531a902ef8SHans Rosenfeld if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0)
8541a902ef8SHans Rosenfeld return (B_FALSE);
8551a902ef8SHans Rosenfeld
8561a902ef8SHans Rosenfeld for (i = 0; i != npart; i++) {
8571a902ef8SHans Rosenfeld int match = 0;
8581a902ef8SHans Rosenfeld
8591a902ef8SHans Rosenfeld u = &gpt->efi_parts[i].p_guid;
8601a902ef8SHans Rosenfeld
8611a902ef8SHans Rosenfeld for (j = 0;
8621a902ef8SHans Rosenfeld j != sizeof (allowed_uuids) / sizeof (struct uuid);
8631a902ef8SHans Rosenfeld j++)
8641a902ef8SHans Rosenfeld if (bcmp(u, &allowed_uuids[j],
8651a902ef8SHans Rosenfeld sizeof (struct uuid)) == 0)
8661a902ef8SHans Rosenfeld match++;
8671a902ef8SHans Rosenfeld
8681a902ef8SHans Rosenfeld if (match == 0)
8691a902ef8SHans Rosenfeld return (B_FALSE);
8701a902ef8SHans Rosenfeld }
8711a902ef8SHans Rosenfeld
8721a902ef8SHans Rosenfeld return (B_TRUE);
8731a902ef8SHans Rosenfeld }
8741a902ef8SHans Rosenfeld
8751a902ef8SHans Rosenfeld static int
be_do_installboot_helper(zpool_handle_t * zphp,nvlist_t * child,char * stage1,char * stage2,uint16_t flags)876a63c99a2SToomas Soome be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1,
877c7c0ceafSToomas Soome char *stage2, uint16_t flags)
8781a902ef8SHans Rosenfeld {
879a63c99a2SToomas Soome char install_cmd[MAXPATHLEN];
8801a902ef8SHans Rosenfeld char be_run_cmd_errbuf[BUFSIZ];
881c7c0ceafSToomas Soome char be_run_cmd_outbuf[BUFSIZ];
8821a902ef8SHans Rosenfeld char diskname[MAXPATHLEN];
8831a902ef8SHans Rosenfeld char *vname;
8841a902ef8SHans Rosenfeld char *path, *dsk_ptr;
885a63c99a2SToomas Soome char *flag = "";
886c7c0ceafSToomas Soome int ret;
88708e9b2dfSHans Rosenfeld vdev_stat_t *vs;
88808e9b2dfSHans Rosenfeld uint_t vsc;
8891a902ef8SHans Rosenfeld
8901a902ef8SHans Rosenfeld if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) {
891a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: "
8921a902ef8SHans Rosenfeld "failed to get device path\n"));
8931a902ef8SHans Rosenfeld return (BE_ERR_NODEV);
8941a902ef8SHans Rosenfeld }
8951a902ef8SHans Rosenfeld
89608e9b2dfSHans Rosenfeld if ((nvlist_lookup_uint64_array(child, ZPOOL_CONFIG_VDEV_STATS,
89708e9b2dfSHans Rosenfeld (uint64_t **)&vs, &vsc) != 0) ||
89808e9b2dfSHans Rosenfeld vs->vs_state < VDEV_STATE_DEGRADED) {
89908e9b2dfSHans Rosenfeld /*
90008e9b2dfSHans Rosenfeld * Don't try to run installgrub on a vdev that is not ONLINE
90108e9b2dfSHans Rosenfeld * or DEGRADED. Try to print a warning for each such vdev.
90208e9b2dfSHans Rosenfeld */
90308e9b2dfSHans Rosenfeld be_print_err(gettext("be_do_installboot: "
90408e9b2dfSHans Rosenfeld "vdev %s is %s, can't install boot loader\n"),
90508e9b2dfSHans Rosenfeld path, zpool_state_to_name(vs->vs_state, vs->vs_aux));
90608e9b2dfSHans Rosenfeld free(path);
90708e9b2dfSHans Rosenfeld return (BE_SUCCESS);
90808e9b2dfSHans Rosenfeld }
90908e9b2dfSHans Rosenfeld
9101a902ef8SHans Rosenfeld /*
9111a902ef8SHans Rosenfeld * Modify the vdev path to point to the raw disk.
9121a902ef8SHans Rosenfeld */
9131a902ef8SHans Rosenfeld path = strdup(path);
9141a902ef8SHans Rosenfeld if (path == NULL)
9151a902ef8SHans Rosenfeld return (BE_ERR_NOMEM);
9161a902ef8SHans Rosenfeld
9171a902ef8SHans Rosenfeld dsk_ptr = strstr(path, "/dsk/");
9181a902ef8SHans Rosenfeld if (dsk_ptr != NULL) {
9191a902ef8SHans Rosenfeld *dsk_ptr = '\0';
9201a902ef8SHans Rosenfeld dsk_ptr++;
9211a902ef8SHans Rosenfeld } else {
9221a902ef8SHans Rosenfeld dsk_ptr = "";
9231a902ef8SHans Rosenfeld }
9241a902ef8SHans Rosenfeld
9251a902ef8SHans Rosenfeld (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
9261a902ef8SHans Rosenfeld free(path);
9271a902ef8SHans Rosenfeld
9281a902ef8SHans Rosenfeld vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE);
9291a902ef8SHans Rosenfeld if (vname == NULL) {
930a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: "
9311a902ef8SHans Rosenfeld "failed to get device name: %s\n"),
9321a902ef8SHans Rosenfeld libzfs_error_description(g_zfs));
9331a902ef8SHans Rosenfeld return (zfs_err_to_be_err(g_zfs));
9341a902ef8SHans Rosenfeld }
9351a902ef8SHans Rosenfeld
936a63c99a2SToomas Soome if (be_is_isa("i386")) {
937c7c0ceafSToomas Soome uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE;
938c7c0ceafSToomas Soome uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR;
939c7c0ceafSToomas Soome
940c7c0ceafSToomas Soome if (force == BE_INSTALLBOOT_FLAG_FORCE) {
941c7c0ceafSToomas Soome if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
942c7c0ceafSToomas Soome be_do_install_mbr(diskname, child))
943c7c0ceafSToomas Soome flag = "-F -m -f";
944c7c0ceafSToomas Soome else
945c7c0ceafSToomas Soome flag = "-F";
946c7c0ceafSToomas Soome } else {
947c7c0ceafSToomas Soome if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
948c7c0ceafSToomas Soome be_do_install_mbr(diskname, child))
949a63c99a2SToomas Soome flag = "-m -f";
950c7c0ceafSToomas Soome }
951c7c0ceafSToomas Soome
9521a47de4eSToomas Soome if (be_has_grub()) {
953a63c99a2SToomas Soome (void) snprintf(install_cmd, sizeof (install_cmd),
954a63c99a2SToomas Soome "%s %s %s %s %s", BE_INSTALL_GRUB, flag,
955a63c99a2SToomas Soome stage1, stage2, diskname);
9561a47de4eSToomas Soome } else {
9571a47de4eSToomas Soome (void) snprintf(install_cmd, sizeof (install_cmd),
9581a47de4eSToomas Soome "%s %s %s %s %s", BE_INSTALL_BOOT, flag,
9591a47de4eSToomas Soome stage1, stage2, diskname);
9601a47de4eSToomas Soome }
96166f18efaSToomas Soome } else if (be_is_isa("sparc")) {
962c7c0ceafSToomas Soome if ((flags & BE_INSTALLBOOT_FLAG_FORCE) ==
963c7c0ceafSToomas Soome BE_INSTALLBOOT_FLAG_FORCE)
964c7c0ceafSToomas Soome flag = "-f -F zfs";
965c7c0ceafSToomas Soome else
966a63c99a2SToomas Soome flag = "-F zfs";
967c7c0ceafSToomas Soome
968a63c99a2SToomas Soome (void) snprintf(install_cmd, sizeof (install_cmd),
969a63c99a2SToomas Soome "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname);
97066f18efaSToomas Soome } else {
97166f18efaSToomas Soome be_print_err(gettext("be_do_installboot: unsupported "
97266f18efaSToomas Soome "architecture.\n"));
97366f18efaSToomas Soome return (BE_ERR_BOOTFILE_INST);
974a63c99a2SToomas Soome }
975a63c99a2SToomas Soome
976c7c0ceafSToomas Soome *be_run_cmd_outbuf = '\0';
977c7c0ceafSToomas Soome *be_run_cmd_errbuf = '\0';
978c7c0ceafSToomas Soome
979c7c0ceafSToomas Soome ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ,
980c7c0ceafSToomas Soome be_run_cmd_outbuf, BUFSIZ);
981c7c0ceafSToomas Soome
982c7c0ceafSToomas Soome if (ret != BE_SUCCESS) {
983a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: install "
9841a902ef8SHans Rosenfeld "failed for device %s.\n"), vname);
985c7c0ceafSToomas Soome ret = BE_ERR_BOOTFILE_INST;
986c7c0ceafSToomas Soome }
987c7c0ceafSToomas Soome
988c7c0ceafSToomas Soome be_print_err(gettext(" Command: \"%s\"\n"), install_cmd);
989c7c0ceafSToomas Soome if (be_run_cmd_outbuf[0] != 0) {
990c7c0ceafSToomas Soome be_print_err(gettext(" Output:\n"));
991c7c0ceafSToomas Soome be_print_err("%s", be_run_cmd_outbuf);
992c7c0ceafSToomas Soome }
993c7c0ceafSToomas Soome
994c7c0ceafSToomas Soome if (be_run_cmd_errbuf[0] != 0) {
995c7c0ceafSToomas Soome be_print_err(gettext(" Errors:\n"));
9961a902ef8SHans Rosenfeld be_print_err("%s", be_run_cmd_errbuf);
9971a902ef8SHans Rosenfeld }
9981a902ef8SHans Rosenfeld free(vname);
9991a902ef8SHans Rosenfeld
1000c7c0ceafSToomas Soome return (ret);
10011a902ef8SHans Rosenfeld }
10021a902ef8SHans Rosenfeld
10031a902ef8SHans Rosenfeld /*
1004a63c99a2SToomas Soome * Function: be_do_copy_grub_cap
1005a63c99a2SToomas Soome * Description: This function will copy grub capability file to BE.
1006f169c0eaSGlenn Lagasse *
1007f169c0eaSGlenn Lagasse * Parameters:
1008f169c0eaSGlenn Lagasse * bt - The transaction data for the BE we're activating.
1009f169c0eaSGlenn Lagasse * Return:
1010f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
1011f169c0eaSGlenn Lagasse * be_errno_t - Failure
1012f169c0eaSGlenn Lagasse *
1013f169c0eaSGlenn Lagasse * Scope:
1014f169c0eaSGlenn Lagasse * Private
1015f169c0eaSGlenn Lagasse */
1016f169c0eaSGlenn Lagasse static int
be_do_copy_grub_cap(be_transaction_data_t * bt)1017a63c99a2SToomas Soome be_do_copy_grub_cap(be_transaction_data_t *bt)
1018f169c0eaSGlenn Lagasse {
1019f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
1020f169c0eaSGlenn Lagasse char cap_file[MAXPATHLEN];
1021f169c0eaSGlenn Lagasse char zpool_cap_file[MAXPATHLEN];
1022a63c99a2SToomas Soome char line[BUFSIZ];
1023a63c99a2SToomas Soome char *tmp_mntpnt = NULL;
1024a63c99a2SToomas Soome char *orig_mntpnt = NULL;
1025a63c99a2SToomas Soome char *pool_mntpnt = NULL;
1026a63c99a2SToomas Soome FILE *cap_fp = NULL;
1027a63c99a2SToomas Soome FILE *zpool_cap_fp = NULL;
1028f169c0eaSGlenn Lagasse int err = 0;
1029a63c99a2SToomas Soome int ret = BE_SUCCESS;
1030f169c0eaSGlenn Lagasse boolean_t pool_mounted = B_FALSE;
1031a63c99a2SToomas Soome boolean_t be_mounted = B_FALSE;
1032f169c0eaSGlenn Lagasse
1033f169c0eaSGlenn Lagasse /*
1034a21e1692SToomas Soome * first get BE dataset mountpoint, we can free all the resources
1035a21e1692SToomas Soome * once cap_file is built, leaving only be unmount to be done.
1036f169c0eaSGlenn Lagasse */
1037a21e1692SToomas Soome if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1038a21e1692SToomas Soome NULL) {
1039a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: failed to "
1040a21e1692SToomas Soome "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1041a21e1692SToomas Soome libzfs_error_description(g_zfs));
1042a21e1692SToomas Soome return (zfs_err_to_be_err(g_zfs));
1043a21e1692SToomas Soome }
1044a21e1692SToomas Soome
1045a21e1692SToomas Soome if (!zfs_is_mounted(zhp, &tmp_mntpnt)) {
1046a21e1692SToomas Soome if ((ret = _be_mount(bt->obe_name, &tmp_mntpnt,
1047a21e1692SToomas Soome BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1048a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: failed to "
1049a21e1692SToomas Soome "mount BE (%s)\n"), bt->obe_name);
1050a21e1692SToomas Soome ZFS_CLOSE(zhp);
1051a21e1692SToomas Soome goto done;
1052a21e1692SToomas Soome }
1053a21e1692SToomas Soome be_mounted = B_TRUE;
1054a21e1692SToomas Soome }
1055a21e1692SToomas Soome ZFS_CLOSE(zhp); /* BE dataset handle is not needed any more */
1056a21e1692SToomas Soome
1057a21e1692SToomas Soome (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpnt,
1058a21e1692SToomas Soome BE_CAP_FILE);
1059a21e1692SToomas Soome free(tmp_mntpnt);
1060a21e1692SToomas Soome
1061a21e1692SToomas Soome /* get pool root dataset mountpoint */
1062a63c99a2SToomas Soome zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM);
1063a63c99a2SToomas Soome if (zhp == NULL) {
1064a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: zfs_open "
1065f169c0eaSGlenn Lagasse "failed: %s\n"), libzfs_error_description(g_zfs));
1066a21e1692SToomas Soome ret = zfs_err_to_be_err(g_zfs);
1067a21e1692SToomas Soome goto done;
1068f169c0eaSGlenn Lagasse }
1069f169c0eaSGlenn Lagasse
1070f169c0eaSGlenn Lagasse /*
1071f169c0eaSGlenn Lagasse * Check to see if the pool's dataset is mounted. If it isn't we'll
1072f169c0eaSGlenn Lagasse * attempt to mount it.
1073f169c0eaSGlenn Lagasse */
1074a21e1692SToomas Soome if ((ret = be_mount_pool(zhp, &tmp_mntpnt,
1075f169c0eaSGlenn Lagasse &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
1076a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: pool dataset "
1077f169c0eaSGlenn Lagasse "(%s) could not be mounted\n"), bt->obe_zpool);
1078f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1079a21e1692SToomas Soome goto done;
1080f169c0eaSGlenn Lagasse }
1081f169c0eaSGlenn Lagasse
1082f169c0eaSGlenn Lagasse /*
1083f169c0eaSGlenn Lagasse * Get the mountpoint for the root pool dataset.
1084a21e1692SToomas Soome * NOTE: zhp must be kept for _be_unmount_pool()
1085f169c0eaSGlenn Lagasse */
1086f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1087a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: pool "
1088f169c0eaSGlenn Lagasse "dataset (%s) is not mounted. Can't check the grub "
1089f169c0eaSGlenn Lagasse "version from the grub capability file.\n"), bt->obe_zpool);
1090f169c0eaSGlenn Lagasse ret = BE_ERR_NO_MENU;
1091f169c0eaSGlenn Lagasse goto done;
1092f169c0eaSGlenn Lagasse }
1093f169c0eaSGlenn Lagasse
1094f169c0eaSGlenn Lagasse (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
1095f169c0eaSGlenn Lagasse pool_mntpnt, BE_CAP_FILE);
1096f169c0eaSGlenn Lagasse free(pool_mntpnt);
1097a63c99a2SToomas Soome
1098f169c0eaSGlenn Lagasse if ((cap_fp = fopen(cap_file, "r")) == NULL) {
1099f169c0eaSGlenn Lagasse err = errno;
1100a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: failed to open grub "
1101f169c0eaSGlenn Lagasse "capability file\n"));
1102f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1103f169c0eaSGlenn Lagasse goto done;
1104f169c0eaSGlenn Lagasse }
1105f169c0eaSGlenn Lagasse if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
1106f169c0eaSGlenn Lagasse err = errno;
1107a21e1692SToomas Soome be_print_err(gettext("be_do_copy_grub_cap: failed to open new "
1108f169c0eaSGlenn Lagasse "grub capability file\n"));
1109f169c0eaSGlenn Lagasse ret = errno_to_be_err(err);
1110f169c0eaSGlenn Lagasse (void) fclose(cap_fp);
1111f169c0eaSGlenn Lagasse goto done;
1112f169c0eaSGlenn Lagasse }
1113f169c0eaSGlenn Lagasse
1114f169c0eaSGlenn Lagasse while (fgets(line, BUFSIZ, cap_fp)) {
1115f169c0eaSGlenn Lagasse (void) fputs(line, zpool_cap_fp);
1116f169c0eaSGlenn Lagasse }
1117f169c0eaSGlenn Lagasse
1118f169c0eaSGlenn Lagasse (void) fclose(zpool_cap_fp);
1119f169c0eaSGlenn Lagasse (void) fclose(cap_fp);
1120f169c0eaSGlenn Lagasse
1121f169c0eaSGlenn Lagasse done:
1122a63c99a2SToomas Soome if (be_mounted)
1123a63c99a2SToomas Soome (void) _be_unmount(bt->obe_name, 0);
1124a63c99a2SToomas Soome
1125f169c0eaSGlenn Lagasse if (pool_mounted) {
1126a21e1692SToomas Soome err = be_unmount_pool(zhp, tmp_mntpnt, orig_mntpnt);
1127f169c0eaSGlenn Lagasse if (ret == BE_SUCCESS)
1128a21e1692SToomas Soome ret = err;
1129f169c0eaSGlenn Lagasse free(orig_mntpnt);
1130a21e1692SToomas Soome free(tmp_mntpnt);
1131a21e1692SToomas Soome zfs_close(zhp);
1132f169c0eaSGlenn Lagasse }
1133a63c99a2SToomas Soome return (ret);
1134a63c99a2SToomas Soome }
1135a63c99a2SToomas Soome
1136a63c99a2SToomas Soome /*
1137a63c99a2SToomas Soome * Function: be_is_install_needed
1138a63c99a2SToomas Soome * Description: Check detached version files to detect if bootloader
1139a63c99a2SToomas Soome * install/update is needed.
1140a63c99a2SToomas Soome *
1141a63c99a2SToomas Soome * Parameters:
1142a63c99a2SToomas Soome * bt - The transaction data for the BE we're activating.
1143a63c99a2SToomas Soome * update - set B_TRUE is update is needed.
1144a63c99a2SToomas Soome * Return:
1145a63c99a2SToomas Soome * BE_SUCCESS - Success
1146a63c99a2SToomas Soome * be_errno_t - Failure
1147a63c99a2SToomas Soome *
1148a63c99a2SToomas Soome * Scope:
1149a63c99a2SToomas Soome * Private
1150a63c99a2SToomas Soome */
1151a63c99a2SToomas Soome static int
be_is_install_needed(be_transaction_data_t * bt,boolean_t * update)1152a63c99a2SToomas Soome be_is_install_needed(be_transaction_data_t *bt, boolean_t *update)
1153a63c99a2SToomas Soome {
1154a63c99a2SToomas Soome int ret = BE_SUCCESS;
1155a63c99a2SToomas Soome char *cur_vers = NULL, *new_vers = NULL;
1156a63c99a2SToomas Soome
1157a63c99a2SToomas Soome assert(bt != NULL);
1158a63c99a2SToomas Soome assert(update != NULL);
1159a63c99a2SToomas Soome
1160a63c99a2SToomas Soome if (!be_has_grub()) {
1161a63c99a2SToomas Soome /*
1162a63c99a2SToomas Soome * no detached versioning, let installboot to manage
1163a63c99a2SToomas Soome * versioning.
1164a63c99a2SToomas Soome */
1165a63c99a2SToomas Soome *update = B_TRUE;
1166a63c99a2SToomas Soome return (ret);
1167a63c99a2SToomas Soome }
1168a63c99a2SToomas Soome
1169a63c99a2SToomas Soome *update = B_FALSE; /* set default */
1170a63c99a2SToomas Soome
1171a63c99a2SToomas Soome /*
1172a63c99a2SToomas Soome * We need to check to see if the version number from
1173a63c99a2SToomas Soome * the BE being activated is greater than the current
1174a63c99a2SToomas Soome * one.
1175a63c99a2SToomas Soome */
1176a63c99a2SToomas Soome ret = be_get_grub_vers(bt, &cur_vers, &new_vers);
1177a63c99a2SToomas Soome if (ret != BE_SUCCESS) {
1178a63c99a2SToomas Soome be_print_err(gettext("be_activate: failed to get grub "
1179a63c99a2SToomas Soome "versions from capability files.\n"));
1180a63c99a2SToomas Soome return (ret);
1181a63c99a2SToomas Soome }
1182a63c99a2SToomas Soome /* update if we have both versions and can compare */
1183a63c99a2SToomas Soome if (cur_vers != NULL) {
1184a63c99a2SToomas Soome if (new_vers != NULL) {
1185a63c99a2SToomas Soome if (atof(cur_vers) < atof(new_vers))
1186a63c99a2SToomas Soome *update = B_TRUE;
1187a63c99a2SToomas Soome free(new_vers);
1188a63c99a2SToomas Soome }
1189a63c99a2SToomas Soome free(cur_vers);
1190a63c99a2SToomas Soome } else if (new_vers != NULL) {
1191a63c99a2SToomas Soome /* we only got new version - update */
1192a63c99a2SToomas Soome *update = B_TRUE;
1193a63c99a2SToomas Soome free(new_vers);
1194a63c99a2SToomas Soome }
1195a63c99a2SToomas Soome return (ret);
1196a63c99a2SToomas Soome }
1197a63c99a2SToomas Soome
1198a63c99a2SToomas Soome /*
1199a63c99a2SToomas Soome * Function: be_do_installboot
1200a63c99a2SToomas Soome * Description: This function runs installgrub/installboot using the boot
1201a63c99a2SToomas Soome * loader files from the BE we're activating and installing
1202a63c99a2SToomas Soome * them on the pool the BE lives in.
1203a63c99a2SToomas Soome *
1204a63c99a2SToomas Soome * Parameters:
1205a63c99a2SToomas Soome * bt - The transaction data for the BE we're activating.
1206c7c0ceafSToomas Soome * flags - flags for bootloader install
1207a63c99a2SToomas Soome * Return:
1208a63c99a2SToomas Soome * BE_SUCCESS - Success
1209a63c99a2SToomas Soome * be_errno_t - Failure
1210a63c99a2SToomas Soome *
1211a63c99a2SToomas Soome * Scope:
1212a63c99a2SToomas Soome * Private
1213a63c99a2SToomas Soome */
1214a63c99a2SToomas Soome static int
be_do_installboot(be_transaction_data_t * bt,uint16_t flags)1215c7c0ceafSToomas Soome be_do_installboot(be_transaction_data_t *bt, uint16_t flags)
1216a63c99a2SToomas Soome {
1217a63c99a2SToomas Soome zpool_handle_t *zphp = NULL;
1218a63c99a2SToomas Soome zfs_handle_t *zhp = NULL;
1219a63c99a2SToomas Soome nvlist_t **child, *nv, *config;
1220a63c99a2SToomas Soome uint_t c, children = 0;
1221a63c99a2SToomas Soome char *tmp_mntpt = NULL;
1222a63c99a2SToomas Soome char stage1[MAXPATHLEN];
1223a63c99a2SToomas Soome char stage2[MAXPATHLEN];
1224a63c99a2SToomas Soome char *vname;
1225a63c99a2SToomas Soome int ret = BE_SUCCESS;
1226a63c99a2SToomas Soome boolean_t be_mounted = B_FALSE;
1227a63c99a2SToomas Soome boolean_t update = B_FALSE;
12281a47de4eSToomas Soome boolean_t verbose = B_FALSE;
1229a63c99a2SToomas Soome
1230a63c99a2SToomas Soome /*
1231a63c99a2SToomas Soome * check versions. This call is to support detached
1232a63c99a2SToomas Soome * version implementation like grub. Embedded versioning is
1233a63c99a2SToomas Soome * checked by actual installer.
1234a63c99a2SToomas Soome */
1235c7c0ceafSToomas Soome if ((flags & BE_INSTALLBOOT_FLAG_FORCE) != BE_INSTALLBOOT_FLAG_FORCE) {
1236a63c99a2SToomas Soome ret = be_is_install_needed(bt, &update);
1237a63c99a2SToomas Soome if (ret != BE_SUCCESS || update == B_FALSE)
1238a63c99a2SToomas Soome return (ret);
1239c7c0ceafSToomas Soome }
12401a47de4eSToomas Soome verbose = do_print;
1241a63c99a2SToomas Soome
1242a63c99a2SToomas Soome if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1243a63c99a2SToomas Soome NULL) {
1244a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to "
1245a63c99a2SToomas Soome "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1246a63c99a2SToomas Soome libzfs_error_description(g_zfs));
1247a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs);
1248a63c99a2SToomas Soome return (ret);
1249a63c99a2SToomas Soome }
1250a63c99a2SToomas Soome if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
1251a63c99a2SToomas Soome if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
1252a63c99a2SToomas Soome BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1253a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to "
1254a63c99a2SToomas Soome "mount BE (%s)\n"), bt->obe_name);
1255a63c99a2SToomas Soome ZFS_CLOSE(zhp);
1256a63c99a2SToomas Soome return (ret);
1257a63c99a2SToomas Soome }
1258a63c99a2SToomas Soome be_mounted = B_TRUE;
1259a63c99a2SToomas Soome }
1260a63c99a2SToomas Soome ZFS_CLOSE(zhp);
1261a63c99a2SToomas Soome
12621a47de4eSToomas Soome if (be_is_isa("i386")) {
1263a63c99a2SToomas Soome if (be_has_grub()) {
1264a63c99a2SToomas Soome (void) snprintf(stage1, sizeof (stage1), "%s%s",
1265a63c99a2SToomas Soome tmp_mntpt, BE_GRUB_STAGE_1);
1266a63c99a2SToomas Soome (void) snprintf(stage2, sizeof (stage2), "%s%s",
1267a63c99a2SToomas Soome tmp_mntpt, BE_GRUB_STAGE_2);
1268a63c99a2SToomas Soome } else {
12691a47de4eSToomas Soome (void) snprintf(stage1, sizeof (stage1), "%s%s",
12701a47de4eSToomas Soome tmp_mntpt, BE_LOADER_STAGE_1);
12711a47de4eSToomas Soome (void) snprintf(stage2, sizeof (stage2), "%s%s",
12721a47de4eSToomas Soome tmp_mntpt, BE_LOADER_STAGE_2);
12731a47de4eSToomas Soome }
12741a47de4eSToomas Soome } else if (be_is_isa("sparc")) {
1275a63c99a2SToomas Soome char *platform = be_get_platform();
1276a63c99a2SToomas Soome
1277a63c99a2SToomas Soome if (platform == NULL) {
12781a47de4eSToomas Soome be_print_err(gettext("be_do_installboot: "
12791a47de4eSToomas Soome "failed to detect system platform name\n"));
1280a63c99a2SToomas Soome if (be_mounted)
1281a63c99a2SToomas Soome (void) _be_unmount(bt->obe_name, 0);
1282a63c99a2SToomas Soome free(tmp_mntpt);
1283a63c99a2SToomas Soome return (BE_ERR_BOOTFILE_INST);
1284a63c99a2SToomas Soome }
1285a63c99a2SToomas Soome stage1[0] = '\0'; /* sparc has no stage1 */
1286a63c99a2SToomas Soome (void) snprintf(stage2, sizeof (stage2),
1287a63c99a2SToomas Soome "%s/usr/platform/%s%s", tmp_mntpt,
1288a63c99a2SToomas Soome platform, BE_SPARC_BOOTBLK);
12891a47de4eSToomas Soome } else {
12901a47de4eSToomas Soome be_print_err(gettext("be_do_installboot: unsupported "
12911a47de4eSToomas Soome "architecture.\n"));
12921a47de4eSToomas Soome return (BE_ERR_BOOTFILE_INST);
1293a63c99a2SToomas Soome }
1294a63c99a2SToomas Soome
1295a63c99a2SToomas Soome if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
1296a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to open "
1297a63c99a2SToomas Soome "pool (%s): %s\n"), bt->obe_zpool,
1298a63c99a2SToomas Soome libzfs_error_description(g_zfs));
1299a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs);
1300a63c99a2SToomas Soome if (be_mounted)
1301a63c99a2SToomas Soome (void) _be_unmount(bt->obe_name, 0);
1302a63c99a2SToomas Soome free(tmp_mntpt);
1303a63c99a2SToomas Soome return (ret);
1304a63c99a2SToomas Soome }
1305a63c99a2SToomas Soome
1306a63c99a2SToomas Soome if ((config = zpool_get_config(zphp, NULL)) == NULL) {
1307a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to get zpool "
1308a63c99a2SToomas Soome "configuration information. %s\n"),
1309a63c99a2SToomas Soome libzfs_error_description(g_zfs));
1310a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs);
1311a63c99a2SToomas Soome goto done;
1312a63c99a2SToomas Soome }
1313a63c99a2SToomas Soome
1314a63c99a2SToomas Soome /*
1315a63c99a2SToomas Soome * Get the vdev tree
1316a63c99a2SToomas Soome */
1317a63c99a2SToomas Soome if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
1318a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to get vdev "
1319a63c99a2SToomas Soome "tree: %s\n"), libzfs_error_description(g_zfs));
1320a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs);
1321a63c99a2SToomas Soome goto done;
1322a63c99a2SToomas Soome }
1323a63c99a2SToomas Soome
1324a63c99a2SToomas Soome if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1325a63c99a2SToomas Soome &children) != 0) {
1326a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: failed to traverse "
1327a63c99a2SToomas Soome "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
1328a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs);
1329a63c99a2SToomas Soome goto done;
1330a63c99a2SToomas Soome }
1331a63c99a2SToomas Soome for (c = 0; c < children; c++) {
1332a63c99a2SToomas Soome uint_t i, nchildren = 0;
1333a63c99a2SToomas Soome nvlist_t **nvchild;
13341a47de4eSToomas Soome
13351a47de4eSToomas Soome /* ensure update on child status */
13361a47de4eSToomas Soome vname = zpool_vdev_name(g_zfs, zphp, child[c], verbose);
1337a63c99a2SToomas Soome if (vname == NULL) {
1338a63c99a2SToomas Soome be_print_err(gettext(
1339a63c99a2SToomas Soome "be_do_installboot: "
1340a63c99a2SToomas Soome "failed to get device name: %s\n"),
1341a63c99a2SToomas Soome libzfs_error_description(g_zfs));
1342a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs);
1343a63c99a2SToomas Soome goto done;
13441a47de4eSToomas Soome } else if (verbose == B_TRUE) {
13451a47de4eSToomas Soome be_print_err(gettext("be_do_installboot: "
13461a47de4eSToomas Soome "device %s\n"), vname);
1347a63c99a2SToomas Soome }
1348a63c99a2SToomas Soome free(vname);
1349a63c99a2SToomas Soome
13501a47de4eSToomas Soome ret = nvlist_lookup_nvlist_array(child[c],
13511a47de4eSToomas Soome ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren);
13521a47de4eSToomas Soome if (ret != 0) {
13531a47de4eSToomas Soome if (ret != ENOENT) {
1354a63c99a2SToomas Soome be_print_err(gettext("be_do_installboot: "
1355a63c99a2SToomas Soome "failed to traverse the vdev tree: %s\n"),
1356a63c99a2SToomas Soome libzfs_error_description(g_zfs));
1357a63c99a2SToomas Soome ret = zfs_err_to_be_err(g_zfs);
1358a63c99a2SToomas Soome goto done;
1359a63c99a2SToomas Soome }
13601a47de4eSToomas Soome nchildren = 0; /* This is leaf device. */
13611a47de4eSToomas Soome }
1362a63c99a2SToomas Soome
13631a47de4eSToomas Soome if (nchildren != 0) {
1364a63c99a2SToomas Soome for (i = 0; i < nchildren; i++) {
13651a47de4eSToomas Soome /* ensure update on child status */
13661a47de4eSToomas Soome vname = zpool_vdev_name(g_zfs, zphp,
13671a47de4eSToomas Soome nvchild[i], verbose);
13681a47de4eSToomas Soome if (vname == NULL) {
13691a47de4eSToomas Soome be_print_err(gettext(
13701a47de4eSToomas Soome "be_do_installboot: "
13711a47de4eSToomas Soome "failed to get device name: %s\n"),
13721a47de4eSToomas Soome libzfs_error_description(g_zfs));
13731a47de4eSToomas Soome ret = zfs_err_to_be_err(g_zfs);
13741a47de4eSToomas Soome goto done;
13751a47de4eSToomas Soome } else if (verbose == B_TRUE) {
13761a47de4eSToomas Soome be_print_err(gettext(
13771a47de4eSToomas Soome "be_do_installboot: device %s\n"),
13781a47de4eSToomas Soome vname);
13791a47de4eSToomas Soome }
13801a47de4eSToomas Soome free(vname);
1381a63c99a2SToomas Soome ret = be_do_installboot_helper(zphp, nvchild[i],
1382c7c0ceafSToomas Soome stage1, stage2, flags);
1383a63c99a2SToomas Soome if (ret != BE_SUCCESS)
1384a63c99a2SToomas Soome goto done;
1385a63c99a2SToomas Soome }
1386a63c99a2SToomas Soome } else {
1387a63c99a2SToomas Soome ret = be_do_installboot_helper(zphp, child[c], stage1,
1388c7c0ceafSToomas Soome stage2, flags);
1389a63c99a2SToomas Soome if (ret != BE_SUCCESS)
1390a63c99a2SToomas Soome goto done;
1391a63c99a2SToomas Soome }
1392a63c99a2SToomas Soome }
1393a63c99a2SToomas Soome
1394a63c99a2SToomas Soome if (be_has_grub()) {
1395a63c99a2SToomas Soome ret = be_do_copy_grub_cap(bt);
1396a63c99a2SToomas Soome }
1397a63c99a2SToomas Soome
1398a63c99a2SToomas Soome done:
1399f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1400f169c0eaSGlenn Lagasse if (be_mounted)
1401f169c0eaSGlenn Lagasse (void) _be_unmount(bt->obe_name, 0);
1402f169c0eaSGlenn Lagasse zpool_close(zphp);
1403f169c0eaSGlenn Lagasse free(tmp_mntpt);
1404f169c0eaSGlenn Lagasse return (ret);
1405f169c0eaSGlenn Lagasse }
1406f169c0eaSGlenn Lagasse
1407f169c0eaSGlenn Lagasse /*
1408f169c0eaSGlenn Lagasse * Function: be_promote_zone_ds
1409f169c0eaSGlenn Lagasse * Description: This function finds the zones for the BE being activated
1410f169c0eaSGlenn Lagasse * and the active zonepath dataset for each zone. Then each
1411f169c0eaSGlenn Lagasse * active zonepath dataset is promoted.
1412f169c0eaSGlenn Lagasse *
1413f169c0eaSGlenn Lagasse * Parameters:
1414f169c0eaSGlenn Lagasse * be_name - the name of the global zone BE that we need to
1415f169c0eaSGlenn Lagasse * find the zones for.
1416f169c0eaSGlenn Lagasse * be_root_ds - the root dataset for be_name.
1417f169c0eaSGlenn Lagasse * Return:
1418f169c0eaSGlenn Lagasse * BE_SUCCESS - Success
1419f169c0eaSGlenn Lagasse * be_errno_t - Failure
1420f169c0eaSGlenn Lagasse *
1421f169c0eaSGlenn Lagasse * Scope:
1422f169c0eaSGlenn Lagasse * Private
1423f169c0eaSGlenn Lagasse */
1424f169c0eaSGlenn Lagasse static int
be_promote_zone_ds(char * be_name,char * be_root_ds)1425f169c0eaSGlenn Lagasse be_promote_zone_ds(char *be_name, char *be_root_ds)
1426f169c0eaSGlenn Lagasse {
1427f169c0eaSGlenn Lagasse char *zone_ds = NULL;
1428f169c0eaSGlenn Lagasse char *temp_mntpt = NULL;
1429f169c0eaSGlenn Lagasse char origin[MAXPATHLEN];
1430f169c0eaSGlenn Lagasse char zoneroot_ds[MAXPATHLEN];
1431f169c0eaSGlenn Lagasse zfs_handle_t *zhp = NULL;
1432f169c0eaSGlenn Lagasse zfs_handle_t *z_zhp = NULL;
1433f169c0eaSGlenn Lagasse zoneList_t zone_list = NULL;
1434f169c0eaSGlenn Lagasse zoneBrandList_t *brands = NULL;
1435f169c0eaSGlenn Lagasse boolean_t be_mounted = B_FALSE;
1436f169c0eaSGlenn Lagasse int zone_index = 0;
1437f169c0eaSGlenn Lagasse int err = BE_SUCCESS;
1438f169c0eaSGlenn Lagasse
1439f169c0eaSGlenn Lagasse /*
1440f169c0eaSGlenn Lagasse * Get the supported zone brands so we can pass that
1441f169c0eaSGlenn Lagasse * to z_get_nonglobal_zone_list_by_brand. Currently
1442f169c0eaSGlenn Lagasse * only the ipkg and labeled brand zones are supported
1443f169c0eaSGlenn Lagasse *
1444f169c0eaSGlenn Lagasse */
1445f169c0eaSGlenn Lagasse if ((brands = be_get_supported_brandlist()) == NULL) {
1446f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: no supported "
1447f169c0eaSGlenn Lagasse "brands\n"));
1448f169c0eaSGlenn Lagasse return (BE_SUCCESS);
1449f169c0eaSGlenn Lagasse }
1450f169c0eaSGlenn Lagasse
1451f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, be_root_ds,
1452f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) {
1453f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: Failed to open "
1454f169c0eaSGlenn Lagasse "dataset (%s): %s\n"), be_root_ds,
1455f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
1456f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs);
1457f169c0eaSGlenn Lagasse z_free_brand_list(brands);
1458f169c0eaSGlenn Lagasse return (err);
1459f169c0eaSGlenn Lagasse }
1460f169c0eaSGlenn Lagasse
1461f169c0eaSGlenn Lagasse if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1462f169c0eaSGlenn Lagasse if ((err = _be_mount(be_name, &temp_mntpt,
1463f169c0eaSGlenn Lagasse BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1464f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: failed to "
1465f169c0eaSGlenn Lagasse "mount the BE for zones procesing.\n"));
1466f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1467f169c0eaSGlenn Lagasse z_free_brand_list(brands);
1468f169c0eaSGlenn Lagasse return (err);
1469f169c0eaSGlenn Lagasse }
1470f169c0eaSGlenn Lagasse be_mounted = B_TRUE;
1471f169c0eaSGlenn Lagasse }
1472f169c0eaSGlenn Lagasse
1473f169c0eaSGlenn Lagasse /*
1474f169c0eaSGlenn Lagasse * Set the zone root to the temp mount point for the BE we just mounted.
1475f169c0eaSGlenn Lagasse */
1476f169c0eaSGlenn Lagasse z_set_zone_root(temp_mntpt);
1477f169c0eaSGlenn Lagasse
1478f169c0eaSGlenn Lagasse /*
1479f169c0eaSGlenn Lagasse * Get all the zones based on the brands we're looking for. If no zones
1480f169c0eaSGlenn Lagasse * are found that we're interested in unmount the BE and move on.
1481f169c0eaSGlenn Lagasse */
1482f169c0eaSGlenn Lagasse if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1483f169c0eaSGlenn Lagasse if (be_mounted)
1484f169c0eaSGlenn Lagasse (void) _be_unmount(be_name, 0);
1485f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1486f169c0eaSGlenn Lagasse z_free_brand_list(brands);
1487f169c0eaSGlenn Lagasse free(temp_mntpt);
1488f169c0eaSGlenn Lagasse return (BE_SUCCESS);
1489f169c0eaSGlenn Lagasse }
1490f169c0eaSGlenn Lagasse for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1491f169c0eaSGlenn Lagasse != NULL; zone_index++) {
1492f169c0eaSGlenn Lagasse char *zone_path = NULL;
1493f169c0eaSGlenn Lagasse
1494f169c0eaSGlenn Lagasse /* Skip zones that aren't at least installed */
1495f169c0eaSGlenn Lagasse if (z_zlist_get_current_state(zone_list, zone_index) <
1496f169c0eaSGlenn Lagasse ZONE_STATE_INSTALLED)
1497f169c0eaSGlenn Lagasse continue;
1498f169c0eaSGlenn Lagasse
1499f169c0eaSGlenn Lagasse if (((zone_path =
1500f169c0eaSGlenn Lagasse z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1501f169c0eaSGlenn Lagasse ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1502f169c0eaSGlenn Lagasse !be_zone_supported(zone_ds))
1503f169c0eaSGlenn Lagasse continue;
1504f169c0eaSGlenn Lagasse
1505f169c0eaSGlenn Lagasse if (be_find_active_zone_root(zhp, zone_ds,
1506f169c0eaSGlenn Lagasse zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1507f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: "
1508f169c0eaSGlenn Lagasse "Zone does not have an active root "
1509f169c0eaSGlenn Lagasse "dataset, skipping this zone.\n"));
1510f169c0eaSGlenn Lagasse continue;
1511f169c0eaSGlenn Lagasse }
1512f169c0eaSGlenn Lagasse
1513f169c0eaSGlenn Lagasse if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1514f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) {
1515f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: "
1516f169c0eaSGlenn Lagasse "Failed to open dataset "
1517f169c0eaSGlenn Lagasse "(%s): %s\n"), zoneroot_ds,
1518f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
1519f169c0eaSGlenn Lagasse err = zfs_err_to_be_err(g_zfs);
1520f169c0eaSGlenn Lagasse goto done;
1521f169c0eaSGlenn Lagasse }
1522f169c0eaSGlenn Lagasse
1523f169c0eaSGlenn Lagasse if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1524f169c0eaSGlenn Lagasse sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1525f169c0eaSGlenn Lagasse ZFS_CLOSE(z_zhp);
1526f169c0eaSGlenn Lagasse continue;
1527f169c0eaSGlenn Lagasse }
1528f169c0eaSGlenn Lagasse
1529f169c0eaSGlenn Lagasse /*
1530f169c0eaSGlenn Lagasse * We don't need to close the zfs handle at this
1531f169c0eaSGlenn Lagasse * point because the callback funtion
1532f169c0eaSGlenn Lagasse * be_promote_ds_callback() will close it for us.
1533f169c0eaSGlenn Lagasse */
1534f169c0eaSGlenn Lagasse if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1535f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_zone_ds: "
1536f169c0eaSGlenn Lagasse "failed to activate the "
1537f169c0eaSGlenn Lagasse "datasets for %s: %s\n"),
1538f169c0eaSGlenn Lagasse zoneroot_ds,
1539f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
1540f169c0eaSGlenn Lagasse err = BE_ERR_PROMOTE;
1541f169c0eaSGlenn Lagasse goto done;
1542f169c0eaSGlenn Lagasse }
1543f169c0eaSGlenn Lagasse }
1544f169c0eaSGlenn Lagasse done:
1545f169c0eaSGlenn Lagasse if (be_mounted)
1546f169c0eaSGlenn Lagasse (void) _be_unmount(be_name, 0);
1547f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1548f169c0eaSGlenn Lagasse free(temp_mntpt);
1549f169c0eaSGlenn Lagasse z_free_brand_list(brands);
1550f169c0eaSGlenn Lagasse z_free_zone_list(zone_list);
1551f169c0eaSGlenn Lagasse return (err);
1552f169c0eaSGlenn Lagasse }
1553f169c0eaSGlenn Lagasse
1554f169c0eaSGlenn Lagasse /*
1555f169c0eaSGlenn Lagasse * Function: be_promote_ds_callback
1556f169c0eaSGlenn Lagasse * Description: This function is used to promote the datasets for the BE
1557f169c0eaSGlenn Lagasse * being activated as well as the datasets for the zones BE
1558f169c0eaSGlenn Lagasse * being activated.
1559f169c0eaSGlenn Lagasse *
1560f169c0eaSGlenn Lagasse * Parameters:
1561f169c0eaSGlenn Lagasse * zhp - the zfs handle for zone BE being activated.
1562f169c0eaSGlenn Lagasse * data - not used.
1563f169c0eaSGlenn Lagasse * Return:
1564f169c0eaSGlenn Lagasse * 0 - Success
1565f169c0eaSGlenn Lagasse * be_errno_t - Failure
1566f169c0eaSGlenn Lagasse *
1567f169c0eaSGlenn Lagasse * Scope:
1568f169c0eaSGlenn Lagasse * Private
1569f169c0eaSGlenn Lagasse */
1570f169c0eaSGlenn Lagasse static int
1571f169c0eaSGlenn Lagasse /* LINTED */
be_promote_ds_callback(zfs_handle_t * zhp,void * data)1572f169c0eaSGlenn Lagasse be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1573f169c0eaSGlenn Lagasse {
1574f169c0eaSGlenn Lagasse char origin[MAXPATHLEN];
1575f169c0eaSGlenn Lagasse char *sub_dataset = NULL;
1576f169c0eaSGlenn Lagasse int ret = 0;
1577f169c0eaSGlenn Lagasse
1578f169c0eaSGlenn Lagasse if (zhp != NULL) {
1579f169c0eaSGlenn Lagasse sub_dataset = strdup(zfs_get_name(zhp));
1580f169c0eaSGlenn Lagasse if (sub_dataset == NULL) {
1581f169c0eaSGlenn Lagasse ret = BE_ERR_NOMEM;
1582f169c0eaSGlenn Lagasse goto done;
1583f169c0eaSGlenn Lagasse }
1584f169c0eaSGlenn Lagasse } else {
1585f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_ds_callback: "
1586f169c0eaSGlenn Lagasse "Invalid zfs handle passed into function\n"));
1587f169c0eaSGlenn Lagasse ret = BE_ERR_INVAL;
1588f169c0eaSGlenn Lagasse goto done;
1589f169c0eaSGlenn Lagasse }
1590f169c0eaSGlenn Lagasse
1591f169c0eaSGlenn Lagasse /*
1592f169c0eaSGlenn Lagasse * This loop makes sure that we promote the dataset to the
1593f169c0eaSGlenn Lagasse * top of the tree so that it is no longer a decendent of any
1594f169c0eaSGlenn Lagasse * dataset. The ZFS close and then open is used to make sure that
1595f169c0eaSGlenn Lagasse * the promotion is updated before we move on.
1596f169c0eaSGlenn Lagasse */
1597f169c0eaSGlenn Lagasse while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1598f169c0eaSGlenn Lagasse sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1599f169c0eaSGlenn Lagasse if (zfs_promote(zhp) != 0) {
1600f169c0eaSGlenn Lagasse if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1601f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_ds_callback: "
1602f169c0eaSGlenn Lagasse "promote of %s failed: %s\n"),
1603f169c0eaSGlenn Lagasse zfs_get_name(zhp),
1604f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
1605f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs);
1606f169c0eaSGlenn Lagasse goto done;
1607f169c0eaSGlenn Lagasse } else {
1608f169c0eaSGlenn Lagasse /*
1609f169c0eaSGlenn Lagasse * If the call to zfs_promote returns the
1610f169c0eaSGlenn Lagasse * error EZFS_EXISTS we've hit a snapshot name
1611f169c0eaSGlenn Lagasse * collision. This means we're probably
1612f169c0eaSGlenn Lagasse * attemping to promote a zone dataset above a
1613f169c0eaSGlenn Lagasse * parent dataset that belongs to another zone
1614f169c0eaSGlenn Lagasse * which this zone was cloned from.
1615f169c0eaSGlenn Lagasse *
1616f169c0eaSGlenn Lagasse * TODO: If this is a zone dataset at some
1617f169c0eaSGlenn Lagasse * point we should skip this if the zone
1618f169c0eaSGlenn Lagasse * paths for the dataset and the snapshot
1619f169c0eaSGlenn Lagasse * don't match.
1620f169c0eaSGlenn Lagasse */
1621f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_ds_callback: "
1622f169c0eaSGlenn Lagasse "promote of %s failed due to snapshot "
1623f169c0eaSGlenn Lagasse "name collision: %s\n"), zfs_get_name(zhp),
1624f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
1625f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs);
1626f169c0eaSGlenn Lagasse goto done;
1627f169c0eaSGlenn Lagasse }
1628f169c0eaSGlenn Lagasse }
1629f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1630f169c0eaSGlenn Lagasse if ((zhp = zfs_open(g_zfs, sub_dataset,
1631f169c0eaSGlenn Lagasse ZFS_TYPE_FILESYSTEM)) == NULL) {
1632f169c0eaSGlenn Lagasse be_print_err(gettext("be_promote_ds_callback: "
1633f169c0eaSGlenn Lagasse "Failed to open dataset (%s): %s\n"), sub_dataset,
1634f169c0eaSGlenn Lagasse libzfs_error_description(g_zfs));
1635f169c0eaSGlenn Lagasse ret = zfs_err_to_be_err(g_zfs);
1636f169c0eaSGlenn Lagasse goto done;
1637f169c0eaSGlenn Lagasse }
1638f169c0eaSGlenn Lagasse }
1639f169c0eaSGlenn Lagasse
1640f169c0eaSGlenn Lagasse /* Iterate down this dataset's children and promote them */
1641f169c0eaSGlenn Lagasse ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1642f169c0eaSGlenn Lagasse
1643f169c0eaSGlenn Lagasse done:
1644f169c0eaSGlenn Lagasse free(sub_dataset);
1645f169c0eaSGlenn Lagasse ZFS_CLOSE(zhp);
1646f169c0eaSGlenn Lagasse return (ret);
1647f169c0eaSGlenn Lagasse }
1648