diff options
Diffstat (limited to 'usr.sbin/smtpd/stat_ramstat.c')
-rw-r--r-- | usr.sbin/smtpd/stat_ramstat.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/usr.sbin/smtpd/stat_ramstat.c b/usr.sbin/smtpd/stat_ramstat.c new file mode 100644 index 00000000000..996f8ff8a24 --- /dev/null +++ b/usr.sbin/smtpd/stat_ramstat.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2012 Gilles Chehade <gilles@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/queue.h> +#include <sys/tree.h> +#include <sys/param.h> + +#include <event.h> +#include <imsg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "smtpd.h" +#include "log.h" + + +static void ramstat_init(void); +static void ramstat_close(void); +static void ramstat_increment(const char *); +static void ramstat_decrement(const char *); +static void ramstat_set(const char *, size_t); +static int ramstat_iter(void **, char **, size_t *); + +struct ramstat_entry { + RB_ENTRY(ramstat_entry) entry; + + char key[STAT_KEY_SIZE]; + size_t value; +}; +RB_HEAD(stats_tree, ramstat_entry) stats; +RB_PROTOTYPE(stats_tree, ramstat_entry, entry, ramstat_entry_cmp); + +struct stat_backend stat_backend_ramstat = { + ramstat_init, + ramstat_close, + ramstat_increment, + ramstat_decrement, + ramstat_set, + ramstat_iter +}; + +static void +ramstat_init(void) +{ + log_trace(TRACE_STAT, "ramstat: init"); + RB_INIT(&stats); + + /* ramstat_set() should be called for each key we want + * to have displayed by smtpctl show stats at startup. + */ + ramstat_set("uptime", env->sc_uptime); +} + +static void +ramstat_close(void) +{ + log_trace(TRACE_STAT, "ramstat: close"); +} + +static void +ramstat_increment(const char *name) +{ + struct ramstat_entry *np, lk; + + log_trace(TRACE_STAT, "ramstat: increment: %s", name); + strlcpy(lk.key, name, sizeof (lk.key)); + np = RB_FIND(stats_tree, &stats, &lk); + if (np == NULL) { + np = calloc(1, sizeof *np); + if (np == NULL) + fatal("calloc"); + strlcpy(np->key, name, sizeof (np->key)); + RB_INSERT(stats_tree, &stats, np); + } + log_trace(TRACE_STAT, "ramstat: %s (%p): %d -> %d", + name, name, (int)np->value, (int)np->value + 1); + np->value++; +} + +static void +ramstat_decrement(const char *name) +{ + struct ramstat_entry *np, lk; + + log_trace(TRACE_STAT, "ramstat: decrement: %s", name); + strlcpy(lk.key, name, sizeof (lk.key)); + np = RB_FIND(stats_tree, &stats, &lk); + if (np == NULL) { + np = calloc(1, sizeof *np); + if (np == NULL) + fatal("calloc"); + strlcpy(np->key, name, sizeof (np->key)); + RB_INSERT(stats_tree, &stats, np); + } + log_trace(TRACE_STAT, "ramstat: %s (%p): %d -> %d", + name, name, (int)np->value, (int)np->value - 1); + np->value--; +} + +static void +ramstat_set(const char *name, size_t val) +{ + struct ramstat_entry *np, lk; + + log_trace(TRACE_STAT, "ramstat: set"); + strlcpy(lk.key, name, sizeof (lk.key)); + np = RB_FIND(stats_tree, &stats, &lk); + if (np == NULL) { + np = calloc(1, sizeof *np); + if (np == NULL) + fatal("calloc"); + strlcpy(np->key, name, sizeof (np->key)); + RB_INSERT(stats_tree, &stats, np); + } + log_trace(TRACE_STAT, "ramstat: %s: %d -> %d", + name, (int)np->value, (int)val); + np->value = val; +} + +static int +ramstat_iter(void **iter, char **name, size_t *val) +{ + struct ramstat_entry *np; + + log_trace(TRACE_STAT, "ramstat: iter"); + if (RB_EMPTY(&stats)) + return 0; + + if (*iter == NULL) + np = RB_ROOT(&stats); + else + np = RB_NEXT(stats_tree, &stats, *iter); + + if (np) { + *name = np->key; + *val = np->value; + } + *iter = np; + return 1; +} + + +static int +ramstat_entry_cmp(struct ramstat_entry *e1, struct ramstat_entry *e2) +{ + return strcmp(e1->key, e2->key); +} + +RB_GENERATE(stats_tree, ramstat_entry, entry, ramstat_entry_cmp); |