1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <libintl.h> 30 #include <libuutil.h> 31 #include <stddef.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <strings.h> 35 36 #include <libzfs.h> 37 38 #include "zpool_util.h" 39 40 /* 41 * Private interface for iterating over pools specified on the command line. 42 * Most consumers will call for_each_pool, but in order to support iostat, we 43 * allow fined grained control through the zpool_list_t interface. 44 */ 45 46 typedef struct zpool_node { 47 zpool_handle_t *zn_handle; 48 uu_avl_node_t zn_avlnode; 49 int zn_mark; 50 } zpool_node_t; 51 52 struct zpool_list { 53 int zl_findall; 54 uu_avl_t *zl_avl; 55 uu_avl_pool_t *zl_pool; 56 }; 57 58 /* ARGSUSED */ 59 static int 60 zpool_compare(const void *larg, const void *rarg, void *unused) 61 { 62 zpool_handle_t *l = ((zpool_node_t *)larg)->zn_handle; 63 zpool_handle_t *r = ((zpool_node_t *)rarg)->zn_handle; 64 const char *lname = zpool_get_name(l); 65 const char *rname = zpool_get_name(r); 66 67 return (strcmp(lname, rname)); 68 } 69 70 /* 71 * Callback function for pool_list_get(). Adds the given pool to the AVL tree 72 * of known pools. 73 */ 74 static int 75 add_pool(zpool_handle_t *zhp, void *data) 76 { 77 zpool_list_t *zlp = data; 78 zpool_node_t *node = safe_malloc(sizeof (zpool_node_t)); 79 uu_avl_index_t idx; 80 81 node->zn_handle = zhp; 82 uu_avl_node_init(node, &node->zn_avlnode, zlp->zl_pool); 83 if (uu_avl_find(zlp->zl_avl, node, NULL, &idx) == NULL) { 84 uu_avl_insert(zlp->zl_avl, node, idx); 85 } else { 86 zpool_close(zhp); 87 free(node); 88 } 89 90 return (0); 91 } 92 93 /* 94 * Create a list of pools based on the given arguments. If we're given no 95 * arguments, then iterate over all pools in the system and add them to the AVL 96 * tree. Otherwise, add only those pool explicitly specified on the command 97 * line. 98 */ 99 zpool_list_t * 100 pool_list_get(int argc, char **argv, int *err) 101 { 102 zpool_list_t *zlp; 103 104 zlp = safe_malloc(sizeof (zpool_list_t)); 105 106 zlp->zl_pool = uu_avl_pool_create("zfs_pool", sizeof (zpool_node_t), 107 offsetof(zpool_node_t, zn_avlnode), zpool_compare, UU_DEFAULT); 108 109 if (zlp->zl_pool == NULL) 110 no_memory(); 111 112 if ((zlp->zl_avl = uu_avl_create(zlp->zl_pool, NULL, 113 UU_DEFAULT)) == NULL) 114 no_memory(); 115 116 if (argc == 0) { 117 (void) zpool_iter(add_pool, zlp); 118 zlp->zl_findall = TRUE; 119 } else { 120 int i; 121 122 for (i = 0; i < argc; i++) { 123 zpool_handle_t *zhp; 124 125 if ((zhp = zpool_open_canfail(argv[i])) != NULL) 126 (void) add_pool(zhp, zlp); 127 else 128 *err = TRUE; 129 } 130 } 131 132 return (zlp); 133 } 134 135 /* 136 * Search for any new pools, adding them to the list. We only add pools when no 137 * options were given on the command line. Otherwise, we keep the list fixed as 138 * those that were explicitly specified. 139 */ 140 void 141 pool_list_update(zpool_list_t *zlp) 142 { 143 if (zlp->zl_findall) 144 (void) zpool_iter(add_pool, zlp); 145 } 146 147 /* 148 * Iterate over all pools in the list, executing the callback for each 149 */ 150 int 151 pool_list_iter(zpool_list_t *zlp, int unavail, zpool_iter_f func, 152 void *data) 153 { 154 zpool_node_t *node, *next_node; 155 int ret = 0; 156 157 for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next_node) { 158 next_node = uu_avl_next(zlp->zl_avl, node); 159 if (zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL || 160 unavail) 161 ret |= func(node->zn_handle, data); 162 } 163 164 return (ret); 165 } 166 167 /* 168 * Remove the given pool from the list. When running iostat, we want to remove 169 * those pools that no longer exist. 170 */ 171 void 172 pool_list_remove(zpool_list_t *zlp, zpool_handle_t *zhp) 173 { 174 zpool_node_t search, *node; 175 176 search.zn_handle = zhp; 177 if ((node = uu_avl_find(zlp->zl_avl, &search, NULL, NULL)) != NULL) { 178 uu_avl_remove(zlp->zl_avl, node); 179 zpool_close(node->zn_handle); 180 free(node); 181 } 182 } 183 184 /* 185 * Free all the handles associated with this list. 186 */ 187 void 188 pool_list_free(zpool_list_t *zlp) 189 { 190 uu_avl_walk_t *walk; 191 zpool_node_t *node; 192 193 if ((walk = uu_avl_walk_start(zlp->zl_avl, UU_WALK_ROBUST)) == NULL) { 194 (void) fprintf(stderr, 195 gettext("internal error: out of memory")); 196 exit(1); 197 } 198 199 while ((node = uu_avl_walk_next(walk)) != NULL) { 200 uu_avl_remove(zlp->zl_avl, node); 201 zpool_close(node->zn_handle); 202 free(node); 203 } 204 205 uu_avl_walk_end(walk); 206 uu_avl_destroy(zlp->zl_avl); 207 uu_avl_pool_destroy(zlp->zl_pool); 208 209 free(zlp); 210 } 211 212 /* 213 * Returns the number of elements in the pool list. 214 */ 215 int 216 pool_list_count(zpool_list_t *zlp) 217 { 218 return (uu_avl_numnodes(zlp->zl_avl)); 219 } 220 221 /* 222 * High level function which iterates over all pools given on the command line, 223 * using the pool_list_* interfaces. 224 */ 225 int 226 for_each_pool(int argc, char **argv, int unavail, zpool_iter_f func, 227 void *data) 228 { 229 zpool_list_t *list; 230 int ret = 0; 231 232 if ((list = pool_list_get(argc, argv, &ret)) == NULL) 233 return (1); 234 235 if (pool_list_iter(list, unavail, func, data) != 0) 236 ret = 1; 237 238 pool_list_free(list); 239 240 return (ret); 241 } 242