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