1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 5*2082Seschrock * Common Development and Distribution License (the "License"). 6*2082Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 221356Seschrock * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <libintl.h> 29789Sahrens #include <libuutil.h> 30789Sahrens #include <stddef.h> 31789Sahrens #include <stdio.h> 32789Sahrens #include <stdlib.h> 33789Sahrens #include <strings.h> 34789Sahrens 35789Sahrens #include <libzfs.h> 36789Sahrens 37789Sahrens #include "zfs_util.h" 38789Sahrens 39789Sahrens /* 40789Sahrens * This is a private interface used to gather up all the datasets specified on 41789Sahrens * the command line so that we can iterate over them in order. 42789Sahrens * 43789Sahrens * First, we iterate over all filesystems, gathering them together into an 44789Sahrens * AVL tree sorted by name. For snapshots, we order them according to 45789Sahrens * creation time. We report errors for any explicitly specified datasets 46789Sahrens * that we couldn't open. 47789Sahrens * 48789Sahrens * When finished, we have an AVL tree of ZFS handles. We go through and execute 49789Sahrens * the provided callback for each one, passing whatever data the user supplied. 50789Sahrens */ 51789Sahrens 52789Sahrens typedef struct zfs_node { 53789Sahrens zfs_handle_t *zn_handle; 54789Sahrens uu_avl_node_t zn_avlnode; 55789Sahrens } zfs_node_t; 56789Sahrens 57789Sahrens typedef struct callback_data { 58789Sahrens uu_avl_t *cb_avl; 59789Sahrens int cb_recurse; 60789Sahrens zfs_type_t cb_types; 61789Sahrens } callback_data_t; 62789Sahrens 63789Sahrens uu_avl_pool_t *avl_pool; 64789Sahrens 65789Sahrens /* 66789Sahrens * Called for each dataset. If the object the object is of an appropriate type, 67789Sahrens * add it to the avl tree and recurse over any children as necessary. 68789Sahrens */ 69789Sahrens int 70789Sahrens zfs_callback(zfs_handle_t *zhp, void *data) 71789Sahrens { 72789Sahrens callback_data_t *cb = data; 73789Sahrens int dontclose = 0; 74789Sahrens 75789Sahrens /* 76789Sahrens * If this object is of the appropriate type, add it to the AVL tree. 77789Sahrens */ 78789Sahrens if (zfs_get_type(zhp) & cb->cb_types) { 79789Sahrens uu_avl_index_t idx; 80789Sahrens zfs_node_t *node = safe_malloc(sizeof (zfs_node_t)); 81789Sahrens 82789Sahrens node->zn_handle = zhp; 83789Sahrens uu_avl_node_init(node, &node->zn_avlnode, avl_pool); 84789Sahrens if (uu_avl_find(cb->cb_avl, node, NULL, &idx) == NULL) { 85789Sahrens uu_avl_insert(cb->cb_avl, node, idx); 86789Sahrens dontclose = 1; 87789Sahrens } else { 88789Sahrens free(node); 89789Sahrens } 90789Sahrens } 91789Sahrens 92789Sahrens /* 931356Seschrock * Recurse if necessary. 94789Sahrens */ 95789Sahrens if (cb->cb_recurse && (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM || 961356Seschrock (zfs_get_type(zhp) == ZFS_TYPE_VOLUME && (cb->cb_types & 971356Seschrock ZFS_TYPE_SNAPSHOT)))) 98789Sahrens (void) zfs_iter_children(zhp, zfs_callback, data); 99789Sahrens 100789Sahrens if (!dontclose) 101789Sahrens zfs_close(zhp); 102789Sahrens 103789Sahrens return (0); 104789Sahrens } 105789Sahrens 106789Sahrens /* ARGSUSED */ 107789Sahrens static int 108789Sahrens zfs_compare(const void *larg, const void *rarg, void *unused) 109789Sahrens { 110789Sahrens zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle; 111789Sahrens zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle; 112789Sahrens const char *lname = zfs_get_name(l); 113789Sahrens const char *rname = zfs_get_name(r); 114789Sahrens char *lat, *rat; 115789Sahrens uint64_t lcreate, rcreate; 116789Sahrens int ret; 117789Sahrens 118789Sahrens lat = (char *)strchr(lname, '@'); 119789Sahrens rat = (char *)strchr(rname, '@'); 120789Sahrens 121789Sahrens if (lat != NULL) 122789Sahrens *lat = '\0'; 123789Sahrens if (rat != NULL) 124789Sahrens *rat = '\0'; 125789Sahrens 126789Sahrens ret = strcmp(lname, rname); 127789Sahrens if (ret == 0) { 128789Sahrens /* 129789Sahrens * If we're comparing a dataset to one of its snapshots, we 130789Sahrens * always make the full dataset first. 131789Sahrens */ 132789Sahrens if (lat == NULL) { 133789Sahrens ret = -1; 134789Sahrens } else if (rat == NULL) { 135789Sahrens ret = 1; 136789Sahrens } else { 137789Sahrens /* 138789Sahrens * If we have two snapshots from the same dataset, then 139789Sahrens * we want to sort them according to creation time. We 140789Sahrens * use the hidden CREATETXG property to get an absolute 141789Sahrens * ordering of snapshots. 142789Sahrens */ 143789Sahrens lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG); 144789Sahrens rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG); 145789Sahrens 146789Sahrens if (lcreate < rcreate) 147789Sahrens ret = -1; 148789Sahrens else if (lcreate > rcreate) 149789Sahrens ret = 1; 150789Sahrens } 151789Sahrens } 152789Sahrens 153789Sahrens if (lat != NULL) 154789Sahrens *lat = '@'; 155789Sahrens if (rat != NULL) 156789Sahrens *rat = '@'; 157789Sahrens 158789Sahrens return (ret); 159789Sahrens } 160789Sahrens 161789Sahrens int 162*2082Seschrock zfs_for_each(int argc, char **argv, boolean_t recurse, zfs_type_t types, 163789Sahrens zfs_iter_f callback, void *data) 164789Sahrens { 165789Sahrens callback_data_t cb; 166789Sahrens int ret = 0; 167789Sahrens zfs_node_t *node; 168789Sahrens uu_avl_walk_t *walk; 169789Sahrens 170789Sahrens avl_pool = uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t), 171789Sahrens offsetof(zfs_node_t, zn_avlnode), zfs_compare, UU_DEFAULT); 172789Sahrens 173789Sahrens if (avl_pool == NULL) { 174789Sahrens (void) fprintf(stderr, 175789Sahrens gettext("internal error: out of memory\n")); 176789Sahrens exit(1); 177789Sahrens } 178789Sahrens 179789Sahrens cb.cb_recurse = recurse; 180789Sahrens cb.cb_types = types; 181789Sahrens if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL) { 182789Sahrens (void) fprintf(stderr, 183789Sahrens gettext("internal error: out of memory\n")); 184789Sahrens exit(1); 185789Sahrens } 186789Sahrens 187789Sahrens if (argc == 0) { 188789Sahrens /* 189789Sahrens * If given no arguments, iterate over all datasets. 190789Sahrens */ 191789Sahrens cb.cb_recurse = 1; 192*2082Seschrock ret = zfs_iter_root(g_zfs, zfs_callback, &cb); 193789Sahrens } else { 194789Sahrens int i; 195789Sahrens zfs_handle_t *zhp; 196789Sahrens zfs_type_t argtype; 197789Sahrens 198789Sahrens /* 199789Sahrens * If we're recursive, then we always allow filesystems as 200789Sahrens * arguments. If we also are interested in snapshots, then we 201789Sahrens * can take volumes as well. 202789Sahrens */ 203789Sahrens argtype = types; 204789Sahrens if (recurse) { 205789Sahrens argtype |= ZFS_TYPE_FILESYSTEM; 206789Sahrens if (types & ZFS_TYPE_SNAPSHOT) 207789Sahrens argtype |= ZFS_TYPE_VOLUME; 208789Sahrens } 209789Sahrens 210789Sahrens for (i = 0; i < argc; i++) { 211*2082Seschrock if ((zhp = zfs_open(g_zfs, argv[i], argtype)) != NULL) 212*2082Seschrock ret |= zfs_callback(zhp, &cb); 213789Sahrens else 214789Sahrens ret = 1; 215789Sahrens } 216789Sahrens } 217789Sahrens 218789Sahrens /* 219789Sahrens * At this point we've got our AVL tree full of zfs handles, so iterate 220789Sahrens * over each one and execute the real user callback. 221789Sahrens */ 222789Sahrens for (node = uu_avl_first(cb.cb_avl); node != NULL; 223789Sahrens node = uu_avl_next(cb.cb_avl, node)) 224789Sahrens ret |= callback(node->zn_handle, data); 225789Sahrens 226789Sahrens /* 227789Sahrens * Finally, clean up the AVL tree. 228789Sahrens */ 229789Sahrens if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL) { 230789Sahrens (void) fprintf(stderr, 231789Sahrens gettext("internal error: out of memory")); 232789Sahrens exit(1); 233789Sahrens } 234789Sahrens 235789Sahrens while ((node = uu_avl_walk_next(walk)) != NULL) { 236789Sahrens uu_avl_remove(cb.cb_avl, node); 237789Sahrens zfs_close(node->zn_handle); 238789Sahrens free(node); 239789Sahrens } 240789Sahrens 241789Sahrens uu_avl_walk_end(walk); 242789Sahrens uu_avl_destroy(cb.cb_avl); 243789Sahrens uu_avl_pool_destroy(avl_pool); 244789Sahrens 245789Sahrens return (ret); 246789Sahrens } 247