1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 #include <assert.h> 27 #include <libintl.h> 28 #include <libnvpair.h> 29 #include <libzfs.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <unistd.h> 37 #include <errno.h> 38 39 #include <libbe.h> 40 #include <libbe_priv.h> 41 42 /* 43 * Callback data used for zfs_iter calls. 44 */ 45 typedef struct list_callback_data { 46 char *zpool_name; 47 char *be_name; 48 be_node_list_t *be_nodes_head; 49 be_node_list_t *be_nodes; 50 char current_be[MAXPATHLEN]; 51 } list_callback_data_t; 52 53 /* 54 * Private function prototypes 55 */ 56 static int be_add_children_callback(zfs_handle_t *zhp, void *data); 57 static int be_get_list_callback(zpool_handle_t *, void *); 58 static int be_get_node_data(zfs_handle_t *, be_node_list_t *, char *, 59 const char *, char *, char *); 60 static int be_get_zone_node_data(be_node_list_t *, char *); 61 static int be_get_ds_data(zfs_handle_t *, char *, be_dataset_list_t *, 62 be_node_list_t *); 63 static int be_get_ss_data(zfs_handle_t *, char *, be_snapshot_list_t *, 64 be_node_list_t *); 65 static void be_sort_list(be_node_list_t **); 66 static int be_qsort_compare_BEs(const void *, const void *); 67 static int be_qsort_compare_snapshots(const void *x, const void *y); 68 static int be_qsort_compare_datasets(const void *x, const void *y); 69 static void *be_list_alloc(int *, size_t); 70 71 /* 72 * Private data. 73 */ 74 static char be_container_ds[MAXPATHLEN]; 75 static boolean_t zone_be = B_FALSE; 76 77 /* ******************************************************************** */ 78 /* Public Functions */ 79 /* ******************************************************************** */ 80 81 /* 82 * Function: be_list 83 * Description: Calls _be_list which finds all the BEs on the system and 84 * returns the datasets and snapshots belonging to each BE. 85 * Also data, such as dataset and snapshot properties, 86 * for each BE and their snapshots and datasets is 87 * returned. The data returned is as described in the 88 * be_dataset_list_t, be_snapshot_list_t and be_node_list_t 89 * structures. 90 * Parameters: 91 * be_name - The name of the BE to look up. 92 * If NULL a list of all BEs will be returned. 93 * be_nodes - A reference pointer to the list of BEs. The list 94 * structure will be allocated by _be_list and must 95 * be freed by a call to be_free_list. If there are no 96 * BEs found on the system this reference will be 97 * set to NULL. 98 * Return: 99 * BE_SUCCESS - Success 100 * be_errno_t - Failure 101 * Scope: 102 * Public 103 */ 104 int 105 be_list(char *be_name, be_node_list_t **be_nodes) 106 { 107 int ret = BE_SUCCESS; 108 109 /* Initialize libzfs handle */ 110 if (!be_zfs_init()) 111 return (BE_ERR_INIT); 112 113 /* Validate be_name if its not NULL */ 114 if (be_name != NULL) { 115 if (!be_valid_be_name(be_name)) { 116 be_print_err(gettext("be_list: " 117 "invalid BE name %s\n"), be_name); 118 return (BE_ERR_INVAL); 119 } 120 } 121 122 ret = _be_list(be_name, be_nodes); 123 124 be_zfs_fini(); 125 126 return (ret); 127 } 128 129 /* ******************************************************************** */ 130 /* Semi-Private Functions */ 131 /* ******************************************************************** */ 132 133 /* 134 * Function: _be_list 135 * Description: This does the actual work described in be_list. 136 * Parameters: 137 * be_name - The name of the BE to look up. 138 * If NULL a list of all BEs will be returned. 139 * be_nodes - A reference pointer to the list of BEs. The list 140 * structure will be allocated here and must 141 * be freed by a call to be_free_list. If there are no 142 * BEs found on the system this reference will be 143 * set to NULL. 144 * Return: 145 * BE_SUCCESS - Success 146 * be_errno_t - Failure 147 * Scope: 148 * Semi-private (library wide use only) 149 */ 150 int 151 _be_list(char *be_name, be_node_list_t **be_nodes) 152 { 153 list_callback_data_t cb = { 0 }; 154 be_transaction_data_t bt = { 0 }; 155 int ret = BE_SUCCESS; 156 157 if (be_nodes == NULL) 158 return (BE_ERR_INVAL); 159 160 if (be_find_current_be(&bt) != BE_SUCCESS) { 161 /* 162 * We were unable to find a currently booted BE which 163 * probably means that we're not booted in a BE envoronment. 164 * None of the BE's will be marked as the active BE. 165 */ 166 (void) strcpy(cb.current_be, "-"); 167 } else { 168 (void) strncpy(cb.current_be, bt.obe_name, 169 sizeof (cb.current_be)); 170 } 171 172 /* 173 * If be_name is NULL we'll look for all BE's on the system. 174 * If not then we will only return data for the specified BE. 175 */ 176 if (be_name != NULL) 177 cb.be_name = strdup(be_name); 178 179 if ((zpool_iter(g_zfs, be_get_list_callback, &cb)) != 0) { 180 if (cb.be_nodes_head != NULL) { 181 be_free_list(cb.be_nodes_head); 182 cb.be_nodes_head = NULL; 183 cb.be_nodes = NULL; 184 } 185 ret = BE_ERR_BE_NOENT; 186 } 187 188 if (cb.be_nodes_head == NULL) { 189 if (be_name != NULL) 190 be_print_err(gettext("be_list: BE (%s) does not " 191 "exist\n"), be_name); 192 else 193 be_print_err(gettext("be_list: No BE's found\n")); 194 ret = BE_ERR_BE_NOENT; 195 } 196 197 *be_nodes = cb.be_nodes_head; 198 199 free(cb.be_name); 200 201 be_sort_list(be_nodes); 202 203 return (ret); 204 } 205 206 /* 207 * Function: be_free_list 208 * Description: Frees up all the data allocated for the list of BEs, 209 * datasets and snapshots returned by be_list. 210 * Parameters: 211 * be_node - be_nodes_t structure returned from call to be_list. 212 * Returns: 213 * none 214 * Scope: 215 * Semi-private (library wide use only) 216 */ 217 void 218 be_free_list(be_node_list_t *be_nodes) 219 { 220 be_node_list_t *temp_node = NULL; 221 be_node_list_t *list = be_nodes; 222 223 while (list != NULL) { 224 be_dataset_list_t *datasets = list->be_node_datasets; 225 be_snapshot_list_t *snapshots = list->be_node_snapshots; 226 227 while (datasets != NULL) { 228 be_dataset_list_t *temp_ds = datasets; 229 datasets = datasets->be_next_dataset; 230 free(temp_ds->be_dataset_name); 231 free(temp_ds->be_ds_mntpt); 232 free(temp_ds->be_ds_plcy_type); 233 free(temp_ds); 234 } 235 236 while (snapshots != NULL) { 237 be_snapshot_list_t *temp_ss = snapshots; 238 snapshots = snapshots->be_next_snapshot; 239 free(temp_ss->be_snapshot_name); 240 free(temp_ss->be_snapshot_type); 241 free(temp_ss); 242 } 243 244 temp_node = list; 245 list = list->be_next_node; 246 free(temp_node->be_node_name); 247 free(temp_node->be_root_ds); 248 free(temp_node->be_rpool); 249 free(temp_node->be_mntpt); 250 free(temp_node->be_policy_type); 251 free(temp_node->be_uuid_str); 252 free(temp_node); 253 } 254 } 255 256 /* 257 * Function: be_get_zone_be_list 258 * Description: Finds all the BEs for this zone on the system. 259 * Parameters: 260 * zone_be_name - The name of the BE to look up. 261 * zone_be_container_ds - The dataset for the zone. 262 * zbe_nodes - A reference pointer to the list of BEs. The list 263 * structure will be allocated here and must 264 * be freed by a call to be_free_list. If there are no 265 * BEs found on the system this reference will be 266 * set to NULL. 267 * Return: 268 * BE_SUCCESS - Success 269 * be_errno_t - Failure 270 * Scope: 271 * Semi-private (library wide use only) 272 */ 273 int 274 be_get_zone_be_list( 275 /* LINTED */ 276 char *zone_be_name, 277 char *zone_be_container_ds, 278 be_node_list_t **zbe_nodes) 279 { 280 zfs_handle_t *zhp = NULL; 281 list_callback_data_t cb = { 0 }; 282 int ret = BE_SUCCESS; 283 284 if (zbe_nodes == NULL) 285 return (BE_ERR_INVAL); 286 287 if (!zfs_dataset_exists(g_zfs, zone_be_container_ds, 288 ZFS_TYPE_FILESYSTEM)) { 289 return (BE_ERR_BE_NOENT); 290 } 291 292 zone_be = B_TRUE; 293 294 if ((zhp = zfs_open(g_zfs, zone_be_container_ds, 295 ZFS_TYPE_FILESYSTEM)) == NULL) { 296 be_print_err(gettext("be_get_zone_be_list: failed to open " 297 "the zone BE dataset %s: %s\n"), zone_be_container_ds, 298 libzfs_error_description(g_zfs)); 299 ret = zfs_err_to_be_err(g_zfs); 300 goto cleanup; 301 } 302 303 (void) strcpy(be_container_ds, zone_be_container_ds); 304 305 if (cb.be_nodes_head == NULL) { 306 if ((cb.be_nodes_head = be_list_alloc(&ret, 307 sizeof (be_node_list_t))) == NULL) { 308 ZFS_CLOSE(zhp); 309 goto cleanup; 310 } 311 cb.be_nodes = cb.be_nodes_head; 312 } 313 if (ret == 0) 314 ret = zfs_iter_filesystems(zhp, be_add_children_callback, &cb); 315 ZFS_CLOSE(zhp); 316 317 *zbe_nodes = cb.be_nodes_head; 318 319 cleanup: 320 zone_be = B_FALSE; 321 322 return (ret); 323 } 324 325 /* ******************************************************************** */ 326 /* Private Functions */ 327 /* ******************************************************************** */ 328 329 /* 330 * Function: be_get_list_callback 331 * Description: Callback function used by zfs_iter to look through all 332 * the pools on the system looking for BEs. If a BE name was 333 * specified only that BE's information will be collected and 334 * returned. 335 * Parameters: 336 * zlp - handle to the first zfs dataset. (provided by the 337 * zfs_iter_* call) 338 * data - pointer to the callback data and where we'll pass 339 * the BE information back. 340 * Returns: 341 * 0 - Success 342 * be_errno_t - Failure 343 * Scope: 344 * Private 345 */ 346 static int 347 be_get_list_callback(zpool_handle_t *zlp, void *data) 348 { 349 list_callback_data_t *cb = (list_callback_data_t *)data; 350 char be_ds[MAXPATHLEN]; 351 char *open_ds = NULL; 352 char *rpool = NULL; 353 zfs_handle_t *zhp = NULL; 354 int ret = 0; 355 356 cb->zpool_name = rpool = (char *)zpool_get_name(zlp); 357 358 /* 359 * Generate string for the BE container dataset 360 */ 361 be_make_container_ds(rpool, be_container_ds, 362 sizeof (be_container_ds)); 363 364 /* 365 * If a BE name was specified we use it's root dataset in place of 366 * the container dataset. This is because we only want to collect 367 * the information for the specified BE. 368 */ 369 if (cb->be_name != NULL) { 370 /* 371 * Generate string for the BE root dataset 372 */ 373 be_make_root_ds(rpool, cb->be_name, be_ds, sizeof (be_ds)); 374 open_ds = be_ds; 375 } else { 376 open_ds = be_container_ds; 377 } 378 379 /* 380 * Check if the dataset exists 381 */ 382 if (!zfs_dataset_exists(g_zfs, open_ds, 383 ZFS_TYPE_FILESYSTEM)) { 384 /* 385 * The specified dataset does not exist in this pool or 386 * there are no valid BE's in this pool. Try the next zpool. 387 */ 388 zpool_close(zlp); 389 return (0); 390 } 391 392 if ((zhp = zfs_open(g_zfs, open_ds, ZFS_TYPE_FILESYSTEM)) == NULL) { 393 be_print_err(gettext("be_get_list_callback: failed to open " 394 "the BE dataset %s: %s\n"), open_ds, 395 libzfs_error_description(g_zfs)); 396 ret = zfs_err_to_be_err(g_zfs); 397 zpool_close(zlp); 398 return (ret); 399 } 400 401 if (cb->be_nodes_head == NULL) { 402 if ((cb->be_nodes_head = be_list_alloc(&ret, 403 sizeof (be_node_list_t))) == NULL) { 404 ZFS_CLOSE(zhp); 405 zpool_close(zlp); 406 return (ret); 407 } 408 cb->be_nodes = cb->be_nodes_head; 409 } 410 411 /* 412 * If a BE name was specified we iterate through the datasets 413 * and snapshots for this BE only. Otherwise we will iterate 414 * through the next level of datasets to find all the BE's 415 * within the pool 416 */ 417 if (cb->be_name != NULL) { 418 if ((ret = be_get_node_data(zhp, cb->be_nodes, cb->be_name, 419 rpool, cb->current_be, be_ds)) != BE_SUCCESS) { 420 ZFS_CLOSE(zhp); 421 zpool_close(zlp); 422 return (ret); 423 } 424 ret = zfs_iter_snapshots(zhp, be_add_children_callback, cb); 425 } 426 427 if (ret == 0) 428 ret = zfs_iter_filesystems(zhp, be_add_children_callback, cb); 429 ZFS_CLOSE(zhp); 430 431 zpool_close(zlp); 432 return (ret); 433 } 434 435 /* 436 * Function: be_add_children_callback 437 * Description: Callback function used by zfs_iter to look through all 438 * the datasets and snapshots for each BE and add them to 439 * the lists of information to be passed back. 440 * Parameters: 441 * zhp - handle to the first zfs dataset. (provided by the 442 * zfs_iter_* call) 443 * data - pointer to the callback data and where we'll pass 444 * the BE information back. 445 * Returns: 446 * 0 - Success 447 * be_errno_t - Failure 448 * Scope: 449 * Private 450 */ 451 static int 452 be_add_children_callback(zfs_handle_t *zhp, void *data) 453 { 454 list_callback_data_t *cb = (list_callback_data_t *)data; 455 char *str = NULL, *ds_path = NULL; 456 int ret = 0; 457 458 ds_path = str = strdup(zfs_get_name(zhp)); 459 460 /* 461 * get past the end of the container dataset plus the trailing "/" 462 */ 463 str = str + (strlen(be_container_ds) + 1); 464 if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT && !zone_be) { 465 be_snapshot_list_t *snapshots = NULL; 466 if (cb->be_nodes->be_node_snapshots == NULL) { 467 if ((cb->be_nodes->be_node_snapshots = 468 be_list_alloc(&ret, sizeof (be_snapshot_list_t))) 469 == NULL || ret != BE_SUCCESS) { 470 ZFS_CLOSE(zhp); 471 return (ret); 472 } 473 cb->be_nodes->be_node_snapshots->be_next_snapshot = 474 NULL; 475 snapshots = cb->be_nodes->be_node_snapshots; 476 } else { 477 for (snapshots = cb->be_nodes->be_node_snapshots; 478 snapshots != NULL; 479 snapshots = snapshots->be_next_snapshot) { 480 if (snapshots->be_next_snapshot != NULL) 481 continue; 482 /* 483 * We're at the end of the list add the 484 * new snapshot. 485 */ 486 if ((snapshots->be_next_snapshot = 487 be_list_alloc(&ret, 488 sizeof (be_snapshot_list_t))) == NULL || 489 ret != BE_SUCCESS) { 490 ZFS_CLOSE(zhp); 491 return (ret); 492 } 493 snapshots = snapshots->be_next_snapshot; 494 snapshots->be_next_snapshot = NULL; 495 break; 496 } 497 } 498 if ((ret = be_get_ss_data(zhp, str, snapshots, 499 cb->be_nodes)) != BE_SUCCESS) { 500 ZFS_CLOSE(zhp); 501 return (ret); 502 } 503 } else if (strchr(str, '/') == NULL) { 504 if (cb->be_nodes->be_node_name != NULL) { 505 if ((cb->be_nodes->be_next_node = 506 be_list_alloc(&ret, sizeof (be_node_list_t))) == 507 NULL || ret != BE_SUCCESS) { 508 ZFS_CLOSE(zhp); 509 return (ret); 510 } 511 cb->be_nodes = cb->be_nodes->be_next_node; 512 cb->be_nodes->be_next_node = NULL; 513 } 514 515 /* 516 * If this is a zone root dataset then we only need 517 * the name of the zone BE at this point. We grab that 518 * and return. 519 */ 520 if (zone_be) { 521 ret = be_get_zone_node_data(cb->be_nodes, str); 522 ZFS_CLOSE(zhp); 523 return (ret); 524 } 525 526 if ((ret = be_get_node_data(zhp, cb->be_nodes, str, 527 cb->zpool_name, cb->current_be, ds_path)) != BE_SUCCESS) { 528 ZFS_CLOSE(zhp); 529 return (ret); 530 } 531 } else if (strchr(str, '/') != NULL && !zone_be) { 532 be_dataset_list_t *datasets = NULL; 533 if (cb->be_nodes->be_node_datasets == NULL) { 534 if ((cb->be_nodes->be_node_datasets = 535 be_list_alloc(&ret, sizeof (be_dataset_list_t))) 536 == NULL || ret != BE_SUCCESS) { 537 ZFS_CLOSE(zhp); 538 return (ret); 539 } 540 cb->be_nodes->be_node_datasets->be_next_dataset = NULL; 541 datasets = cb->be_nodes->be_node_datasets; 542 } else { 543 for (datasets = cb->be_nodes->be_node_datasets; 544 datasets != NULL; 545 datasets = datasets->be_next_dataset) { 546 if (datasets->be_next_dataset != NULL) 547 continue; 548 /* 549 * We're at the end of the list add 550 * the new dataset. 551 */ 552 if ((datasets->be_next_dataset = 553 be_list_alloc(&ret, 554 sizeof (be_dataset_list_t))) 555 == NULL || ret != BE_SUCCESS) { 556 ZFS_CLOSE(zhp); 557 return (ret); 558 } 559 datasets = datasets->be_next_dataset; 560 datasets->be_next_dataset = NULL; 561 break; 562 } 563 } 564 565 if ((ret = be_get_ds_data(zhp, str, 566 datasets, cb->be_nodes)) != BE_SUCCESS) { 567 ZFS_CLOSE(zhp); 568 return (ret); 569 } 570 } 571 ret = zfs_iter_children(zhp, be_add_children_callback, cb); 572 if (ret != 0) { 573 be_print_err(gettext("be_add_children_callback: " 574 "encountered error: %s\n"), 575 libzfs_error_description(g_zfs)); 576 ret = zfs_err_to_be_err(g_zfs); 577 } 578 ZFS_CLOSE(zhp); 579 return (ret); 580 } 581 582 /* 583 * Function: be_sort_list 584 * Description: Sort BE node list 585 * Parameters: 586 * pointer to address of list head 587 * Returns: 588 * nothing 589 * Side effect: 590 * node list sorted by name 591 * Scope: 592 * Private 593 */ 594 static void 595 be_sort_list(be_node_list_t **pstart) 596 { 597 size_t ibe, nbe; 598 be_node_list_t *p = NULL; 599 be_node_list_t **ptrlist = NULL; 600 601 if (pstart == NULL) 602 return; 603 /* build array of linked list BE struct pointers */ 604 for (p = *pstart, nbe = 0; p != NULL; nbe++, p = p->be_next_node) { 605 ptrlist = realloc(ptrlist, 606 sizeof (be_node_list_t *) * (nbe + 2)); 607 ptrlist[nbe] = p; 608 } 609 if (nbe == 0) 610 return; 611 /* in-place list quicksort using qsort(3C) */ 612 if (nbe > 1) /* no sort if less than 2 BEs */ 613 qsort(ptrlist, nbe, sizeof (be_node_list_t *), 614 be_qsort_compare_BEs); 615 616 ptrlist[nbe] = NULL; /* add linked list terminator */ 617 *pstart = ptrlist[0]; /* set new linked list header */ 618 /* for each BE in list */ 619 for (ibe = 0; ibe < nbe; ibe++) { 620 size_t k, ns; /* subordinate index, count */ 621 622 /* rewrite list pointer chain, including terminator */ 623 ptrlist[ibe]->be_next_node = ptrlist[ibe + 1]; 624 /* sort subordinate snapshots */ 625 if (ptrlist[ibe]->be_node_num_snapshots > 1) { 626 const size_t nmax = ptrlist[ibe]->be_node_num_snapshots; 627 be_snapshot_list_t ** const slist = 628 malloc(sizeof (be_snapshot_list_t *) * (nmax + 1)); 629 be_snapshot_list_t *p; 630 631 if (slist == NULL) 632 continue; 633 /* build array of linked list snapshot struct ptrs */ 634 for (ns = 0, p = ptrlist[ibe]->be_node_snapshots; 635 ns < nmax && p != NULL; 636 ns++, p = p->be_next_snapshot) { 637 slist[ns] = p; 638 } 639 if (ns < 2) 640 goto end_snapshot; 641 slist[ns] = NULL; /* add terminator */ 642 /* in-place list quicksort using qsort(3C) */ 643 qsort(slist, ns, sizeof (be_snapshot_list_t *), 644 be_qsort_compare_snapshots); 645 /* rewrite list pointer chain, including terminator */ 646 ptrlist[ibe]->be_node_snapshots = slist[0]; 647 for (k = 0; k < ns; k++) 648 slist[k]->be_next_snapshot = slist[k + 1]; 649 end_snapshot: 650 free(slist); 651 } 652 /* sort subordinate datasets */ 653 if (ptrlist[ibe]->be_node_num_datasets > 1) { 654 const size_t nmax = ptrlist[ibe]->be_node_num_datasets; 655 be_dataset_list_t ** const slist = 656 malloc(sizeof (be_dataset_list_t *) * (nmax + 1)); 657 be_dataset_list_t *p; 658 659 if (slist == NULL) 660 continue; 661 /* build array of linked list dataset struct ptrs */ 662 for (ns = 0, p = ptrlist[ibe]->be_node_datasets; 663 ns < nmax && p != NULL; 664 ns++, p = p->be_next_dataset) { 665 slist[ns] = p; 666 } 667 if (ns < 2) /* subordinate datasets < 2 - no sort */ 668 goto end_dataset; 669 slist[ns] = NULL; /* add terminator */ 670 /* in-place list quicksort using qsort(3C) */ 671 qsort(slist, ns, sizeof (be_dataset_list_t *), 672 be_qsort_compare_datasets); 673 /* rewrite list pointer chain, including terminator */ 674 ptrlist[ibe]->be_node_datasets = slist[0]; 675 for (k = 0; k < ns; k++) 676 slist[k]->be_next_dataset = slist[k + 1]; 677 end_dataset: 678 free(slist); 679 } 680 } 681 free: 682 free(ptrlist); 683 } 684 685 /* 686 * Function: be_qsort_compare_BEs 687 * Description: lexical compare of BE names for qsort(3C) 688 * Parameters: 689 * x,y - BEs with names to compare 690 * Returns: 691 * positive if y>x, negative if x>y, 0 if equal 692 * Scope: 693 * Private 694 */ 695 static int 696 be_qsort_compare_BEs(const void *x, const void *y) 697 { 698 be_node_list_t *p = *(be_node_list_t **)x; 699 be_node_list_t *q = *(be_node_list_t **)y; 700 701 if (p == NULL || p->be_node_name == NULL) 702 return (1); 703 if (q == NULL || q->be_node_name == NULL) 704 return (-1); 705 return (strcmp(p->be_node_name, q->be_node_name)); 706 } 707 708 /* 709 * Function: be_qsort_compare_snapshots 710 * Description: lexical compare of BE names for qsort(3C) 711 * Parameters: 712 * x,y - BE snapshots with names to compare 713 * Returns: 714 * positive if y>x, negative if x>y, 0 if equal 715 * Scope: 716 * Private 717 */ 718 static int 719 be_qsort_compare_snapshots(const void *x, const void *y) 720 { 721 be_snapshot_list_t *p = *(be_snapshot_list_t **)x; 722 be_snapshot_list_t *q = *(be_snapshot_list_t **)y; 723 724 if (p == NULL || p->be_snapshot_name == NULL) 725 return (1); 726 if (q == NULL || q->be_snapshot_name == NULL) 727 return (-1); 728 return (strcmp(p->be_snapshot_name, q->be_snapshot_name)); 729 } 730 731 /* 732 * Function: be_qsort_compare_datasets 733 * Description: lexical compare of dataset names for qsort(3C) 734 * Parameters: 735 * x,y - BE snapshots with names to compare 736 * Returns: 737 * positive if y>x, negative if x>y, 0 if equal 738 * Scope: 739 * Private 740 */ 741 static int 742 be_qsort_compare_datasets(const void *x, const void *y) 743 { 744 be_dataset_list_t *p = *(be_dataset_list_t **)x; 745 be_dataset_list_t *q = *(be_dataset_list_t **)y; 746 747 if (p == NULL || p->be_dataset_name == NULL) 748 return (1); 749 if (q == NULL || q->be_dataset_name == NULL) 750 return (-1); 751 return (strcmp(p->be_dataset_name, q->be_dataset_name)); 752 } 753 754 /* 755 * Function: be_get_node_data 756 * Description: Helper function used to collect all the information to fill 757 * in the be_node_list structure to be returned by be_list. 758 * Parameters: 759 * zhp - Handle to the root dataset for the BE whose information 760 * we're collecting. 761 * be_node - a pointer to the node structure we're filling in. 762 * be_name - The BE name of the node whose information we're 763 * collecting. 764 * current_be - the name of the currently active BE. 765 * be_ds - The dataset name for the BE. 766 * 767 * Returns: 768 * BE_SUCCESS - Success 769 * be_errno_t - Failure 770 * Scope: 771 * Private 772 */ 773 static int 774 be_get_node_data( 775 zfs_handle_t *zhp, 776 be_node_list_t *be_node, 777 char *be_name, 778 const char *rpool, 779 char *current_be, 780 char *be_ds) 781 { 782 char prop_buf[MAXPATHLEN]; 783 nvlist_t *userprops = NULL; 784 nvlist_t *propval = NULL; 785 char *prop_str = NULL; 786 char *grub_default_bootfs = NULL; 787 zpool_handle_t *zphp = NULL; 788 int err = 0; 789 790 if (be_node == NULL || be_name == NULL || current_be == NULL || 791 be_ds == NULL) { 792 be_print_err(gettext("be_get_node_data: invalid arguments, " 793 "can not be NULL\n")); 794 return (BE_ERR_INVAL); 795 } 796 797 errno = 0; 798 799 be_node->be_root_ds = strdup(be_ds); 800 if ((err = errno) != 0 || be_node->be_root_ds == NULL) { 801 be_print_err(gettext("be_get_node_data: failed to " 802 "copy root dataset name\n")); 803 return (errno_to_be_err(err)); 804 } 805 806 be_node->be_node_name = strdup(be_name); 807 if ((err = errno) != 0 || be_node->be_node_name == NULL) { 808 be_print_err(gettext("be_get_node_data: failed to " 809 "copy BE name\n")); 810 return (errno_to_be_err(err)); 811 } 812 if (strncmp(be_name, current_be, MAXPATHLEN) == 0) 813 be_node->be_active = B_TRUE; 814 else 815 be_node->be_active = B_FALSE; 816 817 be_node->be_rpool = strdup(rpool); 818 if (be_node->be_rpool == NULL || (err = errno) != 0) { 819 be_print_err(gettext("be_get_node_data: failed to " 820 "copy root pool name\n")); 821 return (errno_to_be_err(err)); 822 } 823 824 be_node->be_space_used = zfs_prop_get_int(zhp, ZFS_PROP_USED); 825 826 if ((zphp = zpool_open(g_zfs, rpool)) == NULL) { 827 be_print_err(gettext("be_get_node_data: failed to open pool " 828 "(%s): %s\n"), rpool, libzfs_error_description(g_zfs)); 829 return (zfs_err_to_be_err(g_zfs)); 830 } 831 832 (void) zpool_get_prop(zphp, ZPOOL_PROP_BOOTFS, prop_buf, ZFS_MAXPROPLEN, 833 NULL); 834 if (be_has_grub() && 835 (be_default_grub_bootfs(rpool, &grub_default_bootfs) 836 == BE_SUCCESS) && grub_default_bootfs != NULL) 837 if (strcmp(grub_default_bootfs, be_ds) == 0) 838 be_node->be_active_on_boot = B_TRUE; 839 else 840 be_node->be_active_on_boot = B_FALSE; 841 else if (prop_buf != NULL && strcmp(prop_buf, be_ds) == 0) 842 be_node->be_active_on_boot = B_TRUE; 843 else 844 be_node->be_active_on_boot = B_FALSE; 845 free(grub_default_bootfs); 846 zpool_close(zphp); 847 848 /* 849 * If the dataset is mounted use the mount point 850 * returned from the zfs_is_mounted call. If the 851 * dataset is not mounted then pull the mount 852 * point information out of the zfs properties. 853 */ 854 be_node->be_mounted = zfs_is_mounted(zhp, 855 &(be_node->be_mntpt)); 856 if (!be_node->be_mounted) { 857 if (zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop_buf, 858 ZFS_MAXPROPLEN, NULL, NULL, 0, B_FALSE) == 0) 859 be_node->be_mntpt = strdup(prop_buf); 860 else 861 return (zfs_err_to_be_err(g_zfs)); 862 } 863 864 be_node->be_node_creation = (time_t)zfs_prop_get_int(zhp, 865 ZFS_PROP_CREATION); 866 867 /* Get all user properties used for libbe */ 868 if ((userprops = zfs_get_user_props(zhp)) == NULL) { 869 be_node->be_policy_type = strdup(be_default_policy()); 870 } else { 871 if (nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY, 872 &propval) != 0 || propval == NULL) { 873 be_node->be_policy_type = 874 strdup(be_default_policy()); 875 } else { 876 verify(nvlist_lookup_string(propval, ZPROP_VALUE, 877 &prop_str) == 0); 878 if (prop_str == NULL || strcmp(prop_str, "-") == 0 || 879 strcmp(prop_str, "") == 0) 880 be_node->be_policy_type = 881 strdup(be_default_policy()); 882 else 883 be_node->be_policy_type = strdup(prop_str); 884 } 885 886 if (nvlist_lookup_nvlist(userprops, BE_UUID_PROPERTY, &propval) 887 == 0 && nvlist_lookup_string(propval, ZPROP_VALUE, 888 &prop_str) == 0) { 889 be_node->be_uuid_str = strdup(prop_str); 890 } 891 } 892 893 /* 894 * Increment the dataset counter to include the root dataset 895 * of the BE. 896 */ 897 be_node->be_node_num_datasets++; 898 899 return (BE_SUCCESS); 900 } 901 902 /* 903 * Function: be_get_ds_data 904 * Description: Helper function used by be_add_children_callback to collect 905 * the dataset related information that will be returned by 906 * be_list. 907 * Parameters: 908 * zhp - Handle to the zfs dataset whose information we're 909 * collecting. 910 * name - The name of the dataset we're processing. 911 * dataset - A pointer to the be_dataset_list structure 912 * we're filling in. 913 * node - The node structure that this dataset belongs to. 914 * Return: 915 * BE_SUCCESS - Success 916 * be_errno_t - Failure 917 * Scope: 918 * Private 919 */ 920 static int 921 be_get_ds_data( 922 zfs_handle_t *zfshp, 923 char *name, 924 be_dataset_list_t *dataset, 925 be_node_list_t *node) 926 { 927 char prop_buf[ZFS_MAXPROPLEN]; 928 nvlist_t *propval = NULL; 929 nvlist_t *userprops = NULL; 930 char *prop_str = NULL; 931 int err = 0; 932 933 if (zfshp == NULL || name == NULL || dataset == NULL || node == NULL) { 934 be_print_err(gettext("be_get_ds_data: invalid arguments, " 935 "can not be NULL\n")); 936 return (BE_ERR_INVAL); 937 } 938 939 errno = 0; 940 941 dataset->be_dataset_name = strdup(name); 942 if ((err = errno) != 0) { 943 be_print_err(gettext("be_get_ds_data: failed to copy " 944 "dataset name\n")); 945 return (errno_to_be_err(err)); 946 } 947 948 dataset->be_ds_space_used = zfs_prop_get_int(zfshp, ZFS_PROP_USED); 949 950 /* 951 * If the dataset is mounted use the mount point 952 * returned from the zfs_is_mounted call. If the 953 * dataset is not mounted then pull the mount 954 * point information out of the zfs properties. 955 */ 956 if (!(dataset->be_ds_mounted = zfs_is_mounted(zfshp, 957 &(dataset->be_ds_mntpt)))) { 958 if (zfs_prop_get(zfshp, ZFS_PROP_MOUNTPOINT, 959 prop_buf, ZFS_MAXPROPLEN, NULL, NULL, 0, 960 B_FALSE) == 0) 961 dataset->be_ds_mntpt = strdup(prop_buf); 962 else 963 return (zfs_err_to_be_err(g_zfs)); 964 } 965 dataset->be_ds_creation = 966 (time_t)zfs_prop_get_int(zfshp, ZFS_PROP_CREATION); 967 968 /* 969 * Get the user property used for the libbe 970 * cleaup policy 971 */ 972 if ((userprops = zfs_get_user_props(zfshp)) == NULL) { 973 dataset->be_ds_plcy_type = 974 strdup(node->be_policy_type); 975 } else { 976 if (nvlist_lookup_nvlist(userprops, 977 BE_POLICY_PROPERTY, &propval) != 0 || 978 propval == NULL) { 979 dataset->be_ds_plcy_type = 980 strdup(node->be_policy_type); 981 } else { 982 verify(nvlist_lookup_string(propval, 983 ZPROP_VALUE, &prop_str) == 0); 984 if (prop_str == NULL || 985 strcmp(prop_str, "-") == 0 || 986 strcmp(prop_str, "") == 0) 987 dataset->be_ds_plcy_type 988 = strdup(node->be_policy_type); 989 else 990 dataset->be_ds_plcy_type = strdup(prop_str); 991 } 992 } 993 994 node->be_node_num_datasets++; 995 return (BE_SUCCESS); 996 } 997 998 /* 999 * Function: be_get_ss_data 1000 * Description: Helper function used by be_add_children_callback to collect 1001 * the dataset related information that will be returned by 1002 * be_list. 1003 * Parameters: 1004 * zhp - Handle to the zfs snapshot whose information we're 1005 * collecting. 1006 * name - The name of the snapshot we're processing. 1007 * shapshot - A pointer to the be_snapshot_list structure 1008 * we're filling in. 1009 * node - The node structure that this snapshot belongs to. 1010 * Returns: 1011 * BE_SUCCESS - Success 1012 * be_errno_t - Failure 1013 * Scope: 1014 * Private 1015 */ 1016 static int 1017 be_get_ss_data( 1018 zfs_handle_t *zfshp, 1019 char *name, 1020 be_snapshot_list_t *snapshot, 1021 be_node_list_t *node) 1022 { 1023 nvlist_t *propval = NULL; 1024 nvlist_t *userprops = NULL; 1025 char *prop_str = NULL; 1026 int err = 0; 1027 1028 if (zfshp == NULL || name == NULL || snapshot == NULL || node == NULL) { 1029 be_print_err(gettext("be_get_ss_data: invalid arguments, " 1030 "can not be NULL\n")); 1031 return (BE_ERR_INVAL); 1032 } 1033 1034 errno = 0; 1035 1036 snapshot->be_snapshot_name = strdup(name); 1037 if ((err = errno) != 0) { 1038 be_print_err(gettext("be_get_ss_data: failed to copy name\n")); 1039 return (errno_to_be_err(err)); 1040 } 1041 1042 snapshot->be_snapshot_creation = (time_t)zfs_prop_get_int(zfshp, 1043 ZFS_PROP_CREATION); 1044 1045 /* 1046 * Try to get this snapshot's cleanup policy from its 1047 * user properties first. If not there, use default 1048 * cleanup policy. 1049 */ 1050 if ((userprops = zfs_get_user_props(zfshp)) != NULL && 1051 nvlist_lookup_nvlist(userprops, BE_POLICY_PROPERTY, 1052 &propval) == 0 && nvlist_lookup_string(propval, 1053 ZPROP_VALUE, &prop_str) == 0) { 1054 snapshot->be_snapshot_type = 1055 strdup(prop_str); 1056 } else { 1057 snapshot->be_snapshot_type = 1058 strdup(be_default_policy()); 1059 } 1060 1061 snapshot->be_snapshot_space_used = zfs_prop_get_int(zfshp, 1062 ZFS_PROP_USED); 1063 1064 node->be_node_num_snapshots++; 1065 return (BE_SUCCESS); 1066 } 1067 1068 /* 1069 * Function: be_list_alloc 1070 * Description: Helper function used to allocate memory for the various 1071 * sructures that make up a BE node. 1072 * Parameters: 1073 * err - Used to return any errors encountered. 1074 * BE_SUCCESS - Success 1075 * BE_ERR_NOMEM - Allocation failure 1076 * size - The size of memory to allocate. 1077 * Returns: 1078 * Success - A pointer to the allocated memory 1079 * Failure - NULL 1080 * Scope: 1081 * Private 1082 */ 1083 static void* 1084 be_list_alloc(int *err, size_t size) 1085 { 1086 void *bep = NULL; 1087 1088 bep = calloc(1, size); 1089 if (bep == NULL) { 1090 be_print_err(gettext("be_list_alloc: memory " 1091 "allocation failed\n")); 1092 *err = BE_ERR_NOMEM; 1093 } 1094 *err = BE_SUCCESS; 1095 return (bep); 1096 } 1097 1098 /* 1099 * Function: be_get_zone_node_data 1100 * Description: Helper function used to collect all the information to 1101 * fill in the be_node_list structure to be returned by 1102 * be_get_zone_list. 1103 * Parameters: 1104 * be_node - a pointer to the node structure we're filling in. 1105 * be_name - The BE name of the node whose information we're 1106 * Returns: 1107 * BE_SUCCESS - Success 1108 * be_errno_t - Failure 1109 * Scope: 1110 * Private 1111 * 1112 * NOTE: This function currently only collects the zone BE name but when 1113 * support for beadm/libbe in a zone is provided it will need to fill 1114 * in the rest of the information needed for a zone BE. 1115 */ 1116 static int 1117 be_get_zone_node_data(be_node_list_t *be_node, char *be_name) 1118 { 1119 if ((be_node->be_node_name = strdup(be_name)) != NULL) 1120 return (BE_SUCCESS); 1121 return (BE_ERR_NOMEM); 1122 } 1123