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.
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.
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]
23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
28 * Copyright 2015 Toomas Soome <tsoome@me.com>
29 * Copyright 2015 Gary Mills
30 * Copyright (c) 2016 Martin Matuska. All rights reserved.
35 #include <libnvpair.h>
41 #include <sys/types.h>
47 #include <libbe_priv.h>
50 * Callback data used for zfs_iter calls.
52 typedef struct list_callback_data
{
55 be_node_list_t
*be_nodes_head
;
56 be_node_list_t
*be_nodes
;
57 char current_be
[MAXPATHLEN
];
58 } list_callback_data_t
;
61 * Private function prototypes
63 static int be_add_children_callback(zfs_handle_t
*zhp
, void *data
);
64 static int be_get_list_callback(zpool_handle_t
*, void *);
65 static int be_get_node_data(zfs_handle_t
*, be_node_list_t
*, char *,
66 const char *, char *, char *);
67 static int be_get_zone_node_data(be_node_list_t
*, char *);
68 static int be_get_ds_data(zfs_handle_t
*, char *, be_dataset_list_t
*,
70 static int be_get_ss_data(zfs_handle_t
*, char *, be_snapshot_list_t
*,
72 static int be_sort_list(be_node_list_t
**,
73 int (*)(const void *, const void *));
74 static int be_qsort_compare_BEs_name(const void *, const void *);
75 static int be_qsort_compare_BEs_name_rev(const void *, const void *);
76 static int be_qsort_compare_BEs_date(const void *, const void *);
77 static int be_qsort_compare_BEs_date_rev(const void *, const void *);
78 static int be_qsort_compare_BEs_space(const void *, const void *);
79 static int be_qsort_compare_BEs_space_rev(const void *, const void *);
80 static int be_qsort_compare_snapshots(const void *x
, const void *y
);
81 static int be_qsort_compare_datasets(const void *x
, const void *y
);
82 static void *be_list_alloc(int *, size_t);
87 static char be_container_ds
[MAXPATHLEN
];
88 static boolean_t zone_be
= B_FALSE
;
90 /* ******************************************************************** */
91 /* Public Functions */
92 /* ******************************************************************** */
96 * Description: Calls _be_list which finds all the BEs on the system and
97 * returns the datasets and snapshots belonging to each BE.
98 * Also data, such as dataset and snapshot properties,
99 * for each BE and their snapshots and datasets is
100 * returned. The data returned is as described in the
101 * be_dataset_list_t, be_snapshot_list_t and be_node_list_t
104 * be_name - The name of the BE to look up.
105 * If NULL a list of all BEs will be returned.
106 * be_nodes - A reference pointer to the list of BEs. The list
107 * structure will be allocated by _be_list and must
108 * be freed by a call to be_free_list. If there are no
109 * BEs found on the system this reference will be
112 * BE_SUCCESS - Success
113 * be_errno_t - Failure
118 be_list(char *be_name
, be_node_list_t
**be_nodes
)
120 int ret
= BE_SUCCESS
;
122 /* Initialize libzfs handle */
124 return (BE_ERR_INIT
);
126 /* Validate be_name if its not NULL */
127 if (be_name
!= NULL
) {
128 if (!be_valid_be_name(be_name
)) {
129 be_print_err(gettext("be_list: "
130 "invalid BE name %s\n"), be_name
);
131 return (BE_ERR_INVAL
);
135 ret
= _be_list(be_name
, be_nodes
);
144 * Description: Sort BE node list
146 * pointer to address of list head
149 * BE_SUCCESS - Success
150 * be_errno_t - Failure
152 * node list sorted by name
157 be_sort(be_node_list_t
**be_nodes
, int order
)
159 int (*compar
)(const void *, const void *) = be_qsort_compare_BEs_date
;
161 if (be_nodes
== NULL
)
162 return (BE_ERR_INVAL
);
165 case BE_SORT_UNSPECIFIED
:
167 compar
= be_qsort_compare_BEs_date
;
169 case BE_SORT_DATE_REV
:
170 compar
= be_qsort_compare_BEs_date_rev
;
173 compar
= be_qsort_compare_BEs_name
;
175 case BE_SORT_NAME_REV
:
176 compar
= be_qsort_compare_BEs_name_rev
;
179 compar
= be_qsort_compare_BEs_space
;
181 case BE_SORT_SPACE_REV
:
182 compar
= be_qsort_compare_BEs_space_rev
;
185 be_print_err(gettext("be_sort: invalid sort order %d\n"),
187 return (BE_ERR_INVAL
);
190 return (be_sort_list(be_nodes
, compar
));
193 /* ******************************************************************** */
194 /* Semi-Private Functions */
195 /* ******************************************************************** */
199 * Description: This does the actual work described in be_list.
201 * be_name - The name of the BE to look up.
202 * If NULL a list of all BEs will be returned.
203 * be_nodes - A reference pointer to the list of BEs. The list
204 * structure will be allocated here and must
205 * be freed by a call to be_free_list. If there are no
206 * BEs found on the system this reference will be
209 * BE_SUCCESS - Success
210 * be_errno_t - Failure
212 * Semi-private (library wide use only)
215 _be_list(char *be_name
, be_node_list_t
**be_nodes
)
217 list_callback_data_t cb
= { 0 };
218 be_transaction_data_t bt
= { 0 };
219 int ret
= BE_SUCCESS
;
221 zpool_handle_t
*zphp
;
223 struct be_defaults be_defaults
;
225 if (be_nodes
== NULL
)
226 return (BE_ERR_INVAL
);
228 be_get_defaults(&be_defaults
);
230 if (be_find_current_be(&bt
) != BE_SUCCESS
) {
232 * We were unable to find a currently booted BE which
233 * probably means that we're not booted in a BE envoronment.
234 * None of the BE's will be marked as the active BE.
236 (void) strcpy(cb
.current_be
, "-");
238 (void) strncpy(cb
.current_be
, bt
.obe_name
,
239 sizeof (cb
.current_be
));
240 rpool
= bt
.obe_zpool
;
244 * If be_name is NULL we'll look for all BE's on the system.
245 * If not then we will only return data for the specified BE.
248 cb
.be_name
= strdup(be_name
);
250 if (be_defaults
.be_deflt_rpool_container
&& rpool
!= NULL
) {
251 if ((zphp
= zpool_open(g_zfs
, rpool
)) == NULL
) {
252 be_print_err(gettext("be_list: failed to "
253 "open rpool (%s): %s\n"), rpool
,
254 libzfs_error_description(g_zfs
));
256 return (zfs_err_to_be_err(g_zfs
));
259 ret
= be_get_list_callback(zphp
, &cb
);
261 if ((zpool_iter(g_zfs
, be_get_list_callback
, &cb
)) != 0) {
262 if (cb
.be_nodes_head
!= NULL
) {
263 be_free_list(cb
.be_nodes_head
);
264 cb
.be_nodes_head
= NULL
;
267 ret
= BE_ERR_BE_NOENT
;
271 if (cb
.be_nodes_head
== NULL
) {
273 be_print_err(gettext("be_list: BE (%s) does not "
274 "exist\n"), be_name
);
276 be_print_err(gettext("be_list: No BE's found\n"));
277 ret
= BE_ERR_BE_NOENT
;
280 *be_nodes
= cb
.be_nodes_head
;
284 sret
= be_sort(be_nodes
, BE_SORT_DATE
);
286 return ((ret
== BE_SUCCESS
) ? sret
: ret
);
290 * Function: be_free_list
291 * Description: Frees up all the data allocated for the list of BEs,
292 * datasets and snapshots returned by be_list.
294 * be_node - be_nodes_t structure returned from call to be_list.
298 * Semi-private (library wide use only)
301 be_free_list(be_node_list_t
*be_nodes
)
303 be_node_list_t
*temp_node
= NULL
;
304 be_node_list_t
*list
= be_nodes
;
306 while (list
!= NULL
) {
307 be_dataset_list_t
*datasets
= list
->be_node_datasets
;
308 be_snapshot_list_t
*snapshots
= list
->be_node_snapshots
;
310 while (datasets
!= NULL
) {
311 be_dataset_list_t
*temp_ds
= datasets
;
312 datasets
= datasets
->be_next_dataset
;
313 free(temp_ds
->be_dataset_name
);
314 free(temp_ds
->be_ds_mntpt
);
315 free(temp_ds
->be_ds_plcy_type
);
319 while (snapshots
!= NULL
) {
320 be_snapshot_list_t
*temp_ss
= snapshots
;
321 snapshots
= snapshots
->be_next_snapshot
;
322 free(temp_ss
->be_snapshot_name
);
323 free(temp_ss
->be_snapshot_type
);
328 list
= list
->be_next_node
;
329 free(temp_node
->be_node_name
);
330 free(temp_node
->be_root_ds
);
331 free(temp_node
->be_rpool
);
332 free(temp_node
->be_mntpt
);
333 free(temp_node
->be_policy_type
);
334 free(temp_node
->be_uuid_str
);
340 * Function: be_get_zone_be_list
341 * Description: Finds all the BEs for this zone on the system.
343 * zone_be_name - The name of the BE to look up.
344 * zone_be_container_ds - The dataset for the zone.
345 * zbe_nodes - A reference pointer to the list of BEs. The list
346 * structure will be allocated here and must
347 * be freed by a call to be_free_list. If there are no
348 * BEs found on the system this reference will be
351 * BE_SUCCESS - Success
352 * be_errno_t - Failure
354 * Semi-private (library wide use only)
358 be_get_zone_be_list(char *zone_be_name
, char *zone_be_container_ds
,
359 be_node_list_t
**zbe_nodes
)
361 zfs_handle_t
*zhp
= NULL
;
362 list_callback_data_t cb
= { 0 };
363 int ret
= BE_SUCCESS
;
365 if (zbe_nodes
== NULL
)
366 return (BE_ERR_INVAL
);
368 if (!zfs_dataset_exists(g_zfs
, zone_be_container_ds
,
369 ZFS_TYPE_FILESYSTEM
)) {
370 return (BE_ERR_BE_NOENT
);
375 if ((zhp
= zfs_open(g_zfs
, zone_be_container_ds
,
376 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
377 be_print_err(gettext("be_get_zone_be_list: failed to open "
378 "the zone BE dataset %s: %s\n"), zone_be_container_ds
,
379 libzfs_error_description(g_zfs
));
380 ret
= zfs_err_to_be_err(g_zfs
);
384 (void) strcpy(be_container_ds
, zone_be_container_ds
);
386 if (cb
.be_nodes_head
== NULL
) {
387 if ((cb
.be_nodes_head
= be_list_alloc(&ret
,
388 sizeof (be_node_list_t
))) == NULL
) {
392 cb
.be_nodes
= cb
.be_nodes_head
;
395 ret
= zfs_iter_filesystems(zhp
, be_add_children_callback
, &cb
);
398 *zbe_nodes
= cb
.be_nodes_head
;
406 /* ******************************************************************** */
407 /* Private Functions */
408 /* ******************************************************************** */
411 * Function: be_get_list_callback
412 * Description: Callback function used by zfs_iter to look through all
413 * the pools on the system looking for BEs. If a BE name was
414 * specified only that BE's information will be collected and
417 * zlp - handle to the first zfs dataset. (provided by the
419 * data - pointer to the callback data and where we'll pass
420 * the BE information back.
423 * be_errno_t - Failure
428 be_get_list_callback(zpool_handle_t
*zlp
, void *data
)
430 list_callback_data_t
*cb
= (list_callback_data_t
*)data
;
431 char be_ds
[MAXPATHLEN
];
432 char *open_ds
= NULL
;
434 zfs_handle_t
*zhp
= NULL
;
437 cb
->zpool_name
= rpool
= (char *)zpool_get_name(zlp
);
440 * Generate string for the BE container dataset
442 be_make_container_ds(rpool
, be_container_ds
,
443 sizeof (be_container_ds
));
446 * If a BE name was specified we use it's root dataset in place of
447 * the container dataset. This is because we only want to collect
448 * the information for the specified BE.
450 if (cb
->be_name
!= NULL
) {
451 if (!be_valid_be_name(cb
->be_name
))
452 return (BE_ERR_INVAL
);
454 * Generate string for the BE root dataset
456 be_make_root_ds(rpool
, cb
->be_name
, be_ds
, sizeof (be_ds
));
459 open_ds
= be_container_ds
;
463 * Check if the dataset exists
465 if (!zfs_dataset_exists(g_zfs
, open_ds
,
466 ZFS_TYPE_FILESYSTEM
)) {
468 * The specified dataset does not exist in this pool or
469 * there are no valid BE's in this pool. Try the next zpool.
475 if ((zhp
= zfs_open(g_zfs
, open_ds
, ZFS_TYPE_FILESYSTEM
)) == NULL
) {
476 be_print_err(gettext("be_get_list_callback: failed to open "
477 "the BE dataset %s: %s\n"), open_ds
,
478 libzfs_error_description(g_zfs
));
479 ret
= zfs_err_to_be_err(g_zfs
);
485 * If a BE name was specified we iterate through the datasets
486 * and snapshots for this BE only. Otherwise we will iterate
487 * through the next level of datasets to find all the BE's
490 if (cb
->be_name
!= NULL
) {
491 if (cb
->be_nodes_head
== NULL
) {
492 if ((cb
->be_nodes_head
= be_list_alloc(&ret
,
493 sizeof (be_node_list_t
))) == NULL
) {
498 cb
->be_nodes
= cb
->be_nodes_head
;
501 if ((ret
= be_get_node_data(zhp
, cb
->be_nodes
, cb
->be_name
,
502 rpool
, cb
->current_be
, be_ds
)) != BE_SUCCESS
) {
507 ret
= zfs_iter_snapshots(zhp
, B_FALSE
, be_add_children_callback
,
512 ret
= zfs_iter_filesystems(zhp
, be_add_children_callback
, cb
);
520 * Function: be_add_children_callback
521 * Description: Callback function used by zfs_iter to look through all
522 * the datasets and snapshots for each BE and add them to
523 * the lists of information to be passed back.
525 * zhp - handle to the first zfs dataset. (provided by the
527 * data - pointer to the callback data and where we'll pass
528 * the BE information back.
531 * be_errno_t - Failure
536 be_add_children_callback(zfs_handle_t
*zhp
, void *data
)
538 list_callback_data_t
*cb
= (list_callback_data_t
*)data
;
539 char *str
= NULL
, *ds_path
= NULL
;
541 struct be_defaults be_defaults
;
543 be_get_defaults(&be_defaults
);
545 ds_path
= str
= strdup(zfs_get_name(zhp
));
548 * get past the end of the container dataset plus the trailing "/"
550 str
= str
+ (strlen(be_container_ds
) + 1);
551 if (be_defaults
.be_deflt_rpool_container
) {
552 /* just skip if invalid */
553 if (!be_valid_be_name(str
))
557 if (cb
->be_nodes_head
== NULL
) {
558 if ((cb
->be_nodes_head
= be_list_alloc(&ret
,
559 sizeof (be_node_list_t
))) == NULL
) {
563 cb
->be_nodes
= cb
->be_nodes_head
;
566 if (zfs_get_type(zhp
) == ZFS_TYPE_SNAPSHOT
&& !zone_be
) {
567 be_snapshot_list_t
*snapshots
= NULL
;
568 if (cb
->be_nodes
->be_node_snapshots
== NULL
) {
569 if ((cb
->be_nodes
->be_node_snapshots
=
570 be_list_alloc(&ret
, sizeof (be_snapshot_list_t
)))
571 == NULL
|| ret
!= BE_SUCCESS
) {
575 cb
->be_nodes
->be_node_snapshots
->be_next_snapshot
=
577 snapshots
= cb
->be_nodes
->be_node_snapshots
;
579 for (snapshots
= cb
->be_nodes
->be_node_snapshots
;
581 snapshots
= snapshots
->be_next_snapshot
) {
582 if (snapshots
->be_next_snapshot
!= NULL
)
585 * We're at the end of the list add the
588 if ((snapshots
->be_next_snapshot
=
590 sizeof (be_snapshot_list_t
))) == NULL
||
595 snapshots
= snapshots
->be_next_snapshot
;
596 snapshots
->be_next_snapshot
= NULL
;
600 if ((ret
= be_get_ss_data(zhp
, str
, snapshots
,
601 cb
->be_nodes
)) != BE_SUCCESS
) {
605 } else if (strchr(str
, '/') == NULL
) {
606 if (cb
->be_nodes
->be_node_name
!= NULL
) {
607 if ((cb
->be_nodes
->be_next_node
=
608 be_list_alloc(&ret
, sizeof (be_node_list_t
))) ==
609 NULL
|| ret
!= BE_SUCCESS
) {
613 cb
->be_nodes
= cb
->be_nodes
->be_next_node
;
614 cb
->be_nodes
->be_next_node
= NULL
;
618 * If this is a zone root dataset then we only need
619 * the name of the zone BE at this point. We grab that
623 ret
= be_get_zone_node_data(cb
->be_nodes
, str
);
628 if ((ret
= be_get_node_data(zhp
, cb
->be_nodes
, str
,
629 cb
->zpool_name
, cb
->current_be
, ds_path
)) != BE_SUCCESS
) {
633 } else if (strchr(str
, '/') != NULL
&& !zone_be
) {
634 be_dataset_list_t
*datasets
= NULL
;
635 if (cb
->be_nodes
->be_node_datasets
== NULL
) {
636 if ((cb
->be_nodes
->be_node_datasets
=
637 be_list_alloc(&ret
, sizeof (be_dataset_list_t
)))
638 == NULL
|| ret
!= BE_SUCCESS
) {
642 cb
->be_nodes
->be_node_datasets
->be_next_dataset
= NULL
;
643 datasets
= cb
->be_nodes
->be_node_datasets
;
645 for (datasets
= cb
->be_nodes
->be_node_datasets
;
647 datasets
= datasets
->be_next_dataset
) {
648 if (datasets
->be_next_dataset
!= NULL
)
651 * We're at the end of the list add
654 if ((datasets
->be_next_dataset
=
656 sizeof (be_dataset_list_t
)))
657 == NULL
|| ret
!= BE_SUCCESS
) {
661 datasets
= datasets
->be_next_dataset
;
662 datasets
->be_next_dataset
= NULL
;
667 if ((ret
= be_get_ds_data(zhp
, str
,
668 datasets
, cb
->be_nodes
)) != BE_SUCCESS
) {
673 ret
= zfs_iter_children(zhp
, be_add_children_callback
, cb
);
675 be_print_err(gettext("be_add_children_callback: "
676 "encountered error: %s\n"),
677 libzfs_error_description(g_zfs
));
678 ret
= zfs_err_to_be_err(g_zfs
);
685 * Function: be_sort_list
686 * Description: Sort BE node list
688 * pointer to address of list head
691 * BE_SUCCESS - Success
692 * be_errno_t - Failure
694 * node list sorted by name
699 be_sort_list(be_node_list_t
**pstart
, int (*compar
)(const void *, const void *))
701 int ret
= BE_SUCCESS
;
703 be_node_list_t
*p
= NULL
;
704 be_node_list_t
**ptrlist
= NULL
;
705 be_node_list_t
**ptrtmp
;
707 if (pstart
== NULL
) /* Nothing to sort */
709 /* build array of linked list BE struct pointers */
710 for (p
= *pstart
, nbe
= 0; p
!= NULL
; nbe
++, p
= p
->be_next_node
) {
711 ptrtmp
= reallocarray(ptrlist
, nbe
+ 2,
712 sizeof (be_node_list_t
*));
713 if (ptrtmp
== NULL
) { /* out of memory */
714 be_print_err(gettext("be_sort_list: memory "
715 "allocation failed\n"));
722 if (nbe
== 0) /* Nothing to sort */
724 /* in-place list quicksort using qsort(3C) */
725 if (nbe
> 1) /* no sort if less than 2 BEs */
726 qsort(ptrlist
, nbe
, sizeof (be_node_list_t
*), compar
);
728 ptrlist
[nbe
] = NULL
; /* add linked list terminator */
729 *pstart
= ptrlist
[0]; /* set new linked list header */
730 /* for each BE in list */
731 for (ibe
= 0; ibe
< nbe
; ibe
++) {
732 size_t k
, ns
; /* subordinate index, count */
734 /* rewrite list pointer chain, including terminator */
735 ptrlist
[ibe
]->be_next_node
= ptrlist
[ibe
+ 1];
736 /* sort subordinate snapshots */
737 if (ptrlist
[ibe
]->be_node_num_snapshots
> 1) {
738 const size_t nmax
= ptrlist
[ibe
]->be_node_num_snapshots
;
739 be_snapshot_list_t
** const slist
=
740 malloc(sizeof (be_snapshot_list_t
*) * (nmax
+ 1));
741 be_snapshot_list_t
*p
;
747 /* build array of linked list snapshot struct ptrs */
748 for (ns
= 0, p
= ptrlist
[ibe
]->be_node_snapshots
;
749 ns
< nmax
&& p
!= NULL
;
750 ns
++, p
= p
->be_next_snapshot
) {
755 slist
[ns
] = NULL
; /* add terminator */
756 /* in-place list quicksort using qsort(3C) */
757 qsort(slist
, ns
, sizeof (be_snapshot_list_t
*),
758 be_qsort_compare_snapshots
);
759 /* rewrite list pointer chain, including terminator */
760 ptrlist
[ibe
]->be_node_snapshots
= slist
[0];
761 for (k
= 0; k
< ns
; k
++)
762 slist
[k
]->be_next_snapshot
= slist
[k
+ 1];
766 /* sort subordinate datasets */
767 if (ptrlist
[ibe
]->be_node_num_datasets
> 1) {
768 const size_t nmax
= ptrlist
[ibe
]->be_node_num_datasets
;
769 be_dataset_list_t
** const slist
=
770 malloc(sizeof (be_dataset_list_t
*) * (nmax
+ 1));
771 be_dataset_list_t
*p
;
777 /* build array of linked list dataset struct ptrs */
778 for (ns
= 0, p
= ptrlist
[ibe
]->be_node_datasets
;
779 ns
< nmax
&& p
!= NULL
;
780 ns
++, p
= p
->be_next_dataset
) {
783 if (ns
< 2) /* subordinate datasets < 2 - no sort */
785 slist
[ns
] = NULL
; /* add terminator */
786 /* in-place list quicksort using qsort(3C) */
787 qsort(slist
, ns
, sizeof (be_dataset_list_t
*),
788 be_qsort_compare_datasets
);
789 /* rewrite list pointer chain, including terminator */
790 ptrlist
[ibe
]->be_node_datasets
= slist
[0];
791 for (k
= 0; k
< ns
; k
++)
792 slist
[k
]->be_next_dataset
= slist
[k
+ 1];
803 * Function: be_qsort_compare_BEs_date
804 * Description: compare BE creation times for qsort(3C)
805 * will sort BE list from oldest to most recent
807 * x,y - BEs with names to compare
809 * positive if x>y, negative if y>x, 0 if equal
814 be_qsort_compare_BEs_date(const void *x
, const void *y
)
816 be_node_list_t
*p
= *(be_node_list_t
**)x
;
817 be_node_list_t
*q
= *(be_node_list_t
**)y
;
822 if (p
->be_node_creation
> q
->be_node_creation
)
824 if (p
->be_node_creation
< q
->be_node_creation
)
830 * Function: be_qsort_compare_BEs_date_rev
831 * Description: compare BE creation times for qsort(3C)
832 * will sort BE list from recent to oldest
834 * x,y - BEs with names to compare
836 * positive if y>x, negative if x>y, 0 if equal
841 be_qsort_compare_BEs_date_rev(const void *x
, const void *y
)
843 return (be_qsort_compare_BEs_date(y
, x
));
847 * Function: be_qsort_compare_BEs_name
848 * Description: lexical compare of BE names for qsort(3C)
850 * x,y - BEs with names to compare
852 * positive if x>y, negative if y>x, 0 if equal
857 be_qsort_compare_BEs_name(const void *x
, const void *y
)
859 be_node_list_t
*p
= *(be_node_list_t
**)x
;
860 be_node_list_t
*q
= *(be_node_list_t
**)y
;
863 assert(p
->be_node_name
!= NULL
);
865 assert(q
->be_node_name
!= NULL
);
867 return (strcmp(p
->be_node_name
, q
->be_node_name
));
871 * Function: be_qsort_compare_BEs_name_rev
872 * Description: reverse lexical compare of BE names for qsort(3C)
874 * x,y - BEs with names to compare
876 * positive if y>x, negative if x>y, 0 if equal
881 be_qsort_compare_BEs_name_rev(const void *x
, const void *y
)
883 return (be_qsort_compare_BEs_name(y
, x
));
887 * Function: be_qsort_compare_BEs_space
888 * Description: compare BE sizes for qsort(3C)
889 * will sort BE list in growing order
891 * x,y - BEs with names to compare
893 * positive if x>y, negative if y>x, 0 if equal
898 be_qsort_compare_BEs_space(const void *x
, const void *y
)
900 be_node_list_t
*p
= *(be_node_list_t
**)x
;
901 be_node_list_t
*q
= *(be_node_list_t
**)y
;
906 if (p
->be_space_used
> q
->be_space_used
)
908 if (p
->be_space_used
< q
->be_space_used
)
914 * Function: be_qsort_compare_BEs_space_rev
915 * Description: compare BE sizes for qsort(3C)
916 * will sort BE list in shrinking
918 * x,y - BEs with names to compare
920 * positive if y>x, negative if x>y, 0 if equal
925 be_qsort_compare_BEs_space_rev(const void *x
, const void *y
)
927 return (be_qsort_compare_BEs_space(y
, x
));
931 * Function: be_qsort_compare_snapshots
932 * Description: lexical compare of BE names for qsort(3C)
934 * x,y - BE snapshots with names to compare
936 * positive if y>x, negative if x>y, 0 if equal
941 be_qsort_compare_snapshots(const void *x
, const void *y
)
943 be_snapshot_list_t
*p
= *(be_snapshot_list_t
**)x
;
944 be_snapshot_list_t
*q
= *(be_snapshot_list_t
**)y
;
946 if (p
== NULL
|| p
->be_snapshot_name
== NULL
)
948 if (q
== NULL
|| q
->be_snapshot_name
== NULL
)
950 return (strcmp(p
->be_snapshot_name
, q
->be_snapshot_name
));
954 * Function: be_qsort_compare_datasets
955 * Description: lexical compare of dataset names for qsort(3C)
957 * x,y - BE snapshots with names to compare
959 * positive if y>x, negative if x>y, 0 if equal
964 be_qsort_compare_datasets(const void *x
, const void *y
)
966 be_dataset_list_t
*p
= *(be_dataset_list_t
**)x
;
967 be_dataset_list_t
*q
= *(be_dataset_list_t
**)y
;
969 if (p
== NULL
|| p
->be_dataset_name
== NULL
)
971 if (q
== NULL
|| q
->be_dataset_name
== NULL
)
973 return (strcmp(p
->be_dataset_name
, q
->be_dataset_name
));
977 * Function: be_get_node_data
978 * Description: Helper function used to collect all the information to fill
979 * in the be_node_list structure to be returned by be_list.
981 * zhp - Handle to the root dataset for the BE whose information
983 * be_node - a pointer to the node structure we're filling in.
984 * be_name - The BE name of the node whose information we're
986 * current_be - the name of the currently active BE.
987 * be_ds - The dataset name for the BE.
990 * BE_SUCCESS - Success
991 * be_errno_t - Failure
998 be_node_list_t
*be_node
,
1004 char prop_buf
[MAXPATHLEN
];
1005 nvlist_t
*userprops
= NULL
;
1006 nvlist_t
*propval
= NULL
;
1007 nvlist_t
*zone_propval
= NULL
;
1008 char *prop_str
= NULL
;
1009 char *zone_prop_str
= NULL
;
1010 zpool_handle_t
*zphp
= NULL
;
1013 if (be_node
== NULL
|| be_name
== NULL
|| current_be
== NULL
||
1015 be_print_err(gettext("be_get_node_data: invalid arguments, "
1016 "can not be NULL\n"));
1017 return (BE_ERR_INVAL
);
1022 be_node
->be_root_ds
= strdup(be_ds
);
1023 if ((err
= errno
) != 0 || be_node
->be_root_ds
== NULL
) {
1024 be_print_err(gettext("be_get_node_data: failed to "
1025 "copy root dataset name\n"));
1026 return (errno_to_be_err(err
));
1029 be_node
->be_node_name
= strdup(be_name
);
1030 if ((err
= errno
) != 0 || be_node
->be_node_name
== NULL
) {
1031 be_print_err(gettext("be_get_node_data: failed to "
1033 return (errno_to_be_err(err
));
1035 if (strncmp(be_name
, current_be
, MAXPATHLEN
) == 0)
1036 be_node
->be_active
= B_TRUE
;
1038 be_node
->be_active
= B_FALSE
;
1040 be_node
->be_rpool
= strdup(rpool
);
1041 if (be_node
->be_rpool
== NULL
|| (err
= errno
) != 0) {
1042 be_print_err(gettext("be_get_node_data: failed to "
1043 "copy root pool name\n"));
1044 return (errno_to_be_err(err
));
1047 be_node
->be_space_used
= zfs_prop_get_int(zhp
, ZFS_PROP_USED
);
1049 if (getzoneid() == GLOBAL_ZONEID
) {
1050 if ((zphp
= zpool_open(g_zfs
, rpool
)) == NULL
) {
1051 be_print_err(gettext("be_get_node_data: failed to open "
1052 "pool (%s): %s\n"), rpool
,
1053 libzfs_error_description(g_zfs
));
1054 return (zfs_err_to_be_err(g_zfs
));
1057 (void) zpool_get_prop(zphp
, ZPOOL_PROP_BOOTFS
, prop_buf
,
1058 ZFS_MAXPROPLEN
, NULL
, B_FALSE
);
1059 if (strcmp(prop_buf
, be_ds
) == 0)
1060 be_node
->be_active_on_boot
= B_TRUE
;
1062 be_node
->be_active_on_boot
= B_FALSE
;
1064 be_node
->be_global_active
= B_TRUE
;
1068 if (be_zone_compare_uuids(be_node
->be_root_ds
))
1069 be_node
->be_global_active
= B_TRUE
;
1071 be_node
->be_global_active
= B_FALSE
;
1075 * If the dataset is mounted use the mount point
1076 * returned from the zfs_is_mounted call. If the
1077 * dataset is not mounted then pull the mount
1078 * point information out of the zfs properties.
1080 be_node
->be_mounted
= zfs_is_mounted(zhp
,
1081 &(be_node
->be_mntpt
));
1082 if (!be_node
->be_mounted
) {
1083 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, prop_buf
,
1084 ZFS_MAXPROPLEN
, NULL
, NULL
, 0, B_FALSE
) == 0)
1085 be_node
->be_mntpt
= strdup(prop_buf
);
1087 return (zfs_err_to_be_err(g_zfs
));
1090 be_node
->be_node_creation
= (time_t)zfs_prop_get_int(zhp
,
1093 /* Get all user properties used for libbe */
1094 if ((userprops
= zfs_get_user_props(zhp
)) == NULL
) {
1095 be_node
->be_policy_type
= strdup(be_default_policy());
1097 if (getzoneid() != GLOBAL_ZONEID
) {
1098 if (nvlist_lookup_nvlist(userprops
,
1099 BE_ZONE_ACTIVE_PROPERTY
, &zone_propval
) != 0 ||
1100 zone_propval
== NULL
) {
1101 be_node
->be_active_on_boot
= B_FALSE
;
1103 verify(nvlist_lookup_string(zone_propval
,
1104 ZPROP_VALUE
, &zone_prop_str
) == 0);
1105 if (strcmp(zone_prop_str
, "on") == 0) {
1106 be_node
->be_active_on_boot
= B_TRUE
;
1108 be_node
->be_active_on_boot
= B_FALSE
;
1113 if (nvlist_lookup_nvlist(userprops
, BE_POLICY_PROPERTY
,
1114 &propval
) != 0 || propval
== NULL
) {
1115 be_node
->be_policy_type
=
1116 strdup(be_default_policy());
1118 verify(nvlist_lookup_string(propval
, ZPROP_VALUE
,
1120 if (prop_str
== NULL
|| strcmp(prop_str
, "-") == 0 ||
1121 strcmp(prop_str
, "") == 0)
1122 be_node
->be_policy_type
=
1123 strdup(be_default_policy());
1125 be_node
->be_policy_type
= strdup(prop_str
);
1127 if (getzoneid() != GLOBAL_ZONEID
) {
1128 if (nvlist_lookup_nvlist(userprops
,
1129 BE_ZONE_PARENTBE_PROPERTY
, &propval
) != 0 &&
1130 nvlist_lookup_string(propval
, ZPROP_VALUE
,
1132 be_node
->be_uuid_str
= strdup(prop_str
);
1135 if (nvlist_lookup_nvlist(userprops
, BE_UUID_PROPERTY
,
1136 &propval
) == 0 && nvlist_lookup_string(propval
,
1137 ZPROP_VALUE
, &prop_str
) == 0) {
1138 be_node
->be_uuid_str
= strdup(prop_str
);
1144 * Increment the dataset counter to include the root dataset
1147 be_node
->be_node_num_datasets
++;
1149 return (BE_SUCCESS
);
1153 * Function: be_get_ds_data
1154 * Description: Helper function used by be_add_children_callback to collect
1155 * the dataset related information that will be returned by
1158 * zhp - Handle to the zfs dataset whose information we're
1160 * name - The name of the dataset we're processing.
1161 * dataset - A pointer to the be_dataset_list structure
1163 * node - The node structure that this dataset belongs to.
1165 * BE_SUCCESS - Success
1166 * be_errno_t - Failure
1172 zfs_handle_t
*zfshp
,
1174 be_dataset_list_t
*dataset
,
1175 be_node_list_t
*node
)
1177 char prop_buf
[ZFS_MAXPROPLEN
];
1178 nvlist_t
*propval
= NULL
;
1179 nvlist_t
*userprops
= NULL
;
1180 char *prop_str
= NULL
;
1183 if (zfshp
== NULL
|| name
== NULL
|| dataset
== NULL
|| node
== NULL
) {
1184 be_print_err(gettext("be_get_ds_data: invalid arguments, "
1185 "can not be NULL\n"));
1186 return (BE_ERR_INVAL
);
1191 dataset
->be_dataset_name
= strdup(name
);
1192 if ((err
= errno
) != 0) {
1193 be_print_err(gettext("be_get_ds_data: failed to copy "
1195 return (errno_to_be_err(err
));
1198 dataset
->be_ds_space_used
= zfs_prop_get_int(zfshp
, ZFS_PROP_USED
);
1201 * If the dataset is mounted use the mount point
1202 * returned from the zfs_is_mounted call. If the
1203 * dataset is not mounted then pull the mount
1204 * point information out of the zfs properties.
1206 if (!(dataset
->be_ds_mounted
= zfs_is_mounted(zfshp
,
1207 &(dataset
->be_ds_mntpt
)))) {
1208 if (zfs_prop_get(zfshp
, ZFS_PROP_MOUNTPOINT
,
1209 prop_buf
, ZFS_MAXPROPLEN
, NULL
, NULL
, 0,
1211 dataset
->be_ds_mntpt
= strdup(prop_buf
);
1213 return (zfs_err_to_be_err(g_zfs
));
1215 dataset
->be_ds_creation
=
1216 (time_t)zfs_prop_get_int(zfshp
, ZFS_PROP_CREATION
);
1219 * Get the user property used for the libbe
1222 if ((userprops
= zfs_get_user_props(zfshp
)) == NULL
) {
1223 dataset
->be_ds_plcy_type
=
1224 strdup(node
->be_policy_type
);
1226 if (nvlist_lookup_nvlist(userprops
,
1227 BE_POLICY_PROPERTY
, &propval
) != 0 ||
1229 dataset
->be_ds_plcy_type
=
1230 strdup(node
->be_policy_type
);
1232 verify(nvlist_lookup_string(propval
,
1233 ZPROP_VALUE
, &prop_str
) == 0);
1234 if (prop_str
== NULL
||
1235 strcmp(prop_str
, "-") == 0 ||
1236 strcmp(prop_str
, "") == 0)
1237 dataset
->be_ds_plcy_type
1238 = strdup(node
->be_policy_type
);
1240 dataset
->be_ds_plcy_type
= strdup(prop_str
);
1244 node
->be_node_num_datasets
++;
1245 return (BE_SUCCESS
);
1249 * Function: be_get_ss_data
1250 * Description: Helper function used by be_add_children_callback to collect
1251 * the dataset related information that will be returned by
1254 * zhp - Handle to the zfs snapshot whose information we're
1256 * name - The name of the snapshot we're processing.
1257 * shapshot - A pointer to the be_snapshot_list structure
1259 * node - The node structure that this snapshot belongs to.
1261 * BE_SUCCESS - Success
1262 * be_errno_t - Failure
1268 zfs_handle_t
*zfshp
,
1270 be_snapshot_list_t
*snapshot
,
1271 be_node_list_t
*node
)
1273 nvlist_t
*propval
= NULL
;
1274 nvlist_t
*userprops
= NULL
;
1275 char *prop_str
= NULL
;
1278 if (zfshp
== NULL
|| name
== NULL
|| snapshot
== NULL
|| node
== NULL
) {
1279 be_print_err(gettext("be_get_ss_data: invalid arguments, "
1280 "can not be NULL\n"));
1281 return (BE_ERR_INVAL
);
1286 snapshot
->be_snapshot_name
= strdup(name
);
1287 if ((err
= errno
) != 0) {
1288 be_print_err(gettext("be_get_ss_data: failed to copy name\n"));
1289 return (errno_to_be_err(err
));
1292 snapshot
->be_snapshot_creation
= (time_t)zfs_prop_get_int(zfshp
,
1296 * Try to get this snapshot's cleanup policy from its
1297 * user properties first. If not there, use default
1300 if ((userprops
= zfs_get_user_props(zfshp
)) != NULL
&&
1301 nvlist_lookup_nvlist(userprops
, BE_POLICY_PROPERTY
,
1302 &propval
) == 0 && nvlist_lookup_string(propval
,
1303 ZPROP_VALUE
, &prop_str
) == 0) {
1304 snapshot
->be_snapshot_type
=
1307 snapshot
->be_snapshot_type
=
1308 strdup(be_default_policy());
1311 snapshot
->be_snapshot_space_used
= zfs_prop_get_int(zfshp
,
1314 node
->be_node_num_snapshots
++;
1315 return (BE_SUCCESS
);
1319 * Function: be_list_alloc
1320 * Description: Helper function used to allocate memory for the various
1321 * sructures that make up a BE node.
1323 * err - Used to return any errors encountered.
1324 * BE_SUCCESS - Success
1325 * BE_ERR_NOMEM - Allocation failure
1326 * size - The size of memory to allocate.
1328 * Success - A pointer to the allocated memory
1334 be_list_alloc(int *err
, size_t size
)
1338 bep
= calloc(1, size
);
1340 be_print_err(gettext("be_list_alloc: memory "
1341 "allocation failed\n"));
1342 *err
= BE_ERR_NOMEM
;
1349 * Function: be_get_zone_node_data
1350 * Description: Helper function used to collect all the information to
1351 * fill in the be_node_list structure to be returned by
1354 * be_node - a pointer to the node structure we're filling in.
1355 * be_name - The BE name of the node whose information we're
1357 * BE_SUCCESS - Success
1358 * be_errno_t - Failure
1362 * NOTE: This function currently only collects the zone BE name but when
1363 * support for beadm/libbe in a zone is provided it will need to fill
1364 * in the rest of the information needed for a zone BE.
1367 be_get_zone_node_data(be_node_list_t
*be_node
, char *be_name
)
1369 if ((be_node
->be_node_name
= strdup(be_name
)) != NULL
)
1370 return (BE_SUCCESS
);
1371 return (BE_ERR_NOMEM
);