xref: /openbsd-src/usr.sbin/smtpd/stat_ramstat.c (revision d3140113bef2b86d3af61dd20c05a8630ff966c2)
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