Optimize RAIDZ expansion
[zfs.git] / cmd / zed / zed_strings.c
blob52a86e9296fe56cdc7852333ea6223cbae114140
1 /*
2 * This file is part of the ZFS Event Daemon (ZED).
4 * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049).
5 * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC.
6 * Refer to the OpenZFS git commit log for authoritative copyright attribution.
8 * The contents of this file are subject to the terms of the
9 * Common Development and Distribution License Version 1.0 (CDDL-1.0).
10 * You can obtain a copy of the license from the top-level file
11 * "OPENSOLARIS.LICENSE" or at <http://opensource.org/licenses/CDDL-1.0>.
12 * You may not use this file except in compliance with the license.
15 #include <assert.h>
16 #include <errno.h>
17 #include <stddef.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <sys/avl.h>
21 #include <sys/sysmacros.h>
22 #include "zed_strings.h"
24 struct zed_strings {
25 avl_tree_t tree;
26 avl_node_t *iteratorp;
29 struct zed_strings_node {
30 avl_node_t node;
31 char *key;
32 char *val;
35 typedef struct zed_strings_node zed_strings_node_t;
38 * Compare zed_strings_node_t nodes [x1] and [x2].
39 * As required for the AVL tree, return -1 for <, 0 for ==, and +1 for >.
41 static int
42 _zed_strings_node_compare(const void *x1, const void *x2)
44 const char *s1;
45 const char *s2;
46 int rv;
48 assert(x1 != NULL);
49 assert(x2 != NULL);
51 s1 = ((const zed_strings_node_t *) x1)->key;
52 assert(s1 != NULL);
53 s2 = ((const zed_strings_node_t *) x2)->key;
54 assert(s2 != NULL);
55 rv = strcmp(s1, s2);
57 if (rv < 0)
58 return (-1);
60 if (rv > 0)
61 return (1);
63 return (0);
67 * Return a new string container, or NULL on error.
69 zed_strings_t *
70 zed_strings_create(void)
72 zed_strings_t *zsp;
74 zsp = calloc(1, sizeof (*zsp));
75 if (!zsp)
76 return (NULL);
78 avl_create(&zsp->tree, _zed_strings_node_compare,
79 sizeof (zed_strings_node_t), offsetof(zed_strings_node_t, node));
81 zsp->iteratorp = NULL;
82 return (zsp);
86 * Destroy the string node [np].
88 static void
89 _zed_strings_node_destroy(zed_strings_node_t *np)
91 if (!np)
92 return;
94 if (np->key) {
95 if (np->key != np->val)
96 free(np->key);
97 np->key = NULL;
99 if (np->val) {
100 free(np->val);
101 np->val = NULL;
103 free(np);
107 * Return a new string node for storing the string [val], or NULL on error.
108 * If [key] is specified, it will be used to index the node; otherwise,
109 * the string [val] will be used.
111 static zed_strings_node_t *
112 _zed_strings_node_create(const char *key, const char *val)
114 zed_strings_node_t *np;
116 assert(val != NULL);
118 np = calloc(1, sizeof (*np));
119 if (!np)
120 return (NULL);
122 np->val = strdup(val);
123 if (!np->val)
124 goto nomem;
126 if (key) {
127 np->key = strdup(key);
128 if (!np->key)
129 goto nomem;
130 } else {
131 np->key = np->val;
133 return (np);
135 nomem:
136 _zed_strings_node_destroy(np);
137 return (NULL);
141 * Destroy the string container [zsp] and all nodes within.
143 void
144 zed_strings_destroy(zed_strings_t *zsp)
146 void *cookie;
147 zed_strings_node_t *np;
149 if (!zsp)
150 return;
152 cookie = NULL;
153 while ((np = avl_destroy_nodes(&zsp->tree, &cookie)))
154 _zed_strings_node_destroy(np);
156 avl_destroy(&zsp->tree);
157 free(zsp);
161 * Add a copy of the string [s] indexed by [key] to the container [zsp].
162 * If [key] already exists within the container [zsp], it will be replaced
163 * with the new string [s].
164 * If [key] is NULL, the string [s] will be used as the key.
165 * Return 0 on success, or -1 on error.
168 zed_strings_add(zed_strings_t *zsp, const char *key, const char *s)
170 zed_strings_node_t *newp, *oldp;
172 if (!zsp || !s) {
173 errno = EINVAL;
174 return (-1);
176 if (key == s)
177 key = NULL;
179 newp = _zed_strings_node_create(key, s);
180 if (!newp)
181 return (-1);
183 oldp = avl_find(&zsp->tree, newp, NULL);
184 if (oldp) {
185 avl_remove(&zsp->tree, oldp);
186 _zed_strings_node_destroy(oldp);
188 avl_add(&zsp->tree, newp);
189 return (0);
193 * Return the first string in container [zsp].
194 * Return NULL if there are no strings, or on error.
195 * This can be called multiple times to re-traverse [zsp].
196 * XXX: Not thread-safe.
198 const char *
199 zed_strings_first(zed_strings_t *zsp)
201 if (!zsp) {
202 errno = EINVAL;
203 return (NULL);
205 zsp->iteratorp = avl_first(&zsp->tree);
206 if (!zsp->iteratorp)
207 return (NULL);
209 return (((zed_strings_node_t *)zsp->iteratorp)->val);
214 * Return the next string in container [zsp].
215 * Return NULL after the last string, or on error.
216 * This must be called after zed_strings_first().
217 * XXX: Not thread-safe.
219 const char *
220 zed_strings_next(zed_strings_t *zsp)
222 if (!zsp) {
223 errno = EINVAL;
224 return (NULL);
226 if (!zsp->iteratorp)
227 return (NULL);
229 zsp->iteratorp = AVL_NEXT(&zsp->tree, zsp->iteratorp);
230 if (!zsp->iteratorp)
231 return (NULL);
233 return (((zed_strings_node_t *)zsp->iteratorp)->val);
237 * Return the number of strings in container [zsp], or -1 on error.
240 zed_strings_count(zed_strings_t *zsp)
242 if (!zsp) {
243 errno = EINVAL;
244 return (-1);
246 return (avl_numnodes(&zsp->tree));