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