1 /*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
28 * Copyright 2016 Toomas Soome <tsoome@me.com>
29 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
30 */
31
32 #include <assert.h>
33 #include <libintl.h>
34 #include <libnvpair.h>
35 #include <libzfs.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <strings.h>
40 #include <errno.h>
41 #include <sys/mnttab.h>
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #include <unistd.h>
46 #include <sys/efi_partition.h>
47
48 #include <libbe.h>
49 #include <libbe_priv.h>
50
51 char *mnttab = MNTTAB;
52
53 /*
54 * Private function prototypes
55 */
56 static int set_bootfs(char *boot_rpool, char *be_root_ds);
57 static int set_canmount(be_node_list_t *, char *);
58 static boolean_t be_do_install_mbr(char *, nvlist_t *);
59 static int be_do_installboot_helper(zpool_handle_t *, nvlist_t *, char *,
60 char *, uint16_t);
61 static int be_do_installboot(be_transaction_data_t *, uint16_t);
62 static int be_get_grub_vers(be_transaction_data_t *, char **, char **);
63 static int get_ver_from_capfile(char *, char **);
64 static int be_promote_zone_ds(char *, char *);
65 static int be_promote_ds_callback(zfs_handle_t *, void *);
66
67 /* ******************************************************************** */
68 /* Public Functions */
69 /* ******************************************************************** */
70
71 /*
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 * grub menu to the entry corresponding to the entry for the named
78 * BE.
79 * Parameters:
80 * be_attrs - pointer to nvlist_t of attributes being passed in.
81 * The follow attribute values are used by this function:
82 *
83 * BE_ATTR_ORIG_BE_NAME *required
84 * Return:
85 * BE_SUCCESS - Success
86 * be_errno_t - Failure
87 * Scope:
88 * Public
89 */
90 int
be_activate(nvlist_t * be_attrs)91 be_activate(nvlist_t *be_attrs)
92 {
93 int ret = BE_SUCCESS;
94 char *be_name = NULL;
95
96 /* Initialize libzfs handle */
97 if (!be_zfs_init())
98 return (BE_ERR_INIT);
99
100 /* Get the BE name to activate */
101 if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
102 != 0) {
103 be_print_err(gettext("be_activate: failed to "
104 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
105 be_zfs_fini();
106 return (BE_ERR_INVAL);
107 }
108
109 /* Validate BE name */
110 if (!be_valid_be_name(be_name)) {
111 be_print_err(gettext("be_activate: invalid BE name %s\n"),
112 be_name);
113 be_zfs_fini();
114 return (BE_ERR_INVAL);
115 }
116
117 ret = _be_activate(be_name);
118
119 be_zfs_fini();
120
121 return (ret);
122 }
123
124 /*
125 * Function: be_installboot
126 * Description: Calls be_do_installboot to install/update bootloader on
127 * pool passed in through be_attrs. The primary consumer is
128 * bootadm command to avoid duplication of the code.
129 * Parameters:
130 * be_attrs - pointer to nvlist_t of attributes being passed in.
131 * The following attribute values are used:
132 *
133 * BE_ATTR_ORIG_BE_NAME *required
134 * BE_ATTR_ORIG_BE_POOL *required
135 * BE_ATTR_ORIG_BE_ROOT *required
136 * BE_ATTR_INSTALL_FLAGS optional
137 *
138 * Return:
139 * BE_SUCCESS - Success
140 * be_errno_t - Failure
141 * Scope:
142 * Public
143 */
144 int
be_installboot(nvlist_t * be_attrs)145 be_installboot(nvlist_t *be_attrs)
146 {
147 int ret = BE_SUCCESS;
148 uint16_t flags = 0;
149 uint16_t verbose;
150 be_transaction_data_t bt = { 0 };
151
152 /* Get flags */
153 if (nvlist_lookup_pairs(be_attrs, NV_FLAG_NOENTOK,
154 BE_ATTR_INSTALL_FLAGS, DATA_TYPE_UINT16, &flags, NULL) != 0) {
155 be_print_err(gettext("be_installboot: failed to lookup "
156 "BE_ATTR_INSTALL_FLAGS attribute\n"));
157 return (BE_ERR_INVAL);
158 }
159
160 /* Set verbose early, so we get all messages */
161 verbose = flags & BE_INSTALLBOOT_FLAG_VERBOSE;
162 if (verbose == BE_INSTALLBOOT_FLAG_VERBOSE)
163 libbe_print_errors(B_TRUE);
164
165 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME,
166 &bt.obe_name);
167 if (ret != 0) {
168 be_print_err(gettext("be_installboot: failed to "
169 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
170 return (BE_ERR_INVAL);
171 }
172
173 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_POOL,
174 &bt.obe_zpool);
175 if (ret != 0) {
176 be_print_err(gettext("be_installboot: failed to "
177 "lookup BE_ATTR_ORIG_BE_POOL attribute\n"));
178 return (BE_ERR_INVAL);
179 }
180
181 ret = nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_ROOT,
182 &bt.obe_root_ds);
183 if (ret != 0) {
184 be_print_err(gettext("be_installboot: failed to "
185 "lookup BE_ATTR_ORIG_BE_ROOT attribute\n"));
186 return (BE_ERR_INVAL);
187 }
188
189 /* Initialize libzfs handle */
190 if (!be_zfs_init())
191 return (BE_ERR_INIT);
192
193 ret = be_do_installboot(&bt, flags);
194
195 be_zfs_fini();
196
197 return (ret);
198 }
199
200 /* ******************************************************************** */
201 /* Semi Private Functions */
202 /* ******************************************************************** */
203
204 /*
205 * Function: _be_activate
206 * Description: This does the actual work described in be_activate.
207 * Parameters:
208 * be_name - pointer to the name of BE to activate.
209 *
210 * Return:
211 * BE_SUCCESS - Success
212 * be_errnot_t - Failure
213 * Scope:
214 * Public
215 */
216 int
_be_activate(char * be_name)217 _be_activate(char *be_name)
218 {
219 be_transaction_data_t cb = { 0 };
220 zfs_handle_t *zhp = NULL;
221 char root_ds[MAXPATHLEN];
222 char active_ds[MAXPATHLEN];
223 be_node_list_t *be_nodes = NULL;
224 uuid_t uu = {0};
225 int entry, ret = BE_SUCCESS;
226 int zret = 0;
227
228 /*
229 * TODO: The BE needs to be validated to make sure that it is actually
230 * a bootable BE.
231 */
232
233 if (be_name == NULL)
234 return (BE_ERR_INVAL);
235
236 /* Set obe_name to be_name in the cb structure */
237 cb.obe_name = be_name;
238
239 /* find which zpool the be is in */
240 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
241 be_print_err(gettext("be_activate: failed to "
242 "find zpool for BE (%s)\n"), cb.obe_name);
243 return (BE_ERR_BE_NOENT);
244 } else if (zret < 0) {
245 be_print_err(gettext("be_activate: "
246 "zpool_iter failed: %s\n"),
247 libzfs_error_description(g_zfs));
248 ret = zfs_err_to_be_err(g_zfs);
249 return (ret);
250 }
251
252 be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
253 cb.obe_root_ds = strdup(root_ds);
254
255 if (getzoneid() == GLOBAL_ZONEID) {
256 ret = be_do_installboot(&cb, BE_INSTALLBOOT_FLAG_NULL);
257 if (ret != BE_SUCCESS)
258 return (ret);
259
260 if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
261 if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
262 NULL, NULL, NULL)) != BE_SUCCESS) {
263 be_print_err(gettext("be_activate: Failed to "
264 "add BE (%s) to the menu\n"),
265 cb.obe_name);
266 goto done;
267 }
268 }
269 if (be_has_grub()) {
270 if ((ret = be_change_grub_default(cb.obe_name,
271 cb.obe_zpool)) != BE_SUCCESS) {
272 be_print_err(gettext("be_activate: failed to "
273 "change the default entry in menu.lst\n"));
274 goto done;
275 }
276 }
277 }
278
279 if ((ret = _be_list(cb.obe_name, &be_nodes, BE_LIST_DEFAULT))
280 != BE_SUCCESS) {
281 return (ret);
282 }
283
284 if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
285 be_print_err(gettext("be_activate: failed to set "
286 "canmount dataset property\n"));
287 goto done;
288 }
289
290 if (getzoneid() == GLOBAL_ZONEID) {
291 if ((ret = set_bootfs(be_nodes->be_rpool,
292 root_ds)) != BE_SUCCESS) {
293 be_print_err(gettext("be_activate: failed to set "
294 "bootfs pool property for %s\n"), root_ds);
295 goto done;
296 }
297 }
298
299 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
300 /*
301 * We don't need to close the zfs handle at this
302 * point because The callback funtion
303 * be_promote_ds_callback() will close it for us.
304 */
305 if (be_promote_ds_callback(zhp, NULL) != 0) {
306 be_print_err(gettext("be_activate: "
307 "failed to activate the "
308 "datasets for %s: %s\n"),
309 root_ds,
310 libzfs_error_description(g_zfs));
311 ret = BE_ERR_PROMOTE;
312 goto done;
313 }
314 } else {
315 be_print_err(gettext("be_activate: failed to open "
316 "dataset (%s): %s\n"), root_ds,
317 libzfs_error_description(g_zfs));
318 ret = zfs_err_to_be_err(g_zfs);
319 goto done;
320 }
321
322 if (getzoneid() == GLOBAL_ZONEID &&
323 be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
324 (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
325 != BE_SUCCESS) {
326 be_print_err(gettext("be_activate: failed to promote "
327 "the active zonepath datasets for zones in BE %s\n"),
328 cb.obe_name);
329 }
330
331 if (getzoneid() != GLOBAL_ZONEID) {
332 if (!be_zone_compare_uuids(root_ds)) {
333 be_print_err(gettext("be_activate: activating zone "
334 "root dataset from non-active global BE is not "
335 "supported\n"));
336 ret = BE_ERR_NOTSUP;
337 goto done;
338 }
339 if ((zhp = zfs_open(g_zfs, root_ds,
340 ZFS_TYPE_FILESYSTEM)) == NULL) {
341 be_print_err(gettext("be_activate: failed to open "
342 "dataset (%s): %s\n"), root_ds,
343 libzfs_error_description(g_zfs));
344 ret = zfs_err_to_be_err(g_zfs);
345 goto done;
346 }
347 /* Find current active zone root dataset */
348 if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
349 active_ds, sizeof (active_ds))) != BE_SUCCESS) {
350 be_print_err(gettext("be_activate: failed to find "
351 "active zone root dataset\n"));
352 ZFS_CLOSE(zhp);
353 goto done;
354 }
355 /* Do nothing if requested BE is already active */
356 if (strcmp(root_ds, active_ds) == 0) {
357 ret = BE_SUCCESS;
358 ZFS_CLOSE(zhp);
359 goto done;
360 }
361
362 /* Set active property for BE */
363 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
364 be_print_err(gettext("be_activate: failed to set "
365 "active property (%s): %s\n"), root_ds,
366 libzfs_error_description(g_zfs));
367 ret = zfs_err_to_be_err(g_zfs);
368 ZFS_CLOSE(zhp);
369 goto done;
370 }
371 ZFS_CLOSE(zhp);
372
373 /* Unset active property for old active root dataset */
374 if ((zhp = zfs_open(g_zfs, active_ds,
375 ZFS_TYPE_FILESYSTEM)) == NULL) {
376 be_print_err(gettext("be_activate: failed to open "
377 "dataset (%s): %s\n"), active_ds,
378 libzfs_error_description(g_zfs));
379 ret = zfs_err_to_be_err(g_zfs);
380 goto done;
381 }
382 if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
383 be_print_err(gettext("be_activate: failed to unset "
384 "active property (%s): %s\n"), active_ds,
385 libzfs_error_description(g_zfs));
386 ret = zfs_err_to_be_err(g_zfs);
387 ZFS_CLOSE(zhp);
388 goto done;
389 }
390 ZFS_CLOSE(zhp);
391 }
392 done:
393 be_free_list(be_nodes);
394 return (ret);
395 }
396
397 /*
398 * Function: be_activate_current_be
399 * Description: Set the currently "active" BE to be "active on boot"
400 * Paramters:
401 * none
402 * Returns:
403 * BE_SUCCESS - Success
404 * be_errnot_t - Failure
405 * Scope:
406 * Semi-private (library wide use only)
407 */
408 int
be_activate_current_be(void)409 be_activate_current_be(void)
410 {
411 int ret = BE_SUCCESS;
412 be_transaction_data_t bt = { 0 };
413
414 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
415 return (ret);
416 }
417
418 if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
419 be_print_err(gettext("be_activate_current_be: failed to "
420 "activate %s\n"), bt.obe_name);
421 return (ret);
422 }
423
424 return (BE_SUCCESS);
425 }
426
427 /*
428 * Function: be_is_active_on_boot
429 * Description: Checks if the BE name passed in has the "active on boot"
430 * property set to B_TRUE.
431 * Paramters:
432 * be_name - the name of the BE to check
433 * Returns:
434 * B_TRUE - if active on boot.
435 * B_FALSE - if not active on boot.
436 * Scope:
437 * Semi-private (library wide use only)
438 */
439 boolean_t
be_is_active_on_boot(char * be_name)440 be_is_active_on_boot(char *be_name)
441 {
442 be_node_list_t *be_node = NULL;
443
444 if (be_name == NULL) {
445 be_print_err(gettext("be_is_active_on_boot: "
446 "be_name must not be NULL\n"));
447 return (B_FALSE);
448 }
449
450 if (_be_list(be_name, &be_node, BE_LIST_DEFAULT) != BE_SUCCESS) {
451 return (B_FALSE);
452 }
453
454 if (be_node == NULL) {
455 return (B_FALSE);
456 }
457
458 if (be_node->be_active_on_boot) {
459 be_free_list(be_node);
460 return (B_TRUE);
461 } else {
462 be_free_list(be_node);
463 return (B_FALSE);
464 }
465 }
466
467 /* ******************************************************************** */
468 /* Private Functions */
469 /* ******************************************************************** */
470
471 /*
472 * Function: set_bootfs
473 * Description: Sets the bootfs property on the boot pool to be the
474 * root dataset of the activated BE.
475 * Parameters:
476 * boot_pool - The pool we're setting bootfs in.
477 * be_root_ds - The main dataset for the BE.
478 * Return:
479 * BE_SUCCESS - Success
480 * be_errno_t - Failure
481 * Scope:
482 * Private
483 */
484 static int
set_bootfs(char * boot_rpool,char * be_root_ds)485 set_bootfs(char *boot_rpool, char *be_root_ds)
486 {
487 zpool_handle_t *zhp;
488 int err = BE_SUCCESS;
489
490 if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
491 be_print_err(gettext("set_bootfs: failed to open pool "
492 "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
493 err = zfs_err_to_be_err(g_zfs);
494 return (err);
495 }
496
497 err = zpool_set_prop(zhp, "bootfs", be_root_ds);
498 if (err) {
499 be_print_err(gettext("set_bootfs: failed to set "
500 "bootfs property for pool %s: %s\n"), boot_rpool,
501 libzfs_error_description(g_zfs));
502 err = zfs_err_to_be_err(g_zfs);
503 zpool_close(zhp);
504 return (err);
505 }
506
507 zpool_close(zhp);
508 return (BE_SUCCESS);
509 }
510
511 /*
512 * Function: set_canmount
513 * Description: Sets the canmount property on the datasets of the
514 * activated BE.
515 * Parameters:
516 * be_nodes - The be_node_t returned from be_list
517 * value - The value of canmount we setting, on|off|noauto.
518 * Return:
519 * BE_SUCCESS - Success
520 * be_errno_t - Failure
521 * Scope:
522 * Private
523 */
524 static int
set_canmount(be_node_list_t * be_nodes,char * value)525 set_canmount(be_node_list_t *be_nodes, char *value)
526 {
527 char ds_path[MAXPATHLEN];
528 zfs_handle_t *zhp = NULL;
529 be_node_list_t *list = be_nodes;
530 int err = BE_SUCCESS;
531
532 while (list != NULL) {
533 be_dataset_list_t *datasets = list->be_node_datasets;
534
535 be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
536 sizeof (ds_path));
537
538 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
539 NULL) {
540 be_print_err(gettext("set_canmount: failed to open "
541 "dataset (%s): %s\n"), ds_path,
542 libzfs_error_description(g_zfs));
543 err = zfs_err_to_be_err(g_zfs);
544 return (err);
545 }
546 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
547 /*
548 * it's already mounted so we can't change the
549 * canmount property anyway.
550 */
551 err = BE_SUCCESS;
552 } else {
553 err = zfs_prop_set(zhp,
554 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
555 if (err) {
556 ZFS_CLOSE(zhp);
557 be_print_err(gettext("set_canmount: failed to "
558 "set dataset property (%s): %s\n"),
559 ds_path, libzfs_error_description(g_zfs));
560 err = zfs_err_to_be_err(g_zfs);
561 return (err);
562 }
563 }
564 ZFS_CLOSE(zhp);
565
566 while (datasets != NULL) {
567 be_make_root_ds(list->be_rpool,
568 datasets->be_dataset_name, ds_path,
569 sizeof (ds_path));
570
571 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
572 == NULL) {
573 be_print_err(gettext("set_canmount: failed to "
574 "open dataset %s: %s\n"), ds_path,
575 libzfs_error_description(g_zfs));
576 err = zfs_err_to_be_err(g_zfs);
577 return (err);
578 }
579 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
580 /*
581 * it's already mounted so we can't change the
582 * canmount property anyway.
583 */
584 err = BE_SUCCESS;
585 ZFS_CLOSE(zhp);
586 break;
587 }
588 err = zfs_prop_set(zhp,
589 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
590 if (err) {
591 ZFS_CLOSE(zhp);
592 be_print_err(gettext("set_canmount: "
593 "Failed to set property value %s "
594 "for dataset %s: %s\n"), value, ds_path,
595 libzfs_error_description(g_zfs));
596 err = zfs_err_to_be_err(g_zfs);
597 return (err);
598 }
599 ZFS_CLOSE(zhp);
600 datasets = datasets->be_next_dataset;
601 }
602 list = list->be_next_node;
603 }
604 return (err);
605 }
606
607 /*
608 * Function: be_get_grub_vers
609 * Description: Gets the grub version number from /boot/grub/capability. If
610 * capability file doesn't exist NULL is returned.
611 * Parameters:
612 * bt - The transaction data for the BE we're getting the grub
613 * version for.
614 * cur_vers - used to return the current version of grub from
615 * the root pool.
616 * new_vers - used to return the grub version of the BE we're
617 * activating.
618 * Return:
619 * BE_SUCCESS - Success
620 * be_errno_t - Failed to find version
621 * Scope:
622 * Private
623 */
624 static int
be_get_grub_vers(be_transaction_data_t * bt,char ** cur_vers,char ** new_vers)625 be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
626 {
627 zfs_handle_t *zhp = NULL;
628 zfs_handle_t *pool_zhp = NULL;
629 int ret = BE_SUCCESS;
630 char cap_file[MAXPATHLEN];
631 char *temp_mntpnt = NULL;
632 char *zpool_mntpt = NULL;
633 char *ptmp_mntpnt = NULL;
634 char *orig_mntpnt = NULL;
635 boolean_t be_mounted = B_FALSE;
636 boolean_t pool_mounted = B_FALSE;
637
638 if (!be_has_grub()) {
639 be_print_err(gettext("be_get_grub_vers: Not supported on "
640 "this architecture\n"));
641 return (BE_ERR_NOTSUP);
642 }
643
644 if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL ||
645 bt->obe_root_ds == NULL) {
646 be_print_err(gettext("be_get_grub_vers: Invalid BE\n"));
647 return (BE_ERR_INVAL);
648 }
649
650 if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
651 NULL) {
652 be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"),
653 libzfs_error_description(g_zfs));
654 return (zfs_err_to_be_err(g_zfs));
655 }
656
657 /*
658 * Check to see if the pool's dataset is mounted. If it isn't we'll
659 * attempt to mount it.
660 */
661 if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt,
662 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
663 be_print_err(gettext("be_get_grub_vers: pool dataset "
664 "(%s) could not be mounted\n"), bt->obe_zpool);
665 ZFS_CLOSE(pool_zhp);
666 return (ret);
667 }
668
669 /*
670 * Get the mountpoint for the root pool dataset.
671 */
672 if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) {
673 be_print_err(gettext("be_get_grub_vers: pool "
674 "dataset (%s) is not mounted. Can't read the "
675 "grub capability file.\n"), bt->obe_zpool);
676 ret = BE_ERR_NO_MENU;
677 goto cleanup;
678 }
679
680 /*
681 * get the version of the most recent grub update.
682 */
683 (void) snprintf(cap_file, sizeof (cap_file), "%s%s",
684 zpool_mntpt, BE_CAP_FILE);
685 free(zpool_mntpt);
686 zpool_mntpt = NULL;
687
688 if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
689 goto cleanup;
690
691 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
692 NULL) {
693 be_print_err(gettext("be_get_grub_vers: failed to "
694 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
695 libzfs_error_description(g_zfs));
696 free(cur_vers);
697 ret = zfs_err_to_be_err(g_zfs);
698 goto cleanup;
699 }
700 if (!zfs_is_mounted(zhp, &temp_mntpnt)) {
701 if ((ret = _be_mount(bt->obe_name, &temp_mntpnt,
702 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
703 be_print_err(gettext("be_get_grub_vers: failed to "
704 "mount BE (%s)\n"), bt->obe_name);
705 free(*cur_vers);
706 *cur_vers = NULL;
707 ZFS_CLOSE(zhp);
708 goto cleanup;
709 }
710 be_mounted = B_TRUE;
711 }
712 ZFS_CLOSE(zhp);
713
714 /*
715 * Now get the grub version for the BE being activated.
716 */
717 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt,
718 BE_CAP_FILE);
719 ret = get_ver_from_capfile(cap_file, new_vers);
720 if (ret != BE_SUCCESS) {
721 free(*cur_vers);
722 *cur_vers = NULL;
723 }
724 if (be_mounted)
725 (void) _be_unmount(bt->obe_name, 0);
726
727 cleanup:
728 if (pool_mounted) {
729 int iret = BE_SUCCESS;
730 iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt);
731 if (ret == BE_SUCCESS)
732 ret = iret;
733 free(orig_mntpnt);
734 free(ptmp_mntpnt);
735 }
736 ZFS_CLOSE(pool_zhp);
737
738 free(temp_mntpnt);
739 return (ret);
740 }
741
742 /*
743 * Function: get_ver_from_capfile
744 * Description: Parses the capability file passed in looking for the VERSION
745 * line. If found the version is returned in vers, if not then
746 * NULL is returned in vers.
747 *
748 * Parameters:
749 * file - the path to the capability file we want to parse.
750 * vers - the version string that will be passed back.
751 * Return:
752 * BE_SUCCESS - Success
753 * be_errno_t - Failed to find version
754 * Scope:
755 * Private
756 */
757 static int
get_ver_from_capfile(char * file,char ** vers)758 get_ver_from_capfile(char *file, char **vers)
759 {
760 FILE *fp = NULL;
761 char line[BUFSIZ];
762 char *last = NULL;
763 int err = BE_SUCCESS;
764 errno = 0;
765
766 if (!be_has_grub()) {
767 be_print_err(gettext("get_ver_from_capfile: Not supported "
768 "on this architecture\n"));
769 return (BE_ERR_NOTSUP);
770 }
771
772 /*
773 * Set version string to NULL; the only case this shouldn't be set
774 * to be NULL is when we've actually found a version in the capability
775 * file, which is set below.
776 */
777 *vers = NULL;
778
779 /*
780 * If the capability file doesn't exist, we're returning success
781 * because on older releases, the capability file did not exist
782 * so this is a valid scenario.
783 */
784 if (access(file, F_OK) == 0) {
785 if ((fp = fopen(file, "r")) == NULL) {
786 err = errno;
787 be_print_err(gettext("get_ver_from_capfile: failed to "
788 "open file %s with error %s\n"), file,
789 strerror(err));
790 err = errno_to_be_err(err);
791 return (err);
792 }
793
794 while (fgets(line, BUFSIZ, fp)) {
795 char *tok = strtok_r(line, "=", &last);
796
797 if (tok == NULL || tok[0] == '#') {
798 continue;
799 } else if (strcmp(tok, "VERSION") == 0) {
800 *vers = strdup(last);
801 break;
802 }
803 }
804 (void) fclose(fp);
805 }
806
807 return (BE_SUCCESS);
808 }
809
810 /*
811 * To be able to boot EFI labeled disks, stage1 needs to be written
812 * into the MBR. We do not do this if we're on disks with a traditional
813 * fdisk partition table only, or if any foreign EFI partitions exist.
814 * In the trivial case of a whole-disk vdev we always write stage1 into
815 * the MBR.
816 */
817 static boolean_t
be_do_install_mbr(char * diskname,nvlist_t * child)818 be_do_install_mbr(char *diskname, nvlist_t *child)
819 {
820 struct uuid allowed_uuids[] = {
821 EFI_UNUSED,
822 EFI_RESV1,
823 EFI_BOOT,
824 EFI_ROOT,
825 EFI_SWAP,
826 EFI_USR,
827 EFI_BACKUP,
828 EFI_RESV2,
829 EFI_VAR,
830 EFI_HOME,
831 EFI_ALTSCTR,
832 EFI_RESERVED,
833 EFI_SYSTEM,
834 EFI_BIOS_BOOT,
835 EFI_SYMC_PUB,
836 EFI_SYMC_CDS
837 };
838
839 uint64_t whole;
840 struct dk_gpt *gpt;
841 struct uuid *u;
842 int fd, npart, i, j;
843
844 (void) nvlist_lookup_uint64(child, ZPOOL_CONFIG_WHOLE_DISK,
845 &whole);
846
847 if (whole)
848 return (B_TRUE);
849
850 if ((fd = open(diskname, O_RDONLY|O_NDELAY)) < 0)
851 return (B_FALSE);
852
853 if ((npart = efi_alloc_and_read(fd, &gpt)) <= 0)
854 return (B_FALSE);
855
856 for (i = 0; i != npart; i++) {
857 int match = 0;
858
859 u = &gpt->efi_parts[i].p_guid;
860
861 for (j = 0;
862 j != sizeof (allowed_uuids) / sizeof (struct uuid);
863 j++)
864 if (bcmp(u, &allowed_uuids[j],
865 sizeof (struct uuid)) == 0)
866 match++;
867
868 if (match == 0)
869 return (B_FALSE);
870 }
871
872 return (B_TRUE);
873 }
874
875 static int
be_do_installboot_helper(zpool_handle_t * zphp,nvlist_t * child,char * stage1,char * stage2,uint16_t flags)876 be_do_installboot_helper(zpool_handle_t *zphp, nvlist_t *child, char *stage1,
877 char *stage2, uint16_t flags)
878 {
879 char install_cmd[MAXPATHLEN];
880 char be_run_cmd_errbuf[BUFSIZ];
881 char be_run_cmd_outbuf[BUFSIZ];
882 char diskname[MAXPATHLEN];
883 char *vname;
884 char *path, *dsk_ptr;
885 char *flag = "";
886 int ret;
887 vdev_stat_t *vs;
888 uint_t vsc;
889
890 if (nvlist_lookup_string(child, ZPOOL_CONFIG_PATH, &path) != 0) {
891 be_print_err(gettext("be_do_installboot: "
892 "failed to get device path\n"));
893 return (BE_ERR_NODEV);
894 }
895
896 if ((nvlist_lookup_uint64_array(child, ZPOOL_CONFIG_VDEV_STATS,
897 (uint64_t **)&vs, &vsc) != 0) ||
898 vs->vs_state < VDEV_STATE_DEGRADED) {
899 /*
900 * Don't try to run installgrub on a vdev that is not ONLINE
901 * or DEGRADED. Try to print a warning for each such vdev.
902 */
903 be_print_err(gettext("be_do_installboot: "
904 "vdev %s is %s, can't install boot loader\n"),
905 path, zpool_state_to_name(vs->vs_state, vs->vs_aux));
906 free(path);
907 return (BE_SUCCESS);
908 }
909
910 /*
911 * Modify the vdev path to point to the raw disk.
912 */
913 path = strdup(path);
914 if (path == NULL)
915 return (BE_ERR_NOMEM);
916
917 dsk_ptr = strstr(path, "/dsk/");
918 if (dsk_ptr != NULL) {
919 *dsk_ptr = '\0';
920 dsk_ptr++;
921 } else {
922 dsk_ptr = "";
923 }
924
925 (void) snprintf(diskname, sizeof (diskname), "%s/r%s", path, dsk_ptr);
926 free(path);
927
928 vname = zpool_vdev_name(g_zfs, zphp, child, B_FALSE);
929 if (vname == NULL) {
930 be_print_err(gettext("be_do_installboot: "
931 "failed to get device name: %s\n"),
932 libzfs_error_description(g_zfs));
933 return (zfs_err_to_be_err(g_zfs));
934 }
935
936 if (be_is_isa("i386")) {
937 uint16_t force = flags & BE_INSTALLBOOT_FLAG_FORCE;
938 uint16_t mbr = flags & BE_INSTALLBOOT_FLAG_MBR;
939
940 if (force == BE_INSTALLBOOT_FLAG_FORCE) {
941 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
942 be_do_install_mbr(diskname, child))
943 flag = "-F -m -f";
944 else
945 flag = "-F";
946 } else {
947 if (mbr == BE_INSTALLBOOT_FLAG_MBR ||
948 be_do_install_mbr(diskname, child))
949 flag = "-m -f";
950 }
951
952 if (be_has_grub()) {
953 (void) snprintf(install_cmd, sizeof (install_cmd),
954 "%s %s %s %s %s", BE_INSTALL_GRUB, flag,
955 stage1, stage2, diskname);
956 } else {
957 (void) snprintf(install_cmd, sizeof (install_cmd),
958 "%s %s %s %s %s", BE_INSTALL_BOOT, flag,
959 stage1, stage2, diskname);
960 }
961 } else if (be_is_isa("sparc")) {
962 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) ==
963 BE_INSTALLBOOT_FLAG_FORCE)
964 flag = "-f -F zfs";
965 else
966 flag = "-F zfs";
967
968 (void) snprintf(install_cmd, sizeof (install_cmd),
969 "%s %s %s %s", BE_INSTALL_BOOT, flag, stage2, diskname);
970 } else {
971 be_print_err(gettext("be_do_installboot: unsupported "
972 "architecture.\n"));
973 return (BE_ERR_BOOTFILE_INST);
974 }
975
976 *be_run_cmd_outbuf = '\0';
977 *be_run_cmd_errbuf = '\0';
978
979 ret = be_run_cmd(install_cmd, be_run_cmd_errbuf, BUFSIZ,
980 be_run_cmd_outbuf, BUFSIZ);
981
982 if (ret != BE_SUCCESS) {
983 be_print_err(gettext("be_do_installboot: install "
984 "failed for device %s.\n"), vname);
985 ret = BE_ERR_BOOTFILE_INST;
986 }
987
988 be_print_err(gettext(" Command: \"%s\"\n"), install_cmd);
989 if (be_run_cmd_outbuf[0] != 0) {
990 be_print_err(gettext(" Output:\n"));
991 be_print_err("%s", be_run_cmd_outbuf);
992 }
993
994 if (be_run_cmd_errbuf[0] != 0) {
995 be_print_err(gettext(" Errors:\n"));
996 be_print_err("%s", be_run_cmd_errbuf);
997 }
998 free(vname);
999
1000 return (ret);
1001 }
1002
1003 /*
1004 * Function: be_do_copy_grub_cap
1005 * Description: This function will copy grub capability file to BE.
1006 *
1007 * Parameters:
1008 * bt - The transaction data for the BE we're activating.
1009 * Return:
1010 * BE_SUCCESS - Success
1011 * be_errno_t - Failure
1012 *
1013 * Scope:
1014 * Private
1015 */
1016 static int
be_do_copy_grub_cap(be_transaction_data_t * bt)1017 be_do_copy_grub_cap(be_transaction_data_t *bt)
1018 {
1019 zfs_handle_t *zhp = NULL;
1020 char cap_file[MAXPATHLEN];
1021 char zpool_cap_file[MAXPATHLEN];
1022 char line[BUFSIZ];
1023 char *tmp_mntpnt = NULL;
1024 char *orig_mntpnt = NULL;
1025 char *pool_mntpnt = NULL;
1026 FILE *cap_fp = NULL;
1027 FILE *zpool_cap_fp = NULL;
1028 int err = 0;
1029 int ret = BE_SUCCESS;
1030 boolean_t pool_mounted = B_FALSE;
1031 boolean_t be_mounted = B_FALSE;
1032
1033 /*
1034 * first get BE dataset mountpoint, we can free all the resources
1035 * once cap_file is built, leaving only be unmount to be done.
1036 */
1037 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1038 NULL) {
1039 be_print_err(gettext("be_do_copy_grub_cap: failed to "
1040 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1041 libzfs_error_description(g_zfs));
1042 return (zfs_err_to_be_err(g_zfs));
1043 }
1044
1045 if (!zfs_is_mounted(zhp, &tmp_mntpnt)) {
1046 if ((ret = _be_mount(bt->obe_name, &tmp_mntpnt,
1047 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1048 be_print_err(gettext("be_do_copy_grub_cap: failed to "
1049 "mount BE (%s)\n"), bt->obe_name);
1050 ZFS_CLOSE(zhp);
1051 goto done;
1052 }
1053 be_mounted = B_TRUE;
1054 }
1055 ZFS_CLOSE(zhp); /* BE dataset handle is not needed any more */
1056
1057 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpnt,
1058 BE_CAP_FILE);
1059 free(tmp_mntpnt);
1060
1061 /* get pool root dataset mountpoint */
1062 zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM);
1063 if (zhp == NULL) {
1064 be_print_err(gettext("be_do_copy_grub_cap: zfs_open "
1065 "failed: %s\n"), libzfs_error_description(g_zfs));
1066 ret = zfs_err_to_be_err(g_zfs);
1067 goto done;
1068 }
1069
1070 /*
1071 * Check to see if the pool's dataset is mounted. If it isn't we'll
1072 * attempt to mount it.
1073 */
1074 if ((ret = be_mount_pool(zhp, &tmp_mntpnt,
1075 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
1076 be_print_err(gettext("be_do_copy_grub_cap: pool dataset "
1077 "(%s) could not be mounted\n"), bt->obe_zpool);
1078 ZFS_CLOSE(zhp);
1079 goto done;
1080 }
1081
1082 /*
1083 * Get the mountpoint for the root pool dataset.
1084 * NOTE: zhp must be kept for _be_unmount_pool()
1085 */
1086 if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
1087 be_print_err(gettext("be_do_copy_grub_cap: pool "
1088 "dataset (%s) is not mounted. Can't check the grub "
1089 "version from the grub capability file.\n"), bt->obe_zpool);
1090 ret = BE_ERR_NO_MENU;
1091 goto done;
1092 }
1093
1094 (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
1095 pool_mntpnt, BE_CAP_FILE);
1096 free(pool_mntpnt);
1097
1098 if ((cap_fp = fopen(cap_file, "r")) == NULL) {
1099 err = errno;
1100 be_print_err(gettext("be_do_copy_grub_cap: failed to open grub "
1101 "capability file\n"));
1102 ret = errno_to_be_err(err);
1103 goto done;
1104 }
1105 if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
1106 err = errno;
1107 be_print_err(gettext("be_do_copy_grub_cap: failed to open new "
1108 "grub capability file\n"));
1109 ret = errno_to_be_err(err);
1110 (void) fclose(cap_fp);
1111 goto done;
1112 }
1113
1114 while (fgets(line, BUFSIZ, cap_fp)) {
1115 (void) fputs(line, zpool_cap_fp);
1116 }
1117
1118 (void) fclose(zpool_cap_fp);
1119 (void) fclose(cap_fp);
1120
1121 done:
1122 if (be_mounted)
1123 (void) _be_unmount(bt->obe_name, 0);
1124
1125 if (pool_mounted) {
1126 err = be_unmount_pool(zhp, tmp_mntpnt, orig_mntpnt);
1127 if (ret == BE_SUCCESS)
1128 ret = err;
1129 free(orig_mntpnt);
1130 free(tmp_mntpnt);
1131 zfs_close(zhp);
1132 }
1133 return (ret);
1134 }
1135
1136 /*
1137 * Function: be_is_install_needed
1138 * Description: Check detached version files to detect if bootloader
1139 * install/update is needed.
1140 *
1141 * Parameters:
1142 * bt - The transaction data for the BE we're activating.
1143 * update - set B_TRUE is update is needed.
1144 * Return:
1145 * BE_SUCCESS - Success
1146 * be_errno_t - Failure
1147 *
1148 * Scope:
1149 * Private
1150 */
1151 static int
be_is_install_needed(be_transaction_data_t * bt,boolean_t * update)1152 be_is_install_needed(be_transaction_data_t *bt, boolean_t *update)
1153 {
1154 int ret = BE_SUCCESS;
1155 char *cur_vers = NULL, *new_vers = NULL;
1156
1157 assert(bt != NULL);
1158 assert(update != NULL);
1159
1160 if (!be_has_grub()) {
1161 /*
1162 * no detached versioning, let installboot to manage
1163 * versioning.
1164 */
1165 *update = B_TRUE;
1166 return (ret);
1167 }
1168
1169 *update = B_FALSE; /* set default */
1170
1171 /*
1172 * We need to check to see if the version number from
1173 * the BE being activated is greater than the current
1174 * one.
1175 */
1176 ret = be_get_grub_vers(bt, &cur_vers, &new_vers);
1177 if (ret != BE_SUCCESS) {
1178 be_print_err(gettext("be_activate: failed to get grub "
1179 "versions from capability files.\n"));
1180 return (ret);
1181 }
1182 /* update if we have both versions and can compare */
1183 if (cur_vers != NULL) {
1184 if (new_vers != NULL) {
1185 if (atof(cur_vers) < atof(new_vers))
1186 *update = B_TRUE;
1187 free(new_vers);
1188 }
1189 free(cur_vers);
1190 } else if (new_vers != NULL) {
1191 /* we only got new version - update */
1192 *update = B_TRUE;
1193 free(new_vers);
1194 }
1195 return (ret);
1196 }
1197
1198 /*
1199 * Function: be_do_installboot
1200 * Description: This function runs installgrub/installboot using the boot
1201 * loader files from the BE we're activating and installing
1202 * them on the pool the BE lives in.
1203 *
1204 * Parameters:
1205 * bt - The transaction data for the BE we're activating.
1206 * flags - flags for bootloader install
1207 * Return:
1208 * BE_SUCCESS - Success
1209 * be_errno_t - Failure
1210 *
1211 * Scope:
1212 * Private
1213 */
1214 static int
be_do_installboot(be_transaction_data_t * bt,uint16_t flags)1215 be_do_installboot(be_transaction_data_t *bt, uint16_t flags)
1216 {
1217 zpool_handle_t *zphp = NULL;
1218 zfs_handle_t *zhp = NULL;
1219 nvlist_t **child, *nv, *config;
1220 uint_t c, children = 0;
1221 char *tmp_mntpt = NULL;
1222 char stage1[MAXPATHLEN];
1223 char stage2[MAXPATHLEN];
1224 char *vname;
1225 int ret = BE_SUCCESS;
1226 boolean_t be_mounted = B_FALSE;
1227 boolean_t update = B_FALSE;
1228 boolean_t verbose = B_FALSE;
1229
1230 /*
1231 * check versions. This call is to support detached
1232 * version implementation like grub. Embedded versioning is
1233 * checked by actual installer.
1234 */
1235 if ((flags & BE_INSTALLBOOT_FLAG_FORCE) != BE_INSTALLBOOT_FLAG_FORCE) {
1236 ret = be_is_install_needed(bt, &update);
1237 if (ret != BE_SUCCESS || update == B_FALSE)
1238 return (ret);
1239 }
1240 verbose = do_print;
1241
1242 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
1243 NULL) {
1244 be_print_err(gettext("be_do_installboot: failed to "
1245 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
1246 libzfs_error_description(g_zfs));
1247 ret = zfs_err_to_be_err(g_zfs);
1248 return (ret);
1249 }
1250 if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
1251 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
1252 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1253 be_print_err(gettext("be_do_installboot: failed to "
1254 "mount BE (%s)\n"), bt->obe_name);
1255 ZFS_CLOSE(zhp);
1256 return (ret);
1257 }
1258 be_mounted = B_TRUE;
1259 }
1260 ZFS_CLOSE(zhp);
1261
1262 if (be_is_isa("i386")) {
1263 if (be_has_grub()) {
1264 (void) snprintf(stage1, sizeof (stage1), "%s%s",
1265 tmp_mntpt, BE_GRUB_STAGE_1);
1266 (void) snprintf(stage2, sizeof (stage2), "%s%s",
1267 tmp_mntpt, BE_GRUB_STAGE_2);
1268 } else {
1269 (void) snprintf(stage1, sizeof (stage1), "%s%s",
1270 tmp_mntpt, BE_LOADER_STAGE_1);
1271 (void) snprintf(stage2, sizeof (stage2), "%s%s",
1272 tmp_mntpt, BE_LOADER_STAGE_2);
1273 }
1274 } else if (be_is_isa("sparc")) {
1275 char *platform = be_get_platform();
1276
1277 if (platform == NULL) {
1278 be_print_err(gettext("be_do_installboot: "
1279 "failed to detect system platform name\n"));
1280 if (be_mounted)
1281 (void) _be_unmount(bt->obe_name, 0);
1282 free(tmp_mntpt);
1283 return (BE_ERR_BOOTFILE_INST);
1284 }
1285 stage1[0] = '\0'; /* sparc has no stage1 */
1286 (void) snprintf(stage2, sizeof (stage2),
1287 "%s/usr/platform/%s%s", tmp_mntpt,
1288 platform, BE_SPARC_BOOTBLK);
1289 } else {
1290 be_print_err(gettext("be_do_installboot: unsupported "
1291 "architecture.\n"));
1292 return (BE_ERR_BOOTFILE_INST);
1293 }
1294
1295 if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
1296 be_print_err(gettext("be_do_installboot: failed to open "
1297 "pool (%s): %s\n"), bt->obe_zpool,
1298 libzfs_error_description(g_zfs));
1299 ret = zfs_err_to_be_err(g_zfs);
1300 if (be_mounted)
1301 (void) _be_unmount(bt->obe_name, 0);
1302 free(tmp_mntpt);
1303 return (ret);
1304 }
1305
1306 if ((config = zpool_get_config(zphp, NULL)) == NULL) {
1307 be_print_err(gettext("be_do_installboot: failed to get zpool "
1308 "configuration information. %s\n"),
1309 libzfs_error_description(g_zfs));
1310 ret = zfs_err_to_be_err(g_zfs);
1311 goto done;
1312 }
1313
1314 /*
1315 * Get the vdev tree
1316 */
1317 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
1318 be_print_err(gettext("be_do_installboot: failed to get vdev "
1319 "tree: %s\n"), libzfs_error_description(g_zfs));
1320 ret = zfs_err_to_be_err(g_zfs);
1321 goto done;
1322 }
1323
1324 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
1325 &children) != 0) {
1326 be_print_err(gettext("be_do_installboot: failed to traverse "
1327 "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
1328 ret = zfs_err_to_be_err(g_zfs);
1329 goto done;
1330 }
1331 for (c = 0; c < children; c++) {
1332 uint_t i, nchildren = 0;
1333 nvlist_t **nvchild;
1334
1335 /* ensure update on child status */
1336 vname = zpool_vdev_name(g_zfs, zphp, child[c], verbose);
1337 if (vname == NULL) {
1338 be_print_err(gettext(
1339 "be_do_installboot: "
1340 "failed to get device name: %s\n"),
1341 libzfs_error_description(g_zfs));
1342 ret = zfs_err_to_be_err(g_zfs);
1343 goto done;
1344 } else if (verbose == B_TRUE) {
1345 be_print_err(gettext("be_do_installboot: "
1346 "device %s\n"), vname);
1347 }
1348 free(vname);
1349
1350 ret = nvlist_lookup_nvlist_array(child[c],
1351 ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren);
1352 if (ret != 0) {
1353 if (ret != ENOENT) {
1354 be_print_err(gettext("be_do_installboot: "
1355 "failed to traverse the vdev tree: %s\n"),
1356 libzfs_error_description(g_zfs));
1357 ret = zfs_err_to_be_err(g_zfs);
1358 goto done;
1359 }
1360 nchildren = 0; /* This is leaf device. */
1361 }
1362
1363 if (nchildren != 0) {
1364 for (i = 0; i < nchildren; i++) {
1365 /* ensure update on child status */
1366 vname = zpool_vdev_name(g_zfs, zphp,
1367 nvchild[i], verbose);
1368 if (vname == NULL) {
1369 be_print_err(gettext(
1370 "be_do_installboot: "
1371 "failed to get device name: %s\n"),
1372 libzfs_error_description(g_zfs));
1373 ret = zfs_err_to_be_err(g_zfs);
1374 goto done;
1375 } else if (verbose == B_TRUE) {
1376 be_print_err(gettext(
1377 "be_do_installboot: device %s\n"),
1378 vname);
1379 }
1380 free(vname);
1381 ret = be_do_installboot_helper(zphp, nvchild[i],
1382 stage1, stage2, flags);
1383 if (ret != BE_SUCCESS)
1384 goto done;
1385 }
1386 } else {
1387 ret = be_do_installboot_helper(zphp, child[c], stage1,
1388 stage2, flags);
1389 if (ret != BE_SUCCESS)
1390 goto done;
1391 }
1392 }
1393
1394 if (be_has_grub()) {
1395 ret = be_do_copy_grub_cap(bt);
1396 }
1397
1398 done:
1399 ZFS_CLOSE(zhp);
1400 if (be_mounted)
1401 (void) _be_unmount(bt->obe_name, 0);
1402 zpool_close(zphp);
1403 free(tmp_mntpt);
1404 return (ret);
1405 }
1406
1407 /*
1408 * Function: be_promote_zone_ds
1409 * Description: This function finds the zones for the BE being activated
1410 * and the active zonepath dataset for each zone. Then each
1411 * active zonepath dataset is promoted.
1412 *
1413 * Parameters:
1414 * be_name - the name of the global zone BE that we need to
1415 * find the zones for.
1416 * be_root_ds - the root dataset for be_name.
1417 * Return:
1418 * BE_SUCCESS - Success
1419 * be_errno_t - Failure
1420 *
1421 * Scope:
1422 * Private
1423 */
1424 static int
be_promote_zone_ds(char * be_name,char * be_root_ds)1425 be_promote_zone_ds(char *be_name, char *be_root_ds)
1426 {
1427 char *zone_ds = NULL;
1428 char *temp_mntpt = NULL;
1429 char origin[MAXPATHLEN];
1430 char zoneroot_ds[MAXPATHLEN];
1431 zfs_handle_t *zhp = NULL;
1432 zfs_handle_t *z_zhp = NULL;
1433 zoneList_t zone_list = NULL;
1434 zoneBrandList_t *brands = NULL;
1435 boolean_t be_mounted = B_FALSE;
1436 int zone_index = 0;
1437 int err = BE_SUCCESS;
1438
1439 /*
1440 * Get the supported zone brands so we can pass that
1441 * to z_get_nonglobal_zone_list_by_brand. Currently
1442 * only the ipkg and labeled brand zones are supported
1443 *
1444 */
1445 if ((brands = be_get_supported_brandlist()) == NULL) {
1446 be_print_err(gettext("be_promote_zone_ds: no supported "
1447 "brands\n"));
1448 return (BE_SUCCESS);
1449 }
1450
1451 if ((zhp = zfs_open(g_zfs, be_root_ds,
1452 ZFS_TYPE_FILESYSTEM)) == NULL) {
1453 be_print_err(gettext("be_promote_zone_ds: Failed to open "
1454 "dataset (%s): %s\n"), be_root_ds,
1455 libzfs_error_description(g_zfs));
1456 err = zfs_err_to_be_err(g_zfs);
1457 z_free_brand_list(brands);
1458 return (err);
1459 }
1460
1461 if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1462 if ((err = _be_mount(be_name, &temp_mntpt,
1463 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1464 be_print_err(gettext("be_promote_zone_ds: failed to "
1465 "mount the BE for zones procesing.\n"));
1466 ZFS_CLOSE(zhp);
1467 z_free_brand_list(brands);
1468 return (err);
1469 }
1470 be_mounted = B_TRUE;
1471 }
1472
1473 /*
1474 * Set the zone root to the temp mount point for the BE we just mounted.
1475 */
1476 z_set_zone_root(temp_mntpt);
1477
1478 /*
1479 * Get all the zones based on the brands we're looking for. If no zones
1480 * are found that we're interested in unmount the BE and move on.
1481 */
1482 if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1483 if (be_mounted)
1484 (void) _be_unmount(be_name, 0);
1485 ZFS_CLOSE(zhp);
1486 z_free_brand_list(brands);
1487 free(temp_mntpt);
1488 return (BE_SUCCESS);
1489 }
1490 for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1491 != NULL; zone_index++) {
1492 char *zone_path = NULL;
1493
1494 /* Skip zones that aren't at least installed */
1495 if (z_zlist_get_current_state(zone_list, zone_index) <
1496 ZONE_STATE_INSTALLED)
1497 continue;
1498
1499 if (((zone_path =
1500 z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1501 ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1502 !be_zone_supported(zone_ds))
1503 continue;
1504
1505 if (be_find_active_zone_root(zhp, zone_ds,
1506 zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1507 be_print_err(gettext("be_promote_zone_ds: "
1508 "Zone does not have an active root "
1509 "dataset, skipping this zone.\n"));
1510 continue;
1511 }
1512
1513 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1514 ZFS_TYPE_FILESYSTEM)) == NULL) {
1515 be_print_err(gettext("be_promote_zone_ds: "
1516 "Failed to open dataset "
1517 "(%s): %s\n"), zoneroot_ds,
1518 libzfs_error_description(g_zfs));
1519 err = zfs_err_to_be_err(g_zfs);
1520 goto done;
1521 }
1522
1523 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1524 sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1525 ZFS_CLOSE(z_zhp);
1526 continue;
1527 }
1528
1529 /*
1530 * We don't need to close the zfs handle at this
1531 * point because the callback funtion
1532 * be_promote_ds_callback() will close it for us.
1533 */
1534 if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1535 be_print_err(gettext("be_promote_zone_ds: "
1536 "failed to activate the "
1537 "datasets for %s: %s\n"),
1538 zoneroot_ds,
1539 libzfs_error_description(g_zfs));
1540 err = BE_ERR_PROMOTE;
1541 goto done;
1542 }
1543 }
1544 done:
1545 if (be_mounted)
1546 (void) _be_unmount(be_name, 0);
1547 ZFS_CLOSE(zhp);
1548 free(temp_mntpt);
1549 z_free_brand_list(brands);
1550 z_free_zone_list(zone_list);
1551 return (err);
1552 }
1553
1554 /*
1555 * Function: be_promote_ds_callback
1556 * Description: This function is used to promote the datasets for the BE
1557 * being activated as well as the datasets for the zones BE
1558 * being activated.
1559 *
1560 * Parameters:
1561 * zhp - the zfs handle for zone BE being activated.
1562 * data - not used.
1563 * Return:
1564 * 0 - Success
1565 * be_errno_t - Failure
1566 *
1567 * Scope:
1568 * Private
1569 */
1570 static int
1571 /* LINTED */
be_promote_ds_callback(zfs_handle_t * zhp,void * data)1572 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1573 {
1574 char origin[MAXPATHLEN];
1575 char *sub_dataset = NULL;
1576 int ret = 0;
1577
1578 if (zhp != NULL) {
1579 sub_dataset = strdup(zfs_get_name(zhp));
1580 if (sub_dataset == NULL) {
1581 ret = BE_ERR_NOMEM;
1582 goto done;
1583 }
1584 } else {
1585 be_print_err(gettext("be_promote_ds_callback: "
1586 "Invalid zfs handle passed into function\n"));
1587 ret = BE_ERR_INVAL;
1588 goto done;
1589 }
1590
1591 /*
1592 * This loop makes sure that we promote the dataset to the
1593 * top of the tree so that it is no longer a decendent of any
1594 * dataset. The ZFS close and then open is used to make sure that
1595 * the promotion is updated before we move on.
1596 */
1597 while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1598 sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1599 if (zfs_promote(zhp) != 0) {
1600 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1601 be_print_err(gettext("be_promote_ds_callback: "
1602 "promote of %s failed: %s\n"),
1603 zfs_get_name(zhp),
1604 libzfs_error_description(g_zfs));
1605 ret = zfs_err_to_be_err(g_zfs);
1606 goto done;
1607 } else {
1608 /*
1609 * If the call to zfs_promote returns the
1610 * error EZFS_EXISTS we've hit a snapshot name
1611 * collision. This means we're probably
1612 * attemping to promote a zone dataset above a
1613 * parent dataset that belongs to another zone
1614 * which this zone was cloned from.
1615 *
1616 * TODO: If this is a zone dataset at some
1617 * point we should skip this if the zone
1618 * paths for the dataset and the snapshot
1619 * don't match.
1620 */
1621 be_print_err(gettext("be_promote_ds_callback: "
1622 "promote of %s failed due to snapshot "
1623 "name collision: %s\n"), zfs_get_name(zhp),
1624 libzfs_error_description(g_zfs));
1625 ret = zfs_err_to_be_err(g_zfs);
1626 goto done;
1627 }
1628 }
1629 ZFS_CLOSE(zhp);
1630 if ((zhp = zfs_open(g_zfs, sub_dataset,
1631 ZFS_TYPE_FILESYSTEM)) == NULL) {
1632 be_print_err(gettext("be_promote_ds_callback: "
1633 "Failed to open dataset (%s): %s\n"), sub_dataset,
1634 libzfs_error_description(g_zfs));
1635 ret = zfs_err_to_be_err(g_zfs);
1636 goto done;
1637 }
1638 }
1639
1640 /* Iterate down this dataset's children and promote them */
1641 ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1642
1643 done:
1644 free(sub_dataset);
1645 ZFS_CLOSE(zhp);
1646 return (ret);
1647 }
1648