1 789 ahrens /* 2 789 ahrens * CDDL HEADER START 3 789 ahrens * 4 789 ahrens * The contents of this file are subject to the terms of the 5 2082 eschrock * Common Development and Distribution License (the "License"). 6 2082 eschrock * You may not use this file except in compliance with the License. 7 789 ahrens * 8 789 ahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 789 ahrens * or http://www.opensolaris.org/os/licensing. 10 789 ahrens * See the License for the specific language governing permissions 11 789 ahrens * and limitations under the License. 12 789 ahrens * 13 789 ahrens * When distributing Covered Code, include this CDDL HEADER in each 14 789 ahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 789 ahrens * If applicable, add the following below this CDDL HEADER, with the 16 789 ahrens * fields enclosed by brackets "[]" replaced with your own identifying 17 789 ahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18 789 ahrens * 19 789 ahrens * CDDL HEADER END 20 789 ahrens */ 21 789 ahrens /* 22 8802 Sanjeev * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 789 ahrens * Use is subject to license terms. 24 789 ahrens */ 25 789 ahrens 26 789 ahrens #include <libintl.h> 27 789 ahrens #include <libuutil.h> 28 789 ahrens #include <stddef.h> 29 789 ahrens #include <stdio.h> 30 789 ahrens #include <stdlib.h> 31 789 ahrens #include <strings.h> 32 789 ahrens 33 789 ahrens #include <libzfs.h> 34 789 ahrens 35 789 ahrens #include "zfs_util.h" 36 2379 sjelinek #include "zfs_iter.h" 37 789 ahrens 38 789 ahrens /* 39 789 ahrens * This is a private interface used to gather up all the datasets specified on 40 789 ahrens * the command line so that we can iterate over them in order. 41 789 ahrens * 42 789 ahrens * First, we iterate over all filesystems, gathering them together into an 43 2379 sjelinek * AVL tree. We report errors for any explicitly specified datasets 44 789 ahrens * that we couldn't open. 45 789 ahrens * 46 789 ahrens * When finished, we have an AVL tree of ZFS handles. We go through and execute 47 789 ahrens * the provided callback for each one, passing whatever data the user supplied. 48 789 ahrens */ 49 789 ahrens 50 789 ahrens typedef struct zfs_node { 51 789 ahrens zfs_handle_t *zn_handle; 52 789 ahrens uu_avl_node_t zn_avlnode; 53 789 ahrens } zfs_node_t; 54 789 ahrens 55 789 ahrens typedef struct callback_data { 56 9365 Chris uu_avl_t *cb_avl; 57 9365 Chris int cb_flags; 58 9365 Chris zfs_type_t cb_types; 59 9365 Chris zfs_sort_column_t *cb_sortcol; 60 9365 Chris zprop_list_t **cb_proplist; 61 9365 Chris int cb_depth_limit; 62 9365 Chris int cb_depth; 63 9365 Chris uint8_t cb_props_table[ZFS_NUM_PROPS]; 64 789 ahrens } callback_data_t; 65 789 ahrens 66 789 ahrens uu_avl_pool_t *avl_pool; 67 789 ahrens 68 789 ahrens /* 69 7538 Richard * Include snaps if they were requested or if this a zfs list where types 70 7538 Richard * were not specified and the "listsnapshots" property is set on this pool. 71 7538 Richard */ 72 7538 Richard static int 73 7538 Richard zfs_include_snapshots(zfs_handle_t *zhp, callback_data_t *cb) 74 7538 Richard { 75 7538 Richard zpool_handle_t *zph; 76 7538 Richard 77 7538 Richard if ((cb->cb_flags & ZFS_ITER_PROP_LISTSNAPS) == 0) 78 7538 Richard return (cb->cb_types & ZFS_TYPE_SNAPSHOT); 79 7538 Richard 80 7538 Richard zph = zfs_get_pool_handle(zhp); 81 7538 Richard return (zpool_get_prop_int(zph, ZPOOL_PROP_LISTSNAPS, NULL)); 82 7538 Richard } 83 7538 Richard 84 7538 Richard /* 85 7538 Richard * Called for each dataset. If the object is of an appropriate type, 86 789 ahrens * add it to the avl tree and recurse over any children as necessary. 87 789 ahrens */ 88 5367 ahrens static int 89 789 ahrens zfs_callback(zfs_handle_t *zhp, void *data) 90 789 ahrens { 91 789 ahrens callback_data_t *cb = data; 92 789 ahrens int dontclose = 0; 93 7538 Richard int include_snaps = zfs_include_snapshots(zhp, cb); 94 789 ahrens 95 7538 Richard if ((zfs_get_type(zhp) & cb->cb_types) || 96 7538 Richard ((zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) && include_snaps)) { 97 789 ahrens uu_avl_index_t idx; 98 789 ahrens zfs_node_t *node = safe_malloc(sizeof (zfs_node_t)); 99 789 ahrens 100 789 ahrens node->zn_handle = zhp; 101 789 ahrens uu_avl_node_init(node, &node->zn_avlnode, avl_pool); 102 2379 sjelinek if (uu_avl_find(cb->cb_avl, node, cb->cb_sortcol, 103 2379 sjelinek &idx) == NULL) { 104 8802 Sanjeev if (cb->cb_proplist) { 105 8802 Sanjeev if ((*cb->cb_proplist) && 106 8802 Sanjeev !(*cb->cb_proplist)->pl_all) 107 8802 Sanjeev zfs_prune_proplist(zhp, 108 8802 Sanjeev cb->cb_props_table); 109 8802 Sanjeev 110 11022 Tom if (zfs_expand_proplist(zhp, cb->cb_proplist, 111 11022 Tom (cb->cb_flags & ZFS_ITER_RECVD_PROPS)) 112 8802 Sanjeev != 0) { 113 8802 Sanjeev free(node); 114 8802 Sanjeev return (-1); 115 8802 Sanjeev } 116 2676 eschrock } 117 789 ahrens uu_avl_insert(cb->cb_avl, node, idx); 118 789 ahrens dontclose = 1; 119 789 ahrens } else { 120 789 ahrens free(node); 121 789 ahrens } 122 789 ahrens } 123 789 ahrens 124 789 ahrens /* 125 1356 eschrock * Recurse if necessary. 126 789 ahrens */ 127 9365 Chris if (cb->cb_flags & ZFS_ITER_RECURSE && 128 9365 Chris ((cb->cb_flags & ZFS_ITER_DEPTH_LIMIT) == 0 || 129 9365 Chris cb->cb_depth < cb->cb_depth_limit)) { 130 9365 Chris cb->cb_depth++; 131 5367 ahrens if (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM) 132 5367 ahrens (void) zfs_iter_filesystems(zhp, zfs_callback, data); 133 7538 Richard if ((zfs_get_type(zhp) != ZFS_TYPE_SNAPSHOT) && include_snaps) 134 5367 ahrens (void) zfs_iter_snapshots(zhp, zfs_callback, data); 135 9365 Chris cb->cb_depth--; 136 5367 ahrens } 137 789 ahrens 138 789 ahrens if (!dontclose) 139 789 ahrens zfs_close(zhp); 140 789 ahrens 141 789 ahrens return (0); 142 2379 sjelinek } 143 2379 sjelinek 144 2676 eschrock int 145 2676 eschrock zfs_add_sort_column(zfs_sort_column_t **sc, const char *name, 146 2379 sjelinek boolean_t reverse) 147 2379 sjelinek { 148 2379 sjelinek zfs_sort_column_t *col; 149 2676 eschrock zfs_prop_t prop; 150 2676 eschrock 151 5094 lling if ((prop = zfs_name_to_prop(name)) == ZPROP_INVAL && 152 2676 eschrock !zfs_prop_user(name)) 153 2676 eschrock return (-1); 154 2379 sjelinek 155 2379 sjelinek col = safe_malloc(sizeof (zfs_sort_column_t)); 156 2379 sjelinek 157 2379 sjelinek col->sc_prop = prop; 158 2379 sjelinek col->sc_reverse = reverse; 159 5094 lling if (prop == ZPROP_INVAL) { 160 2676 eschrock col->sc_user_prop = safe_malloc(strlen(name) + 1); 161 2676 eschrock (void) strcpy(col->sc_user_prop, name); 162 2676 eschrock } 163 2379 sjelinek 164 2379 sjelinek if (*sc == NULL) { 165 2379 sjelinek col->sc_last = col; 166 2379 sjelinek *sc = col; 167 2379 sjelinek } else { 168 2379 sjelinek (*sc)->sc_last->sc_next = col; 169 2379 sjelinek (*sc)->sc_last = col; 170 2379 sjelinek } 171 2676 eschrock 172 2676 eschrock return (0); 173 2379 sjelinek } 174 2379 sjelinek 175 2379 sjelinek void 176 2379 sjelinek zfs_free_sort_columns(zfs_sort_column_t *sc) 177 2379 sjelinek { 178 2379 sjelinek zfs_sort_column_t *col; 179 2379 sjelinek 180 2379 sjelinek while (sc != NULL) { 181 2379 sjelinek col = sc->sc_next; 182 2676 eschrock free(sc->sc_user_prop); 183 2379 sjelinek free(sc); 184 2379 sjelinek sc = col; 185 2379 sjelinek } 186 789 ahrens } 187 789 ahrens 188 789 ahrens /* ARGSUSED */ 189 789 ahrens static int 190 789 ahrens zfs_compare(const void *larg, const void *rarg, void *unused) 191 789 ahrens { 192 789 ahrens zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle; 193 789 ahrens zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle; 194 789 ahrens const char *lname = zfs_get_name(l); 195 789 ahrens const char *rname = zfs_get_name(r); 196 789 ahrens char *lat, *rat; 197 789 ahrens uint64_t lcreate, rcreate; 198 789 ahrens int ret; 199 789 ahrens 200 789 ahrens lat = (char *)strchr(lname, '@'); 201 789 ahrens rat = (char *)strchr(rname, '@'); 202 789 ahrens 203 789 ahrens if (lat != NULL) 204 789 ahrens *lat = '\0'; 205 789 ahrens if (rat != NULL) 206 789 ahrens *rat = '\0'; 207 789 ahrens 208 789 ahrens ret = strcmp(lname, rname); 209 789 ahrens if (ret == 0) { 210 789 ahrens /* 211 789 ahrens * If we're comparing a dataset to one of its snapshots, we 212 789 ahrens * always make the full dataset first. 213 789 ahrens */ 214 789 ahrens if (lat == NULL) { 215 789 ahrens ret = -1; 216 789 ahrens } else if (rat == NULL) { 217 789 ahrens ret = 1; 218 789 ahrens } else { 219 789 ahrens /* 220 789 ahrens * If we have two snapshots from the same dataset, then 221 789 ahrens * we want to sort them according to creation time. We 222 789 ahrens * use the hidden CREATETXG property to get an absolute 223 789 ahrens * ordering of snapshots. 224 789 ahrens */ 225 789 ahrens lcreate = zfs_prop_get_int(l, ZFS_PROP_CREATETXG); 226 789 ahrens rcreate = zfs_prop_get_int(r, ZFS_PROP_CREATETXG); 227 789 ahrens 228 789 ahrens if (lcreate < rcreate) 229 789 ahrens ret = -1; 230 789 ahrens else if (lcreate > rcreate) 231 789 ahrens ret = 1; 232 789 ahrens } 233 789 ahrens } 234 789 ahrens 235 789 ahrens if (lat != NULL) 236 789 ahrens *lat = '@'; 237 789 ahrens if (rat != NULL) 238 789 ahrens *rat = '@'; 239 789 ahrens 240 789 ahrens return (ret); 241 789 ahrens } 242 789 ahrens 243 2379 sjelinek /* 244 2379 sjelinek * Sort datasets by specified columns. 245 2379 sjelinek * 246 2379 sjelinek * o Numeric types sort in ascending order. 247 2379 sjelinek * o String types sort in alphabetical order. 248 2379 sjelinek * o Types inappropriate for a row sort that row to the literal 249 2379 sjelinek * bottom, regardless of the specified ordering. 250 2379 sjelinek * 251 2379 sjelinek * If no sort columns are specified, or two datasets compare equally 252 2379 sjelinek * across all specified columns, they are sorted alphabetically by name 253 2379 sjelinek * with snapshots grouped under their parents. 254 2379 sjelinek */ 255 2379 sjelinek static int 256 2379 sjelinek zfs_sort(const void *larg, const void *rarg, void *data) 257 2379 sjelinek { 258 2379 sjelinek zfs_handle_t *l = ((zfs_node_t *)larg)->zn_handle; 259 2379 sjelinek zfs_handle_t *r = ((zfs_node_t *)rarg)->zn_handle; 260 2379 sjelinek zfs_sort_column_t *sc = (zfs_sort_column_t *)data; 261 2379 sjelinek zfs_sort_column_t *psc; 262 2379 sjelinek 263 2379 sjelinek for (psc = sc; psc != NULL; psc = psc->sc_next) { 264 2676 eschrock char lbuf[ZFS_MAXPROPLEN], rbuf[ZFS_MAXPROPLEN]; 265 2676 eschrock char *lstr, *rstr; 266 2379 sjelinek uint64_t lnum, rnum; 267 2676 eschrock boolean_t lvalid, rvalid; 268 2379 sjelinek int ret = 0; 269 2379 sjelinek 270 2676 eschrock /* 271 2676 eschrock * We group the checks below the generic code. If 'lstr' and 272 2676 eschrock * 'rstr' are non-NULL, then we do a string based comparison. 273 2676 eschrock * Otherwise, we compare 'lnum' and 'rnum'. 274 2676 eschrock */ 275 2676 eschrock lstr = rstr = NULL; 276 5094 lling if (psc->sc_prop == ZPROP_INVAL) { 277 2676 eschrock nvlist_t *luser, *ruser; 278 2676 eschrock nvlist_t *lval, *rval; 279 2379 sjelinek 280 2676 eschrock luser = zfs_get_user_props(l); 281 2676 eschrock ruser = zfs_get_user_props(r); 282 2379 sjelinek 283 2676 eschrock lvalid = (nvlist_lookup_nvlist(luser, 284 2676 eschrock psc->sc_user_prop, &lval) == 0); 285 2676 eschrock rvalid = (nvlist_lookup_nvlist(ruser, 286 2676 eschrock psc->sc_user_prop, &rval) == 0); 287 2676 eschrock 288 2676 eschrock if (lvalid) 289 2676 eschrock verify(nvlist_lookup_string(lval, 290 5094 lling ZPROP_VALUE, &lstr) == 0); 291 2676 eschrock if (rvalid) 292 2676 eschrock verify(nvlist_lookup_string(rval, 293 5094 lling ZPROP_VALUE, &rstr) == 0); 294 2676 eschrock 295 2676 eschrock } else if (zfs_prop_is_string(psc->sc_prop)) { 296 2676 eschrock lvalid = (zfs_prop_get(l, psc->sc_prop, lbuf, 297 2676 eschrock sizeof (lbuf), NULL, NULL, 0, B_TRUE) == 0); 298 2676 eschrock rvalid = (zfs_prop_get(r, psc->sc_prop, rbuf, 299 2676 eschrock sizeof (rbuf), NULL, NULL, 0, B_TRUE) == 0); 300 2676 eschrock 301 2676 eschrock lstr = lbuf; 302 2676 eschrock rstr = rbuf; 303 2379 sjelinek } else { 304 2379 sjelinek lvalid = zfs_prop_valid_for_type(psc->sc_prop, 305 2379 sjelinek zfs_get_type(l)); 306 2379 sjelinek rvalid = zfs_prop_valid_for_type(psc->sc_prop, 307 2379 sjelinek zfs_get_type(r)); 308 2379 sjelinek 309 2676 eschrock if (lvalid) 310 2676 eschrock (void) zfs_prop_get_numeric(l, psc->sc_prop, 311 2676 eschrock &lnum, NULL, NULL, 0); 312 2676 eschrock if (rvalid) 313 2676 eschrock (void) zfs_prop_get_numeric(r, psc->sc_prop, 314 2676 eschrock &rnum, NULL, NULL, 0); 315 2676 eschrock } 316 2379 sjelinek 317 2676 eschrock if (!lvalid && !rvalid) 318 2676 eschrock continue; 319 2676 eschrock else if (!lvalid) 320 2676 eschrock return (1); 321 2676 eschrock else if (!rvalid) 322 2676 eschrock return (-1); 323 2379 sjelinek 324 2676 eschrock if (lstr) 325 2676 eschrock ret = strcmp(lstr, rstr); 326 7060 rm160521 else if (lnum < rnum) 327 2676 eschrock ret = -1; 328 2676 eschrock else if (lnum > rnum) 329 2676 eschrock ret = 1; 330 2379 sjelinek 331 2379 sjelinek if (ret != 0) { 332 2379 sjelinek if (psc->sc_reverse == B_TRUE) 333 2379 sjelinek ret = (ret < 0) ? 1 : -1; 334 2379 sjelinek return (ret); 335 2379 sjelinek } 336 2379 sjelinek } 337 2379 sjelinek 338 2379 sjelinek return (zfs_compare(larg, rarg, NULL)); 339 2379 sjelinek } 340 2379 sjelinek 341 789 ahrens int 342 7538 Richard zfs_for_each(int argc, char **argv, int flags, zfs_type_t types, 343 9365 Chris zfs_sort_column_t *sortcol, zprop_list_t **proplist, int limit, 344 7538 Richard zfs_iter_f callback, void *data) 345 789 ahrens { 346 8802 Sanjeev callback_data_t cb = {0}; 347 789 ahrens int ret = 0; 348 789 ahrens zfs_node_t *node; 349 789 ahrens uu_avl_walk_t *walk; 350 789 ahrens 351 789 ahrens avl_pool = uu_avl_pool_create("zfs_pool", sizeof (zfs_node_t), 352 2379 sjelinek offsetof(zfs_node_t, zn_avlnode), zfs_sort, UU_DEFAULT); 353 789 ahrens 354 789 ahrens if (avl_pool == NULL) { 355 789 ahrens (void) fprintf(stderr, 356 789 ahrens gettext("internal error: out of memory\n")); 357 789 ahrens exit(1); 358 789 ahrens } 359 789 ahrens 360 2379 sjelinek cb.cb_sortcol = sortcol; 361 7538 Richard cb.cb_flags = flags; 362 2676 eschrock cb.cb_proplist = proplist; 363 789 ahrens cb.cb_types = types; 364 9365 Chris cb.cb_depth_limit = limit; 365 8802 Sanjeev /* 366 10242 chris * If cb_proplist is provided then in the zfs_handles created we 367 8802 Sanjeev * retain only those properties listed in cb_proplist and sortcol. 368 8802 Sanjeev * The rest are pruned. So, the caller should make sure that no other 369 8802 Sanjeev * properties other than those listed in cb_proplist/sortcol are 370 8802 Sanjeev * accessed. 371 8802 Sanjeev * 372 9396 Matthew * If cb_proplist is NULL then we retain all the properties. We 373 9396 Matthew * always retain the zoned property, which some other properties 374 9396 Matthew * need (userquota & friends), and the createtxg property, which 375 9396 Matthew * we need to sort snapshots. 376 8802 Sanjeev */ 377 8802 Sanjeev if (cb.cb_proplist && *cb.cb_proplist) { 378 8802 Sanjeev zprop_list_t *p = *cb.cb_proplist; 379 8802 Sanjeev 380 8802 Sanjeev while (p) { 381 8802 Sanjeev if (p->pl_prop >= ZFS_PROP_TYPE && 382 8802 Sanjeev p->pl_prop < ZFS_NUM_PROPS) { 383 8802 Sanjeev cb.cb_props_table[p->pl_prop] = B_TRUE; 384 8802 Sanjeev } 385 8802 Sanjeev p = p->pl_next; 386 8802 Sanjeev } 387 8802 Sanjeev 388 8802 Sanjeev while (sortcol) { 389 8802 Sanjeev if (sortcol->sc_prop >= ZFS_PROP_TYPE && 390 8802 Sanjeev sortcol->sc_prop < ZFS_NUM_PROPS) { 391 8802 Sanjeev cb.cb_props_table[sortcol->sc_prop] = B_TRUE; 392 8802 Sanjeev } 393 8802 Sanjeev sortcol = sortcol->sc_next; 394 8802 Sanjeev } 395 9396 Matthew 396 9396 Matthew cb.cb_props_table[ZFS_PROP_ZONED] = B_TRUE; 397 9396 Matthew cb.cb_props_table[ZFS_PROP_CREATETXG] = B_TRUE; 398 8802 Sanjeev } else { 399 8802 Sanjeev (void) memset(cb.cb_props_table, B_TRUE, 400 8802 Sanjeev sizeof (cb.cb_props_table)); 401 8802 Sanjeev } 402 8802 Sanjeev 403 789 ahrens if ((cb.cb_avl = uu_avl_create(avl_pool, NULL, UU_DEFAULT)) == NULL) { 404 789 ahrens (void) fprintf(stderr, 405 789 ahrens gettext("internal error: out of memory\n")); 406 789 ahrens exit(1); 407 789 ahrens } 408 789 ahrens 409 789 ahrens if (argc == 0) { 410 789 ahrens /* 411 789 ahrens * If given no arguments, iterate over all datasets. 412 789 ahrens */ 413 7538 Richard cb.cb_flags |= ZFS_ITER_RECURSE; 414 2082 eschrock ret = zfs_iter_root(g_zfs, zfs_callback, &cb); 415 789 ahrens } else { 416 789 ahrens int i; 417 789 ahrens zfs_handle_t *zhp; 418 789 ahrens zfs_type_t argtype; 419 789 ahrens 420 789 ahrens /* 421 789 ahrens * If we're recursive, then we always allow filesystems as 422 789 ahrens * arguments. If we also are interested in snapshots, then we 423 789 ahrens * can take volumes as well. 424 789 ahrens */ 425 789 ahrens argtype = types; 426 7538 Richard if (flags & ZFS_ITER_RECURSE) { 427 789 ahrens argtype |= ZFS_TYPE_FILESYSTEM; 428 789 ahrens if (types & ZFS_TYPE_SNAPSHOT) 429 789 ahrens argtype |= ZFS_TYPE_VOLUME; 430 789 ahrens } 431 789 ahrens 432 789 ahrens for (i = 0; i < argc; i++) { 433 7538 Richard if (flags & ZFS_ITER_ARGS_CAN_BE_PATHS) { 434 3635 ck153898 zhp = zfs_path_to_zhandle(g_zfs, argv[i], 435 3635 ck153898 argtype); 436 3635 ck153898 } else { 437 3635 ck153898 zhp = zfs_open(g_zfs, argv[i], argtype); 438 3635 ck153898 } 439 3635 ck153898 if (zhp != NULL) 440 2082 eschrock ret |= zfs_callback(zhp, &cb); 441 789 ahrens else 442 789 ahrens ret = 1; 443 789 ahrens } 444 789 ahrens } 445 789 ahrens 446 789 ahrens /* 447 789 ahrens * At this point we've got our AVL tree full of zfs handles, so iterate 448 789 ahrens * over each one and execute the real user callback. 449 789 ahrens */ 450 789 ahrens for (node = uu_avl_first(cb.cb_avl); node != NULL; 451 789 ahrens node = uu_avl_next(cb.cb_avl, node)) 452 789 ahrens ret |= callback(node->zn_handle, data); 453 789 ahrens 454 789 ahrens /* 455 789 ahrens * Finally, clean up the AVL tree. 456 789 ahrens */ 457 789 ahrens if ((walk = uu_avl_walk_start(cb.cb_avl, UU_WALK_ROBUST)) == NULL) { 458 789 ahrens (void) fprintf(stderr, 459 789 ahrens gettext("internal error: out of memory")); 460 789 ahrens exit(1); 461 789 ahrens } 462 789 ahrens 463 789 ahrens while ((node = uu_avl_walk_next(walk)) != NULL) { 464 789 ahrens uu_avl_remove(cb.cb_avl, node); 465 789 ahrens zfs_close(node->zn_handle); 466 789 ahrens free(node); 467 789 ahrens } 468 789 ahrens 469 789 ahrens uu_avl_walk_end(walk); 470 789 ahrens uu_avl_destroy(cb.cb_avl); 471 789 ahrens uu_avl_pool_destroy(avl_pool); 472 789 ahrens 473 789 ahrens return (ret); 474 789 ahrens } 475