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 #ifdef  USE_SYSLOG
172     'Y',
173 #endif
174     '\0'
175 };
176
177 /* *INDENT-ON* */
178
179
180 /*
181  * debug_init
182  *
183  * If the -t option is not given on the command line when the server is
184  * started, all debugging output is sent to the file set by LPATH in config.h
185  * Here we just open that file and make sure it is opened to fd 2 so that
186  * any fprintf's to stderr also goto the logfile.  If the debuglevel is not
187  * set from the command line by -x, use /dev/null as the dummy logfile as long
188  * as DEBUGMODE has been defined, else dont waste the fd.
189  */
190 void debug_init(int use_tty)
191 {
192 #ifdef  DEBUGMODE
193   if (debuglevel >= 0) {
194     printf("isatty = %d ttyname = %s\n", isatty(2), ttyname(2));
195     log_debug_init(use_tty ? 0 : LOGFILE);
196   }
197 #endif
198 }
199
200 #ifdef DEBUGMODE
201 void vdebug(int level, const char *form, va_list vl)
202 {
203   static int loop = 0;
204   int err = errno;
205
206   if (!loop && (debuglevel >= 0) && (level <= debuglevel))
207   {
208     loop = 1;
209     log_vwrite(LS_DEBUG, L_DEBUG, 0, form, vl);
210     loop = 0;
211   }
212   errno = err;
213 }
214
215 void debug(int level, const char *form, ...)
216 {
217   va_list vl;
218   va_start(vl, form);
219   vdebug(level, form, vl);
220   va_end(vl);
221 }
222
223 static void debug_enumerator(struct Client* cptr, const char* msg)
224 {
225   assert(0 != cptr);
226   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":%s", msg);
227 }
228
229 /*
230  * This is part of the STATS replies. There is no offical numeric for this
231  * since this isnt an official command, in much the same way as HASH isnt.
232  * It is also possible that some systems wont support this call or have
233  * different field names for "struct rusage".
234  * -avalon
235  */
236 void send_usage(struct Client *cptr, char *nick)
237 {
238   os_get_rusage(cptr, CurrentTime - me.since, debug_enumerator);
239
240   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":DBUF alloc %d used %d",
241              DBufAllocCount, DBufUsedCount);
242 }
243 #endif /* DEBUGMODE */
244
245 void count_memory(struct Client *cptr, char *nick)
246 {
247   struct Client *acptr;
248   struct SLink *link;
249   struct Channel *chptr;
250   struct ConfItem *aconf;
251   const struct ConnectionClass* cltmp;
252   struct Membership* member;
253
254   int lc = 0,                   /* local clients */
255       ch = 0,                   /* channels */
256       lcc = 0,                  /* local client conf links */
257       rc = 0,                   /* remote clients */
258       us = 0,                   /* user structs */
259       chi = 0,                  /* channel invites */
260       chb = 0,                  /* channel bans */
261       wwu = 0,                  /* whowas users */
262       cl = 0,                   /* classes */
263       co = 0,                   /* conf lines */
264       memberships = 0;          /* channel memberships */
265
266   int usi = 0,                  /* users invited */
267       aw = 0,                   /* aways set */
268       wwa = 0;                  /* whowas aways */
269
270   size_t chm = 0,               /* memory used by channels */
271       chbm = 0,                 /* memory used by channel bans */
272       lcm = 0,                  /* memory used by local clients */
273       rcm = 0,                  /* memory used by remote clients */
274       awm = 0,                  /* memory used by aways */
275       wwam = 0,                 /* whowas away memory used */
276       wwm = 0,                  /* whowas array memory used */
277       com = 0,                  /* memory used by conf lines */
278       dbufs_allocated = 0,      /* memory used by dbufs */
279       dbufs_used = 0,           /* memory used by dbufs */
280       rm = 0,                   /* res memory used */
281       totcl = 0, totch = 0, totww = 0, tot = 0;
282
283   count_whowas_memory(&wwu, &wwm, &wwa, &wwam);
284   wwm += sizeof(struct Whowas) * NICKNAMEHISTORYLENGTH;
285   wwm += sizeof(struct Whowas *) * WW_MAX;
286
287   for (acptr = GlobalClientList; acptr; acptr = acptr->next)
288   {
289     if (MyConnect(acptr))
290     {
291       lc++;
292       for (link = acptr->confs; link; link = link->next)
293         lcc++;
294     }
295     else
296       rc++;
297     if (acptr->user)
298     {
299       us++;
300       for (link = acptr->user->invited; link; link = link->next)
301         usi++;
302       for (member = acptr->user->channel; member; member = member->next_channel)
303         ++memberships;
304       if (acptr->user->away)
305       {
306         aw++;
307         awm += (strlen(acptr->user->away) + 1);
308       }
309     }
310   }
311   lcm = lc * CLIENT_LOCAL_SIZE;
312   rcm = rc * CLIENT_REMOTE_SIZE;
313
314   for (chptr = GlobalChannelList; chptr; chptr = chptr->next)
315   {
316     ch++;
317     chm += (strlen(chptr->chname) + sizeof(struct Channel));
318 #if 0
319     /*
320      * XXX - Members already counted in clients, don't count twice
321      */
322     for (member = chptr->members; member; member = member->next_member)
323       chu++;
324 #endif
325     for (link = chptr->invites; link; link = link->next)
326       chi++;
327     for (link = chptr->banlist; link; link = link->next)
328     {
329       chb++;
330       chbm += (strlen(link->value.cp) + 1 + sizeof(struct SLink));
331     }
332   }
333
334   for (aconf = GlobalConfList; aconf; aconf = aconf->next)
335   {
336     co++;
337     com += aconf->host ? strlen(aconf->host) + 1 : 0;
338     com += aconf->passwd ? strlen(aconf->passwd) + 1 : 0;
339     com += aconf->name ? strlen(aconf->name) + 1 : 0;
340     com += sizeof(struct ConfItem);
341   }
342
343   for (cltmp = get_class_list(); cltmp; cltmp = cltmp->next)
344     cl++;
345
346   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
347              ":Client Local %d(%zu) Remote %d(%zu)", lc, lcm, rc, rcm);
348   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
349              ":Users %d(%zu) Invites %d(%zu)", us, us * sizeof(struct User),
350              usi, usi * sizeof(struct SLink));
351   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
352              ":User channels %d(%zu) Aways %d(%zu)", memberships,
353              memberships * sizeof(struct Membership), aw, awm);
354   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Attached confs %d(%zu)",
355              lcc, lcc * sizeof(struct SLink));
356
357   totcl = lcm + rcm + us * sizeof(struct User) + memberships * sizeof(struct Membership) + awm;
358   totcl += lcc * sizeof(struct SLink) + usi * sizeof(struct SLink);
359
360   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Conflines %d(%zu)", co,
361              com);
362
363   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Classes %d(%zu)", cl,
364              cl * sizeof(struct ConnectionClass));
365
366   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
367              ":Channels %d(%zu) Bans %d(%zu)", ch, chm, chb, chbm);
368   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
369              ":Channel membrs %d(%zu) invite %d(%zu)", memberships,
370              memberships * sizeof(struct Membership), chi,
371              chi * sizeof(struct SLink));
372
373   totch = chm + chbm + chi * sizeof(struct SLink);
374
375   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
376              ":Whowas users %d(%zu) away %d(%zu)", wwu,
377              wwu * sizeof(struct User), wwa, wwam);
378   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Whowas array %d(%zu)",
379              NICKNAMEHISTORYLENGTH, wwm);
380
381   totww = wwu * sizeof(struct User) + wwam + wwm;
382
383   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
384              ":Hash: client %d(%zu), chan is the same", HASHSIZE,
385              sizeof(void *) * HASHSIZE);
386
387   /*
388    * NOTE: this count will be accurate only for the exact instant that this
389    * message is being sent, so the count is affected by the dbufs that
390    * are being used to send this message out. If this is not desired, move
391    * the dbuf_count_memory call to a place before we start sending messages
392    * and cache DBufAllocCount and DBufUsedCount in variables until they 
393    * are sent.
394    */
395   dbuf_count_memory(&dbufs_allocated, &dbufs_used);
396   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
397              ":DBufs allocated %d(%zu) used %d(%zu)", DBufAllocCount,
398              dbufs_allocated, DBufUsedCount, dbufs_used);
399
400   rm = cres_mem(cptr);
401
402   tot =
403       totww + totch + totcl + com + cl * sizeof(struct ConnectionClass) + dbufs_allocated +
404       rm;
405   tot += sizeof(void *) * HASHSIZE * 3;
406
407 #if !defined(NDEBUG)
408   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG, ":Allocations: %zu(%zu)",
409              fda_get_block_count(), fda_get_byte_count());
410 #endif
411
412   send_reply(cptr, SND_EXPLICIT | RPL_STATSDEBUG,
413              ":Total: ww %zu ch %zu cl %zu co %zu db %zu", totww, totch,
414              totcl, com, dbufs_allocated);
415 }
416