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