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