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 https://opensource.org/licenses/CDDL-1.0.
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) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24 * Copyright (c) 2012 Pawel Jakub Dawidek <pawel@dawidek.net>.
25 * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
26 * Copyright (c) 2013 by Delphix. All rights reserved.
42 * This is a private interface used to gather up all the datasets specified on
43 * the command line so that we can iterate over them in order.
45 * First, we iterate over all filesystems, gathering them together into an
46 * AVL tree. We report errors for any explicitly specified datasets
47 * that we couldn't open.
49 * When finished, we have an AVL tree of ZFS handles. We go through and execute
50 * the provided callback for each one, passing whatever data the user supplied.
53 typedef struct zfs_node
{
54 zfs_handle_t
*zn_handle
;
55 uu_avl_node_t zn_avlnode
;
58 typedef struct callback_data
{
62 zfs_sort_column_t
*cb_sortcol
;
63 zprop_list_t
**cb_proplist
;
66 uint8_t cb_props_table
[ZFS_NUM_PROPS
];
69 uu_avl_pool_t
*avl_pool
;
72 * Include snaps if they were requested or if this a zfs list where types
73 * were not specified and the "listsnapshots" property is set on this pool.
76 zfs_include_snapshots(zfs_handle_t
*zhp
, callback_data_t
*cb
)
80 if ((cb
->cb_flags
& ZFS_ITER_PROP_LISTSNAPS
) == 0)
81 return (cb
->cb_types
& ZFS_TYPE_SNAPSHOT
);
83 zph
= zfs_get_pool_handle(zhp
);
84 return (zpool_get_prop_int(zph
, ZPOOL_PROP_LISTSNAPS
, NULL
));
88 * Called for each dataset. If the object is of an appropriate type,
89 * add it to the avl tree and recurse over any children as necessary.
92 zfs_callback(zfs_handle_t
*zhp
, void *data
)
94 callback_data_t
*cb
= data
;
95 boolean_t should_close
= B_TRUE
;
96 boolean_t include_snaps
= zfs_include_snapshots(zhp
, cb
);
97 boolean_t include_bmarks
= (cb
->cb_types
& ZFS_TYPE_BOOKMARK
);
99 if ((zfs_get_type(zhp
) & cb
->cb_types
) ||
100 ((zfs_get_type(zhp
) == ZFS_TYPE_SNAPSHOT
) && include_snaps
)) {
102 zfs_node_t
*node
= safe_malloc(sizeof (zfs_node_t
));
104 node
->zn_handle
= zhp
;
105 uu_avl_node_init(node
, &node
->zn_avlnode
, avl_pool
);
106 if (uu_avl_find(cb
->cb_avl
, node
, cb
->cb_sortcol
,
108 if (cb
->cb_proplist
) {
109 if ((*cb
->cb_proplist
) &&
110 !(*cb
->cb_proplist
)->pl_all
)
111 zfs_prune_proplist(zhp
,
114 if (zfs_expand_proplist(zhp
, cb
->cb_proplist
,
115 (cb
->cb_flags
& ZFS_ITER_RECVD_PROPS
),
116 (cb
->cb_flags
& ZFS_ITER_LITERAL_PROPS
))
122 uu_avl_insert(cb
->cb_avl
, node
, idx
);
123 should_close
= B_FALSE
;
130 * Recurse if necessary.
132 if (cb
->cb_flags
& ZFS_ITER_RECURSE
&&
133 ((cb
->cb_flags
& ZFS_ITER_DEPTH_LIMIT
) == 0 ||
134 cb
->cb_depth
< cb
->cb_depth_limit
)) {
138 * If we are not looking for filesystems, we don't need to
139 * recurse into filesystems when we are at our depth limit.
141 if ((cb
->cb_depth
< cb
->cb_depth_limit
||
142 (cb
->cb_flags
& ZFS_ITER_DEPTH_LIMIT
) == 0 ||
144 (ZFS_TYPE_FILESYSTEM
| ZFS_TYPE_VOLUME
))) &&
145 zfs_get_type(zhp
) == ZFS_TYPE_FILESYSTEM
) {
146 (void) zfs_iter_filesystems_v2(zhp
, cb
->cb_flags
,
150 if (((zfs_get_type(zhp
) & (ZFS_TYPE_SNAPSHOT
|
151 ZFS_TYPE_BOOKMARK
)) == 0) && include_snaps
) {
152 (void) zfs_iter_snapshots_v2(zhp
, cb
->cb_flags
,
153 zfs_callback
, data
, 0, 0);
156 if (((zfs_get_type(zhp
) & (ZFS_TYPE_SNAPSHOT
|
157 ZFS_TYPE_BOOKMARK
)) == 0) && include_bmarks
) {
158 (void) zfs_iter_bookmarks_v2(zhp
, cb
->cb_flags
,
172 zfs_add_sort_column(zfs_sort_column_t
**sc
, const char *name
,
175 zfs_sort_column_t
*col
;
178 if ((prop
= zfs_name_to_prop(name
)) == ZPROP_USERPROP
&&
179 !zfs_prop_user(name
))
182 col
= safe_malloc(sizeof (zfs_sort_column_t
));
185 col
->sc_reverse
= reverse
;
186 if (prop
== ZPROP_USERPROP
) {
187 col
->sc_user_prop
= safe_malloc(strlen(name
) + 1);
188 (void) strcpy(col
->sc_user_prop
, name
);
195 (*sc
)->sc_last
->sc_next
= col
;
196 (*sc
)->sc_last
= col
;
203 zfs_free_sort_columns(zfs_sort_column_t
*sc
)
205 zfs_sort_column_t
*col
;
209 free(sc
->sc_user_prop
);
216 * Return true if all of the properties to be sorted are populated by
217 * dsl_dataset_fast_stat(). Note that sc == NULL (no sort) means we
218 * don't need any extra properties, so returns true.
221 zfs_sort_only_by_fast(const zfs_sort_column_t
*sc
)
224 switch (sc
->sc_prop
) {
227 case ZFS_PROP_CREATETXG
:
228 case ZFS_PROP_NUMCLONES
:
229 case ZFS_PROP_INCONSISTENT
:
230 case ZFS_PROP_REDACTED
:
231 case ZFS_PROP_ORIGIN
:
243 zfs_list_only_by_fast(const zprop_list_t
*p
)
246 /* NULL means 'all' so we can't use simple mode */
251 switch (p
->pl_prop
) {
254 case ZFS_PROP_CREATETXG
:
255 case ZFS_PROP_NUMCLONES
:
256 case ZFS_PROP_INCONSISTENT
:
257 case ZFS_PROP_REDACTED
:
258 case ZFS_PROP_ORIGIN
:
270 zfs_compare(const void *larg
, const void *rarg
)
272 zfs_handle_t
*l
= ((zfs_node_t
*)larg
)->zn_handle
;
273 zfs_handle_t
*r
= ((zfs_node_t
*)rarg
)->zn_handle
;
274 const char *lname
= zfs_get_name(l
);
275 const char *rname
= zfs_get_name(r
);
277 uint64_t lcreate
, rcreate
;
280 lat
= (char *)strchr(lname
, '@');
281 rat
= (char *)strchr(rname
, '@');
288 ret
= strcmp(lname
, rname
);
289 if (ret
== 0 && (lat
!= NULL
|| rat
!= NULL
)) {
291 * If we're comparing a dataset to one of its snapshots, we
292 * always make the full dataset first.
296 } else if (rat
== NULL
) {
300 * If we have two snapshots from the same dataset, then
301 * we want to sort them according to creation time. We
302 * use the hidden CREATETXG property to get an absolute
303 * ordering of snapshots.
305 lcreate
= zfs_prop_get_int(l
, ZFS_PROP_CREATETXG
);
306 rcreate
= zfs_prop_get_int(r
, ZFS_PROP_CREATETXG
);
309 * Both lcreate and rcreate being 0 means we don't have
310 * properties and we should compare full name.
312 if (lcreate
== 0 && rcreate
== 0)
313 ret
= strcmp(lat
+ 1, rat
+ 1);
314 else if (lcreate
< rcreate
)
316 else if (lcreate
> rcreate
)
330 * Sort datasets by specified columns.
332 * o Numeric types sort in ascending order.
333 * o String types sort in alphabetical order.
334 * o Types inappropriate for a row sort that row to the literal
335 * bottom, regardless of the specified ordering.
337 * If no sort columns are specified, or two datasets compare equally
338 * across all specified columns, they are sorted alphabetically by name
339 * with snapshots grouped under their parents.
342 zfs_sort(const void *larg
, const void *rarg
, void *data
)
344 zfs_handle_t
*l
= ((zfs_node_t
*)larg
)->zn_handle
;
345 zfs_handle_t
*r
= ((zfs_node_t
*)rarg
)->zn_handle
;
346 zfs_sort_column_t
*sc
= (zfs_sort_column_t
*)data
;
347 zfs_sort_column_t
*psc
;
349 for (psc
= sc
; psc
!= NULL
; psc
= psc
->sc_next
) {
350 char lbuf
[ZFS_MAXPROPLEN
], rbuf
[ZFS_MAXPROPLEN
];
351 const char *lstr
, *rstr
;
352 uint64_t lnum
= 0, rnum
= 0;
353 boolean_t lvalid
, rvalid
;
357 * We group the checks below the generic code. If 'lstr' and
358 * 'rstr' are non-NULL, then we do a string based comparison.
359 * Otherwise, we compare 'lnum' and 'rnum'.
362 if (psc
->sc_prop
== ZPROP_USERPROP
) {
363 nvlist_t
*luser
, *ruser
;
364 nvlist_t
*lval
, *rval
;
366 luser
= zfs_get_user_props(l
);
367 ruser
= zfs_get_user_props(r
);
369 lvalid
= (nvlist_lookup_nvlist(luser
,
370 psc
->sc_user_prop
, &lval
) == 0);
371 rvalid
= (nvlist_lookup_nvlist(ruser
,
372 psc
->sc_user_prop
, &rval
) == 0);
375 verify(nvlist_lookup_string(lval
,
376 ZPROP_VALUE
, &lstr
) == 0);
378 verify(nvlist_lookup_string(rval
,
379 ZPROP_VALUE
, &rstr
) == 0);
380 } else if (psc
->sc_prop
== ZFS_PROP_NAME
) {
381 lvalid
= rvalid
= B_TRUE
;
383 (void) strlcpy(lbuf
, zfs_get_name(l
), sizeof (lbuf
));
384 (void) strlcpy(rbuf
, zfs_get_name(r
), sizeof (rbuf
));
388 } else if (zfs_prop_is_string(psc
->sc_prop
)) {
389 lvalid
= (zfs_prop_get(l
, psc
->sc_prop
, lbuf
,
390 sizeof (lbuf
), NULL
, NULL
, 0, B_TRUE
) == 0);
391 rvalid
= (zfs_prop_get(r
, psc
->sc_prop
, rbuf
,
392 sizeof (rbuf
), NULL
, NULL
, 0, B_TRUE
) == 0);
397 lvalid
= zfs_prop_valid_for_type(psc
->sc_prop
,
398 zfs_get_type(l
), B_FALSE
);
399 rvalid
= zfs_prop_valid_for_type(psc
->sc_prop
,
400 zfs_get_type(r
), B_FALSE
);
403 lnum
= zfs_prop_get_int(l
, psc
->sc_prop
);
405 rnum
= zfs_prop_get_int(r
, psc
->sc_prop
);
408 if (!lvalid
&& !rvalid
)
416 ret
= strcmp(lstr
, rstr
);
417 else if (lnum
< rnum
)
419 else if (lnum
> rnum
)
423 if (psc
->sc_reverse
== B_TRUE
)
424 ret
= (ret
< 0) ? 1 : -1;
429 return (zfs_compare(larg
, rarg
));
433 zfs_for_each(int argc
, char **argv
, int flags
, zfs_type_t types
,
434 zfs_sort_column_t
*sortcol
, zprop_list_t
**proplist
, int limit
,
435 zfs_iter_f callback
, void *data
)
437 callback_data_t cb
= {0};
442 avl_pool
= uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t
),
443 offsetof(zfs_node_t
, zn_avlnode
), zfs_sort
, UU_DEFAULT
);
445 if (avl_pool
== NULL
)
448 cb
.cb_sortcol
= sortcol
;
450 cb
.cb_proplist
= proplist
;
452 cb
.cb_depth_limit
= limit
;
454 * If cb_proplist is provided then in the zfs_handles created we
455 * retain only those properties listed in cb_proplist and sortcol.
456 * The rest are pruned. So, the caller should make sure that no other
457 * properties other than those listed in cb_proplist/sortcol are
460 * If cb_proplist is NULL then we retain all the properties. We
461 * always retain the zoned property, which some other properties
462 * need (userquota & friends), and the createtxg property, which
463 * we need to sort snapshots.
465 if (cb
.cb_proplist
&& *cb
.cb_proplist
) {
466 zprop_list_t
*p
= *cb
.cb_proplist
;
469 if (p
->pl_prop
>= ZFS_PROP_TYPE
&&
470 p
->pl_prop
< ZFS_NUM_PROPS
) {
471 cb
.cb_props_table
[p
->pl_prop
] = B_TRUE
;
477 if (sortcol
->sc_prop
>= ZFS_PROP_TYPE
&&
478 sortcol
->sc_prop
< ZFS_NUM_PROPS
) {
479 cb
.cb_props_table
[sortcol
->sc_prop
] = B_TRUE
;
481 sortcol
= sortcol
->sc_next
;
484 cb
.cb_props_table
[ZFS_PROP_ZONED
] = B_TRUE
;
485 cb
.cb_props_table
[ZFS_PROP_CREATETXG
] = B_TRUE
;
487 (void) memset(cb
.cb_props_table
, B_TRUE
,
488 sizeof (cb
.cb_props_table
));
491 if ((cb
.cb_avl
= uu_avl_create(avl_pool
, NULL
, UU_DEFAULT
)) == NULL
)
496 * If given no arguments, iterate over all datasets.
498 cb
.cb_flags
|= ZFS_ITER_RECURSE
;
499 ret
= zfs_iter_root(g_zfs
, zfs_callback
, &cb
);
501 zfs_handle_t
*zhp
= NULL
;
502 zfs_type_t argtype
= types
;
505 * If we're recursive, then we always allow filesystems as
506 * arguments. If we also are interested in snapshots or
507 * bookmarks, then we can take volumes as well.
509 if (flags
& ZFS_ITER_RECURSE
) {
510 argtype
|= ZFS_TYPE_FILESYSTEM
;
511 if (types
& (ZFS_TYPE_SNAPSHOT
| ZFS_TYPE_BOOKMARK
))
512 argtype
|= ZFS_TYPE_VOLUME
;
515 for (int i
= 0; i
< argc
; i
++) {
516 if (flags
& ZFS_ITER_ARGS_CAN_BE_PATHS
) {
517 zhp
= zfs_path_to_zhandle(g_zfs
, argv
[i
],
520 zhp
= zfs_open(g_zfs
, argv
[i
], argtype
);
523 ret
|= zfs_callback(zhp
, &cb
);
530 * At this point we've got our AVL tree full of zfs handles, so iterate
531 * over each one and execute the real user callback.
533 for (node
= uu_avl_first(cb
.cb_avl
); node
!= NULL
;
534 node
= uu_avl_next(cb
.cb_avl
, node
))
535 ret
|= callback(node
->zn_handle
, data
);
538 * Finally, clean up the AVL tree.
540 if ((walk
= uu_avl_walk_start(cb
.cb_avl
, UU_WALK_ROBUST
)) == NULL
)
543 while ((node
= uu_avl_walk_next(walk
)) != NULL
) {
544 uu_avl_remove(cb
.cb_avl
, node
);
545 zfs_close(node
->zn_handle
);
549 uu_avl_walk_end(walk
);
550 uu_avl_destroy(cb
.cb_avl
);
551 uu_avl_pool_destroy(avl_pool
);