aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/zed
diff options
context:
space:
mode:
authorChris Dunlap <[email protected]>2014-10-19 12:05:07 -0700
committerBrian Behlendorf <[email protected]>2015-01-30 14:46:17 -0800
commit854f30a91fc6a2accc6bf49cb7fcc52b498fda2a (patch)
tree6aa05457e95928a24ce390d445a2c14997f92073 /cmd/zed
parent0365064a9726f6bb6e148611a6e42fa80302d083 (diff)
Protect against adding duplicate strings in ZED
The zed_strings container stores strings in an AVL, but does not check for duplicate strings being added. Within the AVL, strings are indexed by the string value itself. avl_add() requires the node being added must not already exist in the tree, and will assert() if this is not the case. This should not cause problems in practice. ZED uses this container in two places. In zed_conf.c, it is used to store the names of enabled zedlets as zed scans the zedlet directory listing; duplicate entries cannot occur here since duplicate names cannot occur within a directory. In zed_event.c, it is used to store the environment variables (as "NAME=VALUE" strings) that will be passed to zedlets; duplicate strings here should never happen unless there is a bug resulting in a duplicate nvpair or environment variable. This commit protects against adding a duplicate to a zed_strings container by first checking for the string being added, and removing the previous entry should one exist. This implements a "last one wins" policy. This commit also changes the prototype for zed_strings_add() to allow the string key (by which it is indexed in the AVL) to differ from the string value. By adding zedlet environment variables using the variable name as the key, multiple adds for the same variable name will result in only the last value being stored. Finally, this commit routes all additions of zedlet environment variables through the updated _zed_event_add_var(). This ensures all zedlet environment variable names are properly converted. Signed-off-by: Chris Dunlap <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #3042
Diffstat (limited to 'cmd/zed')
-rw-r--r--cmd/zed/zed_conf.c2
-rw-r--r--cmd/zed/zed_event.c291
-rw-r--r--cmd/zed/zed_strings.c99
-rw-r--r--cmd/zed/zed_strings.h2
4 files changed, 243 insertions, 151 deletions
diff --git a/cmd/zed/zed_conf.c b/cmd/zed/zed_conf.c
index 638f728e1..61529bd8f 100644
--- a/cmd/zed/zed_conf.c
+++ b/cmd/zed/zed_conf.c
@@ -419,7 +419,7 @@ zed_conf_scan_dir(struct zed_conf *zcp)
direntp->d_name);
continue;
}
- if (zed_strings_add(zedlets, direntp->d_name) < 0) {
+ if (zed_strings_add(zedlets, NULL, direntp->d_name) < 0) {
zed_log_msg(LOG_WARNING,
"Failed to register \"%s\": %s",
direntp->d_name, strerror(errno));
diff --git a/cmd/zed/zed_event.c b/cmd/zed/zed_event.c
index f3f201800..6f6c5ba42 100644
--- a/cmd/zed/zed_event.c
+++ b/cmd/zed/zed_event.c
@@ -43,6 +43,8 @@
#include "zed_log.h"
#include "zed_strings.h"
+#define MAXBUF 4096
+
/*
* Open the libzfs interface.
*/
@@ -427,6 +429,103 @@ _zed_event_value_is_hex(const char *name)
}
/*
+ * Add an environment variable for [eid] to the container [zsp].
+ *
+ * The variable name is the concatenation of [prefix] and [name] converted to
+ * uppercase with non-alphanumeric characters converted to underscores;
+ * [prefix] is optional, and [name] must begin with an alphabetic character.
+ * If the converted variable name already exists within the container [zsp],
+ * its existing value will be replaced with the new value.
+ *
+ * The variable value is specified by the format string [fmt].
+ *
+ * Returns 0 on success, and -1 on error (with errno set).
+ *
+ * All environment variables in [zsp] should be added through this function.
+ */
+static int
+_zed_event_add_var(uint64_t eid, zed_strings_t *zsp,
+ const char *prefix, const char *name, const char *fmt, ...)
+{
+ char keybuf[MAXBUF];
+ char valbuf[MAXBUF];
+ char *dstp;
+ const char *srcp;
+ const char *lastp;
+ int n;
+ int buflen;
+ va_list vargs;
+
+ assert(zsp != NULL);
+ assert(fmt != NULL);
+
+ if (!name) {
+ errno = EINVAL;
+ zed_log_msg(LOG_WARNING,
+ "Failed to add variable for eid=%llu: Name is empty", eid);
+ return (-1);
+ } else if (!isalpha(name[0])) {
+ errno = EINVAL;
+ zed_log_msg(LOG_WARNING,
+ "Failed to add variable for eid=%llu: "
+ "Name \"%s\" is invalid", eid, name);
+ return (-1);
+ }
+ /*
+ * Construct the string key by converting PREFIX (if present) and NAME.
+ */
+ dstp = keybuf;
+ lastp = keybuf + sizeof (keybuf);
+ if (prefix) {
+ for (srcp = prefix; *srcp && (dstp < lastp); srcp++)
+ *dstp++ = isalnum(*srcp) ? toupper(*srcp) : '_';
+ }
+ for (srcp = name; *srcp && (dstp < lastp); srcp++)
+ *dstp++ = isalnum(*srcp) ? toupper(*srcp) : '_';
+
+ if (dstp == lastp) {
+ errno = ENAMETOOLONG;
+ zed_log_msg(LOG_WARNING,
+ "Failed to add variable for eid=%llu: Name too long", eid);
+ return (-1);
+ }
+ *dstp = '\0';
+ /*
+ * Construct the string specified by "[PREFIX][NAME]=[FMT]".
+ */
+ dstp = valbuf;
+ buflen = sizeof (valbuf);
+ n = strlcpy(dstp, keybuf, buflen);
+ if (n >= sizeof (valbuf)) {
+ errno = EMSGSIZE;
+ zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
+ keybuf, eid, "Exceeded buffer size");
+ return (-1);
+ }
+ dstp += n;
+ buflen -= n;
+
+ *dstp++ = '=';
+ buflen--;
+
+ va_start(vargs, fmt);
+ n = vsnprintf(dstp, buflen, fmt, vargs);
+ va_end(vargs);
+
+ if ((n < 0) || (n >= buflen)) {
+ errno = EMSGSIZE;
+ zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
+ keybuf, eid, "Exceeded buffer size");
+ return (-1);
+ } else if (zed_strings_add(zsp, keybuf, valbuf) < 0) {
+ zed_log_msg(LOG_WARNING, "Failed to add %s for eid=%llu: %s",
+ keybuf, eid, strerror(errno));
+ return (-1);
+ }
+ return (0);
+}
+
+/*
* Convert the nvpair [nvp] to a string which is added to the environment
* of the child process.
* Return 0 on success, -1 on error.
@@ -438,11 +537,8 @@ _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
{
const char *name;
data_type_t type;
- char buf[4096];
- int buflen;
+ char buf[MAXBUF];
int n;
- char *p;
- const char *q;
const char *fmt;
boolean_t b;
@@ -458,133 +554,108 @@ _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
name = nvpair_name(nvp);
type = nvpair_type(nvp);
- buflen = sizeof (buf);
- /* Copy NAME prefix for ZED zevent namespace. */
- n = strlcpy(buf, ZEVENT_VAR_PREFIX, sizeof (buf));
- if (n >= sizeof (buf)) {
- zed_log_msg(LOG_WARNING,
- "Failed to convert nvpair \"%s\" for eid=%llu: %s",
- name, eid, "Exceeded buffer size");
- return;
- }
- buflen -= n;
- p = buf + n;
-
- /* Convert NAME to alphanumeric uppercase. */
- for (q = name; *q && (buflen > 0); q++) {
- *p++ = isalnum(*q) ? toupper(*q) : '_';
- buflen--;
- }
-
- /* Separate NAME from VALUE. */
- if (buflen > 0) {
- *p++ = '=';
- buflen--;
- }
- *p = '\0';
-
- /* Convert VALUE. */
switch (type) {
case DATA_TYPE_BOOLEAN:
- n = snprintf(p, buflen, "%s", "1");
+ n = snprintf(buf, sizeof (buf), "%s", "1");
break;
case DATA_TYPE_BOOLEAN_VALUE:
(void) nvpair_value_boolean_value(nvp, &b);
- n = snprintf(p, buflen, "%s", b ? "1" : "0");
+ n = snprintf(buf, sizeof (buf), "%s", b ? "1" : "0");
break;
case DATA_TYPE_BYTE:
(void) nvpair_value_byte(nvp, &i8);
- n = snprintf(p, buflen, "%d", i8);
+ n = snprintf(buf, sizeof (buf), "%d", i8);
break;
case DATA_TYPE_INT8:
(void) nvpair_value_int8(nvp, (int8_t *) &i8);
- n = snprintf(p, buflen, "%d", i8);
+ n = snprintf(buf, sizeof (buf), "%d", i8);
break;
case DATA_TYPE_UINT8:
(void) nvpair_value_uint8(nvp, &i8);
- n = snprintf(p, buflen, "%u", i8);
+ n = snprintf(buf, sizeof (buf), "%u", i8);
break;
case DATA_TYPE_INT16:
(void) nvpair_value_int16(nvp, (int16_t *) &i16);
- n = snprintf(p, buflen, "%d", i16);
+ n = snprintf(buf, sizeof (buf), "%d", i16);
break;
case DATA_TYPE_UINT16:
(void) nvpair_value_uint16(nvp, &i16);
- n = snprintf(p, buflen, "%u", i16);
+ n = snprintf(buf, sizeof (buf), "%u", i16);
break;
case DATA_TYPE_INT32:
(void) nvpair_value_int32(nvp, (int32_t *) &i32);
- n = snprintf(p, buflen, "%d", i32);
+ n = snprintf(buf, sizeof (buf), "%d", i32);
break;
case DATA_TYPE_UINT32:
(void) nvpair_value_uint32(nvp, &i32);
- n = snprintf(p, buflen, "%u", i32);
+ n = snprintf(buf, sizeof (buf), "%u", i32);
break;
case DATA_TYPE_INT64:
(void) nvpair_value_int64(nvp, (int64_t *) &i64);
- n = snprintf(p, buflen, "%lld", (longlong_t) i64);
+ n = snprintf(buf, sizeof (buf), "%lld", (longlong_t) i64);
break;
case DATA_TYPE_UINT64:
(void) nvpair_value_uint64(nvp, &i64);
fmt = _zed_event_value_is_hex(name) ? "0x%.16llX" : "%llu";
- n = snprintf(p, buflen, fmt, (u_longlong_t) i64);
+ n = snprintf(buf, sizeof (buf), fmt, (u_longlong_t) i64);
break;
case DATA_TYPE_DOUBLE:
(void) nvpair_value_double(nvp, &d);
- n = snprintf(p, buflen, "%g", d);
+ n = snprintf(buf, sizeof (buf), "%g", d);
break;
case DATA_TYPE_HRTIME:
(void) nvpair_value_hrtime(nvp, (hrtime_t *) &i64);
- n = snprintf(p, buflen, "%llu", (u_longlong_t) i64);
+ n = snprintf(buf, sizeof (buf), "%llu", (u_longlong_t) i64);
break;
case DATA_TYPE_NVLIST:
/* FIXME */
- n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
+ n = snprintf(buf, sizeof (buf), "%s", "_NOT_IMPLEMENTED_");
break;
case DATA_TYPE_STRING:
(void) nvpair_value_string(nvp, &str);
- n = snprintf(p, buflen, "%s", (str ? str : "<NULL>"));
+ n = snprintf(buf, sizeof (buf), "%s", (str ? str : "<NULL>"));
break;
case DATA_TYPE_BOOLEAN_ARRAY:
/* FIXME */
- n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
+ n = snprintf(buf, sizeof (buf), "%s", "_NOT_IMPLEMENTED_");
break;
case DATA_TYPE_BYTE_ARRAY:
/* FIXME */
- n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
+ n = snprintf(buf, sizeof (buf), "%s", "_NOT_IMPLEMENTED_");
break;
case DATA_TYPE_INT8_ARRAY:
- n = _zed_event_convert_int8_array(p, buflen, nvp);
+ n = _zed_event_convert_int8_array(buf, sizeof (buf), nvp);
break;
case DATA_TYPE_UINT8_ARRAY:
- n = _zed_event_convert_uint8_array(p, buflen, nvp);
+ n = _zed_event_convert_uint8_array(buf, sizeof (buf), nvp);
break;
case DATA_TYPE_INT16_ARRAY:
- n = _zed_event_convert_int16_array(p, buflen, nvp);
+ n = _zed_event_convert_int16_array(buf, sizeof (buf), nvp);
break;
case DATA_TYPE_UINT16_ARRAY:
- n = _zed_event_convert_uint16_array(p, buflen, nvp);
+ n = _zed_event_convert_uint16_array(buf, sizeof (buf), nvp);
break;
case DATA_TYPE_INT32_ARRAY:
- n = _zed_event_convert_int32_array(p, buflen, nvp);
+ n = _zed_event_convert_int32_array(buf, sizeof (buf), nvp);
break;
case DATA_TYPE_UINT32_ARRAY:
- n = _zed_event_convert_uint32_array(p, buflen, nvp);
+ n = _zed_event_convert_uint32_array(buf, sizeof (buf), nvp);
break;
case DATA_TYPE_INT64_ARRAY:
- n = _zed_event_convert_int64_array(p, buflen, nvp);
+ n = _zed_event_convert_int64_array(buf, sizeof (buf), nvp);
break;
case DATA_TYPE_UINT64_ARRAY:
fmt = _zed_event_value_is_hex(name) ? "0x%.16llX " : "%llu ";
- n = _zed_event_convert_uint64_array(p, buflen, nvp, fmt);
+ n = _zed_event_convert_uint64_array(buf, sizeof (buf),
+ nvp, fmt);
break;
case DATA_TYPE_STRING_ARRAY:
- n = _zed_event_convert_string_array(p, buflen, nvp);
+ n = _zed_event_convert_string_array(buf, sizeof (buf), nvp);
break;
case DATA_TYPE_NVLIST_ARRAY:
/* FIXME */
- n = snprintf(p, buflen, "%s", "_NOT_IMPLEMENTED_");
+ n = snprintf(buf, sizeof (buf), "%s", "_NOT_IMPLEMENTED_");
break;
default:
zed_log_msg(LOG_WARNING,
@@ -598,45 +669,7 @@ _zed_event_add_nvpair(uint64_t eid, zed_strings_t *zsp, nvpair_t *nvp)
name, eid, "Exceeded buffer size");
return;
}
- if (zed_strings_add(zsp, buf) < 0) {
- zed_log_msg(LOG_WARNING,
- "Failed to convert nvpair \"%s\" for eid=%llu: %s",
- name, eid, strerror(ENOMEM));
- return;
- }
-}
-
-/*
- * Add the environment variable specified by the format string [fmt].
- */
-static void
-_zed_event_add_var(uint64_t eid, zed_strings_t *zsp, const char *fmt, ...)
-{
- char buf[4096];
- va_list vargs;
- int n;
- const char *p;
- size_t namelen;
-
- assert(zsp != NULL);
- assert(fmt != NULL);
-
- va_start(vargs, fmt);
- n = vsnprintf(buf, sizeof (buf), fmt, vargs);
- va_end(vargs);
- p = strchr(buf, '=');
- namelen = (p) ? p - buf : strlen(buf);
-
- if ((n < 0) || (n >= sizeof (buf))) {
- zed_log_msg(LOG_WARNING, "Failed to add %.*s for eid=%llu: %s",
- namelen, buf, eid, "Exceeded buffer size");
- } else if (!p) {
- zed_log_msg(LOG_WARNING, "Failed to add %.*s for eid=%llu: %s",
- namelen, buf, eid, "Missing assignment");
- } else if (zed_strings_add(zsp, buf) < 0) {
- zed_log_msg(LOG_WARNING, "Failed to add %.*s for eid=%llu: %s",
- namelen, buf, eid, strerror(ENOMEM));
- }
+ _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, name, "%s", buf);
}
/*
@@ -648,25 +681,25 @@ _zed_event_add_var(uint64_t eid, zed_strings_t *zsp, const char *fmt, ...)
static void
_zed_event_add_env_restrict(uint64_t eid, zed_strings_t *zsp)
{
- const char *env_restrict[] = {
- "IFS= \t\n",
- "PATH=" _PATH_STDPATH,
- "ZDB=" SBINDIR "/zdb",
- "ZED=" SBINDIR "/zed",
- "ZFS=" SBINDIR "/zfs",
- "ZINJECT=" SBINDIR "/zinject",
- "ZPOOL=" SBINDIR "/zpool",
- "ZFS_ALIAS=" ZFS_META_ALIAS,
- "ZFS_VERSION=" ZFS_META_VERSION,
- "ZFS_RELEASE=" ZFS_META_RELEASE,
- NULL
+ const char *env_restrict[][2] = {
+ { "IFS", " \t\n" },
+ { "PATH", _PATH_STDPATH },
+ { "ZDB", SBINDIR "/zdb" },
+ { "ZED", SBINDIR "/zed" },
+ { "ZFS", SBINDIR "/zfs" },
+ { "ZINJECT", SBINDIR "/zinject" },
+ { "ZPOOL", SBINDIR "/zpool" },
+ { "ZFS_ALIAS", ZFS_META_ALIAS },
+ { "ZFS_VERSION", ZFS_META_VERSION },
+ { "ZFS_RELEASE", ZFS_META_RELEASE },
+ { NULL, NULL }
};
- const char **pp;
+ const char *(*pa)[2];
assert(zsp != NULL);
- for (pp = env_restrict; *pp; pp++) {
- _zed_event_add_var(eid, zsp, "%s", *pp);
+ for (pa = env_restrict; *(*pa); pa++) {
+ _zed_event_add_var(eid, zsp, NULL, (*pa)[0], "%s", (*pa)[1]);
}
}
@@ -683,14 +716,14 @@ _zed_event_add_env_preserve(uint64_t eid, zed_strings_t *zsp)
"TZ",
NULL
};
- const char **pp;
- const char *p;
+ const char **keyp;
+ const char *val;
assert(zsp != NULL);
- for (pp = env_preserve; *pp; pp++) {
- if ((p = getenv(*pp)))
- _zed_event_add_var(eid, zsp, "%s=%s", *pp, p);
+ for (keyp = env_preserve; *keyp; keyp++) {
+ if ((val = getenv(*keyp)))
+ _zed_event_add_var(eid, zsp, NULL, *keyp, "%s", val);
}
}
@@ -735,10 +768,10 @@ _zed_event_add_time_strings(uint64_t eid, zed_strings_t *zsp, int64_t etime[])
assert(zsp != NULL);
assert(etime != NULL);
- _zed_event_add_var(eid, zsp, "%s%s=%lld",
- ZEVENT_VAR_PREFIX, "TIME_SECS", (long long int) etime[0]);
- _zed_event_add_var(eid, zsp, "%s%s=%lld",
- ZEVENT_VAR_PREFIX, "TIME_NSECS", (long long int) etime[1]);
+ _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_SECS",
+ "%lld", (long long int) etime[0]);
+ _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_NSECS",
+ "%lld", (long long int) etime[1]);
if (!(stp = localtime((const time_t *) &etime[0]))) {
zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
@@ -747,8 +780,8 @@ _zed_event_add_time_strings(uint64_t eid, zed_strings_t *zsp, int64_t etime[])
zed_log_msg(LOG_WARNING, "Failed to add %s%s for eid=%llu: %s",
ZEVENT_VAR_PREFIX, "TIME_STRING", eid, "strftime error");
} else {
- _zed_event_add_var(eid, zsp, "%s%s=%s",
- ZEVENT_VAR_PREFIX, "TIME_STRING", buf);
+ _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "TIME_STRING",
+ "%s", buf);
}
}
@@ -811,15 +844,13 @@ zed_event_service(struct zed_conf *zcp)
_zed_event_add_env_restrict(eid, zsp);
_zed_event_add_env_preserve(eid, zsp);
- _zed_event_add_var(eid, zsp, "%s%s=%d",
- ZED_VAR_PREFIX, "PID", (int) getpid());
- _zed_event_add_var(eid, zsp, "%s%s=%s",
- ZED_VAR_PREFIX, "ZEDLET_DIR", zcp->zedlet_dir);
-
+ _zed_event_add_var(eid, zsp, ZED_VAR_PREFIX, "PID",
+ "%d", (int) getpid());
+ _zed_event_add_var(eid, zsp, ZED_VAR_PREFIX, "ZEDLET_DIR",
+ "%s", zcp->zedlet_dir);
subclass = _zed_event_get_subclass(class);
- _zed_event_add_var(eid, zsp, "%s%s=%s",
- ZEVENT_VAR_PREFIX, "SUBCLASS",
- (subclass ? subclass : class));
+ _zed_event_add_var(eid, zsp, ZEVENT_VAR_PREFIX, "SUBCLASS",
+ "%s", (subclass ? subclass : class));
_zed_event_add_time_strings(eid, zsp, etime);
zed_exec_process(eid, class, subclass,
diff --git a/cmd/zed/zed_strings.c b/cmd/zed/zed_strings.c
index 8e0f58079..01736e388 100644
--- a/cmd/zed/zed_strings.c
+++ b/cmd/zed/zed_strings.c
@@ -40,7 +40,8 @@ struct zed_strings {
struct zed_strings_node {
avl_node_t node;
- char string[];
+ char *key;
+ char *val;
};
typedef struct zed_strings_node zed_strings_node_t;
@@ -59,9 +60,9 @@ _zed_strings_node_compare(const void *x1, const void *x2)
assert(x1 != NULL);
assert(x2 != NULL);
- s1 = ((const zed_strings_node_t *) x1)->string;
+ s1 = ((const zed_strings_node_t *) x1)->key;
assert(s1 != NULL);
- s2 = ((const zed_strings_node_t *) x2)->string;
+ s2 = ((const zed_strings_node_t *) x2)->key;
assert(s2 != NULL);
rv = strcmp(s1, s2);
@@ -94,7 +95,62 @@ zed_strings_create(void)
}
/*
- * Destroy the string container [zsp] and all strings within.
+ * Destroy the string node [np].
+ */
+static void
+_zed_strings_node_destroy(zed_strings_node_t *np)
+{
+ if (!np)
+ return;
+
+ if (np->key) {
+ if (np->key != np->val)
+ free(np->key);
+ np->key = NULL;
+ }
+ if (np->val) {
+ free(np->val);
+ np->val = NULL;
+ }
+ free(np);
+}
+
+/*
+ * Return a new string node for storing the string [val], or NULL on error.
+ * If [key] is specified, it will be used to index the node; otherwise,
+ * the string [val] will be used.
+ */
+zed_strings_node_t *
+_zed_strings_node_create(const char *key, const char *val)
+{
+ zed_strings_node_t *np;
+
+ assert(val != NULL);
+
+ np = calloc(1, sizeof (*np));
+ if (!np)
+ return (NULL);
+
+ np->val = strdup(val);
+ if (!np->val)
+ goto nomem;
+
+ if (key) {
+ np->key = strdup(key);
+ if (!np->key)
+ goto nomem;
+ } else {
+ np->key = np->val;
+ }
+ return (np);
+
+nomem:
+ _zed_strings_node_destroy(np);
+ return (NULL);
+}
+
+/*
+ * Destroy the string container [zsp] and all nodes within.
*/
void
zed_strings_destroy(zed_strings_t *zsp)
@@ -107,36 +163,41 @@ zed_strings_destroy(zed_strings_t *zsp)
cookie = NULL;
while ((np = avl_destroy_nodes(&zsp->tree, &cookie)))
- free(np);
+ _zed_strings_node_destroy(np);
avl_destroy(&zsp->tree);
free(zsp);
}
/*
- * Add a copy of the string [s] to the container [zsp].
+ * Add a copy of the string [s] indexed by [key] to the container [zsp].
+ * If [key] already exists within the container [zsp], it will be replaced
+ * with the new string [s].
+ * If [key] is NULL, the string [s] will be used as the key.
* Return 0 on success, or -1 on error.
- *
- * FIXME: Handle dup strings.
*/
int
-zed_strings_add(zed_strings_t *zsp, const char *s)
+zed_strings_add(zed_strings_t *zsp, const char *key, const char *s)
{
- size_t len;
- zed_strings_node_t *np;
+ zed_strings_node_t *newp, *oldp;
if (!zsp || !s) {
errno = EINVAL;
return (-1);
}
- len = sizeof (zed_strings_node_t) + strlen(s) + 1;
- np = calloc(1, len);
- if (!np)
+ if (key == s)
+ key = NULL;
+
+ newp = _zed_strings_node_create(key, s);
+ if (!newp)
return (-1);
- assert((char *) np->string + strlen(s) < (char *) np + len);
- (void) strcpy(np->string, s);
- avl_add(&zsp->tree, np);
+ oldp = avl_find(&zsp->tree, newp, NULL);
+ if (oldp) {
+ avl_remove(&zsp->tree, oldp);
+ _zed_strings_node_destroy(oldp);
+ }
+ avl_add(&zsp->tree, newp);
return (0);
}
@@ -157,7 +218,7 @@ zed_strings_first(zed_strings_t *zsp)
if (!zsp->iteratorp)
return (NULL);
- return (((zed_strings_node_t *) zsp->iteratorp)->string);
+ return (((zed_strings_node_t *) zsp->iteratorp)->val);
}
@@ -181,7 +242,7 @@ zed_strings_next(zed_strings_t *zsp)
if (!zsp->iteratorp)
return (NULL);
- return (((zed_strings_node_t *)zsp->iteratorp)->string);
+ return (((zed_strings_node_t *)zsp->iteratorp)->val);
}
/*
diff --git a/cmd/zed/zed_strings.h b/cmd/zed/zed_strings.h
index c1ea804bb..07e85e23f 100644
--- a/cmd/zed/zed_strings.h
+++ b/cmd/zed/zed_strings.h
@@ -33,7 +33,7 @@ zed_strings_t * zed_strings_create(void);
void zed_strings_destroy(zed_strings_t *zsp);
-int zed_strings_add(zed_strings_t *zsp, const char *s);
+int zed_strings_add(zed_strings_t *zsp, const char *key, const char *s);
const char * zed_strings_first(zed_strings_t *zsp);