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>
33 #include <libnvpair.h>
39 #include <sys/types.h>
45 #include <libbe_priv.h>
48 * Callback data used for zfs_iter calls.
50 typedef struct list_callback_data
{
53 be_node_list_t
*be_nodes_head
;
54 be_node_list_t
*be_nodes
;
55 char current_be
[MAXPATHLEN
];
56 } list_callback_data_t
;
59 * Private function prototypes
61 static int be_add_children_callback(zfs_handle_t
*zhp
, void *data
);
62 static int be_get_list_callback(zpool_handle_t
*, void *);
63 static int be_get_node_data(zfs_handle_t
*, be_node_list_t
*, char *,
64 const char *, char *, char *);
65 static int be_get_zone_node_data(be_node_list_t
*, char *);
66 static int be_get_ds_data(zfs_handle_t
*, char *, be_dataset_list_t
*,
68 static int be_get_ss_data(zfs_handle_t
*, char *, be_snapshot_list_t
*,
70 static void be_sort_list(be_node_list_t
**,
71 int (*)(const void *, const void *));
72 static int be_qsort_compare_BEs_name(const void *, const void *);
73 static int be_qsort_compare_BEs_name_rev(const void *, const void *);
74 static int be_qsort_compare_BEs_date(const void *, const void *);
75 static int be_qsort_compare_BEs_date_rev(const void *, const void *);
76 static int be_qsort_compare_BEs_space(const void *, const void *);
77 static int be_qsort_compare_BEs_space_rev(const void *, const void *);
78 static int be_qsort_compare_snapshots(const void *x
, const void *y
);
79 static int be_qsort_compare_datasets(const void *x
, const void *y
);
80 static void *be_list_alloc(int *, size_t);
85 static char be_container_ds
[MAXPATHLEN
];
86 static boolean_t zone_be
= B_FALSE
;
88 /* ******************************************************************** */
89 /* Public Functions */
90 /* ******************************************************************** */
94 * Description: Calls _be_list which finds all the BEs on the system and
95 * returns the datasets and snapshots belonging to each BE.
96 * Also data, such as dataset and snapshot properties,
97 * for each BE and their snapshots and datasets is
98 * returned. The data returned is as described in the
99 * be_dataset_list_t, be_snapshot_list_t and be_node_list_t
102 * be_name - The name of the BE to look up.
103 * If NULL a list of all BEs will be returned.
104 * be_nodes - A reference pointer to the list of BEs. The list
105 * structure will be allocated by _be_list and must
106 * be freed by a call to be_free_list. If there are no
107 * BEs found on the system this reference will be
110 * BE_SUCCESS - Success
111 * be_errno_t - Failure
116 be_list(char *be_name
, be_node_list_t
**be_nodes
)
118 int ret
= BE_SUCCESS
;
120 /* Initialize libzfs handle */
122 return (BE_ERR_INIT
);
124 /* Validate be_name if its not NULL */
125 if (be_name
!= NULL
) {
126 if (!be_valid_be_name(be_name
)) {
127 be_print_err(gettext("be_list: "
128 "invalid BE name %s\n"), be_name
);
129 return (BE_ERR_INVAL
);
133 ret
= _be_list(be_name
, be_nodes
);
142 * Description: Sort BE node list
144 * pointer to address of list head
149 * node list sorted by name
154 be_sort(be_node_list_t
**be_nodes
, int order
)
156 int (*compar
)(const void *, const void *) = be_qsort_compare_BEs_date
;
158 if (be_nodes
== NULL
)
162 case BE_SORT_UNSPECIFIED
:
164 compar
= be_qsort_compare_BEs_date
;
166 case BE_SORT_DATE_REV
:
167 compar
= be_qsort_compare_BEs_date_rev
;
170 compar
= be_qsort_compare_BEs_name
;
172 case BE_SORT_NAME_REV
:
173 compar
= be_qsort_compare_BEs_name_rev
;
176 compar
= be_qsort_compare_BEs_space
;
178 case BE_SORT_SPACE_REV
:
179 compar
= be_qsort_compare_BEs_space_rev
;
182 be_print_err(gettext("be_sort: invalid sort order %d\n"),
187 be_sort_list(be_nodes
, compar
);
190 /* ******************************************************************** */
191 /* Semi-Private Functions */
192 /* ******************************************************************** */
196 * Description: This does the actual work described in be_list.
198 * be_name - The name of the BE to look up.
199 * If NULL a list of all BEs will be returned.
200 * be_nodes - A reference pointer to the list of BEs. The list
201 * structure will be allocated here and must
202 * be freed by a call to be_free_list. If there are no
203 * BEs found on the system this reference will be
206 * BE_SUCCESS - Success
207 * be_errno_t - Failure
209 * Semi-private (library wide use only)
212 _be_list(char *be_name
, be_node_list_t
**be_nodes
)
214 list_callback_data_t cb
= { 0 };
215 be_transaction_data_t bt
= { 0 };
216 int ret
= BE_SUCCESS
;
217 zpool_handle_t
*zphp
;
219 struct be_defaults be_defaults
;
221 if (be_nodes
== NULL
)
222 return (BE_ERR_INVAL
);
224 be_get_defaults(&be_defaults
);
226 if (be_find_current_be(&bt
) != BE_SUCCESS
) {
228 * We were unable to find a currently booted BE which
229 * probably means that we're not booted in a BE envoronment.
230 * None of the BE's will be marked as the active BE.
232 (void) strcpy(cb
.current_be
, "-");
234 (void) strncpy(cb
.current_be
, bt
.obe_name
,
235 sizeof (cb
.current_be
));
236 rpool
= bt
.obe_zpool
;
240 * If be_name is NULL we'll look for all BE's on the system.
241 * If not then we will only return data for the specified BE.
244 cb
.be_name
= strdup(be_name
);
246 if (be_defaults
.be_deflt_rpool_container
&& rpool
!= NULL
) {
247 if ((zphp
= zpool_open(g_zfs
, rpool
)) == NULL
) {
248 be_print_err(gettext("be_list: failed to "
249 "open rpool (%s): %s\n"), rpool
,
250 libzfs_error_description(g_zfs
));
252 return (zfs_err_to_be_err(g_zfs
));
255 ret
= be_get_list_callback(zphp
, &cb
);
257 if ((zpool_iter(g_zfs
, be_get_list_callback
, &cb
)) != 0) {
258 if (cb
.be_nodes_head
!= NULL
) {
259 be_free_list(cb
.be_nodes_head
);
260 cb
.be_nodes_head
= NULL
;
263 ret
= BE_ERR_BE_NOENT
;
267 if (cb
.be_nodes_head
== NULL
) {
269 be_print_err(gettext("be_list: BE (%s) does not "
270 "exist\n"), be_name
);
272 be_print_err(gettext("be_list: No BE's found\n"));
273 ret
= BE_ERR_BE_NOENT
;
276 *be_nodes
= cb
.be_nodes_head
;
280 be_sort(be_nodes
, BE_SORT_DATE
);
286 * Function: be_free_list
287 * Description: Frees up all the data allocated for the list of BEs,
288 * datasets and snapshots returned by be_list.
290 * be_node - be_nodes_t structure returned from call to be_list.
294 * Semi-private (library wide use only)
297 be_free_list(be_node_list_t
*be_nodes
)
299 be_node_list_t
*temp_node
= NULL
;
300 be_node_list_t
*list
= be_nodes
;
302 while (list
!= NULL
) {
303 be_dataset_list_t
*datasets
= list
->be_node_datasets
;
304 be_snapshot_list_t
*snapshots
= list
->be_node_snapshots
;
306 while (datasets
!= NULL
) {
307 be_dataset_list_t
*temp_ds
= datasets
;
308 datasets
= datasets
->be_next_dataset
;
309 free(temp_ds
->be_dataset_name
);
310 free(temp_ds
->be_ds_mntpt
);
311 free(temp_ds
->be_ds_plcy_type
);
315 while (snapshots
!= NULL
) {
316 be_snapshot_list_t
*temp_ss
= snapshots
;
317 snapshots
= snapshots
->be_next_snapshot
;
318 free(temp_ss
->be_snapshot_name
);
319 free(temp_ss
->be_snapshot_type
);
324 list
= list
->be_next_node
;
325 free(temp_node
->be_node_name
);
326 free(temp_node
->be_root_ds
);
327 free(temp_node
->be_rpool
);
328 free(temp_node
->be_mntpt
);
329 free(temp_node
->be_policy_type
);
330 free(temp_node
->be_uuid_str
);
336 * Function: be_get_zone_be_list
337 * Description: Finds all the BEs for this zone on the system.
339 * zone_be_name - The name of the BE to look up.
340 * zone_be_container_ds - The dataset for the zone.
341 * zbe_nodes - A reference pointer to the list of BEs. The list
342 * structure will be allocated here and must
343 * be freed by a call to be_free_list. If there are no
344 * BEs found on the system this reference will be
347 * BE_SUCCESS - Success
348 * be_errno_t - Failure
350 * Semi-private (library wide use only)
356 char *zone_be_container_ds
,
357 be_node_list_t
**zbe_nodes
)
359 zfs_handle_t
*zhp
= NULL
;
360 list_callback_data_t cb
= { 0 };
361 int ret
= BE_SUCCESS
;
363 if (zbe_nodes
== NULL
)
364 return (BE_ERR_INVAL
);
366 if (!zfs_dataset_exists(g_zfs
, zone_be_container_ds
,
367 ZFS_TYPE_FILESYSTEM
)) {
368 return (BE_ERR_BE_NOENT
);
373 if ((zhp
= zfs_open(g_zfs
, zone_be_container_ds
,
374 ZFS_TYPE_FILESYSTEM
)) == NULL
) {
375 be_print_err(gettext("be_get_zone_be_list: failed to open "
376 "the zone BE dataset %s: %s\n"), zone_be_container_ds
,
377 libzfs_error_description(g_zfs
));
378 ret
= zfs_err_to_be_err(g_zfs
);
382 (void) strcpy(be_container_ds
, zone_be_container_ds
);
384 if (cb
.be_nodes_head
== NULL
) {
385 if ((cb
.be_nodes_head
= be_list_alloc(&ret
,
386 sizeof (be_node_list_t
))) == NULL
) {
390 cb
.be_nodes
= cb
.be_nodes_head
;
393 ret
= zfs_iter_filesystems(zhp
, be_add_children_callback
, &cb
);
396 *zbe_nodes
= cb
.be_nodes_head
;
404 /* ******************************************************************** */
405 /* Private Functions */
406 /* ******************************************************************** */
409 * Function: be_get_list_callback
410 * Description: Callback function used by zfs_iter to look through all
411 * the pools on the system looking for BEs. If a BE name was
412 * specified only that BE's information will be collected and
415 * zlp - handle to the first zfs dataset. (provided by the
417 * data - pointer to the callback data and where we'll pass
418 * the BE information back.
421 * be_errno_t - Failure
426 be_get_list_callback(zpool_handle_t
*zlp
, void *data
)
428 list_callback_data_t
*cb
= (list_callback_data_t
*)data
;
429 char be_ds
[MAXPATHLEN
];
430 char *open_ds
= NULL
;
432 zfs_handle_t
*zhp
= NULL
;
435 cb
->zpool_name
= rpool
= (char *)zpool_get_name(zlp
);
438 * Generate string for the BE container dataset
440 be_make_container_ds(rpool
, be_container_ds
,
441 sizeof (be_container_ds
));
444 * If a BE name was specified we use it's root dataset in place of
445 * the container dataset. This is because we only want to collect
446 * the information for the specified BE.
448 if (cb
->be_name
!= NULL
) {
449 if (!be_valid_be_name(cb
->be_name
))
450 return (BE_ERR_INVAL
);
452 * Generate string for the BE root dataset
454 be_make_root_ds(rpool
, cb
->be_name
, be_ds
, sizeof (be_ds
));
457 open_ds
= be_container_ds
;
461 * Check if the dataset exists
463 if (!zfs_dataset_exists(g_zfs
, open_ds
,
464 ZFS_TYPE_FILESYSTEM
)) {
466 * The specified dataset does not exist in this pool or
467 * there are no valid BE's in this pool. Try the next zpool.
473 if ((zhp
= zfs_open(g_zfs
, open_ds
, ZFS_TYPE_FILESYSTEM
)) == NULL
) {
474 be_print_err(gettext("be_get_list_callback: failed to open "
475 "the BE dataset %s: %s\n"), open_ds
,
476 libzfs_error_description(g_zfs
));
477 ret
= zfs_err_to_be_err(g_zfs
);
483 * If a BE name was specified we iterate through the datasets
484 * and snapshots for this BE only. Otherwise we will iterate
485 * through the next level of datasets to find all the BE's
488 if (cb
->be_name
!= NULL
) {
489 if (cb
->be_nodes_head
== NULL
) {
490 if ((cb
->be_nodes_head
= be_list_alloc(&ret
,
491 sizeof (be_node_list_t
))) == NULL
) {
496 cb
->be_nodes
= cb
->be_nodes_head
;
499 if ((ret
= be_get_node_data(zhp
, cb
->be_nodes
, cb
->be_name
,
500 rpool
, cb
->current_be
, be_ds
)) != BE_SUCCESS
) {
505 ret
= zfs_iter_snapshots(zhp
, be_add_children_callback
, cb
);
509 ret
= zfs_iter_filesystems(zhp
, be_add_children_callback
, cb
);
517 * Function: be_add_children_callback
518 * Description: Callback function used by zfs_iter to look through all
519 * the datasets and snapshots for each BE and add them to
520 * the lists of information to be passed back.
522 * zhp - handle to the first zfs dataset. (provided by the
524 * data - pointer to the callback data and where we'll pass
525 * the BE information back.
528 * be_errno_t - Failure
533 be_add_children_callback(zfs_handle_t
*zhp
, void *data
)
535 list_callback_data_t
*cb
= (list_callback_data_t
*)data
;
536 char *str
= NULL
, *ds_path
= NULL
;
538 struct be_defaults be_defaults
;
540 be_get_defaults(&be_defaults
);
542 ds_path
= str
= strdup(zfs_get_name(zhp
));
545 * get past the end of the container dataset plus the trailing "/"
547 str
= str
+ (strlen(be_container_ds
) + 1);
548 if (be_defaults
.be_deflt_rpool_container
) {
549 /* just skip if invalid */
550 if (!be_valid_be_name(str
))
554 if (cb
->be_nodes_head
== NULL
) {
555 if ((cb
->be_nodes_head
= be_list_alloc(&ret
,
556 sizeof (be_node_list_t
))) == NULL
) {
560 cb
->be_nodes
= cb
->be_nodes_head
;
563 if (zfs_get_type(zhp
) == ZFS_TYPE_SNAPSHOT
&& !zone_be
) {
564 be_snapshot_list_t
*snapshots
= NULL
;
565 if (cb
->be_nodes
->be_node_snapshots
== NULL
) {
566 if ((cb
->be_nodes
->be_node_snapshots
=
567 be_list_alloc(&ret
, sizeof (be_snapshot_list_t
)))
568 == NULL
|| ret
!= BE_SUCCESS
) {
572 cb
->be_nodes
->be_node_snapshots
->be_next_snapshot
=
574 snapshots
= cb
->be_nodes
->be_node_snapshots
;
576 for (snapshots
= cb
->be_nodes
->be_node_snapshots
;
578 snapshots
= snapshots
->be_next_snapshot
) {
579 if (snapshots
->be_next_snapshot
!= NULL
)
582 * We're at the end of the list add the
585 if ((snapshots
->be_next_snapshot
=
587 sizeof (be_snapshot_list_t
))) == NULL
||
592 snapshots
= snapshots
->be_next_snapshot
;
593 snapshots
->be_next_snapshot
= NULL
;
597 if ((ret
= be_get_ss_data(zhp
, str
, snapshots
,
598 cb
->be_nodes
)) != BE_SUCCESS
) {
602 } else if (strchr(str
, '/') == NULL
) {
603 if (cb
->be_nodes
->be_node_name
!= NULL
) {
604 if ((cb
->be_nodes
->be_next_node
=
605 be_list_alloc(&ret
, sizeof (be_node_list_t
))) ==
606 NULL
|| ret
!= BE_SUCCESS
) {
610 cb
->be_nodes
= cb
->be_nodes
->be_next_node
;
611 cb
->be_nodes
->be_next_node
= NULL
;
615 * If this is a zone root dataset then we only need
616 * the name of the zone BE at this point. We grab that
620 ret
= be_get_zone_node_data(cb
->be_nodes
, str
);
625 if ((ret
= be_get_node_data(zhp
, cb
->be_nodes
, str
,
626 cb
->zpool_name
, cb
->current_be
, ds_path
)) != BE_SUCCESS
) {
630 } else if (strchr(str
, '/') != NULL
&& !zone_be
) {
631 be_dataset_list_t
*datasets
= NULL
;
632 if (cb
->be_nodes
->be_node_datasets
== NULL
) {
633 if ((cb
->be_nodes
->be_node_datasets
=
634 be_list_alloc(&ret
, sizeof (be_dataset_list_t
)))
635 == NULL
|| ret
!= BE_SUCCESS
) {
639 cb
->be_nodes
->be_node_datasets
->be_next_dataset
= NULL
;
640 datasets
= cb
->be_nodes
->be_node_datasets
;
642 for (datasets
= cb
->be_nodes
->be_node_datasets
;
644 datasets
= datasets
->be_next_dataset
) {
645 if (datasets
->be_next_dataset
!= NULL
)
648 * We're at the end of the list add
651 if ((datasets
->be_next_dataset
=
653 sizeof (be_dataset_list_t
)))
654 == NULL
|| ret
!= BE_SUCCESS
) {
658 datasets
= datasets
->be_next_dataset
;
659 datasets
->be_next_dataset
= NULL
;
664 if ((ret
= be_get_ds_data(zhp
, str
,
665 datasets
, cb
->be_nodes
)) != BE_SUCCESS
) {
670 ret
= zfs_iter_children(zhp
, be_add_children_callback
, cb
);
672 be_print_err(gettext("be_add_children_callback: "
673 "encountered error: %s\n"),
674 libzfs_error_description(g_zfs
));
675 ret
= zfs_err_to_be_err(g_zfs
);
682 * Function: be_sort_list
683 * Description: Sort BE node list
685 * pointer to address of list head
690 * node list sorted by name
695 be_sort_list(be_node_list_t
**pstart
, int (*compar
)(const void *, const void *))
698 be_node_list_t
*p
= NULL
;
699 be_node_list_t
**ptrlist
= NULL
;
703 /* build array of linked list BE struct pointers */
704 for (p
= *pstart
, nbe
= 0; p
!= NULL
; nbe
++, p
= p
->be_next_node
) {
705 ptrlist
= realloc(ptrlist
,
706 sizeof (be_node_list_t
*) * (nbe
+ 2));
711 /* in-place list quicksort using qsort(3C) */
712 if (nbe
> 1) /* no sort if less than 2 BEs */
713 qsort(ptrlist
, nbe
, sizeof (be_node_list_t
*), compar
);
715 ptrlist
[nbe
] = NULL
; /* add linked list terminator */
716 *pstart
= ptrlist
[0]; /* set new linked list header */
717 /* for each BE in list */
718 for (ibe
= 0; ibe
< nbe
; ibe
++) {
719 size_t k
, ns
; /* subordinate index, count */
721 /* rewrite list pointer chain, including terminator */
722 ptrlist
[ibe
]->be_next_node
= ptrlist
[ibe
+ 1];
723 /* sort subordinate snapshots */
724 if (ptrlist
[ibe
]->be_node_num_snapshots
> 1) {
725 const size_t nmax
= ptrlist
[ibe
]->be_node_num_snapshots
;
726 be_snapshot_list_t
** const slist
=
727 malloc(sizeof (be_snapshot_list_t
*) * (nmax
+ 1));
728 be_snapshot_list_t
*p
;
732 /* build array of linked list snapshot struct ptrs */
733 for (ns
= 0, p
= ptrlist
[ibe
]->be_node_snapshots
;
734 ns
< nmax
&& p
!= NULL
;
735 ns
++, p
= p
->be_next_snapshot
) {
740 slist
[ns
] = NULL
; /* add terminator */
741 /* in-place list quicksort using qsort(3C) */
742 qsort(slist
, ns
, sizeof (be_snapshot_list_t
*),
743 be_qsort_compare_snapshots
);
744 /* rewrite list pointer chain, including terminator */
745 ptrlist
[ibe
]->be_node_snapshots
= slist
[0];
746 for (k
= 0; k
< ns
; k
++)
747 slist
[k
]->be_next_snapshot
= slist
[k
+ 1];
751 /* sort subordinate datasets */
752 if (ptrlist
[ibe
]->be_node_num_datasets
> 1) {
753 const size_t nmax
= ptrlist
[ibe
]->be_node_num_datasets
;
754 be_dataset_list_t
** const slist
=
755 malloc(sizeof (be_dataset_list_t
*) * (nmax
+ 1));
756 be_dataset_list_t
*p
;
760 /* build array of linked list dataset struct ptrs */
761 for (ns
= 0, p
= ptrlist
[ibe
]->be_node_datasets
;
762 ns
< nmax
&& p
!= NULL
;
763 ns
++, p
= p
->be_next_dataset
) {
766 if (ns
< 2) /* subordinate datasets < 2 - no sort */
768 slist
[ns
] = NULL
; /* add terminator */
769 /* in-place list quicksort using qsort(3C) */
770 qsort(slist
, ns
, sizeof (be_dataset_list_t
*),
771 be_qsort_compare_datasets
);
772 /* rewrite list pointer chain, including terminator */
773 ptrlist
[ibe
]->be_node_datasets
= slist
[0];
774 for (k
= 0; k
< ns
; k
++)
775 slist
[k
]->be_next_dataset
= slist
[k
+ 1];
785 * Function: be_qsort_compare_BEs_date
786 * Description: compare BE creation times for qsort(3C)
787 * will sort BE list from oldest to most recent
789 * x,y - BEs with names to compare
791 * positive if x>y, negative if y>x, 0 if equal
796 be_qsort_compare_BEs_date(const void *x
, const void *y
)
798 be_node_list_t
*p
= *(be_node_list_t
**)x
;
799 be_node_list_t
*q
= *(be_node_list_t
**)y
;
804 if (p
->be_node_creation
> q
->be_node_creation
)
806 if (p
->be_node_creation
< q
->be_node_creation
)
812 * Function: be_qsort_compare_BEs_date_rev
813 * Description: compare BE creation times for qsort(3C)
814 * will sort BE list from recent to oldest
816 * x,y - BEs with names to compare
818 * positive if y>x, negative if x>y, 0 if equal
823 be_qsort_compare_BEs_date_rev(const void *x
, const void *y
)
825 return (be_qsort_compare_BEs_date(y
, x
));
829 * Function: be_qsort_compare_BEs_name
830 * Description: lexical compare of BE names for qsort(3C)
832 * x,y - BEs with names to compare
834 * positive if x>y, negative if y>x, 0 if equal
839 be_qsort_compare_BEs_name(const void *x
, const void *y
)
841 be_node_list_t
*p
= *(be_node_list_t
**)x
;
842 be_node_list_t
*q
= *(be_node_list_t
**)y
;
845 assert(p
->be_node_name
!= NULL
);
847 assert(q
->be_node_name
!= NULL
);
849 return (strcmp(p
->be_node_name
, q
->be_node_name
));
853 * Function: be_qsort_compare_BEs_name_rev
854 * Description: reverse lexical compare of BE names for qsort(3C)
856 * x,y - BEs with names to compare
858 * positive if y>x, negative if x>y, 0 if equal
863 be_qsort_compare_BEs_name_rev(const void *x
, const void *y
)
865 return (be_qsort_compare_BEs_name(y
, x
));
869 * Function: be_qsort_compare_BEs_space
870 * Description: compare BE sizes for qsort(3C)
871 * will sort BE list in growing order
873 * x,y - BEs with names to compare
875 * positive if x>y, negative if y>x, 0 if equal
880 be_qsort_compare_BEs_space(const void *x
, const void *y
)
882 be_node_list_t
*p
= *(be_node_list_t
**)x
;
883 be_node_list_t
*q
= *(be_node_list_t
**)y
;
888 if (p
->be_space_used
> q
->be_space_used
)
890 if (p
->be_space_used
< q
->be_space_used
)
896 * Function: be_qsort_compare_BEs_space_rev
897 * Description: compare BE sizes for qsort(3C)
898 * will sort BE list in shrinking
900 * x,y - BEs with names to compare
902 * positive if y>x, negative if x>y, 0 if equal
907 be_qsort_compare_BEs_space_rev(const void *x
, const void *y
)
909 return (be_qsort_compare_BEs_space(y
, x
));
913 * Function: be_qsort_compare_snapshots
914 * Description: lexical compare of BE names for qsort(3C)
916 * x,y - BE snapshots with names to compare
918 * positive if y>x, negative if x>y, 0 if equal
923 be_qsort_compare_snapshots(const void *x
, const void *y
)
925 be_snapshot_list_t
*p
= *(be_snapshot_list_t
**)x
;
926 be_snapshot_list_t
*q
= *(be_snapshot_list_t
**)y
;
928 if (p
== NULL
|| p
->be_snapshot_name
== NULL
)
930 if (q
== NULL
|| q
->be_snapshot_name
== NULL
)
932 return (strcmp(p
->be_snapshot_name
, q
->be_snapshot_name
));
936 * Function: be_qsort_compare_datasets
937 * Description: lexical compare of dataset names for qsort(3C)
939 * x,y - BE snapshots with names to compare
941 * positive if y>x, negative if x>y, 0 if equal
946 be_qsort_compare_datasets(const void *x
, const void *y
)
948 be_dataset_list_t
*p
= *(be_dataset_list_t
**)x
;
949 be_dataset_list_t
*q
= *(be_dataset_list_t
**)y
;
951 if (p
== NULL
|| p
->be_dataset_name
== NULL
)
953 if (q
== NULL
|| q
->be_dataset_name
== NULL
)
955 return (strcmp(p
->be_dataset_name
, q
->be_dataset_name
));
959 * Function: be_get_node_data
960 * Description: Helper function used to collect all the information to fill
961 * in the be_node_list structure to be returned by be_list.
963 * zhp - Handle to the root dataset for the BE whose information
965 * be_node - a pointer to the node structure we're filling in.
966 * be_name - The BE name of the node whose information we're
968 * current_be - the name of the currently active BE.
969 * be_ds - The dataset name for the BE.
972 * BE_SUCCESS - Success
973 * be_errno_t - Failure
980 be_node_list_t
*be_node
,
986 char prop_buf
[MAXPATHLEN
];
987 nvlist_t
*userprops
= NULL
;
988 nvlist_t
*propval
= NULL
;
989 nvlist_t
*zone_propval
= NULL
;
990 char *prop_str
= NULL
;
991 char *zone_prop_str
= NULL
;
992 char *grub_default_bootfs
= NULL
;
993 zpool_handle_t
*zphp
= NULL
;
996 if (be_node
== NULL
|| be_name
== NULL
|| current_be
== NULL
||
998 be_print_err(gettext("be_get_node_data: invalid arguments, "
999 "can not be NULL\n"));
1000 return (BE_ERR_INVAL
);
1005 be_node
->be_root_ds
= strdup(be_ds
);
1006 if ((err
= errno
) != 0 || be_node
->be_root_ds
== NULL
) {
1007 be_print_err(gettext("be_get_node_data: failed to "
1008 "copy root dataset name\n"));
1009 return (errno_to_be_err(err
));
1012 be_node
->be_node_name
= strdup(be_name
);
1013 if ((err
= errno
) != 0 || be_node
->be_node_name
== NULL
) {
1014 be_print_err(gettext("be_get_node_data: failed to "
1016 return (errno_to_be_err(err
));
1018 if (strncmp(be_name
, current_be
, MAXPATHLEN
) == 0)
1019 be_node
->be_active
= B_TRUE
;
1021 be_node
->be_active
= B_FALSE
;
1023 be_node
->be_rpool
= strdup(rpool
);
1024 if (be_node
->be_rpool
== NULL
|| (err
= errno
) != 0) {
1025 be_print_err(gettext("be_get_node_data: failed to "
1026 "copy root pool name\n"));
1027 return (errno_to_be_err(err
));
1030 be_node
->be_space_used
= zfs_prop_get_int(zhp
, ZFS_PROP_USED
);
1032 if (getzoneid() == GLOBAL_ZONEID
) {
1033 if ((zphp
= zpool_open(g_zfs
, rpool
)) == NULL
) {
1034 be_print_err(gettext("be_get_node_data: failed to open "
1035 "pool (%s): %s\n"), rpool
,
1036 libzfs_error_description(g_zfs
));
1037 return (zfs_err_to_be_err(g_zfs
));
1040 (void) zpool_get_prop(zphp
, ZPOOL_PROP_BOOTFS
, prop_buf
,
1041 ZFS_MAXPROPLEN
, NULL
, B_FALSE
);
1042 if (be_has_grub() && (be_default_grub_bootfs(rpool
,
1043 &grub_default_bootfs
) == BE_SUCCESS
) &&
1044 grub_default_bootfs
!= NULL
)
1045 if (strcmp(grub_default_bootfs
, be_ds
) == 0)
1046 be_node
->be_active_on_boot
= B_TRUE
;
1048 be_node
->be_active_on_boot
= B_FALSE
;
1049 else if (prop_buf
!= NULL
&& strcmp(prop_buf
, be_ds
) == 0)
1050 be_node
->be_active_on_boot
= B_TRUE
;
1052 be_node
->be_active_on_boot
= B_FALSE
;
1054 be_node
->be_global_active
= B_TRUE
;
1056 free(grub_default_bootfs
);
1059 if (be_zone_compare_uuids(be_node
->be_root_ds
))
1060 be_node
->be_global_active
= B_TRUE
;
1062 be_node
->be_global_active
= B_FALSE
;
1066 * If the dataset is mounted use the mount point
1067 * returned from the zfs_is_mounted call. If the
1068 * dataset is not mounted then pull the mount
1069 * point information out of the zfs properties.
1071 be_node
->be_mounted
= zfs_is_mounted(zhp
,
1072 &(be_node
->be_mntpt
));
1073 if (!be_node
->be_mounted
) {
1074 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, prop_buf
,
1075 ZFS_MAXPROPLEN
, NULL
, NULL
, 0, B_FALSE
) == 0)
1076 be_node
->be_mntpt
= strdup(prop_buf
);
1078 return (zfs_err_to_be_err(g_zfs
));
1081 be_node
->be_node_creation
= (time_t)zfs_prop_get_int(zhp
,
1084 /* Get all user properties used for libbe */
1085 if ((userprops
= zfs_get_user_props(zhp
)) == NULL
) {
1086 be_node
->be_policy_type
= strdup(be_default_policy());
1088 if (getzoneid() != GLOBAL_ZONEID
) {
1089 if (nvlist_lookup_nvlist(userprops
,
1090 BE_ZONE_ACTIVE_PROPERTY
, &zone_propval
) != 0 ||
1091 zone_propval
== NULL
) {
1092 be_node
->be_active_on_boot
= B_FALSE
;
1094 verify(nvlist_lookup_string(zone_propval
,
1095 ZPROP_VALUE
, &zone_prop_str
) == 0);
1096 if (strcmp(zone_prop_str
, "on") == 0) {
1097 be_node
->be_active_on_boot
= B_TRUE
;
1099 be_node
->be_active_on_boot
= B_FALSE
;
1104 if (nvlist_lookup_nvlist(userprops
, BE_POLICY_PROPERTY
,
1105 &propval
) != 0 || propval
== NULL
) {
1106 be_node
->be_policy_type
=
1107 strdup(be_default_policy());
1109 verify(nvlist_lookup_string(propval
, ZPROP_VALUE
,
1111 if (prop_str
== NULL
|| strcmp(prop_str
, "-") == 0 ||
1112 strcmp(prop_str
, "") == 0)
1113 be_node
->be_policy_type
=
1114 strdup(be_default_policy());
1116 be_node
->be_policy_type
= strdup(prop_str
);
1118 if (getzoneid() != GLOBAL_ZONEID
) {
1119 if (nvlist_lookup_nvlist(userprops
,
1120 BE_ZONE_PARENTBE_PROPERTY
, &propval
) != 0 &&
1121 nvlist_lookup_string(propval
, ZPROP_VALUE
,
1123 be_node
->be_uuid_str
= strdup(prop_str
);
1126 if (nvlist_lookup_nvlist(userprops
, BE_UUID_PROPERTY
,
1127 &propval
) == 0 && nvlist_lookup_string(propval
,
1128 ZPROP_VALUE
, &prop_str
) == 0) {
1129 be_node
->be_uuid_str
= strdup(prop_str
);
1135 * Increment the dataset counter to include the root dataset
1138 be_node
->be_node_num_datasets
++;
1140 return (BE_SUCCESS
);
1144 * Function: be_get_ds_data
1145 * Description: Helper function used by be_add_children_callback to collect
1146 * the dataset related information that will be returned by
1149 * zhp - Handle to the zfs dataset whose information we're
1151 * name - The name of the dataset we're processing.
1152 * dataset - A pointer to the be_dataset_list structure
1154 * node - The node structure that this dataset belongs to.
1156 * BE_SUCCESS - Success
1157 * be_errno_t - Failure
1163 zfs_handle_t
*zfshp
,
1165 be_dataset_list_t
*dataset
,
1166 be_node_list_t
*node
)
1168 char prop_buf
[ZFS_MAXPROPLEN
];
1169 nvlist_t
*propval
= NULL
;
1170 nvlist_t
*userprops
= NULL
;
1171 char *prop_str
= NULL
;
1174 if (zfshp
== NULL
|| name
== NULL
|| dataset
== NULL
|| node
== NULL
) {
1175 be_print_err(gettext("be_get_ds_data: invalid arguments, "
1176 "can not be NULL\n"));
1177 return (BE_ERR_INVAL
);
1182 dataset
->be_dataset_name
= strdup(name
);
1183 if ((err
= errno
) != 0) {
1184 be_print_err(gettext("be_get_ds_data: failed to copy "
1186 return (errno_to_be_err(err
));
1189 dataset
->be_ds_space_used
= zfs_prop_get_int(zfshp
, ZFS_PROP_USED
);
1192 * If the dataset is mounted use the mount point
1193 * returned from the zfs_is_mounted call. If the
1194 * dataset is not mounted then pull the mount
1195 * point information out of the zfs properties.
1197 if (!(dataset
->be_ds_mounted
= zfs_is_mounted(zfshp
,
1198 &(dataset
->be_ds_mntpt
)))) {
1199 if (zfs_prop_get(zfshp
, ZFS_PROP_MOUNTPOINT
,
1200 prop_buf
, ZFS_MAXPROPLEN
, NULL
, NULL
, 0,
1202 dataset
->be_ds_mntpt
= strdup(prop_buf
);
1204 return (zfs_err_to_be_err(g_zfs
));
1206 dataset
->be_ds_creation
=
1207 (time_t)zfs_prop_get_int(zfshp
, ZFS_PROP_CREATION
);
1210 * Get the user property used for the libbe
1213 if ((userprops
= zfs_get_user_props(zfshp
)) == NULL
) {
1214 dataset
->be_ds_plcy_type
=
1215 strdup(node
->be_policy_type
);
1217 if (nvlist_lookup_nvlist(userprops
,
1218 BE_POLICY_PROPERTY
, &propval
) != 0 ||
1220 dataset
->be_ds_plcy_type
=
1221 strdup(node
->be_policy_type
);
1223 verify(nvlist_lookup_string(propval
,
1224 ZPROP_VALUE
, &prop_str
) == 0);
1225 if (prop_str
== NULL
||
1226 strcmp(prop_str
, "-") == 0 ||
1227 strcmp(prop_str
, "") == 0)
1228 dataset
->be_ds_plcy_type
1229 = strdup(node
->be_policy_type
);
1231 dataset
->be_ds_plcy_type
= strdup(prop_str
);
1235 node
->be_node_num_datasets
++;
1236 return (BE_SUCCESS
);
1240 * Function: be_get_ss_data
1241 * Description: Helper function used by be_add_children_callback to collect
1242 * the dataset related information that will be returned by
1245 * zhp - Handle to the zfs snapshot whose information we're
1247 * name - The name of the snapshot we're processing.
1248 * shapshot - A pointer to the be_snapshot_list structure
1250 * node - The node structure that this snapshot belongs to.
1252 * BE_SUCCESS - Success
1253 * be_errno_t - Failure
1259 zfs_handle_t
*zfshp
,
1261 be_snapshot_list_t
*snapshot
,
1262 be_node_list_t
*node
)
1264 nvlist_t
*propval
= NULL
;
1265 nvlist_t
*userprops
= NULL
;
1266 char *prop_str
= NULL
;
1269 if (zfshp
== NULL
|| name
== NULL
|| snapshot
== NULL
|| node
== NULL
) {
1270 be_print_err(gettext("be_get_ss_data: invalid arguments, "
1271 "can not be NULL\n"));
1272 return (BE_ERR_INVAL
);
1277 snapshot
->be_snapshot_name
= strdup(name
);
1278 if ((err
= errno
) != 0) {
1279 be_print_err(gettext("be_get_ss_data: failed to copy name\n"));
1280 return (errno_to_be_err(err
));
1283 snapshot
->be_snapshot_creation
= (time_t)zfs_prop_get_int(zfshp
,
1287 * Try to get this snapshot's cleanup policy from its
1288 * user properties first. If not there, use default
1291 if ((userprops
= zfs_get_user_props(zfshp
)) != NULL
&&
1292 nvlist_lookup_nvlist(userprops
, BE_POLICY_PROPERTY
,
1293 &propval
) == 0 && nvlist_lookup_string(propval
,
1294 ZPROP_VALUE
, &prop_str
) == 0) {
1295 snapshot
->be_snapshot_type
=
1298 snapshot
->be_snapshot_type
=
1299 strdup(be_default_policy());
1302 snapshot
->be_snapshot_space_used
= zfs_prop_get_int(zfshp
,
1305 node
->be_node_num_snapshots
++;
1306 return (BE_SUCCESS
);
1310 * Function: be_list_alloc
1311 * Description: Helper function used to allocate memory for the various
1312 * sructures that make up a BE node.
1314 * err - Used to return any errors encountered.
1315 * BE_SUCCESS - Success
1316 * BE_ERR_NOMEM - Allocation failure
1317 * size - The size of memory to allocate.
1319 * Success - A pointer to the allocated memory
1325 be_list_alloc(int *err
, size_t size
)
1329 bep
= calloc(1, size
);
1331 be_print_err(gettext("be_list_alloc: memory "
1332 "allocation failed\n"));
1333 *err
= BE_ERR_NOMEM
;
1340 * Function: be_get_zone_node_data
1341 * Description: Helper function used to collect all the information to
1342 * fill in the be_node_list structure to be returned by
1345 * be_node - a pointer to the node structure we're filling in.
1346 * be_name - The BE name of the node whose information we're
1348 * BE_SUCCESS - Success
1349 * be_errno_t - Failure
1353 * NOTE: This function currently only collects the zone BE name but when
1354 * support for beadm/libbe in a zone is provided it will need to fill
1355 * in the rest of the information needed for a zone BE.
1358 be_get_zone_node_data(be_node_list_t
*be_node
, char *be_name
)
1360 if ((be_node
->be_node_name
= strdup(be_name
)) != NULL
)
1361 return (BE_SUCCESS
);
1362 return (BE_ERR_NOMEM
);