1 /* $OpenBSD: stat_ramstat.c,v 1.12 2021/06/14 17:58:16 eric Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <string.h> 20 21 #include "smtpd.h" 22 23 static void ramstat_init(void); 24 static void ramstat_close(void); 25 static void ramstat_increment(const char *, size_t); 26 static void ramstat_decrement(const char *, size_t); 27 static void ramstat_set(const char *, const struct stat_value *); 28 static int ramstat_iter(void **, char **, struct stat_value *); 29 30 struct ramstat_entry { 31 RB_ENTRY(ramstat_entry) entry; 32 char key[STAT_KEY_SIZE]; 33 struct stat_value value; 34 }; 35 RB_HEAD(stats_tree, ramstat_entry) stats; 36 RB_PROTOTYPE(stats_tree, ramstat_entry, entry, ramstat_entry_cmp); 37 38 struct stat_backend stat_backend_ramstat = { 39 ramstat_init, 40 ramstat_close, 41 ramstat_increment, 42 ramstat_decrement, 43 ramstat_set, 44 ramstat_iter 45 }; 46 47 static void 48 ramstat_init(void) 49 { 50 log_trace(TRACE_STAT, "ramstat: init"); 51 52 RB_INIT(&stats); 53 54 /* ramstat_set() should be called for each key we want 55 * to have displayed by smtpctl show stats at startup. 56 */ 57 ramstat_set("uptime", stat_timestamp(env->sc_uptime)); 58 } 59 60 static void 61 ramstat_close(void) 62 { 63 log_trace(TRACE_STAT, "ramstat: close"); 64 } 65 66 static void 67 ramstat_increment(const char *name, size_t val) 68 { 69 struct ramstat_entry *np, lk; 70 71 log_trace(TRACE_STAT, "ramstat: increment: %s", name); 72 (void)strlcpy(lk.key, name, sizeof (lk.key)); 73 np = RB_FIND(stats_tree, &stats, &lk); 74 if (np == NULL) { 75 np = xcalloc(1, sizeof *np); 76 (void)strlcpy(np->key, name, sizeof (np->key)); 77 RB_INSERT(stats_tree, &stats, np); 78 } 79 log_trace(TRACE_STAT, "ramstat: %s (%p): %zd -> %zd", 80 name, name, np->value.u.counter, np->value.u.counter + val); 81 np->value.u.counter += val; 82 } 83 84 static void 85 ramstat_decrement(const char *name, size_t val) 86 { 87 struct ramstat_entry *np, lk; 88 89 log_trace(TRACE_STAT, "ramstat: decrement: %s", name); 90 (void)strlcpy(lk.key, name, sizeof (lk.key)); 91 np = RB_FIND(stats_tree, &stats, &lk); 92 if (np == NULL) { 93 np = xcalloc(1, sizeof *np); 94 (void)strlcpy(np->key, name, sizeof (np->key)); 95 RB_INSERT(stats_tree, &stats, np); 96 } 97 log_trace(TRACE_STAT, "ramstat: %s (%p): %zd -> %zd", 98 name, name, np->value.u.counter, np->value.u.counter - val); 99 np->value.u.counter -= val; 100 } 101 102 static void 103 ramstat_set(const char *name, const struct stat_value *val) 104 { 105 struct ramstat_entry *np, lk; 106 107 log_trace(TRACE_STAT, "ramstat: set: %s", name); 108 (void)strlcpy(lk.key, name, sizeof (lk.key)); 109 np = RB_FIND(stats_tree, &stats, &lk); 110 if (np == NULL) { 111 np = xcalloc(1, sizeof *np); 112 (void)strlcpy(np->key, name, sizeof (np->key)); 113 RB_INSERT(stats_tree, &stats, np); 114 } 115 log_trace(TRACE_STAT, "ramstat: %s: n/a -> n/a", name); 116 np->value = *val; 117 } 118 119 static int 120 ramstat_iter(void **iter, char **name, struct stat_value *val) 121 { 122 struct ramstat_entry *np; 123 124 log_trace(TRACE_STAT, "ramstat: iter"); 125 if (RB_EMPTY(&stats)) 126 return 0; 127 128 if (*iter == NULL) 129 np = RB_MIN(stats_tree, &stats); 130 else 131 np = RB_NEXT(stats_tree, &stats, *iter); 132 133 *iter = np; 134 if (np == NULL) 135 return 0; 136 137 *name = np->key; 138 *val = np->value; 139 return 1; 140 } 141 142 143 static int 144 ramstat_entry_cmp(struct ramstat_entry *e1, struct ramstat_entry *e2) 145 { 146 return strcmp(e1->key, e2->key); 147 } 148 149 RB_GENERATE(stats_tree, ramstat_entry, entry, ramstat_entry_cmp); 150