Path: blob/main/sys/contrib/openzfs/cmd/zed/zed_strings.c
48380 views
// SPDX-License-Identifier: CDDL-1.01/*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 OpenZFS git commit log for authoritative copyright attribution.7*8* The contents of this file are subject to the terms of the9* Common Development and Distribution License Version 1.0 (CDDL-1.0).10* You can obtain a copy of the license from the top-level file11* "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*/1415#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"2324struct zed_strings {25avl_tree_t tree;26avl_node_t *iteratorp;27};2829struct zed_strings_node {30avl_node_t node;31char *key;32char *val;33};3435typedef struct zed_strings_node zed_strings_node_t;3637/*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*/41static int42_zed_strings_node_compare(const void *x1, const void *x2)43{44const char *s1;45const char *s2;46int rv;4748assert(x1 != NULL);49assert(x2 != NULL);5051s1 = ((const zed_strings_node_t *) x1)->key;52assert(s1 != NULL);53s2 = ((const zed_strings_node_t *) x2)->key;54assert(s2 != NULL);55rv = strcmp(s1, s2);5657if (rv < 0)58return (-1);5960if (rv > 0)61return (1);6263return (0);64}6566/*67* Return a new string container, or NULL on error.68*/69zed_strings_t *70zed_strings_create(void)71{72zed_strings_t *zsp;7374zsp = calloc(1, sizeof (*zsp));75if (!zsp)76return (NULL);7778avl_create(&zsp->tree, _zed_strings_node_compare,79sizeof (zed_strings_node_t), offsetof(zed_strings_node_t, node));8081zsp->iteratorp = NULL;82return (zsp);83}8485/*86* Destroy the string node [np].87*/88static void89_zed_strings_node_destroy(zed_strings_node_t *np)90{91if (!np)92return;9394if (np->key) {95if (np->key != np->val)96free(np->key);97np->key = NULL;98}99if (np->val) {100free(np->val);101np->val = NULL;102}103free(np);104}105106/*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*/111static zed_strings_node_t *112_zed_strings_node_create(const char *key, const char *val)113{114zed_strings_node_t *np;115116assert(val != NULL);117118np = calloc(1, sizeof (*np));119if (!np)120return (NULL);121122np->val = strdup(val);123if (!np->val)124goto nomem;125126if (key) {127np->key = strdup(key);128if (!np->key)129goto nomem;130} else {131np->key = np->val;132}133return (np);134135nomem:136_zed_strings_node_destroy(np);137return (NULL);138}139140/*141* Destroy the string container [zsp] and all nodes within.142*/143void144zed_strings_destroy(zed_strings_t *zsp)145{146void *cookie;147zed_strings_node_t *np;148149if (!zsp)150return;151152cookie = NULL;153while ((np = avl_destroy_nodes(&zsp->tree, &cookie)))154_zed_strings_node_destroy(np);155156avl_destroy(&zsp->tree);157free(zsp);158}159160/*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 replaced163* 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*/167int168zed_strings_add(zed_strings_t *zsp, const char *key, const char *s)169{170zed_strings_node_t *newp, *oldp;171172if (!zsp || !s) {173errno = EINVAL;174return (-1);175}176if (key == s)177key = NULL;178179newp = _zed_strings_node_create(key, s);180if (!newp)181return (-1);182183oldp = avl_find(&zsp->tree, newp, NULL);184if (oldp) {185avl_remove(&zsp->tree, oldp);186_zed_strings_node_destroy(oldp);187}188avl_add(&zsp->tree, newp);189return (0);190}191192/*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*/198const char *199zed_strings_first(zed_strings_t *zsp)200{201if (!zsp) {202errno = EINVAL;203return (NULL);204}205zsp->iteratorp = avl_first(&zsp->tree);206if (!zsp->iteratorp)207return (NULL);208209return (((zed_strings_node_t *)zsp->iteratorp)->val);210211}212213/*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*/219const char *220zed_strings_next(zed_strings_t *zsp)221{222if (!zsp) {223errno = EINVAL;224return (NULL);225}226if (!zsp->iteratorp)227return (NULL);228229zsp->iteratorp = AVL_NEXT(&zsp->tree, zsp->iteratorp);230if (!zsp->iteratorp)231return (NULL);232233return (((zed_strings_node_t *)zsp->iteratorp)->val);234}235236/*237* Return the number of strings in container [zsp], or -1 on error.238*/239int240zed_strings_count(zed_strings_t *zsp)241{242if (!zsp) {243errno = EINVAL;244return (-1);245}246return (avl_numnodes(&zsp->tree));247}248249250