1168404Spjd/*
2168404Spjd * CDDL HEADER START
3168404Spjd *
4168404Spjd * The contents of this file are subject to the terms of the
5168404Spjd * Common Development and Distribution License (the "License").
6168404Spjd * You may not use this file except in compliance with the License.
7168404Spjd *
8168404Spjd * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9168404Spjd * or http://www.opensolaris.org/os/licensing.
10168404Spjd * See the License for the specific language governing permissions
11168404Spjd * and limitations under the License.
12168404Spjd *
13168404Spjd * When distributing Covered Code, include this CDDL HEADER in each
14168404Spjd * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15168404Spjd * If applicable, add the following below this CDDL HEADER, with the
16168404Spjd * fields enclosed by brackets "[]" replaced with your own identifying
17168404Spjd * information: Portions Copyright [yyyy] [name of copyright owner]
18168404Spjd *
19168404Spjd * CDDL HEADER END
20168404Spjd */
21168404Spjd/*
22168404Spjd * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23168404Spjd * Use is subject to license terms.
24168404Spjd */
25296537Smav/*
26296537Smav * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
27296537Smav */
28168404Spjd
29168404Spjd#include <solaris.h>
30168404Spjd#include <libintl.h>
31168404Spjd#include <libuutil.h>
32168404Spjd#include <stddef.h>
33168404Spjd#include <stdio.h>
34168404Spjd#include <stdlib.h>
35168404Spjd#include <strings.h>
36168404Spjd
37168404Spjd#include <libzfs.h>
38168404Spjd
39168404Spjd#include "zpool_util.h"
40168404Spjd
41168404Spjd/*
42168404Spjd * Private interface for iterating over pools specified on the command line.
43168404Spjd * Most consumers will call for_each_pool, but in order to support iostat, we
44168404Spjd * allow fined grained control through the zpool_list_t interface.
45168404Spjd */
46168404Spjd
47168404Spjdtypedef struct zpool_node {
48168404Spjd	zpool_handle_t	*zn_handle;
49168404Spjd	uu_avl_node_t	zn_avlnode;
50168404Spjd	int		zn_mark;
51168404Spjd} zpool_node_t;
52168404Spjd
53168404Spjdstruct zpool_list {
54168404Spjd	boolean_t	zl_findall;
55168404Spjd	uu_avl_t	*zl_avl;
56168404Spjd	uu_avl_pool_t	*zl_pool;
57185029Spjd	zprop_list_t	**zl_proplist;
58168404Spjd};
59168404Spjd
60168404Spjd/* ARGSUSED */
61168404Spjdstatic int
62168404Spjdzpool_compare(const void *larg, const void *rarg, void *unused)
63168404Spjd{
64168404Spjd	zpool_handle_t *l = ((zpool_node_t *)larg)->zn_handle;
65168404Spjd	zpool_handle_t *r = ((zpool_node_t *)rarg)->zn_handle;
66168404Spjd	const char *lname = zpool_get_name(l);
67168404Spjd	const char *rname = zpool_get_name(r);
68168404Spjd
69168404Spjd	return (strcmp(lname, rname));
70168404Spjd}
71168404Spjd
72168404Spjd/*
73168404Spjd * Callback function for pool_list_get().  Adds the given pool to the AVL tree
74168404Spjd * of known pools.
75168404Spjd */
76168404Spjdstatic int
77168404Spjdadd_pool(zpool_handle_t *zhp, void *data)
78168404Spjd{
79168404Spjd	zpool_list_t *zlp = data;
80168404Spjd	zpool_node_t *node = safe_malloc(sizeof (zpool_node_t));
81168404Spjd	uu_avl_index_t idx;
82168404Spjd
83168404Spjd	node->zn_handle = zhp;
84168404Spjd	uu_avl_node_init(node, &node->zn_avlnode, zlp->zl_pool);
85168404Spjd	if (uu_avl_find(zlp->zl_avl, node, NULL, &idx) == NULL) {
86185029Spjd		if (zlp->zl_proplist &&
87185029Spjd		    zpool_expand_proplist(zhp, zlp->zl_proplist) != 0) {
88185029Spjd			zpool_close(zhp);
89185029Spjd			free(node);
90185029Spjd			return (-1);
91185029Spjd		}
92168404Spjd		uu_avl_insert(zlp->zl_avl, node, idx);
93168404Spjd	} else {
94168404Spjd		zpool_close(zhp);
95168404Spjd		free(node);
96168404Spjd		return (-1);
97168404Spjd	}
98168404Spjd
99168404Spjd	return (0);
100168404Spjd}
101168404Spjd
102168404Spjd/*
103168404Spjd * Create a list of pools based on the given arguments.  If we're given no
104168404Spjd * arguments, then iterate over all pools in the system and add them to the AVL
105168404Spjd * tree.  Otherwise, add only those pool explicitly specified on the command
106168404Spjd * line.
107168404Spjd */
108168404Spjdzpool_list_t *
109185029Spjdpool_list_get(int argc, char **argv, zprop_list_t **proplist, int *err)
110168404Spjd{
111168404Spjd	zpool_list_t *zlp;
112168404Spjd
113168404Spjd	zlp = safe_malloc(sizeof (zpool_list_t));
114168404Spjd
115168404Spjd	zlp->zl_pool = uu_avl_pool_create("zfs_pool", sizeof (zpool_node_t),
116168404Spjd	    offsetof(zpool_node_t, zn_avlnode), zpool_compare, UU_DEFAULT);
117168404Spjd
118168404Spjd	if (zlp->zl_pool == NULL)
119168404Spjd		zpool_no_memory();
120168404Spjd
121168404Spjd	if ((zlp->zl_avl = uu_avl_create(zlp->zl_pool, NULL,
122168404Spjd	    UU_DEFAULT)) == NULL)
123168404Spjd		zpool_no_memory();
124168404Spjd
125185029Spjd	zlp->zl_proplist = proplist;
126185029Spjd
127168404Spjd	if (argc == 0) {
128168404Spjd		(void) zpool_iter(g_zfs, add_pool, zlp);
129168404Spjd		zlp->zl_findall = B_TRUE;
130168404Spjd	} else {
131168404Spjd		int i;
132168404Spjd
133168404Spjd		for (i = 0; i < argc; i++) {
134168404Spjd			zpool_handle_t *zhp;
135168404Spjd
136296537Smav			if ((zhp = zpool_open_canfail(g_zfs, argv[i])) !=
137296537Smav			    NULL) {
138185029Spjd				if (add_pool(zhp, zlp) != 0)
139168404Spjd					*err = B_TRUE;
140185029Spjd			} else {
141168404Spjd				*err = B_TRUE;
142185029Spjd			}
143168404Spjd		}
144168404Spjd	}
145168404Spjd
146168404Spjd	return (zlp);
147168404Spjd}
148168404Spjd
149168404Spjd/*
150168404Spjd * Search for any new pools, adding them to the list.  We only add pools when no
151168404Spjd * options were given on the command line.  Otherwise, we keep the list fixed as
152168404Spjd * those that were explicitly specified.
153168404Spjd */
154168404Spjdvoid
155168404Spjdpool_list_update(zpool_list_t *zlp)
156168404Spjd{
157168404Spjd	if (zlp->zl_findall)
158168404Spjd		(void) zpool_iter(g_zfs, add_pool, zlp);
159168404Spjd}
160168404Spjd
161168404Spjd/*
162168404Spjd * Iterate over all pools in the list, executing the callback for each
163168404Spjd */
164168404Spjdint
165168404Spjdpool_list_iter(zpool_list_t *zlp, int unavail, zpool_iter_f func,
166168404Spjd    void *data)
167168404Spjd{
168168404Spjd	zpool_node_t *node, *next_node;
169168404Spjd	int ret = 0;
170168404Spjd
171168404Spjd	for (node = uu_avl_first(zlp->zl_avl); node != NULL; node = next_node) {
172168404Spjd		next_node = uu_avl_next(zlp->zl_avl, node);
173168404Spjd		if (zpool_get_state(node->zn_handle) != POOL_STATE_UNAVAIL ||
174168404Spjd		    unavail)
175168404Spjd			ret |= func(node->zn_handle, data);
176168404Spjd	}
177168404Spjd
178168404Spjd	return (ret);
179168404Spjd}
180168404Spjd
181168404Spjd/*
182168404Spjd * Remove the given pool from the list.  When running iostat, we want to remove
183168404Spjd * those pools that no longer exist.
184168404Spjd */
185168404Spjdvoid
186168404Spjdpool_list_remove(zpool_list_t *zlp, zpool_handle_t *zhp)
187168404Spjd{
188168404Spjd	zpool_node_t search, *node;
189168404Spjd
190168404Spjd	search.zn_handle = zhp;
191168404Spjd	if ((node = uu_avl_find(zlp->zl_avl, &search, NULL, NULL)) != NULL) {
192168404Spjd		uu_avl_remove(zlp->zl_avl, node);
193168404Spjd		zpool_close(node->zn_handle);
194168404Spjd		free(node);
195168404Spjd	}
196168404Spjd}
197168404Spjd
198168404Spjd/*
199168404Spjd * Free all the handles associated with this list.
200168404Spjd */
201168404Spjdvoid
202168404Spjdpool_list_free(zpool_list_t *zlp)
203168404Spjd{
204168404Spjd	uu_avl_walk_t *walk;
205168404Spjd	zpool_node_t *node;
206168404Spjd
207168404Spjd	if ((walk = uu_avl_walk_start(zlp->zl_avl, UU_WALK_ROBUST)) == NULL) {
208168404Spjd		(void) fprintf(stderr,
209168404Spjd		    gettext("internal error: out of memory"));
210168404Spjd		exit(1);
211168404Spjd	}
212168404Spjd
213168404Spjd	while ((node = uu_avl_walk_next(walk)) != NULL) {
214168404Spjd		uu_avl_remove(zlp->zl_avl, node);
215168404Spjd		zpool_close(node->zn_handle);
216168404Spjd		free(node);
217168404Spjd	}
218168404Spjd
219168404Spjd	uu_avl_walk_end(walk);
220168404Spjd	uu_avl_destroy(zlp->zl_avl);
221168404Spjd	uu_avl_pool_destroy(zlp->zl_pool);
222168404Spjd
223168404Spjd	free(zlp);
224168404Spjd}
225168404Spjd
226168404Spjd/*
227168404Spjd * Returns the number of elements in the pool list.
228168404Spjd */
229168404Spjdint
230168404Spjdpool_list_count(zpool_list_t *zlp)
231168404Spjd{
232168404Spjd	return (uu_avl_numnodes(zlp->zl_avl));
233168404Spjd}
234168404Spjd
235168404Spjd/*
236168404Spjd * High level function which iterates over all pools given on the command line,
237168404Spjd * using the pool_list_* interfaces.
238168404Spjd */
239168404Spjdint
240168404Spjdfor_each_pool(int argc, char **argv, boolean_t unavail,
241185029Spjd    zprop_list_t **proplist, zpool_iter_f func, void *data)
242168404Spjd{
243168404Spjd	zpool_list_t *list;
244168404Spjd	int ret = 0;
245168404Spjd
246168404Spjd	if ((list = pool_list_get(argc, argv, proplist, &ret)) == NULL)
247168404Spjd		return (1);
248168404Spjd
249168404Spjd	if (pool_list_iter(list, unavail, func, data) != 0)
250168404Spjd		ret = 1;
251168404Spjd
252168404Spjd	pool_list_free(list);
253168404Spjd
254168404Spjd	return (ret);
255168404Spjd}
256