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