]>
Commit | Line | Data |
---|---|---|
189935b1 | 1 | /* |
2 | * IRC - Internet Relay Chat, ircd/s_debug.c | |
3 | * Copyright (C) 1990 Jarkko Oikarinen and | |
4 | * University of Oulu, Computing Center | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 1, or (at your option) | |
9 | * any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | */ | |
20 | /** @file | |
21 | * @brief Debug support for the ircd. | |
22 | * @version $Id: s_debug.c,v 1.41 2005/06/19 02:31:27 entrope Exp $ | |
23 | */ | |
24 | #include "config.h" | |
25 | ||
26 | #include "s_debug.h" | |
27 | #include "channel.h" | |
28 | #include "class.h" | |
29 | #include "client.h" | |
30 | #include "gline.h" | |
31 | #include "hash.h" | |
32 | #include "ircd_alloc.h" | |
33 | #include "ircd_features.h" | |
34 | #include "ircd_log.h" | |
35 | #include "ircd_osdep.h" | |
36 | #include "ircd_reply.h" | |
37 | #include "ircd.h" | |
38 | #include "jupe.h" | |
39 | #include "list.h" | |
40 | #include "listener.h" | |
41 | #include "motd.h" | |
42 | #include "msgq.h" | |
43 | #include "numeric.h" | |
44 | #include "numnicks.h" | |
45 | #include "res.h" | |
46 | #include "s_bsd.h" | |
47 | #include "s_conf.h" | |
48 | #include "s_user.h" | |
49 | #include "s_stats.h" | |
50 | #include "send.h" | |
51 | #include "struct.h" | |
52 | #include "sys.h" | |
53 | #include "whowas.h" | |
54 | ||
55 | /* #include <assert.h> -- Now using assert in ircd_log.h */ | |
56 | #include <errno.h> | |
57 | #include <fcntl.h> | |
58 | #include <stdarg.h> | |
59 | #include <stddef.h> /* offsetof */ | |
60 | #include <stdio.h> | |
61 | #include <string.h> | |
62 | #include <unistd.h> | |
63 | ||
64 | /* | |
65 | * Option string. Must be before #ifdef DEBUGMODE. | |
66 | */ | |
67 | static char serveropts[256]; /* should be large enough for anything */ | |
68 | ||
69 | /** Return a string describing important configuration information. | |
70 | * @return Pointer to a static buffer. | |
71 | */ | |
72 | const char* debug_serveropts(void) | |
73 | { | |
74 | int bp; | |
75 | int i = 0; | |
76 | #define AddC(c) serveropts[i++] = (c) | |
77 | ||
78 | bp = feature_int(FEAT_BUFFERPOOL); | |
79 | if (bp < 1000000) { | |
80 | AddC('b'); | |
81 | if (bp > 99999) | |
82 | AddC((char)('0' + (bp / 100000))); | |
83 | if (bp > 9999) | |
84 | AddC((char)('0' + (bp / 10000) % 10)); | |
85 | AddC((char)('0' + (bp / 1000) % 10)); | |
86 | } else { | |
87 | AddC('B'); | |
88 | if (bp > 99999999) | |
89 | AddC((char)('0' + (bp / 100000000))); | |
90 | if (bp > 9999999) | |
91 | AddC((char)('0' + (bp / 10000000) % 10)); | |
92 | AddC((char)('0' + (bp / 1000000) % 10)); | |
93 | } | |
94 | ||
95 | #ifndef NDEBUG | |
96 | AddC('A'); | |
97 | #endif | |
98 | #ifdef DEBUGMODE | |
99 | AddC('D'); | |
100 | #endif | |
101 | ||
102 | if (feature_bool(FEAT_HUB)) | |
103 | AddC('H'); | |
104 | ||
105 | if (feature_bool(FEAT_IDLE_FROM_MSG)) | |
106 | AddC('M'); | |
107 | ||
108 | if (feature_bool(FEAT_RELIABLE_CLOCK)) | |
109 | AddC('R'); | |
110 | ||
111 | #if defined(USE_POLL) && defined(HAVE_POLL_H) | |
112 | AddC('U'); | |
113 | #endif | |
114 | #ifdef IPV6 | |
115 | AddC('6'); | |
116 | #endif | |
117 | ||
118 | serveropts[i] = '\0'; | |
119 | ||
120 | return serveropts; | |
121 | } | |
122 | ||
123 | /** Initialize debugging. | |
124 | * If the -t option is not given on the command line when the server is | |
125 | * started, all debugging output is sent to the file set by LPATH in config.h | |
126 | * Here we just open that file and make sure it is opened to fd 2 so that | |
127 | * any fprintf's to stderr also go to the logfile. If the debuglevel is not | |
128 | * set from the command line by -x, use /dev/null as the dummy logfile as long | |
129 | * as DEBUGMODE has been defined, else don't waste the fd. | |
130 | * @param use_tty Passed to log_debug_init(). | |
131 | */ | |
132 | void debug_init(int use_tty) | |
133 | { | |
134 | #ifdef DEBUGMODE | |
135 | if (debuglevel >= 0) { | |
136 | printf("isatty = %d ttyname = %s\n", isatty(2), ttyname(2)); | |
137 | log_debug_init(use_tty); | |
138 | } | |
139 | #endif | |
140 | } | |
141 | ||
142 | #ifdef DEBUGMODE | |
143 | /** Log a debug message using a va_list. | |
144 | * If the current #debuglevel is less than \a level, do not display. | |
145 | * @param level Debug level for message. | |
146 | * @param form Format string, passed to log_vwrite(). | |
147 | * @param vl Varargs argument list for format string. | |
148 | */ | |
149 | void vdebug(int level, const char *form, va_list vl) | |
150 | { | |
151 | static int loop = 0; | |
152 | int err = errno; | |
153 | ||
154 | if (!loop && (debuglevel >= 0) && (level <= debuglevel)) | |
155 | { | |
156 | loop = 1; | |
157 | log_vwrite(LS_DEBUG, L_DEBUG, 0, form, vl); | |
158 | loop = 0; | |
159 | } | |
160 | errno = err; | |
161 | } | |
162 | ||
163 | /** Log a debug message using a variable number of arguments. | |
164 | * This is a simple wrapper around debug(\a level, \a form, vl). | |
165 | * @param level Debug level for message. | |
166 | * @param form Format string of message. | |
167 | */ | |
168 | void debug(int level, const char *form, ...) | |
169 | { | |
170 | va_list vl; | |
171 | va_start(vl, form); | |
172 | vdebug(level, form, vl); | |
173 | va_end(vl); | |
174 | } | |
175 | ||
176 | /** Send a literal RPL_STATSDEBUG message to a user. | |
177 | * @param cptr Client to receive the message. | |
178 | * @param msg Text message to send to user. | |
179 | */ | |
180 | static void debug_enumerator(struct Client* cptr, const char* msg) | |
181 | { | |
182 | assert(0 != cptr); | |
183 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":%s", msg); | |
184 | } | |
185 | ||
186 | /** Send resource usage statistics to a client. | |
187 | * @param cptr Client to send data to. | |
188 | * @param sd StatDesc that generated the stats request (ignored). | |
189 | * @param param Extra parameter from user (ignored). | |
190 | */ | |
191 | void send_usage(struct Client *cptr, const struct StatDesc *sd, | |
192 | char *param) | |
193 | { | |
194 | os_get_rusage(cptr, CurrentTime - cli_since(&me), debug_enumerator); | |
195 | ||
196 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":DBUF alloc %d used %d", | |
197 | DBufAllocCount, DBufUsedCount); | |
198 | } | |
199 | #endif /* DEBUGMODE */ | |
200 | ||
201 | /** Report memory usage statistics to a client. | |
202 | * @param cptr Client to send data to. | |
203 | * @param sd StatDesc that generated the stats request (ignored). | |
204 | * @param param Extra parameter from user (ignored). | |
205 | */ | |
206 | void count_memory(struct Client *cptr, const struct StatDesc *sd, | |
207 | char *param) | |
208 | { | |
209 | struct Client *acptr; | |
210 | struct SLink *link; | |
211 | struct Ban *ban; | |
212 | struct Channel *chptr; | |
213 | struct ConfItem *aconf; | |
214 | const struct ConnectionClass* cltmp; | |
215 | struct Membership* member; | |
216 | ||
217 | int acc = 0, /* accounts */ | |
218 | c = 0, /* clients */ | |
219 | cn = 0, /* connections */ | |
220 | ch = 0, /* channels */ | |
221 | lcc = 0, /* local client conf links */ | |
222 | chi = 0, /* channel invites */ | |
223 | chb = 0, /* channel bans */ | |
224 | wwu = 0, /* whowas users */ | |
225 | cl = 0, /* classes */ | |
226 | co = 0, /* conf lines */ | |
227 | listeners = 0, /* listeners */ | |
228 | memberships = 0; /* channel memberships */ | |
229 | ||
230 | int usi = 0, /* users invited */ | |
231 | aw = 0, /* aways set */ | |
232 | wwa = 0, /* whowas aways */ | |
233 | gl = 0, /* glines */ | |
234 | ju = 0; /* jupes */ | |
235 | ||
236 | size_t chm = 0, /* memory used by channels */ | |
237 | chbm = 0, /* memory used by channel bans */ | |
238 | cm = 0, /* memory used by clients */ | |
239 | cnm = 0, /* memory used by connections */ | |
240 | us = 0, /* user structs */ | |
241 | usm = 0, /* memory used by user structs */ | |
242 | awm = 0, /* memory used by aways */ | |
243 | wwam = 0, /* whowas away memory used */ | |
244 | wwm = 0, /* whowas array memory used */ | |
245 | glm = 0, /* memory used by glines */ | |
246 | jum = 0, /* memory used by jupes */ | |
247 | com = 0, /* memory used by conf lines */ | |
248 | dbufs_allocated = 0, /* memory used by dbufs */ | |
249 | dbufs_used = 0, /* memory used by dbufs */ | |
250 | msg_allocated = 0, /* memory used by struct Msg */ | |
251 | msgbuf_allocated = 0, /* memory used by struct MsgBuf */ | |
252 | listenersm = 0, /* memory used by listetners */ | |
253 | rm = 0, /* res memory used */ | |
254 | totcl = 0, totch = 0, totww = 0, tot = 0; | |
255 | ||
256 | count_whowas_memory(&wwu, &wwm, &wwa, &wwam); | |
257 | wwm += sizeof(struct Whowas) * feature_int(FEAT_NICKNAMEHISTORYLENGTH); | |
258 | wwm += sizeof(struct Whowas *) * WW_MAX; | |
259 | ||
260 | for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) | |
261 | { | |
262 | c++; | |
263 | if (MyConnect(acptr)) | |
264 | { | |
265 | cn++; | |
266 | for (link = cli_confs(acptr); link; link = link->next) | |
267 | lcc++; | |
268 | } | |
269 | if (cli_user(acptr)) | |
270 | { | |
271 | for (link = cli_user(acptr)->invited; link; link = link->next) | |
272 | usi++; | |
273 | for (member = cli_user(acptr)->channel; member; member = member->next_channel) | |
274 | ++memberships; | |
275 | if (cli_user(acptr)->away) | |
276 | { | |
277 | aw++; | |
278 | awm += (strlen(cli_user(acptr)->away) + 1); | |
279 | } | |
280 | } | |
281 | ||
282 | if (IsAccount(acptr)) | |
283 | acc++; | |
284 | } | |
285 | cm = c * sizeof(struct Client); | |
286 | cnm = cn * sizeof(struct Connection); | |
287 | user_count_memory(&us, &usm); | |
288 | ||
289 | for (chptr = GlobalChannelList; chptr; chptr = chptr->next) | |
290 | { | |
291 | ch++; | |
292 | chm += (strlen(chptr->chname) + sizeof(struct Channel)); | |
293 | for (link = chptr->invites; link; link = link->next) | |
294 | chi++; | |
295 | for (ban = chptr->banlist; ban; ban = ban->next) | |
296 | { | |
297 | chb++; | |
298 | chbm += strlen(ban->who) + strlen(ban->banstr) + 2 + sizeof(*ban); | |
299 | } | |
300 | } | |
301 | ||
302 | for (aconf = GlobalConfList; aconf; aconf = aconf->next) | |
303 | { | |
304 | co++; | |
305 | com += aconf->host ? strlen(aconf->host) + 1 : 0; | |
306 | com += aconf->passwd ? strlen(aconf->passwd) + 1 : 0; | |
307 | com += aconf->name ? strlen(aconf->name) + 1 : 0; | |
308 | com += sizeof(struct ConfItem); | |
309 | } | |
310 | ||
311 | for (cltmp = get_class_list(); cltmp; cltmp = cltmp->next) | |
312 | cl++; | |
313 | ||
314 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, | |
315 | ":Clients %d(%zu) Connections %d(%zu)", c, cm, cn, cnm); | |
316 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, | |
317 | ":Users %zu(%zu) Accounts %d(%zu) Invites %d(%zu)", | |
318 | us, usm, acc, acc * (ACCOUNTLEN + 1), | |
319 | usi, usi * sizeof(struct SLink)); | |
320 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, | |
321 | ":User channels %d(%zu) Aways %d(%zu)", memberships, | |
322 | memberships * sizeof(struct Membership), aw, awm); | |
323 | ||
324 | totcl = cm + cnm + us * sizeof(struct User) + memberships * sizeof(struct Membership) + awm; | |
325 | totcl += lcc * sizeof(struct SLink) + usi * sizeof(struct SLink); | |
326 | ||
327 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Conflines %d(%zu) Attached %d(%zu) Classes %d(%zu)", | |
328 | co, com, lcc, lcc * sizeof(struct SLink), | |
329 | cl, cl * sizeof(struct ConnectionClass)); | |
330 | ||
331 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, | |
332 | ":Channels %d(%zu) Bans %d(%zu)", ch, chm, chb, chbm); | |
333 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, | |
334 | ":Channel Members %d(%zu) Invites %d(%zu)", memberships, | |
335 | memberships * sizeof(struct Membership), chi, | |
336 | chi * sizeof(struct SLink)); | |
337 | ||
338 | totch = chm + chbm + chi * sizeof(struct SLink); | |
339 | ||
340 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, | |
341 | ":Whowas Users %d(%zu) Away %d(%zu) Array %d(%zu)", | |
342 | wwu, wwu * sizeof(struct User), wwa, wwam, | |
343 | feature_int(FEAT_NICKNAMEHISTORYLENGTH), wwm); | |
344 | ||
345 | totww = wwu * sizeof(struct User) + wwam + wwm; | |
346 | ||
347 | motd_memory_count(cptr); | |
348 | ||
349 | gl = gline_memory_count(&glm); | |
350 | ju = jupe_memory_count(&jum); | |
351 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, | |
352 | ":Glines %d(%zu) Jupes %d(%zu)", gl, glm, ju, jum); | |
353 | ||
354 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, | |
355 | ":Hash: client %d(%zu), chan is the same", HASHSIZE, | |
356 | sizeof(void *) * HASHSIZE); | |
357 | ||
358 | count_listener_memory(&listeners, &listenersm); | |
359 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, | |
360 | ":Listeners allocated %d(%zu)", listeners, listenersm); | |
361 | /* | |
362 | * NOTE: this count will be accurate only for the exact instant that this | |
363 | * message is being sent, so the count is affected by the dbufs that | |
364 | * are being used to send this message out. If this is not desired, move | |
365 | * the dbuf_count_memory call to a place before we start sending messages | |
366 | * and cache DBufAllocCount and DBufUsedCount in variables until they | |
367 | * are sent. | |
368 | */ | |
369 | dbuf_count_memory(&dbufs_allocated, &dbufs_used); | |
370 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, | |
371 | ":DBufs allocated %d(%zu) used %d(%zu)", DBufAllocCount, | |
372 | dbufs_allocated, DBufUsedCount, dbufs_used); | |
373 | ||
374 | /* The DBuf caveats now count for this, but this routine now sends | |
375 | * replies all on its own. | |
376 | */ | |
377 | msgq_count_memory(cptr, &msg_allocated, &msgbuf_allocated); | |
378 | ||
379 | rm = cres_mem(cptr); | |
380 | ||
381 | tot = | |
382 | totww + totch + totcl + com + cl * sizeof(struct ConnectionClass) + | |
383 | dbufs_allocated + msg_allocated + msgbuf_allocated + rm; | |
384 | tot += sizeof(void *) * HASHSIZE * 3; | |
385 | ||
386 | #if defined(MDEBUG) | |
387 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Allocations: %zu(%zu)", | |
388 | fda_get_block_count(), fda_get_byte_count()); | |
389 | #endif | |
390 | ||
391 | send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, | |
392 | ":Total: ww %zu ch %zu cl %zu co %zu db %zu ms %zu mb %zu", | |
393 | totww, totch, totcl, com, dbufs_allocated, msg_allocated, | |
394 | msgbuf_allocated); | |
395 | } |