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