Author: Kev <klmitch@mit.edu>
[ircu2.10.12-pk.git] / ircd / s_debug.c
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  * $Id$
21  *
22  */
23 #include "s_debug.h"
24 #include "channel.h"
25 #include "class.h"
26 #include "client.h"
27 #include "hash.h"
28 #include "ircd_alloc.h"
29 #include "ircd_log.h"
30 #include "ircd_osdep.h"
31 #include "ircd_reply.h"
32 #include "ircd.h"
33 #include "list.h"
34 #include "msgq.h"
35 #include "numeric.h"
36 #include "numnicks.h"
37 #include "res.h"
38 #include "s_bsd.h"
39 #include "s_conf.h"
40 #include "send.h"
41 #include "struct.h"
42 #include "sys.h"
43 #include "whowas.h"
44
45 #include <assert.h>
46 #include <errno.h>
47 #include <fcntl.h>
48 #include <stdarg.h>
49 #include <stddef.h>     /* offsetof */
50 #include <stdio.h>
51 #include <string.h>
52 #include <unistd.h>
53
54 /* *INDENT-OFF* */
55
56 /*
57  * Option string.  Must be before #ifdef DEBUGMODE.
58  */
59 char serveropts[] = {
60 #if BUFFERPOOL < 1000000
61     'b',
62 #if BUFFERPOOL > 99999
63     (char)('0' + (BUFFERPOOL/100000)),
64 #endif
65 #if BUFFERPOOL > 9999
66     (char)('0' + (BUFFERPOOL/10000) % 10),
67 #endif
68     (char)('0' + (BUFFERPOOL/1000) % 10),
69 #else
70     'B',
71 #if BUFFERPOOL > 99999999
72     (char)('0' + (BUFFERPOOL/100000000)),
73 #endif
74 #if BUFFERPOOL > 9999999
75     (char)('0' + (BUFFERPOOL/10000000) % 10),
76 #endif
77     (char)('0' + (BUFFERPOOL/1000000) % 10),
78 #endif
79 #ifdef  CHROOTDIR
80     'c',
81 #endif
82 #ifdef  CMDLINE_CONFIG
83     'C',
84 #endif
85 #ifdef  DO_ID
86     'd',
87 #endif
88 #ifdef  DEBUGMODE
89     'D',
90 #endif
91 #ifdef  LOCOP_REHASH
92     'e',
93 #endif
94 #ifdef  OPER_REHASH
95     'E',
96 #endif
97 #ifdef OPER_NO_CHAN_LIMIT
98     'F',
99 #endif
100 #ifdef OPER_MODE_LCHAN
101     'f',
102 #endif
103 #ifdef  HUB
104     'H',
105 #endif
106 #if defined(SHOW_INVISIBLE_USERS) ||  defined(SHOW_ALL_INVISIBLE_USERS)
107 #ifdef  SHOW_ALL_INVISIBLE_USERS
108     'I',
109 #else
110     'i',
111 #endif
112 #endif
113 #ifdef  OPER_KILL
114 #ifdef  LOCAL_KILL_ONLY
115     'k',
116 #else
117     'K',
118 #endif
119 #endif
120 #ifdef  LEAST_IDLE
121     'L',
122 #endif
123 #ifdef OPER_WALK_THROUGH_LMODES
124     'l',
125 #endif
126 #ifdef  IDLE_FROM_MSG
127     'M',
128 #endif
129 #ifdef  USEONE
130     'O',
131 #endif
132 #ifdef NO_OPER_DEOP_LCHAN
133     'o',
134 #endif
135 #ifdef  CRYPT_OPER_PASSWORD
136     'p',
137 #endif
138 #ifdef  CRYPT_LINK_PASSWORD
139     'P',
140 #endif
141 #ifdef  DEBUGMALLOC
142 #ifdef  MEMLEAKSTATS
143     'Q',
144 #else
145     'q',
146 #endif
147 #endif
148 #ifdef  RELIABLE_CLOCK
149     'R',
150 #endif
151 #ifdef  LOCOP_RESTART
152     's',
153 #endif
154 #ifdef  OPER_RESTART
155     'S',
156 #endif
157 #ifdef  OPER_REMOTE
158     't',
159 #endif
160 #if defined(USE_POLL) && defined(HAVE_POLL_H)
161     'U',
162 #endif
163 #ifdef  VIRTUAL_HOST
164     'v',
165 #endif
166 #ifdef BADCHAN
167     'W',
168 #ifdef LOCAL_BADCHAN
169     'x',
170 #endif
171 #endif
172     '\0'
173 };
174
175 /* *INDENT-ON* */
176
177
178 /*
179  * debug_init
180  *
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.
187  */
188 void debug_init(int use_tty)
189 {
190 #ifdef  DEBUGMODE
191   if (debuglevel >= 0) {
192     printf("isatty = %d ttyname = %s\n", isatty(2), ttyname(2));
193     log_debug_init(use_tty ? 0 : LOGFILE);
194   }
195 #endif
196 }
197
198 #ifdef DEBUGMODE
199 void vdebug(int level, const char *form, va_list vl)
200 {
201   static int loop = 0;
202   int err = errno;
203
204   if (!loop && (debuglevel >= 0) && (level <= debuglevel))
205   {
206     loop = 1;
207     log_vwrite(LS_DEBUG, L_DEBUG, 0, form, vl);
208     loop = 0;
209   }
210   errno = err;
211 }
212
213 void debug(int level, const char *form, ...)
214 {
215   va_list vl;
216   va_start(vl, form);
217   vdebug(level, form, vl);
218   va_end(vl);
219 }
220
221 static void debug_enumerator(struct Client* cptr, const char* msg)
222 {
223   assert(0 != cptr);
224   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":%s", msg);
225 }
226
227 /*
228  * This is part of the STATS replies. There is no offical numeric for this
229  * since this isnt an official command, in much the same way as HASH isnt.
230  * It is also possible that some systems wont support this call or have
231  * different field names for "struct rusage".
232  * -avalon
233  */
234 void send_usage(struct Client *cptr, char *nick)
235 {
236   os_get_rusage(cptr, CurrentTime - me.since, debug_enumerator);
237
238   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":DBUF alloc %d used %d",
239              DBufAllocCount, DBufUsedCount);
240 }
241 #endif /* DEBUGMODE */
242
243 void count_memory(struct Client *cptr, char *nick)
244 {
245   struct Client *acptr;
246   struct SLink *link;
247   struct Channel *chptr;
248   struct ConfItem *aconf;
249   const struct ConnectionClass* cltmp;
250   struct Membership* member;
251
252   int lc = 0,                   /* local clients */
253       ch = 0,                   /* channels */
254       lcc = 0,                  /* local client conf links */
255       rc = 0,                   /* remote clients */
256       us = 0,                   /* user structs */
257       chi = 0,                  /* channel invites */
258       chb = 0,                  /* channel bans */
259       wwu = 0,                  /* whowas users */
260       cl = 0,                   /* classes */
261       co = 0,                   /* conf lines */
262       memberships = 0;          /* channel memberships */
263
264   int usi = 0,                  /* users invited */
265       aw = 0,                   /* aways set */
266       wwa = 0;                  /* whowas aways */
267
268   size_t chm = 0,               /* memory used by channels */
269       chbm = 0,                 /* memory used by channel bans */
270       lcm = 0,                  /* memory used by local clients */
271       rcm = 0,                  /* memory used by remote clients */
272       awm = 0,                  /* memory used by aways */
273       wwam = 0,                 /* whowas away memory used */
274       wwm = 0,                  /* whowas array memory used */
275       com = 0,                  /* memory used by conf lines */
276       dbufs_allocated = 0,      /* memory used by dbufs */
277       dbufs_used = 0,           /* memory used by dbufs */
278       msg_allocated = 0,        /* memory used by struct Msg */
279       msg_used = 0,             /* memory used by struct Msg */
280       msgbuf_allocated = 0,     /* memory used by struct MsgBuf */
281       msgbuf_used = 0,          /* memory used by struct MsgBuf */
282       rm = 0,                   /* res memory used */
283       totcl = 0, totch = 0, totww = 0, tot = 0;
284
285   count_whowas_memory(&wwu, &wwm, &wwa, &wwam);
286   wwm += sizeof(struct Whowas) * NICKNAMEHISTORYLENGTH;
287   wwm += sizeof(struct Whowas *) * WW_MAX;
288
289   for (acptr = GlobalClientList; acptr; acptr = acptr->next)
290   {
291     if (MyConnect(acptr))
292     {
293       lc++;
294       for (link = acptr->confs; link; link = link->next)
295         lcc++;
296     }
297     else
298       rc++;
299     if (acptr->user)
300     {
301       us++;
302       for (link = acptr->user->invited; link; link = link->next)
303         usi++;
304       for (member = acptr->user->channel; member; member = member->next_channel)
305         ++memberships;
306       if (acptr->user->away)
307       {
308         aw++;
309         awm += (strlen(acptr->user->away) + 1);
310       }
311     }
312   }
313   lcm = lc * CLIENT_LOCAL_SIZE;
314   rcm = rc * CLIENT_REMOTE_SIZE;
315
316   for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
317   {
318     ch++;
319     chm += (strlen(chptr->chname) + sizeof(struct Channel));
320 #if 0
321     /*
322      * XXX - Members already counted in clients, don't count twice
323      */
324     for (member = chptr->members; member; member = member->next_member)
325       chu++;
326 #endif
327     for (link = chptr->invites; link; link = link->next)
328       chi++;
329     for (link = chptr->banlist; link; link = link->next)
330     {
331       chb++;
332       chbm += (strlen(link->value.cp) + 1 + sizeof(struct SLink));
333     }
334   }
335
336   for (aconf = GlobalConfList; aconf; aconf = aconf->next)
337   {
338     co++;
339     com += aconf->host ? strlen(aconf->host) + 1 : 0;
340     com += aconf->passwd ? strlen(aconf->passwd) + 1 : 0;
341     com += aconf->name ? strlen(aconf->name) + 1 : 0;
342     com += sizeof(struct ConfItem);
343   }
344
345   for (cltmp = get_class_list(); cltmp; cltmp = cltmp->next)
346     cl++;
347
348   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
349              ":Client Local %d(%zu) Remote %d(%zu)", lc, lcm, rc, rcm);
350   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
351              ":Users %d(%zu) Invites %d(%zu)", us, us * sizeof(struct User),
352              usi, usi * sizeof(struct SLink));
353   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
354              ":User channels %d(%zu) Aways %d(%zu)", memberships,
355              memberships * sizeof(struct Membership), aw, awm);
356   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Attached confs %d(%zu)",
357              lcc, lcc * sizeof(struct SLink));
358
359   totcl = lcm + rcm + us * sizeof(struct User) + memberships * sizeof(struct Membership) + awm;
360   totcl += lcc * sizeof(struct SLink) + usi * sizeof(struct SLink);
361
362   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Conflines %d(%zu)", co,
363              com);
364
365   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Classes %d(%zu)", cl,
366              cl * sizeof(struct ConnectionClass));
367
368   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
369              ":Channels %d(%zu) Bans %d(%zu)", ch, chm, chb, chbm);
370   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
371              ":Channel membrs %d(%zu) invite %d(%zu)", memberships,
372              memberships * sizeof(struct Membership), chi,
373              chi * sizeof(struct SLink));
374
375   totch = chm + chbm + chi * sizeof(struct SLink);
376
377   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
378              ":Whowas users %d(%zu) away %d(%zu)", wwu,
379              wwu * sizeof(struct User), wwa, wwam);
380   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Whowas array %d(%zu)",
381              NICKNAMEHISTORYLENGTH, wwm);
382
383   totww = wwu * sizeof(struct User) + wwam + wwm;
384
385   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
386              ":Hash: client %d(%zu), chan is the same", HASHSIZE,
387              sizeof(void *) * HASHSIZE);
388
389   /*
390    * NOTE: this count will be accurate only for the exact instant that this
391    * message is being sent, so the count is affected by the dbufs that
392    * are being used to send this message out. If this is not desired, move
393    * the dbuf_count_memory call to a place before we start sending messages
394    * and cache DBufAllocCount and DBufUsedCount in variables until they 
395    * are sent.
396    */
397   dbuf_count_memory(&dbufs_allocated, &dbufs_used);
398   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
399              ":DBufs allocated %d(%zu) used %d(%zu)", DBufAllocCount,
400              dbufs_allocated, DBufUsedCount, dbufs_used);
401
402   msgq_count_memory(&msg_allocated, &msg_used, &msgbuf_allocated,
403                     &msgbuf_used);
404   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
405              ":Msgs allocated %d(%zu) used %d(%zu)", msgCounts.alloc,
406              msg_allocated, msgCounts.used, msg_used);
407   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
408              ":MsgBufs allocated %d(%zu) used %d(%zu)", msgBufCounts.alloc,
409              msgbuf_allocated, msgBufCounts.used, msgbuf_used);
410
411   rm = cres_mem(cptr);
412
413   tot =
414       totww + totch + totcl + com + cl * sizeof(struct ConnectionClass) +
415       dbufs_allocated + msg_allocated + msgbuf_allocated + rm;
416   tot += sizeof(void *) * HASHSIZE * 3;
417
418 #if !defined(NDEBUG)
419   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Allocations: %zu(%zu)",
420              fda_get_block_count(), fda_get_byte_count());
421 #endif
422
423   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
424              ":Total: ww %zu ch %zu cl %zu co %zu db %zu ms %zu mb %zu",
425              totww, totch, totcl, com, dbufs_allocated, msg_allocated,
426              msgbuf_allocated);
427 }
428