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