Print this page
*** NO COMMENTS ***
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
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
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 +/*
27 + * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28 + */
29 +
26 30 #include <assert.h>
27 31 #include <libintl.h>
28 32 #include <libnvpair.h>
29 33 #include <libzfs.h>
30 34 #include <stdio.h>
31 35 #include <stdlib.h>
32 36 #include <string.h>
33 37 #include <errno.h>
34 38 #include <sys/mnttab.h>
35 39 #include <sys/types.h>
36 40 #include <sys/stat.h>
37 41 #include <unistd.h>
38 42
39 43 #include <libbe.h>
40 44 #include <libbe_priv.h>
41 45
42 46 char *mnttab = MNTTAB;
43 47
44 48 /*
45 49 * Private function prototypes
46 50 */
47 51 static int set_bootfs(char *boot_rpool, char *be_root_ds);
48 52 static int set_canmount(be_node_list_t *, char *);
49 53 static int be_do_installgrub(be_transaction_data_t *);
50 54 static int be_get_grub_vers(be_transaction_data_t *, char **, char **);
51 55 static int get_ver_from_capfile(char *, char **);
52 56 static int be_promote_zone_ds(char *, char *);
53 57 static int be_promote_ds_callback(zfs_handle_t *, void *);
54 58
55 59 /* ******************************************************************** */
56 60 /* Public Functions */
57 61 /* ******************************************************************** */
58 62
59 63 /*
60 64 * Function: be_activate
61 65 * Description: Calls _be_activate which activates the BE named in the
62 66 * attributes passed in through be_attrs. The process of
63 67 * activation sets the bootfs property of the root pool, resets
64 68 * the canmount property to noauto, and sets the default in the
65 69 * grub menu to the entry corresponding to the entry for the named
66 70 * BE.
67 71 * Parameters:
68 72 * be_attrs - pointer to nvlist_t of attributes being passed in.
69 73 * The follow attribute values are used by this function:
70 74 *
71 75 * BE_ATTR_ORIG_BE_NAME *required
72 76 * Return:
73 77 * BE_SUCCESS - Success
74 78 * be_errno_t - Failure
75 79 * Scope:
76 80 * Public
77 81 */
78 82 int
79 83 be_activate(nvlist_t *be_attrs)
80 84 {
81 85 int ret = BE_SUCCESS;
82 86 char *be_name = NULL;
83 87
84 88 /* Initialize libzfs handle */
85 89 if (!be_zfs_init())
86 90 return (BE_ERR_INIT);
87 91
88 92 /* Get the BE name to activate */
89 93 if (nvlist_lookup_string(be_attrs, BE_ATTR_ORIG_BE_NAME, &be_name)
90 94 != 0) {
91 95 be_print_err(gettext("be_activate: failed to "
92 96 "lookup BE_ATTR_ORIG_BE_NAME attribute\n"));
93 97 be_zfs_fini();
94 98 return (BE_ERR_INVAL);
95 99 }
96 100
97 101 /* Validate BE name */
98 102 if (!be_valid_be_name(be_name)) {
99 103 be_print_err(gettext("be_activate: invalid BE name %s\n"),
100 104 be_name);
101 105 be_zfs_fini();
102 106 return (BE_ERR_INVAL);
103 107 }
104 108
105 109 ret = _be_activate(be_name);
106 110
107 111 be_zfs_fini();
108 112
109 113 return (ret);
110 114 }
111 115
112 116 /* ******************************************************************** */
113 117 /* Semi Private Functions */
114 118 /* ******************************************************************** */
115 119
116 120 /*
117 121 * Function: _be_activate
118 122 * Description: This does the actual work described in be_activate.
119 123 * Parameters:
120 124 * be_name - pointer to the name of BE to activate.
121 125 *
122 126 * Return:
123 127 * BE_SUCCESS - Success
↓ open down ↓ |
88 lines elided |
↑ open up ↑ |
124 128 * be_errnot_t - Failure
125 129 * Scope:
126 130 * Public
127 131 */
128 132 int
129 133 _be_activate(char *be_name)
130 134 {
131 135 be_transaction_data_t cb = { 0 };
132 136 zfs_handle_t *zhp = NULL;
133 137 char root_ds[MAXPATHLEN];
138 + char active_ds[MAXPATHLEN];
134 139 char *cur_vers = NULL, *new_vers = NULL;
135 140 be_node_list_t *be_nodes = NULL;
136 141 uuid_t uu = {0};
137 142 int entry, ret = BE_SUCCESS;
138 143 int zret = 0;
139 144
140 145 /*
141 146 * TODO: The BE needs to be validated to make sure that it is actually
142 147 * a bootable BE.
143 148 */
144 149
145 150 if (be_name == NULL)
146 151 return (BE_ERR_INVAL);
147 152
148 153 /* Set obe_name to be_name in the cb structure */
149 154 cb.obe_name = be_name;
150 155
151 156 /* find which zpool the be is in */
152 157 if ((zret = zpool_iter(g_zfs, be_find_zpool_callback, &cb)) == 0) {
153 158 be_print_err(gettext("be_activate: failed to "
154 159 "find zpool for BE (%s)\n"), cb.obe_name);
155 160 return (BE_ERR_BE_NOENT);
156 161 } else if (zret < 0) {
157 162 be_print_err(gettext("be_activate: "
158 163 "zpool_iter failed: %s\n"),
159 164 libzfs_error_description(g_zfs));
160 165 ret = zfs_err_to_be_err(g_zfs);
161 166 return (ret);
162 167 }
163 168
164 169 be_make_root_ds(cb.obe_zpool, cb.obe_name, root_ds, sizeof (root_ds));
165 170 cb.obe_root_ds = strdup(root_ds);
166 171
167 172 if (getzoneid() == GLOBAL_ZONEID) {
168 173 if (be_has_grub() && (ret = be_get_grub_vers(&cb, &cur_vers,
169 174 &new_vers)) != BE_SUCCESS) {
170 175 be_print_err(gettext("be_activate: failed to get grub "
171 176 "versions from capability files.\n"));
172 177 return (ret);
173 178 }
174 179 if (cur_vers != NULL) {
175 180 /*
176 181 * We need to check to see if the version number from
177 182 * the BE being activated is greater than the current
178 183 * one.
179 184 */
180 185 if (new_vers != NULL &&
181 186 atof(cur_vers) < atof(new_vers)) {
182 187 if ((ret = be_do_installgrub(&cb))
183 188 != BE_SUCCESS) {
184 189 free(new_vers);
185 190 free(cur_vers);
186 191 return (ret);
187 192 }
188 193 free(new_vers);
189 194 }
190 195 free(cur_vers);
191 196 } else if (new_vers != NULL) {
192 197 if ((ret = be_do_installgrub(&cb)) != BE_SUCCESS) {
193 198 free(new_vers);
194 199 return (ret);
195 200 }
196 201 free(new_vers);
197 202 }
198 203 if (!be_has_menu_entry(root_ds, cb.obe_zpool, &entry)) {
199 204 if ((ret = be_append_menu(cb.obe_name, cb.obe_zpool,
200 205 NULL, NULL, NULL)) != BE_SUCCESS) {
201 206 be_print_err(gettext("be_activate: Failed to "
202 207 "add BE (%s) to the GRUB menu\n"),
203 208 cb.obe_name);
204 209 goto done;
205 210 }
206 211 }
207 212 if (be_has_grub()) {
208 213 if ((ret = be_change_grub_default(cb.obe_name,
209 214 cb.obe_zpool)) != BE_SUCCESS) {
210 215 be_print_err(gettext("be_activate: failed to "
211 216 "change the default entry in menu.lst\n"));
212 217 goto done;
213 218 }
214 219 }
215 220 }
216 221
↓ open down ↓ |
73 lines elided |
↑ open up ↑ |
217 222 if ((ret = _be_list(cb.obe_name, &be_nodes)) != BE_SUCCESS) {
218 223 return (ret);
219 224 }
220 225
221 226 if ((ret = set_canmount(be_nodes, "noauto")) != BE_SUCCESS) {
222 227 be_print_err(gettext("be_activate: failed to set "
223 228 "canmount dataset property\n"));
224 229 goto done;
225 230 }
226 231
227 - if ((ret = set_bootfs(be_nodes->be_rpool, root_ds)) != BE_SUCCESS) {
228 - be_print_err(gettext("be_activate: failed to set "
229 - "bootfs pool property for %s\n"), root_ds);
230 - goto done;
232 + if (getzoneid() == GLOBAL_ZONEID) {
233 + if ((ret = set_bootfs(be_nodes->be_rpool,
234 + root_ds)) != BE_SUCCESS) {
235 + be_print_err(gettext("be_activate: failed to set "
236 + "bootfs pool property for %s\n"), root_ds);
237 + goto done;
238 + }
231 239 }
232 240
233 241 if ((zhp = zfs_open(g_zfs, root_ds, ZFS_TYPE_FILESYSTEM)) != NULL) {
234 242 /*
235 243 * We don't need to close the zfs handle at this
236 244 * point because The callback funtion
237 245 * be_promote_ds_callback() will close it for us.
238 246 */
239 247 if (be_promote_ds_callback(zhp, NULL) != 0) {
240 248 be_print_err(gettext("be_activate: "
241 249 "failed to activate the "
242 250 "datasets for %s: %s\n"),
243 251 root_ds,
244 252 libzfs_error_description(g_zfs));
245 253 ret = BE_ERR_PROMOTE;
246 254 goto done;
247 255 }
248 256 } else {
249 - be_print_err(gettext("be_activate:: failed to open "
257 + be_print_err(gettext("be_activate: failed to open "
250 258 "dataset (%s): %s\n"), root_ds,
251 259 libzfs_error_description(g_zfs));
252 260 ret = zfs_err_to_be_err(g_zfs);
253 261 goto done;
254 262 }
255 263
256 264 if (getzoneid() == GLOBAL_ZONEID &&
257 265 be_get_uuid(cb.obe_root_ds, &uu) == BE_SUCCESS &&
258 266 (ret = be_promote_zone_ds(cb.obe_name, cb.obe_root_ds))
259 267 != BE_SUCCESS) {
260 268 be_print_err(gettext("be_activate: failed to promote "
261 269 "the active zonepath datasets for zones in BE %s\n"),
262 270 cb.obe_name);
263 271 }
264 272
273 + if (getzoneid() != GLOBAL_ZONEID) {
274 + if (!be_zone_compare_uuids(root_ds)) {
275 + be_print_err(gettext("be_activate: activating zone "
276 + "root dataset from non-active global BE is not "
277 + "supported\n"));
278 + ret = BE_ERR_NOTSUP;
279 + goto done;
280 + }
281 + if ((zhp = zfs_open(g_zfs, root_ds,
282 + ZFS_TYPE_FILESYSTEM)) == NULL) {
283 + be_print_err(gettext("be_activate: failed to open "
284 + "dataset (%s): %s\n"), root_ds,
285 + libzfs_error_description(g_zfs));
286 + ret = zfs_err_to_be_err(g_zfs);
287 + goto done;
288 + }
289 + /* Find current active zone root dataset */
290 + if ((ret = be_find_active_zone_root(zhp, cb.obe_zpool,
291 + active_ds, sizeof (active_ds))) != BE_SUCCESS) {
292 + be_print_err(gettext("be_activate: failed to find "
293 + "active zone root dataset\n"));
294 + ZFS_CLOSE(zhp);
295 + goto done;
296 + }
297 + /* Do nothing if requested BE is already active */
298 + if (strcmp(root_ds, active_ds) == 0) {
299 + ret = BE_SUCCESS;
300 + ZFS_CLOSE(zhp);
301 + goto done;
302 + }
303 +
304 + /* Set active property for BE */
305 + if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "on") != 0) {
306 + be_print_err(gettext("be_activate: failed to set "
307 + "active property (%s): %s\n"), root_ds,
308 + libzfs_error_description(g_zfs));
309 + ret = zfs_err_to_be_err(g_zfs);
310 + ZFS_CLOSE(zhp);
311 + goto done;
312 + }
313 + ZFS_CLOSE(zhp);
314 +
315 + /* Unset active property for old active root dataset */
316 + if ((zhp = zfs_open(g_zfs, active_ds,
317 + ZFS_TYPE_FILESYSTEM)) == NULL) {
318 + be_print_err(gettext("be_activate: failed to open "
319 + "dataset (%s): %s\n"), active_ds,
320 + libzfs_error_description(g_zfs));
321 + ret = zfs_err_to_be_err(g_zfs);
322 + goto done;
323 + }
324 + if (zfs_prop_set(zhp, BE_ZONE_ACTIVE_PROPERTY, "off") != 0) {
325 + be_print_err(gettext("be_activate: failed to unset "
326 + "active property (%s): %s\n"), active_ds,
327 + libzfs_error_description(g_zfs));
328 + ret = zfs_err_to_be_err(g_zfs);
329 + ZFS_CLOSE(zhp);
330 + goto done;
331 + }
332 + ZFS_CLOSE(zhp);
333 + }
265 334 done:
266 335 be_free_list(be_nodes);
267 336 return (ret);
268 337 }
269 338
270 339 /*
271 340 * Function: be_activate_current_be
272 341 * Description: Set the currently "active" BE to be "active on boot"
273 342 * Paramters:
274 343 * none
275 344 * Returns:
276 345 * BE_SUCCESS - Success
277 346 * be_errnot_t - Failure
278 347 * Scope:
279 348 * Semi-private (library wide use only)
280 349 */
281 350 int
282 351 be_activate_current_be(void)
283 352 {
284 353 int ret = BE_SUCCESS;
285 354 be_transaction_data_t bt = { 0 };
286 355
287 356 if ((ret = be_find_current_be(&bt)) != BE_SUCCESS) {
288 357 return (ret);
289 358 }
290 359
291 360 if ((ret = _be_activate(bt.obe_name)) != BE_SUCCESS) {
292 361 be_print_err(gettext("be_activate_current_be: failed to "
293 362 "activate %s\n"), bt.obe_name);
294 363 return (ret);
295 364 }
296 365
297 366 return (BE_SUCCESS);
298 367 }
299 368
300 369 /*
301 370 * Function: be_is_active_on_boot
302 371 * Description: Checks if the BE name passed in has the "active on boot"
303 372 * property set to B_TRUE.
304 373 * Paramters:
305 374 * be_name - the name of the BE to check
306 375 * Returns:
307 376 * B_TRUE - if active on boot.
308 377 * B_FALSE - if not active on boot.
309 378 * Scope:
310 379 * Semi-private (library wide use only)
311 380 */
312 381 boolean_t
313 382 be_is_active_on_boot(char *be_name)
314 383 {
315 384 be_node_list_t *be_node = NULL;
316 385
317 386 if (be_name == NULL) {
318 387 be_print_err(gettext("be_is_active_on_boot: "
319 388 "be_name must not be NULL\n"));
320 389 return (B_FALSE);
321 390 }
322 391
323 392 if (_be_list(be_name, &be_node) != BE_SUCCESS) {
324 393 return (B_FALSE);
325 394 }
326 395
327 396 if (be_node == NULL) {
328 397 return (B_FALSE);
329 398 }
330 399
331 400 if (be_node->be_active_on_boot) {
332 401 be_free_list(be_node);
333 402 return (B_TRUE);
334 403 } else {
335 404 be_free_list(be_node);
336 405 return (B_FALSE);
337 406 }
338 407 }
339 408
340 409 /* ******************************************************************** */
341 410 /* Private Functions */
342 411 /* ******************************************************************** */
343 412
344 413 /*
345 414 * Function: set_bootfs
346 415 * Description: Sets the bootfs property on the boot pool to be the
347 416 * root dataset of the activated BE.
348 417 * Parameters:
349 418 * boot_pool - The pool we're setting bootfs in.
350 419 * be_root_ds - The main dataset for the BE.
351 420 * Return:
352 421 * BE_SUCCESS - Success
353 422 * be_errno_t - Failure
354 423 * Scope:
355 424 * Private
356 425 */
357 426 static int
358 427 set_bootfs(char *boot_rpool, char *be_root_ds)
359 428 {
360 429 zpool_handle_t *zhp;
361 430 int err = BE_SUCCESS;
362 431
363 432 if ((zhp = zpool_open(g_zfs, boot_rpool)) == NULL) {
364 433 be_print_err(gettext("set_bootfs: failed to open pool "
365 434 "(%s): %s\n"), boot_rpool, libzfs_error_description(g_zfs));
366 435 err = zfs_err_to_be_err(g_zfs);
367 436 return (err);
368 437 }
369 438
370 439 err = zpool_set_prop(zhp, "bootfs", be_root_ds);
371 440 if (err) {
372 441 be_print_err(gettext("set_bootfs: failed to set "
373 442 "bootfs property for pool %s: %s\n"), boot_rpool,
374 443 libzfs_error_description(g_zfs));
375 444 err = zfs_err_to_be_err(g_zfs);
376 445 zpool_close(zhp);
377 446 return (err);
378 447 }
379 448
380 449 zpool_close(zhp);
381 450 return (BE_SUCCESS);
382 451 }
383 452
384 453 /*
385 454 * Function: set_canmount
386 455 * Description: Sets the canmount property on the datasets of the
387 456 * activated BE.
388 457 * Parameters:
389 458 * be_nodes - The be_node_t returned from be_list
390 459 * value - The value of canmount we setting, on|off|noauto.
391 460 * Return:
392 461 * BE_SUCCESS - Success
393 462 * be_errno_t - Failure
394 463 * Scope:
395 464 * Private
396 465 */
397 466 static int
398 467 set_canmount(be_node_list_t *be_nodes, char *value)
399 468 {
400 469 char ds_path[MAXPATHLEN];
401 470 zfs_handle_t *zhp = NULL;
402 471 be_node_list_t *list = be_nodes;
403 472 int err = BE_SUCCESS;
404 473
405 474 while (list != NULL) {
406 475 be_dataset_list_t *datasets = list->be_node_datasets;
407 476
408 477 be_make_root_ds(list->be_rpool, list->be_node_name, ds_path,
409 478 sizeof (ds_path));
410 479
411 480 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET)) ==
412 481 NULL) {
413 482 be_print_err(gettext("set_canmount: failed to open "
414 483 "dataset (%s): %s\n"), ds_path,
415 484 libzfs_error_description(g_zfs));
416 485 err = zfs_err_to_be_err(g_zfs);
417 486 return (err);
418 487 }
419 488 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
420 489 /*
421 490 * it's already mounted so we can't change the
422 491 * canmount property anyway.
423 492 */
424 493 err = BE_SUCCESS;
425 494 } else {
426 495 err = zfs_prop_set(zhp,
427 496 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
428 497 if (err) {
429 498 ZFS_CLOSE(zhp);
430 499 be_print_err(gettext("set_canmount: failed to "
431 500 "set dataset property (%s): %s\n"),
432 501 ds_path, libzfs_error_description(g_zfs));
433 502 err = zfs_err_to_be_err(g_zfs);
434 503 return (err);
435 504 }
436 505 }
437 506 ZFS_CLOSE(zhp);
438 507
439 508 while (datasets != NULL) {
440 509 be_make_root_ds(list->be_rpool,
441 510 datasets->be_dataset_name, ds_path,
442 511 sizeof (ds_path));
443 512
444 513 if ((zhp = zfs_open(g_zfs, ds_path, ZFS_TYPE_DATASET))
445 514 == NULL) {
446 515 be_print_err(gettext("set_canmount: failed to "
447 516 "open dataset %s: %s\n"), ds_path,
448 517 libzfs_error_description(g_zfs));
449 518 err = zfs_err_to_be_err(g_zfs);
450 519 return (err);
451 520 }
452 521 if (zfs_prop_get_int(zhp, ZFS_PROP_MOUNTED)) {
453 522 /*
454 523 * it's already mounted so we can't change the
455 524 * canmount property anyway.
456 525 */
457 526 err = BE_SUCCESS;
458 527 ZFS_CLOSE(zhp);
459 528 break;
460 529 }
461 530 err = zfs_prop_set(zhp,
462 531 zfs_prop_to_name(ZFS_PROP_CANMOUNT), value);
463 532 if (err) {
464 533 ZFS_CLOSE(zhp);
465 534 be_print_err(gettext("set_canmount: "
466 535 "Failed to set property value %s "
467 536 "for dataset %s: %s\n"), value, ds_path,
468 537 libzfs_error_description(g_zfs));
469 538 err = zfs_err_to_be_err(g_zfs);
470 539 return (err);
471 540 }
472 541 ZFS_CLOSE(zhp);
473 542 datasets = datasets->be_next_dataset;
474 543 }
475 544 list = list->be_next_node;
476 545 }
477 546 return (err);
478 547 }
479 548
480 549 /*
481 550 * Function: be_get_grub_vers
482 551 * Description: Gets the grub version number from /boot/grub/capability. If
483 552 * capability file doesn't exist NULL is returned.
484 553 * Parameters:
485 554 * bt - The transaction data for the BE we're getting the grub
486 555 * version for.
487 556 * cur_vers - used to return the current version of grub from
488 557 * the root pool.
489 558 * new_vers - used to return the grub version of the BE we're
490 559 * activating.
491 560 * Return:
492 561 * BE_SUCCESS - Success
493 562 * be_errno_t - Failed to find version
494 563 * Scope:
495 564 * Private
496 565 */
497 566 static int
498 567 be_get_grub_vers(be_transaction_data_t *bt, char **cur_vers, char **new_vers)
499 568 {
500 569 zfs_handle_t *zhp = NULL;
501 570 zfs_handle_t *pool_zhp = NULL;
502 571 int ret = BE_SUCCESS;
503 572 char cap_file[MAXPATHLEN];
504 573 char *temp_mntpnt = NULL;
505 574 char *zpool_mntpt = NULL;
506 575 char *ptmp_mntpnt = NULL;
507 576 char *orig_mntpnt = NULL;
508 577 boolean_t be_mounted = B_FALSE;
509 578 boolean_t pool_mounted = B_FALSE;
510 579
511 580 if (!be_has_grub()) {
512 581 be_print_err(gettext("be_get_grub_vers: Not supported on "
513 582 "this architecture\n"));
514 583 return (BE_ERR_NOTSUP);
515 584 }
516 585
517 586 if (bt == NULL || bt->obe_name == NULL || bt->obe_zpool == NULL ||
518 587 bt->obe_root_ds == NULL) {
519 588 be_print_err(gettext("be_get_grub_vers: Invalid BE\n"));
520 589 return (BE_ERR_INVAL);
521 590 }
522 591
523 592 if ((pool_zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
524 593 NULL) {
525 594 be_print_err(gettext("be_get_grub_vers: zfs_open failed: %s\n"),
526 595 libzfs_error_description(g_zfs));
527 596 return (zfs_err_to_be_err(g_zfs));
528 597 }
529 598
530 599 /*
531 600 * Check to see if the pool's dataset is mounted. If it isn't we'll
532 601 * attempt to mount it.
533 602 */
534 603 if ((ret = be_mount_pool(pool_zhp, &ptmp_mntpnt,
535 604 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
536 605 be_print_err(gettext("be_get_grub_vers: pool dataset "
537 606 "(%s) could not be mounted\n"), bt->obe_zpool);
538 607 ZFS_CLOSE(pool_zhp);
539 608 return (ret);
540 609 }
541 610
542 611 /*
543 612 * Get the mountpoint for the root pool dataset.
544 613 */
545 614 if (!zfs_is_mounted(pool_zhp, &zpool_mntpt)) {
546 615 be_print_err(gettext("be_get_grub_vers: pool "
547 616 "dataset (%s) is not mounted. Can't set the "
548 617 "default BE in the grub menu.\n"), bt->obe_zpool);
549 618 ret = BE_ERR_NO_MENU;
550 619 goto cleanup;
551 620 }
552 621
553 622 /*
554 623 * get the version of the most recent grub update.
555 624 */
556 625 (void) snprintf(cap_file, sizeof (cap_file), "%s%s",
557 626 zpool_mntpt, BE_CAP_FILE);
558 627 free(zpool_mntpt);
559 628 zpool_mntpt = NULL;
560 629
561 630 if ((ret = get_ver_from_capfile(cap_file, cur_vers)) != BE_SUCCESS)
562 631 goto cleanup;
563 632
564 633 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
565 634 NULL) {
566 635 be_print_err(gettext("be_get_grub_vers: failed to "
567 636 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
568 637 libzfs_error_description(g_zfs));
569 638 free(cur_vers);
570 639 ret = zfs_err_to_be_err(g_zfs);
571 640 goto cleanup;
572 641 }
573 642 if (!zfs_is_mounted(zhp, &temp_mntpnt)) {
574 643 if ((ret = _be_mount(bt->obe_name, &temp_mntpnt,
575 644 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
576 645 be_print_err(gettext("be_get_grub_vers: failed to "
577 646 "mount BE (%s)\n"), bt->obe_name);
578 647 free(*cur_vers);
579 648 *cur_vers = NULL;
580 649 ZFS_CLOSE(zhp);
581 650 goto cleanup;
582 651 }
583 652 be_mounted = B_TRUE;
584 653 }
585 654 ZFS_CLOSE(zhp);
586 655
587 656 /*
588 657 * Now get the grub version for the BE being activated.
589 658 */
590 659 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", temp_mntpnt,
591 660 BE_CAP_FILE);
592 661 ret = get_ver_from_capfile(cap_file, new_vers);
593 662 if (ret != BE_SUCCESS) {
594 663 free(*cur_vers);
595 664 *cur_vers = NULL;
596 665 }
597 666 if (be_mounted)
598 667 (void) _be_unmount(bt->obe_name, 0);
599 668
600 669 cleanup:
601 670 if (pool_mounted) {
602 671 int iret = BE_SUCCESS;
603 672 iret = be_unmount_pool(pool_zhp, ptmp_mntpnt, orig_mntpnt);
604 673 if (ret == BE_SUCCESS)
605 674 ret = iret;
606 675 free(orig_mntpnt);
607 676 free(ptmp_mntpnt);
608 677 }
609 678 ZFS_CLOSE(pool_zhp);
610 679
611 680 free(temp_mntpnt);
612 681 return (ret);
613 682 }
614 683
615 684 /*
616 685 * Function: get_ver_from_capfile
617 686 * Description: Parses the capability file passed in looking for the VERSION
618 687 * line. If found the version is returned in vers, if not then
619 688 * NULL is returned in vers.
620 689 *
621 690 * Parameters:
622 691 * file - the path to the capability file we want to parse.
623 692 * vers - the version string that will be passed back.
624 693 * Return:
625 694 * BE_SUCCESS - Success
626 695 * be_errno_t - Failed to find version
627 696 * Scope:
628 697 * Private
629 698 */
630 699 static int
631 700 get_ver_from_capfile(char *file, char **vers)
632 701 {
633 702 FILE *fp = NULL;
634 703 char line[BUFSIZ];
635 704 char *last = NULL;
636 705 int err = BE_SUCCESS;
637 706 errno = 0;
638 707
639 708 if (!be_has_grub()) {
640 709 be_print_err(gettext("get_ver_from_capfile: Not supported "
641 710 "on this architecture\n"));
642 711 return (BE_ERR_NOTSUP);
643 712 }
644 713
645 714 /*
646 715 * Set version string to NULL; the only case this shouldn't be set
647 716 * to be NULL is when we've actually found a version in the capability
648 717 * file, which is set below.
649 718 */
650 719 *vers = NULL;
651 720
652 721 /*
653 722 * If the capability file doesn't exist, we're returning success
654 723 * because on older releases, the capability file did not exist
655 724 * so this is a valid scenario.
656 725 */
657 726 if (access(file, F_OK) == 0) {
658 727 if ((fp = fopen(file, "r")) == NULL) {
659 728 err = errno;
660 729 be_print_err(gettext("get_ver_from_capfile: failed to "
661 730 "open file %s with error %s\n"), file,
662 731 strerror(err));
663 732 err = errno_to_be_err(err);
664 733 return (err);
665 734 }
666 735
667 736 while (fgets(line, BUFSIZ, fp)) {
668 737 char *tok = strtok_r(line, "=", &last);
669 738
670 739 if (tok == NULL || tok[0] == '#') {
671 740 continue;
672 741 } else if (strcmp(tok, "VERSION") == 0) {
673 742 *vers = strdup(last);
674 743 break;
675 744 }
676 745 }
677 746 (void) fclose(fp);
678 747 }
679 748
680 749 return (BE_SUCCESS);
681 750 }
682 751
683 752 /*
684 753 * Function: be_do_installgrub
685 754 * Description: This function runs installgrub using the grub loader files
686 755 * from the BE we're activating and installing them on the
687 756 * pool the BE lives in.
688 757 *
689 758 * Parameters:
690 759 * bt - The transaction data for the BE we're activating.
691 760 * Return:
692 761 * BE_SUCCESS - Success
693 762 * be_errno_t - Failure
694 763 *
695 764 * Scope:
696 765 * Private
697 766 */
698 767 static int
699 768 be_do_installgrub(be_transaction_data_t *bt)
700 769 {
701 770 zpool_handle_t *zphp = NULL;
702 771 zfs_handle_t *zhp = NULL;
703 772 nvlist_t **child, *nv, *config;
704 773 uint_t c, children = 0;
705 774 char *tmp_mntpt = NULL;
706 775 char *pool_mntpnt = NULL;
707 776 char *ptmp_mntpnt = NULL;
708 777 char *orig_mntpnt = NULL;
709 778 FILE *cap_fp = NULL;
710 779 FILE *zpool_cap_fp = NULL;
711 780 char line[BUFSIZ];
712 781 char cap_file[MAXPATHLEN];
713 782 char zpool_cap_file[MAXPATHLEN];
714 783 char stage1[MAXPATHLEN];
715 784 char stage2[MAXPATHLEN];
716 785 char installgrub_cmd[MAXPATHLEN];
717 786 char *vname;
718 787 char be_run_cmd_errbuf[BUFSIZ];
719 788 int ret = BE_SUCCESS;
720 789 int err = 0;
721 790 boolean_t be_mounted = B_FALSE;
722 791 boolean_t pool_mounted = B_FALSE;
723 792
724 793 if (!be_has_grub()) {
725 794 be_print_err(gettext("be_do_installgrub: Not supported "
726 795 "on this architecture\n"));
727 796 return (BE_ERR_NOTSUP);
728 797 }
729 798
730 799 if ((zhp = zfs_open(g_zfs, bt->obe_root_ds, ZFS_TYPE_FILESYSTEM)) ==
731 800 NULL) {
732 801 be_print_err(gettext("be_do_installgrub: failed to "
733 802 "open BE root dataset (%s): %s\n"), bt->obe_root_ds,
734 803 libzfs_error_description(g_zfs));
735 804 ret = zfs_err_to_be_err(g_zfs);
736 805 return (ret);
737 806 }
738 807 if (!zfs_is_mounted(zhp, &tmp_mntpt)) {
739 808 if ((ret = _be_mount(bt->obe_name, &tmp_mntpt,
740 809 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
741 810 be_print_err(gettext("be_do_installgrub: failed to "
742 811 "mount BE (%s)\n"), bt->obe_name);
743 812 ZFS_CLOSE(zhp);
744 813 return (ret);
745 814 }
746 815 be_mounted = B_TRUE;
747 816 }
748 817 ZFS_CLOSE(zhp);
749 818
750 819 (void) snprintf(stage1, sizeof (stage1), "%s%s", tmp_mntpt, BE_STAGE_1);
751 820 (void) snprintf(stage2, sizeof (stage2), "%s%s", tmp_mntpt, BE_STAGE_2);
752 821
753 822 if ((zphp = zpool_open(g_zfs, bt->obe_zpool)) == NULL) {
754 823 be_print_err(gettext("be_do_installgrub: failed to open "
755 824 "pool (%s): %s\n"), bt->obe_zpool,
756 825 libzfs_error_description(g_zfs));
757 826 ret = zfs_err_to_be_err(g_zfs);
758 827 if (be_mounted)
759 828 (void) _be_unmount(bt->obe_name, 0);
760 829 free(tmp_mntpt);
761 830 return (ret);
762 831 }
763 832
764 833 if ((config = zpool_get_config(zphp, NULL)) == NULL) {
765 834 be_print_err(gettext("be_do_installgrub: failed to get zpool "
766 835 "configuration information. %s\n"),
767 836 libzfs_error_description(g_zfs));
768 837 ret = zfs_err_to_be_err(g_zfs);
769 838 goto done;
770 839 }
771 840
772 841 /*
773 842 * Get the vdev tree
774 843 */
775 844 if (nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nv) != 0) {
776 845 be_print_err(gettext("be_do_installgrub: failed to get vdev "
777 846 "tree: %s\n"), libzfs_error_description(g_zfs));
778 847 ret = zfs_err_to_be_err(g_zfs);
779 848 goto done;
780 849 }
781 850
782 851 if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_CHILDREN, &child,
783 852 &children) != 0) {
784 853 be_print_err(gettext("be_do_installgrub: failed to traverse "
785 854 "the vdev tree: %s\n"), libzfs_error_description(g_zfs));
786 855 ret = zfs_err_to_be_err(g_zfs);
787 856 goto done;
788 857 }
789 858 for (c = 0; c < children; c++) {
790 859 uint_t i, nchildren = 0;
791 860 nvlist_t **nvchild;
792 861 vname = zpool_vdev_name(g_zfs, zphp, child[c], B_FALSE);
793 862 if (vname == NULL) {
794 863 be_print_err(gettext(
795 864 "be_do_installgrub: "
796 865 "failed to get device name: %s\n"),
797 866 libzfs_error_description(g_zfs));
798 867 ret = zfs_err_to_be_err(g_zfs);
799 868 goto done;
800 869 }
801 870 if (strcmp(vname, "mirror") == 0 || vname[0] != 'c') {
802 871
803 872 if (nvlist_lookup_nvlist_array(child[c],
804 873 ZPOOL_CONFIG_CHILDREN, &nvchild, &nchildren) != 0) {
805 874 be_print_err(gettext("be_do_installgrub: "
806 875 "failed to traverse the vdev tree: %s\n"),
807 876 libzfs_error_description(g_zfs));
808 877 ret = zfs_err_to_be_err(g_zfs);
809 878 goto done;
810 879 }
811 880
812 881 for (i = 0; i < nchildren; i++) {
813 882 vname = zpool_vdev_name(g_zfs, zphp,
814 883 nvchild[i], B_FALSE);
815 884 if (vname == NULL) {
816 885 be_print_err(gettext(
817 886 "be_do_installgrub: "
818 887 "failed to get device name: %s\n"),
819 888 libzfs_error_description(g_zfs));
820 889 ret = zfs_err_to_be_err(g_zfs);
821 890 goto done;
822 891 }
823 892
824 893 (void) snprintf(installgrub_cmd,
825 894 sizeof (installgrub_cmd),
826 895 "%s %s %s /dev/rdsk/%s",
827 896 BE_INSTALL_GRUB, stage1, stage2, vname);
828 897 if (be_run_cmd(installgrub_cmd,
829 898 be_run_cmd_errbuf, BUFSIZ, NULL, 0) !=
830 899 BE_SUCCESS) {
831 900 be_print_err(gettext(
832 901 "be_do_installgrub: installgrub "
833 902 "failed for device %s.\n"), vname);
834 903 /* Assume localized cmd err output. */
835 904 be_print_err(gettext(
836 905 " Command: \"%s\"\n"),
837 906 installgrub_cmd);
838 907 be_print_err("%s", be_run_cmd_errbuf);
839 908 free(vname);
840 909 ret = BE_ERR_BOOTFILE_INST;
841 910 goto done;
842 911 }
843 912 free(vname);
844 913 }
845 914 } else {
846 915 (void) snprintf(installgrub_cmd,
847 916 sizeof (installgrub_cmd), "%s %s %s /dev/rdsk/%s",
848 917 BE_INSTALL_GRUB, stage1, stage2, vname);
849 918 if (be_run_cmd(installgrub_cmd, be_run_cmd_errbuf,
850 919 BUFSIZ, NULL, 0) != BE_SUCCESS) {
851 920 be_print_err(gettext(
852 921 "be_do_installgrub: installgrub "
853 922 "failed for device %s.\n"), vname);
854 923 /* Assume localized cmd err output. */
855 924 be_print_err(gettext(" Command: \"%s\"\n"),
856 925 installgrub_cmd);
857 926 be_print_err("%s", be_run_cmd_errbuf);
858 927 free(vname);
859 928 ret = BE_ERR_BOOTFILE_INST;
860 929 goto done;
861 930 }
862 931 free(vname);
863 932 }
864 933 }
865 934
866 935 /*
867 936 * Copy the grub capability file from the BE we're activating into
868 937 * the root pool.
869 938 */
870 939 (void) snprintf(cap_file, sizeof (cap_file), "%s%s", tmp_mntpt,
871 940 BE_CAP_FILE);
872 941
873 942 if ((zhp = zfs_open(g_zfs, bt->obe_zpool, ZFS_TYPE_FILESYSTEM)) ==
874 943 NULL) {
875 944 be_print_err(gettext("be_do_installgrub: zfs_open "
876 945 "failed: %s\n"), libzfs_error_description(g_zfs));
877 946 zpool_close(zphp);
878 947 return (zfs_err_to_be_err(g_zfs));
879 948 }
880 949
881 950 /*
882 951 * Check to see if the pool's dataset is mounted. If it isn't we'll
883 952 * attempt to mount it.
884 953 */
885 954 if ((ret = be_mount_pool(zhp, &ptmp_mntpnt,
886 955 &orig_mntpnt, &pool_mounted)) != BE_SUCCESS) {
887 956 be_print_err(gettext("be_do_installgrub: pool dataset "
888 957 "(%s) could not be mounted\n"), bt->obe_zpool);
889 958 ZFS_CLOSE(zhp);
890 959 zpool_close(zphp);
891 960 return (ret);
892 961 }
893 962
894 963 /*
895 964 * Get the mountpoint for the root pool dataset.
896 965 */
897 966 if (!zfs_is_mounted(zhp, &pool_mntpnt)) {
898 967 be_print_err(gettext("be_do_installgrub: pool "
899 968 "dataset (%s) is not mounted. Can't check the grub "
900 969 "version from the grub capability file.\n"), bt->obe_zpool);
901 970 ret = BE_ERR_NO_MENU;
902 971 goto done;
903 972 }
904 973
905 974 (void) snprintf(zpool_cap_file, sizeof (zpool_cap_file), "%s%s",
906 975 pool_mntpnt, BE_CAP_FILE);
907 976
908 977 free(pool_mntpnt);
909 978 pool_mntpnt = NULL;
910 979
911 980 if ((cap_fp = fopen(cap_file, "r")) == NULL) {
912 981 err = errno;
913 982 be_print_err(gettext("be_do_installgrub: failed to open grub "
914 983 "capability file\n"));
915 984 ret = errno_to_be_err(err);
916 985 goto done;
917 986 }
918 987 if ((zpool_cap_fp = fopen(zpool_cap_file, "w")) == NULL) {
919 988 err = errno;
920 989 be_print_err(gettext("be_do_installgrub: failed to open new "
921 990 "grub capability file\n"));
922 991 ret = errno_to_be_err(err);
923 992 (void) fclose(cap_fp);
924 993 goto done;
925 994 }
926 995
927 996 while (fgets(line, BUFSIZ, cap_fp)) {
928 997 (void) fputs(line, zpool_cap_fp);
929 998 }
930 999
931 1000 (void) fclose(zpool_cap_fp);
932 1001 (void) fclose(cap_fp);
933 1002
934 1003 done:
935 1004 if (pool_mounted) {
936 1005 int iret = 0;
937 1006 iret = be_unmount_pool(zhp, ptmp_mntpnt, orig_mntpnt);
938 1007 if (ret == BE_SUCCESS)
939 1008 ret = iret;
940 1009 free(orig_mntpnt);
941 1010 free(ptmp_mntpnt);
942 1011 }
943 1012 ZFS_CLOSE(zhp);
944 1013 if (be_mounted)
945 1014 (void) _be_unmount(bt->obe_name, 0);
946 1015 zpool_close(zphp);
947 1016 free(tmp_mntpt);
948 1017 return (ret);
949 1018 }
950 1019
951 1020 /*
952 1021 * Function: be_promote_zone_ds
953 1022 * Description: This function finds the zones for the BE being activated
954 1023 * and the active zonepath dataset for each zone. Then each
955 1024 * active zonepath dataset is promoted.
956 1025 *
957 1026 * Parameters:
958 1027 * be_name - the name of the global zone BE that we need to
959 1028 * find the zones for.
960 1029 * be_root_ds - the root dataset for be_name.
961 1030 * Return:
962 1031 * BE_SUCCESS - Success
963 1032 * be_errno_t - Failure
964 1033 *
965 1034 * Scope:
966 1035 * Private
967 1036 */
968 1037 static int
969 1038 be_promote_zone_ds(char *be_name, char *be_root_ds)
970 1039 {
971 1040 char *zone_ds = NULL;
972 1041 char *temp_mntpt = NULL;
973 1042 char origin[MAXPATHLEN];
974 1043 char zoneroot_ds[MAXPATHLEN];
975 1044 zfs_handle_t *zhp = NULL;
976 1045 zfs_handle_t *z_zhp = NULL;
977 1046 zoneList_t zone_list = NULL;
978 1047 zoneBrandList_t *brands = NULL;
979 1048 boolean_t be_mounted = B_FALSE;
980 1049 int zone_index = 0;
981 1050 int err = BE_SUCCESS;
982 1051
983 1052 /*
984 1053 * Get the supported zone brands so we can pass that
985 1054 * to z_get_nonglobal_zone_list_by_brand. Currently
986 1055 * only the ipkg and labeled brand zones are supported
987 1056 *
988 1057 */
989 1058 if ((brands = be_get_supported_brandlist()) == NULL) {
990 1059 be_print_err(gettext("be_promote_zone_ds: no supported "
991 1060 "brands\n"));
992 1061 return (BE_SUCCESS);
993 1062 }
994 1063
995 1064 if ((zhp = zfs_open(g_zfs, be_root_ds,
996 1065 ZFS_TYPE_FILESYSTEM)) == NULL) {
997 1066 be_print_err(gettext("be_promote_zone_ds: Failed to open "
998 1067 "dataset (%s): %s\n"), be_root_ds,
999 1068 libzfs_error_description(g_zfs));
1000 1069 err = zfs_err_to_be_err(g_zfs);
1001 1070 z_free_brand_list(brands);
1002 1071 return (err);
1003 1072 }
1004 1073
1005 1074 if (!zfs_is_mounted(zhp, &temp_mntpt)) {
1006 1075 if ((err = _be_mount(be_name, &temp_mntpt,
1007 1076 BE_MOUNT_FLAG_NO_ZONES)) != BE_SUCCESS) {
1008 1077 be_print_err(gettext("be_promote_zone_ds: failed to "
1009 1078 "mount the BE for zones procesing.\n"));
1010 1079 ZFS_CLOSE(zhp);
1011 1080 z_free_brand_list(brands);
1012 1081 return (err);
1013 1082 }
1014 1083 be_mounted = B_TRUE;
1015 1084 }
1016 1085
1017 1086 /*
1018 1087 * Set the zone root to the temp mount point for the BE we just mounted.
1019 1088 */
1020 1089 z_set_zone_root(temp_mntpt);
1021 1090
1022 1091 /*
1023 1092 * Get all the zones based on the brands we're looking for. If no zones
1024 1093 * are found that we're interested in unmount the BE and move on.
1025 1094 */
1026 1095 if ((zone_list = z_get_nonglobal_zone_list_by_brand(brands)) == NULL) {
1027 1096 if (be_mounted)
1028 1097 (void) _be_unmount(be_name, 0);
1029 1098 ZFS_CLOSE(zhp);
1030 1099 z_free_brand_list(brands);
1031 1100 free(temp_mntpt);
1032 1101 return (BE_SUCCESS);
1033 1102 }
1034 1103 for (zone_index = 0; z_zlist_get_zonename(zone_list, zone_index)
1035 1104 != NULL; zone_index++) {
1036 1105 char *zone_path = NULL;
1037 1106
1038 1107 /* Skip zones that aren't at least installed */
1039 1108 if (z_zlist_get_current_state(zone_list, zone_index) <
1040 1109 ZONE_STATE_INSTALLED)
1041 1110 continue;
1042 1111
1043 1112 if (((zone_path =
1044 1113 z_zlist_get_zonepath(zone_list, zone_index)) == NULL) ||
1045 1114 ((zone_ds = be_get_ds_from_dir(zone_path)) == NULL) ||
1046 1115 !be_zone_supported(zone_ds))
1047 1116 continue;
1048 1117
1049 1118 if (be_find_active_zone_root(zhp, zone_ds,
1050 1119 zoneroot_ds, sizeof (zoneroot_ds)) != 0) {
1051 1120 be_print_err(gettext("be_promote_zone_ds: "
1052 1121 "Zone does not have an active root "
1053 1122 "dataset, skipping this zone.\n"));
1054 1123 continue;
1055 1124 }
1056 1125
1057 1126 if ((z_zhp = zfs_open(g_zfs, zoneroot_ds,
1058 1127 ZFS_TYPE_FILESYSTEM)) == NULL) {
1059 1128 be_print_err(gettext("be_promote_zone_ds: "
1060 1129 "Failed to open dataset "
1061 1130 "(%s): %s\n"), zoneroot_ds,
1062 1131 libzfs_error_description(g_zfs));
1063 1132 err = zfs_err_to_be_err(g_zfs);
1064 1133 goto done;
1065 1134 }
1066 1135
1067 1136 if (zfs_prop_get(z_zhp, ZFS_PROP_ORIGIN, origin,
1068 1137 sizeof (origin), NULL, NULL, 0, B_FALSE) != 0) {
1069 1138 ZFS_CLOSE(z_zhp);
1070 1139 continue;
1071 1140 }
1072 1141
1073 1142 /*
1074 1143 * We don't need to close the zfs handle at this
1075 1144 * point because the callback funtion
1076 1145 * be_promote_ds_callback() will close it for us.
1077 1146 */
1078 1147 if (be_promote_ds_callback(z_zhp, NULL) != 0) {
1079 1148 be_print_err(gettext("be_promote_zone_ds: "
1080 1149 "failed to activate the "
1081 1150 "datasets for %s: %s\n"),
1082 1151 zoneroot_ds,
1083 1152 libzfs_error_description(g_zfs));
1084 1153 err = BE_ERR_PROMOTE;
1085 1154 goto done;
1086 1155 }
1087 1156 }
1088 1157 done:
1089 1158 if (be_mounted)
1090 1159 (void) _be_unmount(be_name, 0);
1091 1160 ZFS_CLOSE(zhp);
1092 1161 free(temp_mntpt);
1093 1162 z_free_brand_list(brands);
1094 1163 z_free_zone_list(zone_list);
1095 1164 return (err);
1096 1165 }
1097 1166
1098 1167 /*
1099 1168 * Function: be_promote_ds_callback
1100 1169 * Description: This function is used to promote the datasets for the BE
1101 1170 * being activated as well as the datasets for the zones BE
1102 1171 * being activated.
1103 1172 *
1104 1173 * Parameters:
1105 1174 * zhp - the zfs handle for zone BE being activated.
1106 1175 * data - not used.
1107 1176 * Return:
1108 1177 * 0 - Success
1109 1178 * be_errno_t - Failure
1110 1179 *
1111 1180 * Scope:
1112 1181 * Private
1113 1182 */
1114 1183 static int
1115 1184 /* LINTED */
1116 1185 be_promote_ds_callback(zfs_handle_t *zhp, void *data)
1117 1186 {
1118 1187 char origin[MAXPATHLEN];
1119 1188 char *sub_dataset = NULL;
1120 1189 int ret = 0;
1121 1190
1122 1191 if (zhp != NULL) {
1123 1192 sub_dataset = strdup(zfs_get_name(zhp));
1124 1193 if (sub_dataset == NULL) {
1125 1194 ret = BE_ERR_NOMEM;
1126 1195 goto done;
1127 1196 }
1128 1197 } else {
1129 1198 be_print_err(gettext("be_promote_ds_callback: "
1130 1199 "Invalid zfs handle passed into function\n"));
1131 1200 ret = BE_ERR_INVAL;
1132 1201 goto done;
1133 1202 }
1134 1203
1135 1204 /*
1136 1205 * This loop makes sure that we promote the dataset to the
1137 1206 * top of the tree so that it is no longer a decendent of any
1138 1207 * dataset. The ZFS close and then open is used to make sure that
1139 1208 * the promotion is updated before we move on.
1140 1209 */
1141 1210 while (zfs_prop_get(zhp, ZFS_PROP_ORIGIN, origin,
1142 1211 sizeof (origin), NULL, NULL, 0, B_FALSE) == 0) {
1143 1212 if (zfs_promote(zhp) != 0) {
1144 1213 if (libzfs_errno(g_zfs) != EZFS_EXISTS) {
1145 1214 be_print_err(gettext("be_promote_ds_callback: "
1146 1215 "promote of %s failed: %s\n"),
1147 1216 zfs_get_name(zhp),
1148 1217 libzfs_error_description(g_zfs));
1149 1218 ret = zfs_err_to_be_err(g_zfs);
1150 1219 goto done;
1151 1220 } else {
1152 1221 /*
1153 1222 * If the call to zfs_promote returns the
1154 1223 * error EZFS_EXISTS we've hit a snapshot name
1155 1224 * collision. This means we're probably
1156 1225 * attemping to promote a zone dataset above a
1157 1226 * parent dataset that belongs to another zone
1158 1227 * which this zone was cloned from.
1159 1228 *
1160 1229 * TODO: If this is a zone dataset at some
1161 1230 * point we should skip this if the zone
1162 1231 * paths for the dataset and the snapshot
1163 1232 * don't match.
1164 1233 */
1165 1234 be_print_err(gettext("be_promote_ds_callback: "
1166 1235 "promote of %s failed due to snapshot "
1167 1236 "name collision: %s\n"), zfs_get_name(zhp),
1168 1237 libzfs_error_description(g_zfs));
1169 1238 ret = zfs_err_to_be_err(g_zfs);
1170 1239 goto done;
1171 1240 }
1172 1241 }
1173 1242 ZFS_CLOSE(zhp);
1174 1243 if ((zhp = zfs_open(g_zfs, sub_dataset,
1175 1244 ZFS_TYPE_FILESYSTEM)) == NULL) {
1176 1245 be_print_err(gettext("be_promote_ds_callback: "
1177 1246 "Failed to open dataset (%s): %s\n"), sub_dataset,
1178 1247 libzfs_error_description(g_zfs));
1179 1248 ret = zfs_err_to_be_err(g_zfs);
1180 1249 goto done;
1181 1250 }
1182 1251 }
1183 1252
1184 1253 /* Iterate down this dataset's children and promote them */
1185 1254 ret = zfs_iter_filesystems(zhp, be_promote_ds_callback, NULL);
1186 1255
1187 1256 done:
1188 1257 free(sub_dataset);
1189 1258 ZFS_CLOSE(zhp);
1190 1259 return (ret);
1191 1260 }
↓ open down ↓ |
917 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX