1 /* 2 * This file is part of the ZFS Event Daemon (ZED). 3 * 4 * Developed at Lawrence Livermore National Laboratory (LLNL-CODE-403049). 5 * Copyright (C) 2013-2014 Lawrence Livermore National Security, LLC. 6 * Refer to the ZoL git commit log for authoritative copyright attribution. 7 * 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. 13 */ 14 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" 23 24 struct zed_strings { 25 avl_tree_t tree; 26 avl_node_t *iteratorp; 27 }; 28 29 struct zed_strings_node { 30 avl_node_t node; 31 char *key; 32 char *val; 33 }; 34 35 typedef struct zed_strings_node zed_strings_node_t; 36 37 /* 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 >. 40 */ 41 static int 42 _zed_strings_node_compare(const void *x1, const void *x2) 43 { 44 const char *s1; 45 const char *s2; 46 int rv; 47 48 assert(x1 != NULL); 49 assert(x2 != NULL); 50 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); 56 57 if (rv < 0) 58 return (-1); 59 60 if (rv > 0) 61 return (1); 62 63 return (0); 64 } 65 66 /* 67 * Return a new string container, or NULL on error. 68 */ 69 zed_strings_t * 70 zed_strings_create(void) 71 { 72 zed_strings_t *zsp; 73 74 zsp = calloc(1, sizeof (*zsp)); 75 if (!zsp) 76 return (NULL); 77 78 avl_create(&zsp->tree, _zed_strings_node_compare, 79 sizeof (zed_strings_node_t), offsetof(zed_strings_node_t, node)); 80 81 zsp->iteratorp = NULL; 82 return (zsp); 83 } 84 85 /* 86 * Destroy the string node [np]. 87 */ 88 static void 89 _zed_strings_node_destroy(zed_strings_node_t *np) 90 { 91 if (!np) 92 return; 93 94 if (np->key) { 95 if (np->key != np->val) 96 free(np->key); 97 np->key = NULL; 98 } 99 if (np->val) { 100 free(np->val); 101 np->val = NULL; 102 } 103 free(np); 104 } 105 106 /* 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. 110 */ 111 static zed_strings_node_t * 112 _zed_strings_node_create(const char *key, const char *val) 113 { 114 zed_strings_node_t *np; 115 116 assert(val != NULL); 117 118 np = calloc(1, sizeof (*np)); 119 if (!np) 120 return (NULL); 121 122 np->val = strdup(val); 123 if (!np->val) 124 goto nomem; 125 126 if (key) { 127 np->key = strdup(key); 128 if (!np->key) 129 goto nomem; 130 } else { 131 np->key = np->val; 132 } 133 return (np); 134 135 nomem: 136 _zed_strings_node_destroy(np); 137 return (NULL); 138 } 139 140 /* 141 * Destroy the string container [zsp] and all nodes within. 142 */ 143 void 144 zed_strings_destroy(zed_strings_t *zsp) 145 { 146 void *cookie; 147 zed_strings_node_t *np; 148 149 if (!zsp) 150 return; 151 152 cookie = NULL; 153 while ((np = avl_destroy_nodes(&zsp->tree, &cookie))) 154 _zed_strings_node_destroy(np); 155 156 avl_destroy(&zsp->tree); 157 free(zsp); 158 } 159 160 /* 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. 166 */ 167 int 168 zed_strings_add(zed_strings_t *zsp, const char *key, const char *s) 169 { 170 zed_strings_node_t *newp, *oldp; 171 172 if (!zsp || !s) { 173 errno = EINVAL; 174 return (-1); 175 } 176 if (key == s) 177 key = NULL; 178 179 newp = _zed_strings_node_create(key, s); 180 if (!newp) 181 return (-1); 182 183 oldp = avl_find(&zsp->tree, newp, NULL); 184 if (oldp) { 185 avl_remove(&zsp->tree, oldp); 186 _zed_strings_node_destroy(oldp); 187 } 188 avl_add(&zsp->tree, newp); 189 return (0); 190 } 191 192 /* 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. 197 */ 198 const char * 199 zed_strings_first(zed_strings_t *zsp) 200 { 201 if (!zsp) { 202 errno = EINVAL; 203 return (NULL); 204 } 205 zsp->iteratorp = avl_first(&zsp->tree); 206 if (!zsp->iteratorp) 207 return (NULL); 208 209 return (((zed_strings_node_t *)zsp->iteratorp)->val); 210 211 } 212 213 /* 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. 218 */ 219 const char * 220 zed_strings_next(zed_strings_t *zsp) 221 { 222 if (!zsp) { 223 errno = EINVAL; 224 return (NULL); 225 } 226 if (!zsp->iteratorp) 227 return (NULL); 228 229 zsp->iteratorp = AVL_NEXT(&zsp->tree, zsp->iteratorp); 230 if (!zsp->iteratorp) 231 return (NULL); 232 233 return (((zed_strings_node_t *)zsp->iteratorp)->val); 234 } 235 236 /* 237 * Return the number of strings in container [zsp], or -1 on error. 238 */ 239 int 240 zed_strings_count(zed_strings_t *zsp) 241 { 242 if (!zsp) { 243 errno = EINVAL; 244 return (-1); 245 } 246 return (avl_numnodes(&zsp->tree)); 247 } 248