Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/openzfs/cmd/zed/zed_strings.c
48380 views
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
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 *
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
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 *
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
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
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 *
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 *
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
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
250