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
= realloc(ptrlist
,
712 sizeof (be_node_list_t
*) * (nbe
+ 2));
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 char *grub_default_bootfs
= NULL
;
1011 zpool_handle_t
*zphp
= NULL
;
1014 if (be_node
== NULL
|| be_name
== NULL
|| current_be
== NULL
||
1016 be_print_err(gettext("be_get_node_data: invalid arguments, "
1017 "can not be NULL\n"));
1018 return (BE_ERR_INVAL
);
1023 be_node
->be_root_ds
= strdup(be_ds
);
1024 if ((err
= errno
) != 0 || be_node
->be_root_ds
== NULL
) {
1025 be_print_err(gettext("be_get_node_data: failed to "
1026 "copy root dataset name\n"));
1027 return (errno_to_be_err(err
));
1030 be_node
->be_node_name
= strdup(be_name
);
1031 if ((err
= errno
) != 0 || be_node
->be_node_name
== NULL
) {
1032 be_print_err(gettext("be_get_node_data: failed to "
1034 return (errno_to_be_err(err
));
1036 if (strncmp(be_name
, current_be
, MAXPATHLEN
) == 0)
1037 be_node
->be_active
= B_TRUE
;
1039 be_node
->be_active
= B_FALSE
;
1041 be_node
->be_rpool
= strdup(rpool
);
1042 if (be_node
->be_rpool
== NULL
|| (err
= errno
) != 0) {
1043 be_print_err(gettext("be_get_node_data: failed to "
1044 "copy root pool name\n"));
1045 return (errno_to_be_err(err
));
1048 be_node
->be_space_used
= zfs_prop_get_int(zhp
, ZFS_PROP_USED
);
1050 if (getzoneid() == GLOBAL_ZONEID
) {
1051 if ((zphp
= zpool_open(g_zfs
, rpool
)) == NULL
) {
1052 be_print_err(gettext("be_get_node_data: failed to open "
1053 "pool (%s): %s\n"), rpool
,
1054 libzfs_error_description(g_zfs
));
1055 return (zfs_err_to_be_err(g_zfs
));
1058 (void) zpool_get_prop(zphp
, ZPOOL_PROP_BOOTFS
, prop_buf
,
1059 ZFS_MAXPROPLEN
, NULL
, B_FALSE
);
1060 if (be_has_grub() && (be_default_grub_bootfs(rpool
,
1061 &grub_default_bootfs
) == BE_SUCCESS
) &&
1062 grub_default_bootfs
!= NULL
)
1063 if (strcmp(grub_default_bootfs
, be_ds
) == 0)
1064 be_node
->be_active_on_boot
= B_TRUE
;
1066 be_node
->be_active_on_boot
= B_FALSE
;
1067 else if (strcmp(prop_buf
, be_ds
) == 0)
1068 be_node
->be_active_on_boot
= B_TRUE
;
1070 be_node
->be_active_on_boot
= B_FALSE
;
1072 be_node
->be_global_active
= B_TRUE
;
1074 free(grub_default_bootfs
);
1077 if (be_zone_compare_uuids(be_node
->be_root_ds
))
1078 be_node
->be_global_active
= B_TRUE
;
1080 be_node
->be_global_active
= B_FALSE
;
1084 * If the dataset is mounted use the mount point
1085 * returned from the zfs_is_mounted call. If the
1086 * dataset is not mounted then pull the mount
1087 * point information out of the zfs properties.
1089 be_node
->be_mounted
= zfs_is_mounted(zhp
,
1090 &(be_node
->be_mntpt
));
1091 if (!be_node
->be_mounted
) {
1092 if (zfs_prop_get(zhp
, ZFS_PROP_MOUNTPOINT
, prop_buf
,
1093 ZFS_MAXPROPLEN
, NULL
, NULL
, 0, B_FALSE
) == 0)
1094 be_node
->be_mntpt
= strdup(prop_buf
);
1096 return (zfs_err_to_be_err(g_zfs
));
1099 be_node
->be_node_creation
= (time_t)zfs_prop_get_int(zhp
,
1102 /* Get all user properties used for libbe */
1103 if ((userprops
= zfs_get_user_props(zhp
)) == NULL
) {
1104 be_node
->be_policy_type
= strdup(be_default_policy());
1106 if (getzoneid() != GLOBAL_ZONEID
) {
1107 if (nvlist_lookup_nvlist(userprops
,
1108 BE_ZONE_ACTIVE_PROPERTY
, &zone_propval
) != 0 ||
1109 zone_propval
== NULL
) {
1110 be_node
->be_active_on_boot
= B_FALSE
;
1112 verify(nvlist_lookup_string(zone_propval
,
1113 ZPROP_VALUE
, &zone_prop_str
) == 0);
1114 if (strcmp(zone_prop_str
, "on") == 0) {
1115 be_node
->be_active_on_boot
= B_TRUE
;
1117 be_node
->be_active_on_boot
= B_FALSE
;
1122 if (nvlist_lookup_nvlist(userprops
, BE_POLICY_PROPERTY
,
1123 &propval
) != 0 || propval
== NULL
) {
1124 be_node
->be_policy_type
=
1125 strdup(be_default_policy());
1127 verify(nvlist_lookup_string(propval
, ZPROP_VALUE
,
1129 if (prop_str
== NULL
|| strcmp(prop_str
, "-") == 0 ||
1130 strcmp(prop_str
, "") == 0)
1131 be_node
->be_policy_type
=
1132 strdup(be_default_policy());
1134 be_node
->be_policy_type
= strdup(prop_str
);
1136 if (getzoneid() != GLOBAL_ZONEID
) {
1137 if (nvlist_lookup_nvlist(userprops
,
1138 BE_ZONE_PARENTBE_PROPERTY
, &propval
) != 0 &&
1139 nvlist_lookup_string(propval
, ZPROP_VALUE
,
1141 be_node
->be_uuid_str
= strdup(prop_str
);
1144 if (nvlist_lookup_nvlist(userprops
, BE_UUID_PROPERTY
,
1145 &propval
) == 0 && nvlist_lookup_string(propval
,
1146 ZPROP_VALUE
, &prop_str
) == 0) {
1147 be_node
->be_uuid_str
= strdup(prop_str
);
1153 * Increment the dataset counter to include the root dataset
1156 be_node
->be_node_num_datasets
++;
1158 return (BE_SUCCESS
);
1162 * Function: be_get_ds_data
1163 * Description: Helper function used by be_add_children_callback to collect
1164 * the dataset related information that will be returned by
1167 * zhp - Handle to the zfs dataset whose information we're
1169 * name - The name of the dataset we're processing.
1170 * dataset - A pointer to the be_dataset_list structure
1172 * node - The node structure that this dataset belongs to.
1174 * BE_SUCCESS - Success
1175 * be_errno_t - Failure
1181 zfs_handle_t
*zfshp
,
1183 be_dataset_list_t
*dataset
,
1184 be_node_list_t
*node
)
1186 char prop_buf
[ZFS_MAXPROPLEN
];
1187 nvlist_t
*propval
= NULL
;
1188 nvlist_t
*userprops
= NULL
;
1189 char *prop_str
= NULL
;
1192 if (zfshp
== NULL
|| name
== NULL
|| dataset
== NULL
|| node
== NULL
) {
1193 be_print_err(gettext("be_get_ds_data: invalid arguments, "
1194 "can not be NULL\n"));
1195 return (BE_ERR_INVAL
);
1200 dataset
->be_dataset_name
= strdup(name
);
1201 if ((err
= errno
) != 0) {
1202 be_print_err(gettext("be_get_ds_data: failed to copy "
1204 return (errno_to_be_err(err
));
1207 dataset
->be_ds_space_used
= zfs_prop_get_int(zfshp
, ZFS_PROP_USED
);
1210 * If the dataset is mounted use the mount point
1211 * returned from the zfs_is_mounted call. If the
1212 * dataset is not mounted then pull the mount
1213 * point information out of the zfs properties.
1215 if (!(dataset
->be_ds_mounted
= zfs_is_mounted(zfshp
,
1216 &(dataset
->be_ds_mntpt
)))) {
1217 if (zfs_prop_get(zfshp
, ZFS_PROP_MOUNTPOINT
,
1218 prop_buf
, ZFS_MAXPROPLEN
, NULL
, NULL
, 0,
1220 dataset
->be_ds_mntpt
= strdup(prop_buf
);
1222 return (zfs_err_to_be_err(g_zfs
));
1224 dataset
->be_ds_creation
=
1225 (time_t)zfs_prop_get_int(zfshp
, ZFS_PROP_CREATION
);
1228 * Get the user property used for the libbe
1231 if ((userprops
= zfs_get_user_props(zfshp
)) == NULL
) {
1232 dataset
->be_ds_plcy_type
=
1233 strdup(node
->be_policy_type
);
1235 if (nvlist_lookup_nvlist(userprops
,
1236 BE_POLICY_PROPERTY
, &propval
) != 0 ||
1238 dataset
->be_ds_plcy_type
=
1239 strdup(node
->be_policy_type
);
1241 verify(nvlist_lookup_string(propval
,
1242 ZPROP_VALUE
, &prop_str
) == 0);
1243 if (prop_str
== NULL
||
1244 strcmp(prop_str
, "-") == 0 ||
1245 strcmp(prop_str
, "") == 0)
1246 dataset
->be_ds_plcy_type
1247 = strdup(node
->be_policy_type
);
1249 dataset
->be_ds_plcy_type
= strdup(prop_str
);
1253 node
->be_node_num_datasets
++;
1254 return (BE_SUCCESS
);
1258 * Function: be_get_ss_data
1259 * Description: Helper function used by be_add_children_callback to collect
1260 * the dataset related information that will be returned by
1263 * zhp - Handle to the zfs snapshot whose information we're
1265 * name - The name of the snapshot we're processing.
1266 * shapshot - A pointer to the be_snapshot_list structure
1268 * node - The node structure that this snapshot belongs to.
1270 * BE_SUCCESS - Success
1271 * be_errno_t - Failure
1277 zfs_handle_t
*zfshp
,
1279 be_snapshot_list_t
*snapshot
,
1280 be_node_list_t
*node
)
1282 nvlist_t
*propval
= NULL
;
1283 nvlist_t
*userprops
= NULL
;
1284 char *prop_str
= NULL
;
1287 if (zfshp
== NULL
|| name
== NULL
|| snapshot
== NULL
|| node
== NULL
) {
1288 be_print_err(gettext("be_get_ss_data: invalid arguments, "
1289 "can not be NULL\n"));
1290 return (BE_ERR_INVAL
);
1295 snapshot
->be_snapshot_name
= strdup(name
);
1296 if ((err
= errno
) != 0) {
1297 be_print_err(gettext("be_get_ss_data: failed to copy name\n"));
1298 return (errno_to_be_err(err
));
1301 snapshot
->be_snapshot_creation
= (time_t)zfs_prop_get_int(zfshp
,
1305 * Try to get this snapshot's cleanup policy from its
1306 * user properties first. If not there, use default
1309 if ((userprops
= zfs_get_user_props(zfshp
)) != NULL
&&
1310 nvlist_lookup_nvlist(userprops
, BE_POLICY_PROPERTY
,
1311 &propval
) == 0 && nvlist_lookup_string(propval
,
1312 ZPROP_VALUE
, &prop_str
) == 0) {
1313 snapshot
->be_snapshot_type
=
1316 snapshot
->be_snapshot_type
=
1317 strdup(be_default_policy());
1320 snapshot
->be_snapshot_space_used
= zfs_prop_get_int(zfshp
,
1323 node
->be_node_num_snapshots
++;
1324 return (BE_SUCCESS
);
1328 * Function: be_list_alloc
1329 * Description: Helper function used to allocate memory for the various
1330 * sructures that make up a BE node.
1332 * err - Used to return any errors encountered.
1333 * BE_SUCCESS - Success
1334 * BE_ERR_NOMEM - Allocation failure
1335 * size - The size of memory to allocate.
1337 * Success - A pointer to the allocated memory
1343 be_list_alloc(int *err
, size_t size
)
1347 bep
= calloc(1, size
);
1349 be_print_err(gettext("be_list_alloc: memory "
1350 "allocation failed\n"));
1351 *err
= BE_ERR_NOMEM
;
1358 * Function: be_get_zone_node_data
1359 * Description: Helper function used to collect all the information to
1360 * fill in the be_node_list structure to be returned by
1363 * be_node - a pointer to the node structure we're filling in.
1364 * be_name - The BE name of the node whose information we're
1366 * BE_SUCCESS - Success
1367 * be_errno_t - Failure
1371 * NOTE: This function currently only collects the zone BE name but when
1372 * support for beadm/libbe in a zone is provided it will need to fill
1373 * in the rest of the information needed for a zone BE.
1376 be_get_zone_node_data(be_node_list_t
*be_node
, char *be_name
)
1378 if ((be_node
->be_node_name
= strdup(be_name
)) != NULL
)
1379 return (BE_SUCCESS
);
1380 return (BE_ERR_NOMEM
);