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