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