1 /* $OpenBSD: stat_ramstat.c,v 1.9 2014/04/19 14:11:55 gilles 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 <sys/types.h> 20 #include <sys/socket.h> 21 #include <sys/queue.h> 22 #include <sys/tree.h> 23 24 #include <event.h> 25 #include <imsg.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 30 #include "smtpd.h" 31 #include "log.h" 32 33 34 static void ramstat_init(void); 35 static void ramstat_close(void); 36 static void ramstat_increment(const char *, size_t); 37 static void ramstat_decrement(const char *, size_t); 38 static void ramstat_set(const char *, const struct stat_value *); 39 static int ramstat_iter(void **, char **, struct stat_value *); 40 41 struct ramstat_entry { 42 RB_ENTRY(ramstat_entry) entry; 43 char key[STAT_KEY_SIZE]; 44 struct stat_value value; 45 }; 46 RB_HEAD(stats_tree, ramstat_entry) stats; 47 RB_PROTOTYPE(stats_tree, ramstat_entry, entry, ramstat_entry_cmp); 48 49 struct stat_backend stat_backend_ramstat = { 50 ramstat_init, 51 ramstat_close, 52 ramstat_increment, 53 ramstat_decrement, 54 ramstat_set, 55 ramstat_iter 56 }; 57 58 static void 59 ramstat_init(void) 60 { 61 log_trace(TRACE_STAT, "ramstat: init"); 62 63 RB_INIT(&stats); 64 65 /* ramstat_set() should be called for each key we want 66 * to have displayed by smtpctl show stats at startup. 67 */ 68 ramstat_set("uptime", stat_timestamp(env->sc_uptime)); 69 } 70 71 static void 72 ramstat_close(void) 73 { 74 log_trace(TRACE_STAT, "ramstat: close"); 75 } 76 77 static void 78 ramstat_increment(const char *name, size_t val) 79 { 80 struct ramstat_entry *np, lk; 81 82 log_trace(TRACE_STAT, "ramstat: increment: %s", name); 83 (void)strlcpy(lk.key, name, sizeof (lk.key)); 84 np = RB_FIND(stats_tree, &stats, &lk); 85 if (np == NULL) { 86 np = xcalloc(1, sizeof *np, "ramstat_increment"); 87 (void)strlcpy(np->key, name, sizeof (np->key)); 88 RB_INSERT(stats_tree, &stats, np); 89 } 90 log_trace(TRACE_STAT, "ramstat: %s (%p): %zd -> %zd", 91 name, name, np->value.u.counter, np->value.u.counter + val); 92 np->value.u.counter += val; 93 } 94 95 static void 96 ramstat_decrement(const char *name, size_t val) 97 { 98 struct ramstat_entry *np, lk; 99 100 log_trace(TRACE_STAT, "ramstat: decrement: %s", name); 101 (void)strlcpy(lk.key, name, sizeof (lk.key)); 102 np = RB_FIND(stats_tree, &stats, &lk); 103 if (np == NULL) { 104 np = xcalloc(1, sizeof *np, "ramstat_decrement"); 105 (void)strlcpy(np->key, name, sizeof (np->key)); 106 RB_INSERT(stats_tree, &stats, np); 107 } 108 log_trace(TRACE_STAT, "ramstat: %s (%p): %zd -> %zd", 109 name, name, np->value.u.counter, np->value.u.counter - val); 110 np->value.u.counter -= val; 111 } 112 113 static void 114 ramstat_set(const char *name, const struct stat_value *val) 115 { 116 struct ramstat_entry *np, lk; 117 118 log_trace(TRACE_STAT, "ramstat: set: %s", name); 119 (void)strlcpy(lk.key, name, sizeof (lk.key)); 120 np = RB_FIND(stats_tree, &stats, &lk); 121 if (np == NULL) { 122 np = xcalloc(1, sizeof *np, "ramstat_set"); 123 (void)strlcpy(np->key, name, sizeof (np->key)); 124 RB_INSERT(stats_tree, &stats, np); 125 } 126 log_trace(TRACE_STAT, "ramstat: %s: n/a -> n/a", name); 127 np->value = *val; 128 } 129 130 static int 131 ramstat_iter(void **iter, char **name, struct stat_value *val) 132 { 133 struct ramstat_entry *np; 134 135 log_trace(TRACE_STAT, "ramstat: iter"); 136 if (RB_EMPTY(&stats)) 137 return 0; 138 139 if (*iter == NULL) 140 np = RB_MIN(stats_tree, &stats); 141 else 142 np = RB_NEXT(stats_tree, &stats, *iter); 143 144 *iter = np; 145 if (np == NULL) 146 return 0; 147 148 *name = np->key; 149 *val = np->value; 150 return 1; 151 } 152 153 154 static int 155 ramstat_entry_cmp(struct ramstat_entry *e1, struct ramstat_entry *e2) 156 { 157 return strcmp(e1->key, e2->key); 158 } 159 160 RB_GENERATE(stats_tree, ramstat_entry, entry, ramstat_entry_cmp); 161