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