xref: /freebsd-src/sys/contrib/openzfs/cmd/zed/zed_strings.c (revision eda14cbc264d6969b02f2b1994cef11148e914f1)
1*eda14cbcSMatt Macy /*
2*eda14cbcSMatt Macy  * This file is part of the ZFS Event Daemon (ZED)
3*eda14cbcSMatt Macy  * for ZFS on Linux (ZoL) <http://zfsonlinux.org/>.
4*eda14cbcSMatt Macy  * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
5*eda14cbcSMatt Macy  * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
6*eda14cbcSMatt Macy  * Refer to the ZoL git commit log for authoritative copyright attribution.
7*eda14cbcSMatt Macy  *
8*eda14cbcSMatt Macy  * The contents of this file are subject to the terms of the
9*eda14cbcSMatt Macy  * Common Development and Distribution License Version 1.0 (CDDL-1.0).
10*eda14cbcSMatt Macy  * You can obtain a copy of the license from the top-level file
11*eda14cbcSMatt Macy  * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
12*eda14cbcSMatt Macy  * You may not use this file except in compliance with the license.
13*eda14cbcSMatt Macy  */
14*eda14cbcSMatt Macy 
15*eda14cbcSMatt Macy #include <assert.h>
16*eda14cbcSMatt Macy #include <errno.h>
17*eda14cbcSMatt Macy #include <stddef.h>
18*eda14cbcSMatt Macy #include <stdlib.h>
19*eda14cbcSMatt Macy #include <string.h>
20*eda14cbcSMatt Macy #include <sys/avl.h>
21*eda14cbcSMatt Macy #include <sys/sysmacros.h>
22*eda14cbcSMatt Macy #include "zed_strings.h"
23*eda14cbcSMatt Macy 
24*eda14cbcSMatt Macy struct zed_strings {
25*eda14cbcSMatt Macy 	avl_tree_t tree;
26*eda14cbcSMatt Macy 	avl_node_t *iteratorp;
27*eda14cbcSMatt Macy };
28*eda14cbcSMatt Macy 
29*eda14cbcSMatt Macy struct zed_strings_node {
30*eda14cbcSMatt Macy 	avl_node_t node;
31*eda14cbcSMatt Macy 	char *key;
32*eda14cbcSMatt Macy 	char *val;
33*eda14cbcSMatt Macy };
34*eda14cbcSMatt Macy 
35*eda14cbcSMatt Macy typedef struct zed_strings_node zed_strings_node_t;
36*eda14cbcSMatt Macy 
37*eda14cbcSMatt Macy /*
38*eda14cbcSMatt Macy  * Compare zed_strings_node_t nodes [x1] and [x2].
39*eda14cbcSMatt Macy  * As required for the AVL tree, return -1 for <, 0 for ==, and +1 for >.
40*eda14cbcSMatt Macy  */
41*eda14cbcSMatt Macy static int
42*eda14cbcSMatt Macy _zed_strings_node_compare(const void *x1, const void *x2)
43*eda14cbcSMatt Macy {
44*eda14cbcSMatt Macy 	const char *s1;
45*eda14cbcSMatt Macy 	const char *s2;
46*eda14cbcSMatt Macy 	int rv;
47*eda14cbcSMatt Macy 
48*eda14cbcSMatt Macy 	assert(x1 != NULL);
49*eda14cbcSMatt Macy 	assert(x2 != NULL);
50*eda14cbcSMatt Macy 
51*eda14cbcSMatt Macy 	s1 = ((const zed_strings_node_t *) x1)->key;
52*eda14cbcSMatt Macy 	assert(s1 != NULL);
53*eda14cbcSMatt Macy 	s2 = ((const zed_strings_node_t *) x2)->key;
54*eda14cbcSMatt Macy 	assert(s2 != NULL);
55*eda14cbcSMatt Macy 	rv = strcmp(s1, s2);
56*eda14cbcSMatt Macy 
57*eda14cbcSMatt Macy 	if (rv < 0)
58*eda14cbcSMatt Macy 		return (-1);
59*eda14cbcSMatt Macy 
60*eda14cbcSMatt Macy 	if (rv > 0)
61*eda14cbcSMatt Macy 		return (1);
62*eda14cbcSMatt Macy 
63*eda14cbcSMatt Macy 	return (0);
64*eda14cbcSMatt Macy }
65*eda14cbcSMatt Macy 
66*eda14cbcSMatt Macy /*
67*eda14cbcSMatt Macy  * Return a new string container, or NULL on error.
68*eda14cbcSMatt Macy  */
69*eda14cbcSMatt Macy zed_strings_t *
70*eda14cbcSMatt Macy zed_strings_create(void)
71*eda14cbcSMatt Macy {
72*eda14cbcSMatt Macy 	zed_strings_t *zsp;
73*eda14cbcSMatt Macy 
74*eda14cbcSMatt Macy 	zsp = calloc(1, sizeof (*zsp));
75*eda14cbcSMatt Macy 	if (!zsp)
76*eda14cbcSMatt Macy 		return (NULL);
77*eda14cbcSMatt Macy 
78*eda14cbcSMatt Macy 	avl_create(&zsp->tree, _zed_strings_node_compare,
79*eda14cbcSMatt Macy 	    sizeof (zed_strings_node_t), offsetof(zed_strings_node_t, node));
80*eda14cbcSMatt Macy 
81*eda14cbcSMatt Macy 	zsp->iteratorp = NULL;
82*eda14cbcSMatt Macy 	return (zsp);
83*eda14cbcSMatt Macy }
84*eda14cbcSMatt Macy 
85*eda14cbcSMatt Macy /*
86*eda14cbcSMatt Macy  * Destroy the string node [np].
87*eda14cbcSMatt Macy  */
88*eda14cbcSMatt Macy static void
89*eda14cbcSMatt Macy _zed_strings_node_destroy(zed_strings_node_t *np)
90*eda14cbcSMatt Macy {
91*eda14cbcSMatt Macy 	if (!np)
92*eda14cbcSMatt Macy 		return;
93*eda14cbcSMatt Macy 
94*eda14cbcSMatt Macy 	if (np->key) {
95*eda14cbcSMatt Macy 		if (np->key != np->val)
96*eda14cbcSMatt Macy 			free(np->key);
97*eda14cbcSMatt Macy 		np->key = NULL;
98*eda14cbcSMatt Macy 	}
99*eda14cbcSMatt Macy 	if (np->val) {
100*eda14cbcSMatt Macy 		free(np->val);
101*eda14cbcSMatt Macy 		np->val = NULL;
102*eda14cbcSMatt Macy 	}
103*eda14cbcSMatt Macy 	free(np);
104*eda14cbcSMatt Macy }
105*eda14cbcSMatt Macy 
106*eda14cbcSMatt Macy /*
107*eda14cbcSMatt Macy  * Return a new string node for storing the string [val], or NULL on error.
108*eda14cbcSMatt Macy  * If [key] is specified, it will be used to index the node; otherwise,
109*eda14cbcSMatt Macy  * the string [val] will be used.
110*eda14cbcSMatt Macy  */
111*eda14cbcSMatt Macy static zed_strings_node_t *
112*eda14cbcSMatt Macy _zed_strings_node_create(const char *key, const char *val)
113*eda14cbcSMatt Macy {
114*eda14cbcSMatt Macy 	zed_strings_node_t *np;
115*eda14cbcSMatt Macy 
116*eda14cbcSMatt Macy 	assert(val != NULL);
117*eda14cbcSMatt Macy 
118*eda14cbcSMatt Macy 	np = calloc(1, sizeof (*np));
119*eda14cbcSMatt Macy 	if (!np)
120*eda14cbcSMatt Macy 		return (NULL);
121*eda14cbcSMatt Macy 
122*eda14cbcSMatt Macy 	np->val = strdup(val);
123*eda14cbcSMatt Macy 	if (!np->val)
124*eda14cbcSMatt Macy 		goto nomem;
125*eda14cbcSMatt Macy 
126*eda14cbcSMatt Macy 	if (key) {
127*eda14cbcSMatt Macy 		np->key = strdup(key);
128*eda14cbcSMatt Macy 		if (!np->key)
129*eda14cbcSMatt Macy 			goto nomem;
130*eda14cbcSMatt Macy 	} else {
131*eda14cbcSMatt Macy 		np->key = np->val;
132*eda14cbcSMatt Macy 	}
133*eda14cbcSMatt Macy 	return (np);
134*eda14cbcSMatt Macy 
135*eda14cbcSMatt Macy nomem:
136*eda14cbcSMatt Macy 	_zed_strings_node_destroy(np);
137*eda14cbcSMatt Macy 	return (NULL);
138*eda14cbcSMatt Macy }
139*eda14cbcSMatt Macy 
140*eda14cbcSMatt Macy /*
141*eda14cbcSMatt Macy  * Destroy the string container [zsp] and all nodes within.
142*eda14cbcSMatt Macy  */
143*eda14cbcSMatt Macy void
144*eda14cbcSMatt Macy zed_strings_destroy(zed_strings_t *zsp)
145*eda14cbcSMatt Macy {
146*eda14cbcSMatt Macy 	void *cookie;
147*eda14cbcSMatt Macy 	zed_strings_node_t *np;
148*eda14cbcSMatt Macy 
149*eda14cbcSMatt Macy 	if (!zsp)
150*eda14cbcSMatt Macy 		return;
151*eda14cbcSMatt Macy 
152*eda14cbcSMatt Macy 	cookie = NULL;
153*eda14cbcSMatt Macy 	while ((np = avl_destroy_nodes(&zsp->tree, &cookie)))
154*eda14cbcSMatt Macy 		_zed_strings_node_destroy(np);
155*eda14cbcSMatt Macy 
156*eda14cbcSMatt Macy 	avl_destroy(&zsp->tree);
157*eda14cbcSMatt Macy 	free(zsp);
158*eda14cbcSMatt Macy }
159*eda14cbcSMatt Macy 
160*eda14cbcSMatt Macy /*
161*eda14cbcSMatt Macy  * Add a copy of the string [s] indexed by [key] to the container [zsp].
162*eda14cbcSMatt Macy  * If [key] already exists within the container [zsp], it will be replaced
163*eda14cbcSMatt Macy  * with the new string [s].
164*eda14cbcSMatt Macy  * If [key] is NULL, the string [s] will be used as the key.
165*eda14cbcSMatt Macy  * Return 0 on success, or -1 on error.
166*eda14cbcSMatt Macy  */
167*eda14cbcSMatt Macy int
168*eda14cbcSMatt Macy zed_strings_add(zed_strings_t *zsp, const char *key, const char *s)
169*eda14cbcSMatt Macy {
170*eda14cbcSMatt Macy 	zed_strings_node_t *newp, *oldp;
171*eda14cbcSMatt Macy 
172*eda14cbcSMatt Macy 	if (!zsp || !s) {
173*eda14cbcSMatt Macy 		errno = EINVAL;
174*eda14cbcSMatt Macy 		return (-1);
175*eda14cbcSMatt Macy 	}
176*eda14cbcSMatt Macy 	if (key == s)
177*eda14cbcSMatt Macy 		key = NULL;
178*eda14cbcSMatt Macy 
179*eda14cbcSMatt Macy 	newp = _zed_strings_node_create(key, s);
180*eda14cbcSMatt Macy 	if (!newp)
181*eda14cbcSMatt Macy 		return (-1);
182*eda14cbcSMatt Macy 
183*eda14cbcSMatt Macy 	oldp = avl_find(&zsp->tree, newp, NULL);
184*eda14cbcSMatt Macy 	if (oldp) {
185*eda14cbcSMatt Macy 		avl_remove(&zsp->tree, oldp);
186*eda14cbcSMatt Macy 		_zed_strings_node_destroy(oldp);
187*eda14cbcSMatt Macy 	}
188*eda14cbcSMatt Macy 	avl_add(&zsp->tree, newp);
189*eda14cbcSMatt Macy 	return (0);
190*eda14cbcSMatt Macy }
191*eda14cbcSMatt Macy 
192*eda14cbcSMatt Macy /*
193*eda14cbcSMatt Macy  * Return the first string in container [zsp].
194*eda14cbcSMatt Macy  * Return NULL if there are no strings, or on error.
195*eda14cbcSMatt Macy  * This can be called multiple times to re-traverse [zsp].
196*eda14cbcSMatt Macy  * XXX: Not thread-safe.
197*eda14cbcSMatt Macy  */
198*eda14cbcSMatt Macy const char *
199*eda14cbcSMatt Macy zed_strings_first(zed_strings_t *zsp)
200*eda14cbcSMatt Macy {
201*eda14cbcSMatt Macy 	if (!zsp) {
202*eda14cbcSMatt Macy 		errno = EINVAL;
203*eda14cbcSMatt Macy 		return (NULL);
204*eda14cbcSMatt Macy 	}
205*eda14cbcSMatt Macy 	zsp->iteratorp = avl_first(&zsp->tree);
206*eda14cbcSMatt Macy 	if (!zsp->iteratorp)
207*eda14cbcSMatt Macy 		return (NULL);
208*eda14cbcSMatt Macy 
209*eda14cbcSMatt Macy 	return (((zed_strings_node_t *)zsp->iteratorp)->val);
210*eda14cbcSMatt Macy 
211*eda14cbcSMatt Macy }
212*eda14cbcSMatt Macy 
213*eda14cbcSMatt Macy /*
214*eda14cbcSMatt Macy  * Return the next string in container [zsp].
215*eda14cbcSMatt Macy  * Return NULL after the last string, or on error.
216*eda14cbcSMatt Macy  * This must be called after zed_strings_first().
217*eda14cbcSMatt Macy  * XXX: Not thread-safe.
218*eda14cbcSMatt Macy  */
219*eda14cbcSMatt Macy const char *
220*eda14cbcSMatt Macy zed_strings_next(zed_strings_t *zsp)
221*eda14cbcSMatt Macy {
222*eda14cbcSMatt Macy 	if (!zsp) {
223*eda14cbcSMatt Macy 		errno = EINVAL;
224*eda14cbcSMatt Macy 		return (NULL);
225*eda14cbcSMatt Macy 	}
226*eda14cbcSMatt Macy 	if (!zsp->iteratorp)
227*eda14cbcSMatt Macy 		return (NULL);
228*eda14cbcSMatt Macy 
229*eda14cbcSMatt Macy 	zsp->iteratorp = AVL_NEXT(&zsp->tree, zsp->iteratorp);
230*eda14cbcSMatt Macy 	if (!zsp->iteratorp)
231*eda14cbcSMatt Macy 		return (NULL);
232*eda14cbcSMatt Macy 
233*eda14cbcSMatt Macy 	return (((zed_strings_node_t *)zsp->iteratorp)->val);
234*eda14cbcSMatt Macy }
235*eda14cbcSMatt Macy 
236*eda14cbcSMatt Macy /*
237*eda14cbcSMatt Macy  * Return the number of strings in container [zsp], or -1 on error.
238*eda14cbcSMatt Macy  */
239*eda14cbcSMatt Macy int
240*eda14cbcSMatt Macy zed_strings_count(zed_strings_t *zsp)
241*eda14cbcSMatt Macy {
242*eda14cbcSMatt Macy 	if (!zsp) {
243*eda14cbcSMatt Macy 		errno = EINVAL;
244*eda14cbcSMatt Macy 		return (-1);
245*eda14cbcSMatt Macy 	}
246*eda14cbcSMatt Macy 	return (avl_numnodes(&zsp->tree));
247*eda14cbcSMatt Macy }
248