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
ramstat_init(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
ramstat_close(void)61 ramstat_close(void)
62 {
63 log_trace(TRACE_STAT, "ramstat: close");
64 }
65
66 static void
ramstat_increment(const char * name,size_t val)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
ramstat_decrement(const char * name,size_t val)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
ramstat_set(const char * name,const struct stat_value * val)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
ramstat_iter(void ** iter,char ** name,struct stat_value * val)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
ramstat_entry_cmp(struct ramstat_entry * e1,struct ramstat_entry * e2)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