2 * IRC - Internet Relay Chat, ircd/s_debug.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
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)
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.
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.
28 #include "ircd_alloc.h"
29 #include "ircd_osdep.h"
46 #include <stddef.h> /* offsetof */
54 * Option string. Must be before #ifdef DEBUGMODE.
57 #if BUFFERPOOL < 1000000
59 #if BUFFERPOOL > 99999
60 (char)('0' + (BUFFERPOOL/100000)),
63 (char)('0' + (BUFFERPOOL/10000) % 10),
65 (char)('0' + (BUFFERPOOL/1000) % 10),
68 #if BUFFERPOOL > 99999999
69 (char)('0' + (BUFFERPOOL/100000000)),
71 #if BUFFERPOOL > 9999999
72 (char)('0' + (BUFFERPOOL/10000000) % 10),
74 (char)('0' + (BUFFERPOOL/1000000) % 10),
94 #ifdef OPER_NO_CHAN_LIMIT
97 #ifdef OPER_MODE_LCHAN
103 #if defined(SHOW_INVISIBLE_USERS) || defined(SHOW_ALL_INVISIBLE_USERS)
104 #ifdef SHOW_ALL_INVISIBLE_USERS
111 #ifdef LOCAL_KILL_ONLY
120 #ifdef OPER_WALK_THROUGH_LMODES
129 #ifdef NO_OPER_DEOP_LCHAN
132 #ifdef CRYPT_OPER_PASSWORD
135 #ifdef CRYPT_LINK_PASSWORD
145 #ifdef RELIABLE_CLOCK
157 #if defined(USE_POLL) && defined(HAVE_POLL_H)
181 * If the -t option is not given on the command line when the server is
182 * started, all debugging output is sent to the file set by LPATH in config.h
183 * Here we just open that file and make sure it is opened to fd 2 so that
184 * any fprintf's to stderr also goto the logfile. If the debuglevel is not
185 * set from the command line by -x, use /dev/null as the dummy logfile as long
186 * as DEBUGMODE has been defined, else dont waste the fd.
188 void debug_init(int use_tty)
191 if (debuglevel >= 0) {
192 printf("isatty = %d ttyname = %#x\n", isatty(2), (unsigned int)ttyname(2));
196 * leave debugging output on fd 2
198 if ((fd = open(LOGFILE, O_CREAT | O_WRONLY | O_APPEND, 0600)) < 0) {
199 if ((fd = open("/dev/null", O_WRONLY)) < 0)
212 static char debugbuf[1024];
214 void vdebug(int level, const char *form, va_list vl)
218 if ((debuglevel >= 0) && (level <= debuglevel))
220 vsprintf(debugbuf, form, vl);
221 fprintf(stderr, "%s\n", debugbuf);
226 void debug(int level, const char *form, ...)
230 vdebug(level, form, vl);
234 static void debug_enumerator(struct Client* cptr, const char* msg)
237 sendto_one(cptr, ":%s %d %s :%s", me.name, RPL_STATSDEBUG, cptr->name, msg);
241 * This is part of the STATS replies. There is no offical numeric for this
242 * since this isnt an official command, in much the same way as HASH isnt.
243 * It is also possible that some systems wont support this call or have
244 * different field names for "struct rusage".
247 void send_usage(struct Client *cptr, char *nick)
249 os_get_rusage(cptr, CurrentTime - me.since, debug_enumerator);
251 sendto_one(cptr, ":%s %d %s :DBUF alloc %d used %d",
252 me.name, RPL_STATSDEBUG, nick, DBufAllocCount, DBufUsedCount);
254 #endif /* DEBUGMODE */
256 void count_memory(struct Client *cptr, char *nick)
258 struct Client *acptr;
260 struct Channel *chptr;
261 struct ConfItem *aconf;
262 struct ConfClass *cltmp;
263 struct Membership* member;
265 int lc = 0, /* local clients */
266 ch = 0, /* channels */
267 lcc = 0, /* local client conf links */
268 rc = 0, /* remote clients */
269 us = 0, /* user structs */
270 chi = 0, /* channel invites */
271 chb = 0, /* channel bans */
272 wwu = 0, /* whowas users */
273 cl = 0, /* classes */
274 co = 0, /* conf lines */
275 memberships = 0; /* channel memberships */
277 int usi = 0, /* users invited */
278 aw = 0, /* aways set */
279 wwa = 0; /* whowas aways */
281 size_t chm = 0, /* memory used by channels */
282 chbm = 0, /* memory used by channel bans */
283 lcm = 0, /* memory used by local clients */
284 rcm = 0, /* memory used by remote clients */
285 awm = 0, /* memory used by aways */
286 wwam = 0, /* whowas away memory used */
287 wwm = 0, /* whowas array memory used */
288 com = 0, /* memory used by conf lines */
289 dbufs_allocated = 0, /* memory used by dbufs */
290 dbufs_used = 0, /* memory used by dbufs */
291 rm = 0, /* res memory used */
292 totcl = 0, totch = 0, totww = 0, tot = 0;
294 count_whowas_memory(&wwu, &wwm, &wwa, &wwam);
295 wwm += sizeof(struct Whowas) * NICKNAMEHISTORYLENGTH;
296 wwm += sizeof(struct Whowas *) * WW_MAX;
298 for (acptr = GlobalClientList; acptr; acptr = acptr->next)
300 if (MyConnect(acptr))
303 for (link = acptr->confs; link; link = link->next)
311 for (link = acptr->user->invited; link; link = link->next)
313 for (member = acptr->user->channel; member; member = member->next_channel)
315 if (acptr->user->away)
318 awm += (strlen(acptr->user->away) + 1);
322 lcm = lc * CLIENT_LOCAL_SIZE;
323 rcm = rc * CLIENT_REMOTE_SIZE;
325 for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
328 chm += (strlen(chptr->chname) + sizeof(struct Channel));
331 * XXX - Members already counted in clients, don't count twice
333 for (member = chptr->members; member; member = member->next_member)
336 for (link = chptr->invites; link; link = link->next)
338 for (link = chptr->banlist; link; link = link->next)
341 chbm += (strlen(link->value.cp) + 1 + sizeof(struct SLink));
345 for (aconf = GlobalConfList; aconf; aconf = aconf->next)
348 com += aconf->host ? strlen(aconf->host) + 1 : 0;
349 com += aconf->passwd ? strlen(aconf->passwd) + 1 : 0;
350 com += aconf->name ? strlen(aconf->name) + 1 : 0;
351 com += sizeof(struct ConfItem);
354 for (cltmp = classes; cltmp; cltmp = cltmp->next)
357 sendto_one(cptr, ":%s %d %s :Client Local %d(" SIZE_T_FMT
358 ") Remote %d(" SIZE_T_FMT ")",
359 me.name, RPL_STATSDEBUG, nick, lc, lcm, rc, rcm);
360 sendto_one(cptr, ":%s %d %s :Users %d(" SIZE_T_FMT
361 ") Invites %d(" SIZE_T_FMT ")",
362 me.name, RPL_STATSDEBUG, nick, us, us * sizeof(struct User), usi,
363 usi * sizeof(struct SLink));
365 ":%s %d %s :User channels %d(" SIZE_T_FMT ") Aways %d(" SIZE_T_FMT ")",
366 me.name, RPL_STATSDEBUG, nick, memberships,
367 memberships * sizeof(struct Membership), aw, awm);
368 sendto_one(cptr, ":%s %d %s :Attached confs %d(" SIZE_T_FMT ")",
369 me.name, RPL_STATSDEBUG, nick, lcc, lcc * sizeof(struct SLink));
371 totcl = lcm + rcm + us * sizeof(struct User) + memberships * sizeof(struct Membership) + awm;
372 totcl += lcc * sizeof(struct SLink) + usi * sizeof(struct SLink);
374 sendto_one(cptr, ":%s %d %s :Conflines %d(" SIZE_T_FMT ")",
375 me.name, RPL_STATSDEBUG, nick, co, com);
377 sendto_one(cptr, ":%s %d %s :Classes %d(" SIZE_T_FMT ")",
378 me.name, RPL_STATSDEBUG, nick, cl, cl * sizeof(struct ConfClass));
380 sendto_one(cptr, ":%s %d %s :Channels %d(" SIZE_T_FMT
381 ") Bans %d(" SIZE_T_FMT ")",
382 me.name, RPL_STATSDEBUG, nick, ch, chm, chb, chbm);
383 sendto_one(cptr, ":%s %d %s :Channel membrs %d(" SIZE_T_FMT ") invite %d(" SIZE_T_FMT ")",
384 me.name, RPL_STATSDEBUG, nick, memberships, memberships * sizeof(struct Membership),
385 chi, chi * sizeof(struct SLink));
387 totch = chm + chbm + chi * sizeof(struct SLink);
389 sendto_one(cptr, ":%s %d %s :Whowas users %d(" SIZE_T_FMT
390 ") away %d(" SIZE_T_FMT ")",
391 me.name, RPL_STATSDEBUG, nick, wwu, wwu * sizeof(struct User), wwa, wwam);
392 sendto_one(cptr, ":%s %d %s :Whowas array %d(" SIZE_T_FMT ")",
393 me.name, RPL_STATSDEBUG, nick, NICKNAMEHISTORYLENGTH, wwm);
395 totww = wwu * sizeof(struct User) + wwam + wwm;
397 sendto_one(cptr, ":%s %d %s :Hash: client %d(" SIZE_T_FMT
398 "), chan is the same",
399 me.name, RPL_STATSDEBUG, nick, HASHSIZE, sizeof(void *) * HASHSIZE);
402 * NOTE: this count will be accurate only for the exact instant that this
403 * message is being sent, so the count is affected by the dbufs that
404 * are being used to send this message out. If this is not desired, move
405 * the dbuf_count_memory call to a place before we start sending messages
406 * and cache DBufAllocCount and DBufUsedCount in variables until they
409 dbuf_count_memory(&dbufs_allocated, &dbufs_used);
411 ":%s %d %s :DBufs allocated %d(" SIZE_T_FMT ") used %d(" SIZE_T_FMT ")",
412 me.name, RPL_STATSDEBUG, nick, DBufAllocCount, dbufs_allocated,
413 DBufUsedCount, dbufs_used);
418 totww + totch + totcl + com + cl * sizeof(struct ConfClass) + dbufs_allocated +
420 tot += sizeof(void *) * HASHSIZE * 3;
423 sendto_one(cptr, ":%s %d %s :Allocations: " SIZE_T_FMT "(" SIZE_T_FMT ")",
424 me.name, RPL_STATSDEBUG, nick, fda_get_block_count(),
425 fda_get_byte_count());
428 sendto_one(cptr, ":%s %d %s :Total: ww " SIZE_T_FMT " ch " SIZE_T_FMT
429 " cl " SIZE_T_FMT " co " SIZE_T_FMT " db " SIZE_T_FMT,
430 me.name, RPL_STATSDEBUG, nick, totww, totch, totcl, com, dbufs_allocated);