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