ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/modules/m_stats.c
Revision: 741
Committed: Sun Jul 23 13:49:20 2006 UTC (19 years, 1 month ago) by adx
Content type: text/x-csrc
File size: 44641 byte(s)
Log Message:
+ removed s_conf.h and superseded parts of s_conf.c

File Contents

# Content
1 /*
2 * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3 * m_stats.c: Sends the user statistics or config information.
4 *
5 * Copyright (C) 2002 by the past and present ircd coders, and others.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 * $Id$
23 */
24
25 #include "stdinc.h"
26 #include "conf/conf.h"
27 #include "handlers.h" /* m_pass prototype */
28 #include "client.h" /* Client */
29 #include "common.h" /* TRUE/FALSE */
30 #include "ircd.h" /* me */
31 #include "listener.h" /* show_ports */
32 #include "ircd_handler.h"
33 #include "msg.h" /* Message */
34 #include "hostmask.h"
35 #include "numeric.h" /* ERR_xxx */
36 #include "send.h" /* sendto_one */
37 #include "s_serv.h" /* hunt_server */
38 #include "s_user.h" /* show_opers */
39 #include "parse.h"
40 #include "resv.h" /* report_resv */
41 #include "whowas.h"
42 #include "watch.h"
43 #include "channel.h"
44
45 static void *do_stats(va_list args);
46 static void m_stats(struct Client *, struct Client *, int, char *[]);
47 static void mo_stats(struct Client *, struct Client *, int, char *[]);
48
49 struct Message stats_msgtab = {
50 "STATS", 0, 0, 2, 0, MFLG_SLOW, 0,
51 { m_unregistered, m_stats, mo_stats, m_ignore, mo_stats, m_ignore }
52 };
53
54 static struct Callback *stats_cb;
55
56 INIT_MODULE(m_stats, "$Revision$")
57 {
58 stats_cb = register_callback("doing_stats", do_stats);
59 mod_add_cmd(&stats_msgtab);
60 }
61
62 CLEANUP_MODULE
63 {
64 mod_del_cmd(&stats_msgtab);
65 uninstall_hook(stats_cb, do_stats);
66 }
67
68 static char *parse_stats_args(int, char **, int *, int *);
69 static void stats_L(struct Client *, char *, int, int, char);
70 static void stats_L_list(struct Client *s, char *, int, int, dlink_list *, char);
71
72 static void stats_dns_servers(struct Client *);
73 static void stats_connect(struct Client *);
74 static void stats_deny(struct Client *);
75 static void stats_tdeny(struct Client *);
76 static void stats_exempt(struct Client *);
77 static void stats_events(struct Client *);
78 static void stats_pending_glines(struct Client *);
79 static void stats_glines(struct Client *);
80 static void stats_gdeny(struct Client *);
81 static void stats_hubleaf(struct Client *);
82 static void stats_auth(struct Client *);
83 static void stats_tklines(struct Client *);
84 static void stats_klines(struct Client *);
85 static void stats_messages(struct Client *);
86 static void stats_oper(struct Client *);
87 static void stats_operedup(struct Client *);
88 static void stats_ports(struct Client *);
89 static void stats_resv(struct Client *);
90 static void stats_usage(struct Client *);
91 static void stats_tstats(struct Client *);
92 static void stats_uptime(struct Client *);
93 static void stats_shared(struct Client *);
94 static void stats_servers(struct Client *);
95 static void stats_gecos(struct Client *);
96 static void stats_class(struct Client *);
97 static void stats_memory(struct Client *);
98 static void stats_servlinks(struct Client *);
99 static void stats_ltrace(struct Client *, int, char **);
100 static void stats_ziplinks(struct Client *);
101 static void stats_hooks(struct Client *);
102 static void fd_dump(struct Client *);
103
104 /* This table contains the possible stats items, in order:
105 * /stats name, function to call, operonly? adminonly? /stats letter
106 * case only matters in the stats letter column.. -- fl_ */
107 static const struct StatsStruct
108 {
109 const unsigned char letter;
110 void (*handler)();
111 const unsigned int need_oper;
112 const unsigned int need_admin;
113 } stats_cmd_table[] = {
114 /* letter function need_oper need_admin */
115 { 'a', stats_dns_servers, 1, 1, },
116 { 'A', stats_dns_servers, 1, 1, },
117 { 'c', stats_connect, 1, 0, },
118 { 'C', stats_connect, 1, 0, },
119 { 'd', stats_tdeny, 1, 0, },
120 { 'D', stats_deny, 1, 0, },
121 { 'e', stats_exempt, 1, 0, },
122 { 'E', stats_events, 1, 1, },
123 { 'f', fd_dump, 1, 1, },
124 { 'F', fd_dump, 1, 1, },
125 { 'g', stats_pending_glines, 1, 0, },
126 { 'G', stats_glines, 1, 0, },
127 { 'h', stats_hooks, 1, 1, },
128 { 'H', stats_hubleaf, 1, 0, },
129 { 'i', stats_auth, 0, 0, },
130 { 'I', stats_auth, 0, 0, },
131 { 'k', stats_tklines, 0, 0, },
132 { 'K', stats_klines, 0, 0, },
133 { 'l', stats_ltrace, 1, 0, },
134 { 'L', stats_ltrace, 1, 0, },
135 { 'm', stats_messages, 0, 0, },
136 { 'M', stats_messages, 0, 0, },
137 { 'o', stats_oper, 0, 0, },
138 { 'O', stats_oper, 0, 0, },
139 { 'p', stats_operedup, 0, 0, },
140 { 'P', stats_ports, 0, 0, },
141 { 'q', stats_resv, 1, 0, },
142 { 'Q', stats_resv, 1, 0, },
143 { 'r', stats_usage, 1, 0, },
144 { 'R', stats_usage, 1, 0, },
145 { 't', stats_tstats, 1, 0, },
146 { 'T', stats_tstats, 1, 0, },
147 { 'u', stats_uptime, 0, 0, },
148 { 'U', stats_shared, 1, 0, },
149 { 'v', stats_servers, 1, 0, },
150 { 'V', stats_gdeny, 1, 0, },
151 { 'x', stats_gecos, 1, 0, },
152 { 'X', stats_gecos, 1, 0, },
153 { 'y', stats_class, 1, 0, },
154 { 'Y', stats_class, 1, 0, },
155 { 'z', stats_memory, 1, 0, },
156 { 'Z', stats_ziplinks, 1, 0, },
157 { '?', stats_servlinks, 0, 0, },
158 { '\0', (void(*)())0, 0, 0, }
159 };
160
161 const char *from, *to;
162
163 static void *
164 do_stats(va_list args)
165 {
166 struct Client *source_p = va_arg(args, struct Client *);
167 int parc = va_arg(args, int);
168 char **parv = va_arg(args, char **);
169 char statchar = *parv[1];
170 int i;
171
172 if (statchar == '\0')
173 {
174 sendto_one(source_p, form_str(RPL_ENDOFSTATS),
175 from, to, '*');
176 return NULL;
177 }
178
179 for (i = 0; stats_cmd_table[i].handler; i++)
180 {
181 if (stats_cmd_table[i].letter == statchar)
182 {
183 /* The stats table says what privs are needed, so check --fl_ */
184 if ((stats_cmd_table[i].need_admin && !IsAdmin(source_p)) ||
185 (stats_cmd_table[i].need_oper && !IsOper(source_p)))
186 {
187 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
188 from, to);
189 break;
190 }
191
192 /* Blah, stats L needs the parameters, none of the others do.. */
193 if (statchar == 'L' || statchar == 'l')
194 stats_cmd_table[i].handler(source_p, parc, parv);
195 else
196 stats_cmd_table[i].handler(source_p);
197
198 break;
199 }
200 }
201
202 sendto_one(source_p, form_str(RPL_ENDOFSTATS),
203 from, to, statchar);
204 return NULL;
205 }
206
207 /*
208 * m_stats()
209 * parv[0] = sender prefix
210 * parv[1] = stat letter/command
211 * parv[2] = (if present) server/mask in stats L
212 *
213 * This will search the tables for the appropriate stats letter/command,
214 * if found execute it.
215 */
216 static void
217 m_stats(struct Client *client_p, struct Client *source_p,
218 int parc, char *parv[])
219 {
220 static time_t last_used = 0;
221
222 /* Is the stats meant for us? */
223 if (!ConfigFileEntry.disable_remote)
224 if (hunt_server(source_p, ":%s STATS %s :%s", 2,
225 parc, parv) != HUNTED_ISME)
226 return;
227
228 if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
229 {
230 from = me.id;
231 to = source_p->id;
232 }
233 else
234 {
235 from = me.name;
236 to = source_p->name;
237 }
238
239 /* Check the user is actually allowed to do /stats, and isnt flooding */
240 if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
241 {
242 sendto_one(source_p,form_str(RPL_LOAD2HI),
243 from, to);
244 return;
245 }
246
247 last_used = CurrentTime;
248
249 execute_callback(stats_cb, source_p, parc, parv);
250 }
251
252 /*
253 * mo_stats()
254 * parv[0] = sender prefix
255 * parv[1] = stat letter/command
256 * parv[2] = (if present) server/mask in stats L, or target
257 *
258 * This will search the tables for the appropriate stats letter,
259 * if found execute it.
260 */
261 static void
262 mo_stats(struct Client *client_p, struct Client *source_p,
263 int parc, char *parv[])
264 {
265 if (!IsClient(source_p))
266 return;
267
268 if (hunt_server(source_p, ":%s STATS %s :%s", 2,
269 parc, parv) != HUNTED_ISME)
270 return;
271
272 if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
273 {
274 from = me.id;
275 to = source_p->id;
276 }
277 else
278 {
279 from = me.name;
280 to = source_p->name;
281 }
282
283 execute_callback(stats_cb, source_p, parc, parv);
284 }
285
286 /*
287 * This is part of the STATS replies. There is no offical numeric for this
288 * since this isnt an official command, in much the same way as HASH isnt.
289 * It is also possible that some systems wont support this call or have
290 * different field names for "struct rusage".
291 * -avalon
292 */
293 static void
294 send_usage(struct Client *source_p)
295 {
296 #ifndef _WIN32
297 struct rusage rus;
298 time_t secs;
299 time_t rup;
300 #ifdef hz
301 # define hzz hz
302 #else
303 # ifdef HZ
304 # define hzz HZ
305 # else
306 int hzz = 1;
307 # endif
308 #endif
309
310 if (getrusage(RUSAGE_SELF, &rus) == -1)
311 {
312 sendto_one(source_p, ":%s NOTICE %s :Getruseage error: %s",
313 me.name, source_p->name, strerror(errno));
314 return;
315 }
316
317 secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
318
319 if (secs == 0)
320 secs = 1;
321
322 rup = (CurrentTime - me.since) * hzz;
323
324 if (rup == 0)
325 rup = 1;
326
327 sendto_one(source_p,
328 ":%s %d %s R :CPU Secs %d:%d User %d:%d System %d:%d",
329 me.name, RPL_STATSDEBUG, source_p->name, (int)(secs/60), (int)(secs%60),
330 (int)(rus.ru_utime.tv_sec/60), (int)(rus.ru_utime.tv_sec%60),
331 (int)(rus.ru_stime.tv_sec/60), (int)(rus.ru_stime.tv_sec%60));
332 sendto_one(source_p, ":%s %d %s R :RSS %ld ShMem %ld Data %ld Stack %ld",
333 me.name, RPL_STATSDEBUG, source_p->name, rus.ru_maxrss,
334 (rus.ru_ixrss / rup), (rus.ru_idrss / rup),
335 (rus.ru_isrss / rup));
336 sendto_one(source_p, ":%s %d %s R :Swaps %d Reclaims %d Faults %d",
337 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_nswap,
338 (int)rus.ru_minflt, (int)rus.ru_majflt);
339 sendto_one(source_p, ":%s %d %s R :Block in %d out %d",
340 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_inblock,
341 (int)rus.ru_oublock);
342 sendto_one(source_p, ":%s %d %s R :Msg Rcv %d Send %d",
343 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_msgrcv,
344 (int)rus.ru_msgsnd);
345 sendto_one(source_p, ":%s %d %s R :Signals %d Context Vol. %d Invol %d",
346 me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_nsignals,
347 (int)rus.ru_nvcsw, (int)rus.ru_nivcsw);
348 #endif
349 }
350
351 static void
352 count_memory(struct Client *source_p)
353 {
354 const dlink_node *gptr = NULL;
355 const dlink_node *dlink = NULL;
356
357 int users_counted = 0; /* real Clients counted, i.e. not a server */
358
359 int channel_users = 0; /* XXX */
360 unsigned int channel_invites = 0;
361 int channel_bans = 0;
362 int channel_except = 0;
363 int channel_invex = 0;
364
365 int class_count = 0; /* classes */
366 int aways_counted = 0;
367 int number_ips_stored; /* number of ip addresses hashed */
368
369 size_t channel_memory = 0;
370 size_t channel_ban_memory = 0;
371 size_t channel_except_memory = 0;
372 size_t channel_invex_memory = 0;
373
374 unsigned int safelist_count = 0;
375 size_t safelist_memory = 0;
376
377 size_t away_memory = 0; /* memory used by aways */
378 size_t mem_ips_stored; /* memory used by ip address hash */
379 size_t total_channel_memory = 0;
380
381 unsigned int local_client_count = 0;
382 unsigned int remote_client_count = 0;
383
384 unsigned int local_client_memory_used = 0;
385 unsigned int remote_client_memory_used = 0;
386
387 size_t total_memory = 0;
388 unsigned int topic_count = 0;
389
390 unsigned int wlh = 0; /* watchlist headers */
391 unsigned int wle = 0; /* watchlist entries */
392 size_t wlhm = 0; /* watchlist memory used */
393
394 DLINK_FOREACH(gptr, global_client_list.head)
395 {
396 struct Client *target_p = gptr->data;
397
398 if (MyConnect(target_p))
399 {
400 ++local_client_count;
401 wle += dlink_list_length(&target_p->localClient->watches);
402 }
403 else
404 ++remote_client_count;
405
406 if (IsClient(target_p))
407 {
408 ++users_counted;
409
410 if (target_p->away != NULL)
411 {
412 ++aways_counted;
413 away_memory += strlen(target_p->away) + 1;
414 }
415 }
416 }
417
418 /* Count up all channels, ban lists, except lists, Invex lists */
419 channel_memory = dlink_list_length(&global_channel_list) *
420 sizeof(struct Channel);
421 DLINK_FOREACH(gptr, global_channel_list.head)
422 {
423 struct Ban *actualBan;
424 struct Channel *chptr = gptr->data;
425
426 channel_users += dlink_list_length(&chptr->members);
427 channel_invites += dlink_list_length(&chptr->invites);
428
429 if (chptr->topic != NULL)
430 ++topic_count;
431
432 if ((channel_bans = dlink_list_length(&chptr->banlist)))
433 {
434 channel_ban_memory = channel_bans * sizeof(struct Ban);
435
436 DLINK_FOREACH(dlink, chptr->banlist.head)
437 {
438 actualBan = dlink->data;
439 assert(actualBan->who);
440
441 channel_ban_memory += actualBan->len + 3;
442 channel_ban_memory += strlen(actualBan->who) + 1;
443 }
444 }
445
446 if ((channel_except = dlink_list_length(&chptr->exceptlist)))
447 {
448 channel_except_memory = channel_except * sizeof(struct Ban);
449
450 DLINK_FOREACH(dlink, chptr->exceptlist.head)
451 {
452 actualBan = dlink->data;
453 assert(actualBan->who);
454
455 channel_except_memory += actualBan->len + 3;
456 channel_except_memory += strlen(actualBan->who) + 1;
457 }
458 }
459
460 if ((channel_invex = dlink_list_length(&chptr->invexlist)))
461 {
462 channel_invex_memory = channel_invex * sizeof(struct Ban);
463
464 DLINK_FOREACH(dlink, chptr->invexlist.head)
465 {
466 actualBan = dlink->data;
467 assert(actualBan->who);
468
469 channel_invex_memory += actualBan->len + 3;
470 channel_invex_memory += strlen(actualBan->who) + 1;
471 }
472 }
473 }
474
475 if ((safelist_count = dlink_list_length(&listing_client_list)))
476 {
477 safelist_memory = safelist_count * sizeof(struct ListTask);
478 DLINK_FOREACH(gptr, listing_client_list.head)
479 {
480 struct Client *acptr = gptr->data;
481
482 DLINK_FOREACH(dlink, acptr->localClient->list_task->show_mask.head)
483 safelist_memory += strlen(dlink->data);
484
485 DLINK_FOREACH(dlink, acptr->localClient->list_task->hide_mask.head)
486 safelist_memory += strlen(dlink->data);
487 }
488 }
489
490 watch_count_memory(&wlh, &wlhm);
491
492 sendto_one(source_p, ":%s %d %s z :WATCH headers %u(%u) entries %d(%d)",
493 me.name, RPL_STATSDEBUG, source_p->name, wlh, wlhm, wle,
494 wle * sizeof(dlink_node));
495
496 /* count up all classes */
497 class_count = dlink_list_length(&class_items);
498
499 sendto_one(source_p, ":%s %d %s z :Clients %u(%lu)",
500 me.name, RPL_STATSDEBUG, source_p->name, users_counted,
501 (unsigned long)(users_counted * sizeof(struct Client)));
502
503 sendto_one(source_p, ":%s %d %s z :User aways %u(%u)",
504 me.name, RPL_STATSDEBUG, source_p->name,
505 aways_counted, away_memory);
506
507 sendto_one(source_p, ":%s %d %s z :Resv channels %lu(%lu) nicks %lu(%lu)",
508 me.name, RPL_STATSDEBUG, source_p->name,
509 dlink_list_length(&resv_channel_list),
510 dlink_list_length(&resv_channel_list) * sizeof(struct ResvChannel),
511 dlink_list_length(&nresv_items),
512 dlink_list_length(&nresv_items) * sizeof(struct MatchItem));
513
514 sendto_one(source_p, ":%s %d %s z :Classes %u(%lu)",
515 me.name, RPL_STATSDEBUG, source_p->name,
516 class_count, (unsigned long)(class_count * sizeof(struct ClassItem)));
517
518 sendto_one(source_p, ":%s %d %s z :Channels %lu(%u) Topics %u(%d)",
519 me.name, RPL_STATSDEBUG, source_p->name,
520 dlink_list_length(&global_channel_list),
521 channel_memory, topic_count, topic_count *
522 (TOPICLEN + 1 + USERHOST_REPLYLEN));
523
524 sendto_one(source_p, ":%s %d %s z :Bans %u(%u)",
525 me.name, RPL_STATSDEBUG, source_p->name,
526 channel_bans, channel_ban_memory);
527
528 sendto_one(source_p, ":%s %d %s z :Exceptions %u(%u)",
529 me.name, RPL_STATSDEBUG, source_p->name,
530 channel_except, channel_except_memory);
531
532 sendto_one(source_p, ":%s %d %s z :Invex %u(%u)",
533 me.name, RPL_STATSDEBUG, source_p->name,
534 channel_invex, channel_invex_memory);
535
536 sendto_one(source_p, ":%s %d %s z :Channel members %u(%lu) invites %u(%u)",
537 me.name, RPL_STATSDEBUG, source_p->name, channel_users,
538 (unsigned long)(channel_users * sizeof(struct Membership)),
539 channel_invites, channel_invites * sizeof(dlink_node) * 2);
540
541 total_channel_memory = channel_memory + channel_ban_memory +
542 channel_users * sizeof(struct Membership) +
543 channel_invites * sizeof(dlink_node);
544
545 sendto_one(source_p, ":%s %d %s z :Safelist %u(%u)",
546 me.name, RPL_STATSDEBUG, source_p->name,
547 safelist_count, safelist_memory);
548
549 count_ip_hash(&number_ips_stored, &mem_ips_stored);
550
551 sendto_one(source_p, ":%s %d %s z :iphash %u(%u)",
552 me.name, RPL_STATSDEBUG, source_p->name,
553 number_ips_stored, mem_ips_stored);
554
555 total_memory = total_channel_memory + class_count *
556 sizeof(struct ClassItem);
557
558 sendto_one(source_p, ":%s %d %s z :Total: channel %u",
559 me.name, RPL_STATSDEBUG, source_p->name,
560 total_channel_memory);
561
562 local_client_memory_used = local_client_count*(sizeof(struct Client) + sizeof(struct LocalUser));
563 total_memory += local_client_memory_used;
564 sendto_one(source_p, ":%s %d %s z :Local client Memory in use: %d(%d)",
565 me.name, RPL_STATSDEBUG, source_p->name, local_client_count,
566 local_client_memory_used);
567
568 remote_client_memory_used = remote_client_count * sizeof(struct Client);
569 total_memory += remote_client_memory_used;
570 sendto_one(source_p, ":%s %d %s z :Remote client Memory in use: %d(%d)",
571 me.name, RPL_STATSDEBUG, source_p->name, remote_client_count,
572 remote_client_memory_used);
573
574 DLINK_FOREACH(gptr, block_heap_get_heap_list()->head)
575 {
576 const struct BlockHeap *bh = gptr->data;
577 sendto_one(source_p,
578 ":%s %d %s z :%s mempool: used %u/%u free %u/%u (size %u/%u)",
579 me.name, RPL_STATSDEBUG, source_p->name, bh->name,
580 block_heap_get_used_elm(bh),
581 block_heap_get_used_mem(bh),
582 block_heap_get_free_elm(bh),
583 block_heap_get_free_mem(bh),
584 block_heap_get_size_elm(bh),
585 block_heap_get_size_mem(bh));
586 }
587
588 sendto_one(source_p, ":%s %d %s z :TOTAL: %u",
589 me.name, RPL_STATSDEBUG, source_p->name,
590 total_memory);
591 }
592
593 static void
594 stats_connect(struct Client *source_p)
595 {
596 report_confitem_types(source_p, SERVER_TYPE, 0);
597 }
598
599 /* stats_deny()
600 *
601 * input - client to report to
602 * output - none
603 * side effects - client is given dline list.
604 */
605 static void
606 stats_deny(struct Client *source_p)
607 {
608 struct AddressRec *arec;
609 struct ConfItem *conf;
610 struct AccessItem *aconf;
611 int i;
612
613 for (i = 0; i < ATABLE_SIZE; ++i)
614 {
615 for (arec = atable[i]; arec; arec=arec->next)
616 {
617 if (arec->type == CONF_DLINE)
618 {
619 aconf = arec->aconf;
620
621 /* dont report a tdline as a dline */
622 if (aconf->flags & CONF_FLAGS_TEMPORARY)
623 continue;
624
625 conf = aconf->conf_ptr;
626
627 sendto_one(source_p, form_str(RPL_STATSDLINE),
628 from, to, 'D', aconf->host, aconf->reason,
629 aconf->oper_reason);
630 }
631 }
632 }
633 }
634
635 /* stats_tdeny()
636 *
637 * input - client to report to
638 * output - none
639 * side effects - client is given dline list.
640 */
641 static void
642 stats_tdeny(struct Client *source_p)
643 {
644 struct AddressRec *arec;
645 struct ConfItem *conf;
646 struct AccessItem *aconf;
647 int i;
648
649 for (i = 0; i < ATABLE_SIZE; ++i)
650 {
651 for (arec = atable[i]; arec; arec=arec->next)
652 {
653 if (arec->type == CONF_DLINE)
654 {
655 aconf = arec->aconf;
656
657 /* dont report a permanent dline as a tdline */
658 if (!(aconf->flags & CONF_FLAGS_TEMPORARY))
659 continue;
660
661 conf = aconf->conf_ptr;
662
663 sendto_one(source_p, form_str(RPL_STATSDLINE),
664 from, to, 'd', aconf->host, aconf->reason,
665 aconf->oper_reason);
666 }
667 }
668 }
669 }
670
671 /* stats_exempt()
672 *
673 * input - client to report to
674 * output - none
675 * side effects - client is given list of exempt blocks
676 */
677 static void
678 stats_exempt(struct Client *source_p)
679 {
680 struct AddressRec *arec;
681 struct ConfItem *conf;
682 struct AccessItem *aconf;
683 int i;
684
685 for (i = 0; i < ATABLE_SIZE; ++i)
686 {
687 for (arec = atable[i]; arec; arec=arec->next)
688 {
689 if (arec->type == CONF_EXEMPTDLINE)
690 {
691 aconf = arec->aconf;
692
693 conf = aconf->conf_ptr;
694
695 sendto_one(source_p, form_str(RPL_STATSDLINE),
696 from, to, 'e', aconf->host,
697 aconf->reason, aconf->oper_reason);
698 }
699 }
700 }
701 }
702
703 /* stats_pending_glines()
704 *
705 * input - client pointer
706 * output - none
707 * side effects - client is shown list of pending glines
708 */
709 static void
710 stats_pending_glines(struct Client *source_p)
711 {
712 #ifdef GLINE_VOTING
713 dlink_node *pending_node = NULL;
714 char timebuffer[MAX_DATE_STRING];
715
716 if (!ConfigFileEntry.glines)
717 {
718 sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
719 from, to);
720 return;
721 }
722
723 if (dlink_list_length(&pending_glines) > 0)
724 sendto_one(source_p, ":%s NOTICE %s :Pending G-lines",
725 from, to);
726
727 DLINK_FOREACH(pending_node, pending_glines.head)
728 {
729 struct gline_pending *glp_ptr = pending_node->data;
730 struct tm *tmptr = localtime(&glp_ptr->request1.time_request);
731
732 strftime(timebuffer, sizeof(timebuffer), "%Y/%m/%d %H:%M:%S", tmptr);
733
734 sendto_one(source_p,
735 ":%s NOTICE %s :1) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
736 from, to, glp_ptr->request1.nick,
737 glp_ptr->request1.user, glp_ptr->request1.host,
738 glp_ptr->request1.server, timebuffer,
739 glp_ptr->user, glp_ptr->host, glp_ptr->request1.reason);
740
741 if (glp_ptr->request2.nick[0] != '\0')
742 {
743 tmptr = localtime(&glp_ptr->request2.time_request);
744 strftime(timebuffer, sizeof(timebuffer), "%Y/%m/%d %H:%M:%S", tmptr);
745
746 sendto_one(source_p,
747 ":%s NOTICE %s :2) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
748 from, to, glp_ptr->request2.nick,
749 glp_ptr->request2.user, glp_ptr->request2.host,
750 glp_ptr->request2.server, timebuffer,
751 glp_ptr->user, glp_ptr->host, glp_ptr->request2.reason);
752 }
753 }
754
755 sendto_one(source_p, ":%s NOTICE %s :End of Pending G-lines",
756 from, to);
757 #else
758 sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Line voting",
759 from, to);
760 #endif /* GLINE VOTING */
761 }
762
763 /* stats_glines()
764 *
765 * input - client pointer
766 * output - none
767 * side effects - client is shown list of glines
768 */
769 static void
770 stats_glines(struct Client *source_p)
771 {
772 struct AddressRec *arec = NULL;
773 int i = 0;
774
775 if (!ConfigFileEntry.glines)
776 {
777 sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
778 from, to);
779 return;
780 }
781
782 for (; i < ATABLE_SIZE; ++i)
783 {
784 for (arec = atable[i]; arec; arec=arec->next)
785 {
786 if (arec->type == CONF_GLINE)
787 {
788 const struct AccessItem *aconf = arec->aconf;
789
790 sendto_one(source_p, form_str(RPL_STATSKLINE),
791 from, to, "G",
792 aconf->host ? aconf->host : "*",
793 aconf->user ? aconf->user : "*",
794 aconf->reason ? aconf->reason : "No reason", "" );
795 }
796 }
797 }
798 }
799
800 /* stats_gdeny()
801 *
802 * input - client pointer
803 * outputs - none
804 * side effects - client is shown gline ACL
805 */
806 static void
807 stats_gdeny(struct Client *source_p)
808 {
809 if (!ConfigFileEntry.glines)
810 {
811 sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
812 from, to);
813 return;
814 }
815
816 report_confitem_types(source_p, GDENY_TYPE, 0);
817 }
818
819 static void
820 stats_hubleaf(struct Client *source_p)
821 {
822 report_confitem_types(source_p, HUB_TYPE, 0);
823 report_confitem_types(source_p, LEAF_TYPE, 0);
824 }
825
826 static void
827 stats_auth(struct Client *source_p)
828 {
829 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
830 if ((ConfigFileEntry.stats_i_oper_only == 2) && !IsOper(source_p))
831 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
832 from, to);
833
834 /* If unopered, Only return matching auth blocks */
835 else if ((ConfigFileEntry.stats_i_oper_only == 1) && !IsOper(source_p))
836 {
837 struct ConfItem *conf;
838 struct AccessItem *aconf;
839
840 if (MyConnect(source_p))
841 aconf = find_conf_by_address(source_p->host,
842 &source_p->localClient->ip,
843 CONF_CLIENT,
844 source_p->localClient->aftype,
845 source_p->username,
846 source_p->localClient->passwd);
847 else
848 aconf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
849 0, source_p->username, NULL);
850
851 if (aconf == NULL)
852 return;
853
854 conf = aconf->conf_ptr;
855
856 sendto_one(source_p, form_str(RPL_STATSILINE), from,
857 to, 'I', "*",
858 make_iline_prefix(source_p, aconf), aconf->user,
859 aconf->host, aconf->port,
860 aconf->class_ptr ? aconf->class_ptr->name : "<default>");
861 }
862 /* They are opered, or allowed to see all auth blocks */
863 else
864 report_auth(source_p);
865 }
866
867 static void
868 stats_tklines(struct Client *source_p)
869 {
870 struct ConfItem *conf = NULL;
871 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
872 if ((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
873 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
874 from, to);
875
876 /* If unopered, Only return matching klines */
877 else if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
878 {
879 struct AccessItem *aconf;
880
881 if (MyConnect(source_p))
882 aconf = find_conf_by_address(source_p->host,
883 &source_p->localClient->ip,
884 CONF_KILL,
885 source_p->localClient->aftype,
886 source_p->username, NULL);
887 else
888 aconf = find_conf_by_address(source_p->host, NULL, CONF_KILL,
889 0, source_p->username, NULL);
890
891 if (aconf == NULL)
892 return;
893
894 /* dont report a permanent kline as a tkline */
895 if (!(aconf->flags & CONF_FLAGS_TEMPORARY))
896 return;
897
898 conf = aconf->conf_ptr;
899
900 sendto_one(source_p, form_str(RPL_STATSKLINE), from,
901 to, "k", aconf->host, aconf->user, aconf->reason, "");
902 }
903 /* Theyre opered, or allowed to see all klines */
904 else
905 {
906 report_Klines(source_p, 1);
907 report_confitem_types(source_p, RKLINE_TYPE, 1);
908 }
909 }
910
911 static void
912 stats_klines(struct Client *source_p)
913 {
914 /* Oper only, if unopered, return ERR_NOPRIVILEGES */
915 if ((ConfigFileEntry.stats_k_oper_only == 2) && !IsOper(source_p))
916 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
917 from, to);
918
919 /* If unopered, Only return matching klines */
920 else if ((ConfigFileEntry.stats_k_oper_only == 1) && !IsOper(source_p))
921 {
922 struct AccessItem *aconf;
923
924 /* search for a kline */
925 if (MyConnect(source_p))
926 aconf = find_conf_by_address(source_p->host,
927 &source_p->localClient->ip,
928 CONF_KILL,
929 source_p->localClient->aftype,
930 source_p->username, NULL);
931 else
932 aconf = find_conf_by_address(source_p->host, NULL, CONF_KILL,
933 0, source_p->username, NULL);
934
935 if (aconf == NULL)
936 return;
937
938 /* dont report a tkline as a kline */
939 if (aconf->flags & CONF_FLAGS_TEMPORARY)
940 return;
941
942 sendto_one(source_p, form_str(RPL_STATSKLINE), from,
943 to, "K", aconf->host, aconf->user, aconf->reason,
944 aconf->oper_reason);
945 }
946 /* Theyre opered, or allowed to see all klines */
947 else
948 {
949 report_Klines(source_p, 0);
950 report_confitem_types(source_p, RKLINE_TYPE, 0);
951 }
952 }
953
954 static void
955 stats_messages(struct Client *source_p)
956 {
957 report_messages(source_p);
958 }
959
960 static void
961 stats_oper(struct Client *source_p)
962 {
963 if (!IsOper(source_p) && ConfigFileEntry.stats_o_oper_only)
964 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
965 from, to);
966 else
967 report_confitem_types(source_p, OPER_TYPE, 0);
968 }
969
970 /* stats_operedup()
971 *
972 * input - client pointer
973 * output - none
974 * side effects - client is shown a list of active opers
975 */
976 static void
977 stats_operedup(struct Client *source_p)
978 {
979 dlink_node *ptr;
980
981 DLINK_FOREACH(ptr, oper_list.head)
982 {
983 const struct Client *target_p = ptr->data;
984
985 if (IsOperHidden(target_p) && !IsOper(source_p))
986 continue;
987
988 if (MyClient(source_p) && IsOper(source_p))
989 sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %d",
990 from, RPL_STATSDEBUG, to,
991 IsAdmin(target_p) ?
992 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
993 oper_privs_as_string(target_p->localClient->operflags),
994 target_p->name, target_p->username, target_p->host,
995 (int)(CurrentTime - target_p->localClient->last));
996 else
997 sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %d",
998 from, RPL_STATSDEBUG, to,
999 IsAdmin(target_p) ?
1000 (IsOperHiddenAdmin(target_p) ? 'O' : 'A') : 'O',
1001 target_p->name, target_p->username, target_p->host,
1002 (int)(CurrentTime - target_p->localClient->last));
1003 }
1004
1005 sendto_one(source_p, ":%s %d %s p :%lu OPER(s)",
1006 from, RPL_STATSDEBUG, to, dlink_list_length(&oper_list));
1007 }
1008
1009 /* show_ports()
1010 *
1011 * inputs - pointer to client to show ports to
1012 * output - none
1013 * side effects - send port listing to a client
1014 */
1015 static void
1016 show_ports(struct Client *source_p)
1017 {
1018 char buf[4];
1019 char *p = NULL;
1020 const dlink_node *ptr = NULL;
1021
1022 DLINK_FOREACH(ptr, listener_get_list()->head)
1023 {
1024 const struct Listener *listener = ptr->data;
1025 p = buf;
1026
1027 if (listener->flags & LISTENER_HIDDEN) {
1028 if (!IsAdmin(source_p))
1029 continue;
1030 *p++ = 'H';
1031 }
1032
1033 if (listener->flags & LISTENER_SSL)
1034 *p++ = 's';
1035 *p = '\0';
1036 sendto_one(source_p, form_str(RPL_STATSPLINE),
1037 me.name, source_p->name, 'P', listener->port,
1038 IsAdmin(source_p) ? listener->name : me.name,
1039 listener->ref_count, buf,
1040 listener->active ? "active" : "disabled");
1041 }
1042 }
1043
1044 static void
1045 stats_ports(struct Client *source_p)
1046 {
1047 if (!IsOper(source_p) && ConfigFileEntry.stats_P_oper_only)
1048 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1049 from, to);
1050 else
1051 show_ports(source_p);
1052 }
1053
1054 static void
1055 stats_resv(struct Client *source_p)
1056 {
1057 report_resv(source_p);
1058 }
1059
1060 static void
1061 stats_usage(struct Client *source_p)
1062 {
1063 send_usage(source_p);
1064 }
1065
1066 static void
1067 stats_tstats(struct Client *source_p)
1068 {
1069 const struct Client *target_p = NULL;
1070 struct ServerStatistics sp;
1071 dlink_node *ptr = NULL;
1072
1073 memcpy(&sp, &ServerStats, sizeof(sp));
1074
1075 /*
1076 * must use the += operator. is_sv is not the number of currently
1077 * active server connections. Note the incrementation in
1078 * s_bsd.c:close_connection.
1079 */
1080 sp.is_sv += dlink_list_length(&serv_list);
1081
1082 DLINK_FOREACH(ptr, serv_list.head)
1083 {
1084 target_p = ptr->data;
1085
1086 sp.is_sbs += target_p->localClient->send.bytes;
1087 sp.is_sbr += target_p->localClient->recv.bytes;
1088 sp.is_sti += CurrentTime - target_p->firsttime;
1089 }
1090
1091 sp.is_cl += dlink_list_length(&local_client_list);
1092
1093 DLINK_FOREACH(ptr, local_client_list.head)
1094 {
1095 target_p = ptr->data;
1096
1097 sp.is_cbs += target_p->localClient->send.bytes;
1098 sp.is_cbr += target_p->localClient->recv.bytes;
1099 sp.is_cti += CurrentTime - target_p->firsttime;
1100 }
1101
1102 sp.is_ni += dlink_list_length(&unknown_list);
1103
1104 sendto_one(source_p, ":%s %d %s T :accepts %u refused %u",
1105 me.name, RPL_STATSDEBUG, source_p->name, sp.is_ac, sp.is_ref);
1106 sendto_one(source_p, ":%s %d %s T :unknown commands %u prefixes %u",
1107 me.name, RPL_STATSDEBUG, source_p->name, sp.is_unco, sp.is_unpf);
1108 sendto_one(source_p, ":%s %d %s T :nick collisions %u unknown closes %u",
1109 me.name, RPL_STATSDEBUG, source_p->name, sp.is_kill, sp.is_ni);
1110 sendto_one(source_p, ":%s %d %s T :wrong direction %u empty %u",
1111 me.name, RPL_STATSDEBUG, source_p->name, sp.is_wrdi, sp.is_empt);
1112 sendto_one(source_p, ":%s %d %s T :numerics seen %u",
1113 me.name, RPL_STATSDEBUG, source_p->name, sp.is_num);
1114 sendto_one(source_p, ":%s %d %s T :auth successes %u fails %u",
1115 me.name, RPL_STATSDEBUG, source_p->name, sp.is_asuc, sp.is_abad);
1116 sendto_one(source_p, ":%s %d %s T :Client Server",
1117 me.name, RPL_STATSDEBUG, source_p->name);
1118
1119 sendto_one(source_p, ":%s %d %s T :connected %u %u",
1120 me.name, RPL_STATSDEBUG, source_p->name,
1121 (unsigned int)sp.is_cl,
1122 (unsigned int)sp.is_sv);
1123 sendto_one(source_p, ":%s %d %s T :bytes sent %llu %llu",
1124 me.name, RPL_STATSDEBUG, source_p->name,
1125 sp.is_cbs, sp.is_sbs);
1126 sendto_one(source_p, ":%s %d %s T :bytes recv %llu %llu",
1127 me.name, RPL_STATSDEBUG, source_p->name,
1128 sp.is_cbr, sp.is_sbr);
1129 sendto_one(source_p, ":%s %d %s T :time connected %u %u",
1130 me.name, RPL_STATSDEBUG, source_p->name,
1131 (unsigned int)sp.is_cti,
1132 (unsigned int)sp.is_sti);
1133 }
1134
1135 static void
1136 stats_uptime(struct Client *source_p)
1137 {
1138 time_t now = CurrentTime - me.since;
1139 sendto_one(source_p, form_str(RPL_STATSUPTIME), from, to,
1140 now/86400, (now/3600)%24, (now/60)%60, now%60);
1141 if (!ConfigFileEntry.disable_remote || IsOper(source_p))
1142 sendto_one(source_p, form_str(RPL_STATSCONN), from, to,
1143 MaxConnectionCount, MaxClientCount, Count.totalrestartcount);
1144 }
1145
1146 static void
1147 stats_shared(struct Client *source_p)
1148 {
1149 report_confitem_types(source_p, ULINE_TYPE, 0);
1150 }
1151
1152 /* stats_servers()
1153 *
1154 * input - client pointer
1155 * output - none
1156 * side effects - client is shown lists of who connected servers
1157 */
1158 static void
1159 stats_servers(struct Client *source_p)
1160 {
1161 dlink_node *ptr = NULL;
1162
1163 DLINK_FOREACH(ptr, serv_list.head)
1164 {
1165 const struct Client *target_p = ptr->data;
1166
1167 sendto_one(source_p, ":%s %d %s v :%s (%s!%s@%s) Idle: %d",
1168 from, RPL_STATSDEBUG, to,
1169 target_p->name,
1170 (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
1171 "*", "*", (int)(CurrentTime - target_p->lasttime));
1172 }
1173
1174 sendto_one(source_p, ":%s %d %s v :%lu Server(s)",
1175 from, RPL_STATSDEBUG, to,
1176 dlink_list_length(&serv_list));
1177 }
1178
1179 static void
1180 stats_gecos(struct Client *source_p)
1181 {
1182 report_confitem_types(source_p, XLINE_TYPE, 0);
1183 report_confitem_types(source_p, RXLINE_TYPE, 0);
1184 }
1185
1186 static void
1187 stats_class(struct Client *source_p)
1188 {
1189 report_confitem_types(source_p, CLASS_TYPE, 0);
1190 }
1191
1192 static void
1193 stats_memory(struct Client *source_p)
1194 {
1195 count_memory(source_p);
1196 }
1197
1198 static void
1199 stats_ziplinks(struct Client *source_p)
1200 {
1201 dlink_node *ptr;
1202 struct Client *target_p;
1203 unsigned int sent_data = 0;
1204
1205 DLINK_FOREACH(ptr, serv_list.head)
1206 {
1207 target_p = ptr->data;
1208
1209 if (IsCapable(target_p, CAP_ZIP))
1210 {
1211 /*
1212 * we use memcpy(3) and a local copy of the structure to
1213 * work around a register use bug on GCC on the SPARC.
1214 * -jmallett, 04/27/2002
1215 */
1216 struct ZipStats zipstats;
1217 memcpy(&zipstats, &target_p->localClient->zipstats, sizeof (struct ZipStats));
1218
1219 sendto_one(source_p, ":%s %d %s Z :ZipLinks stats for %s send[%.2f%% "
1220 "compression (%lu bytes data/%lu bytes wire)] recv[%.2f%% "
1221 "compression (%lu bytes data/%lu bytes wire)]",
1222 from, RPL_STATSDEBUG, to, target_p->name,
1223 zipstats.out_ratio, zipstats.out, zipstats.out_wire,
1224 zipstats.in_ratio, zipstats.in, zipstats.in_wire);
1225 ++sent_data;
1226 }
1227 }
1228
1229 sendto_one(source_p, ":%s %d %s Z :%u ziplink(s)",
1230 from, RPL_STATSDEBUG, to, sent_data);
1231 }
1232
1233 static void
1234 stats_servlinks(struct Client *source_p)
1235 {
1236 uint64_t sendB = 0, recvB = 0;
1237 time_t uptime = 0;
1238 dlink_node *ptr = NULL;
1239
1240 if (ConfigServerHide.flatten_links && !IsOper(source_p))
1241 {
1242 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1243 from, to);
1244 return;
1245 }
1246
1247 DLINK_FOREACH(ptr, serv_list.head)
1248 {
1249 const struct Client *target_p = ptr->data;
1250
1251 sendB += target_p->localClient->send.bytes;
1252 recvB += target_p->localClient->recv.bytes;
1253
1254 /* ":%s 211 %s %s %u %u %llu %u %llu :%u %u %s" */
1255 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1256 from, to,
1257 get_client_name(target_p, IsAdmin(source_p) ? SHOW_IP : MASK_IP),
1258 dbuf_length(&target_p->localClient->buf_sendq),
1259 target_p->localClient->send.messages,
1260 target_p->localClient->send.bytes >> 10,
1261 target_p->localClient->recv.messages,
1262 target_p->localClient->recv.bytes >> 10,
1263 (unsigned)(CurrentTime - target_p->firsttime),
1264 (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since): 0,
1265 IsOper(source_p) ? show_capabilities(target_p) : "TS");
1266 }
1267
1268 sendB >>= 10;
1269 recvB >>= 10;
1270
1271 uptime = (CurrentTime - me.since);
1272
1273 sendto_one(source_p, ":%s %d %s ? :%u total server(s)",
1274 from, RPL_STATSDEBUG, to, dlink_list_length(&serv_list));
1275 sendto_one(source_p, ":%s %d %s ? :Sent total : %7.2f %s",
1276 from, RPL_STATSDEBUG, to,
1277 _GMKv(sendB), _GMKs(sendB));
1278 sendto_one(source_p, ":%s %d %s ? :Recv total : %7.2f %s",
1279 from, RPL_STATSDEBUG, to,
1280 _GMKv(recvB), _GMKs(recvB));
1281
1282 sendto_one(source_p, ":%s %d %s ? :Server send: %7.2f %s (%4.1f K/s)",
1283 from, RPL_STATSDEBUG, to,
1284 _GMKv((me.localClient->send.bytes>>10)),
1285 _GMKs((me.localClient->send.bytes>>10)),
1286 (float)((float)(me.localClient->send.bytes >> 10) /
1287 (float)uptime));
1288 sendto_one(source_p, ":%s %d %s ? :Server recv: %7.2f %s (%4.1f K/s)",
1289 from, RPL_STATSDEBUG, to,
1290 _GMKv((me.localClient->recv.bytes>>10)),
1291 _GMKs((me.localClient->recv.bytes>>10)),
1292 (float)((float)(me.localClient->recv.bytes >> 10) /
1293 (float)uptime));
1294 }
1295
1296 static void
1297 stats_ltrace(struct Client *source_p, int parc, char *parv[])
1298 {
1299 int doall = 0;
1300 int wilds = 0;
1301 char *name = NULL;
1302 char statchar;
1303
1304 if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
1305 {
1306 statchar = *parv[1];
1307
1308 stats_L(source_p, name, doall, wilds, statchar);
1309 }
1310 else
1311 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
1312 from, to, "STATS");
1313 }
1314
1315 static void
1316 stats_hooks(struct Client *source_p)
1317 {
1318 dlink_node *ptr;
1319 struct Callback *cb;
1320 char lastused[32];
1321
1322 sendto_one(source_p, ":%s %d %s : %-20s %-20s Used Hooks", me.name,
1323 RPL_STATSDEBUG, source_p->name, "Callback", "Last Execution");
1324 sendto_one(source_p, ":%s %d %s : ------------------------------------"
1325 "--------------------", me.name, RPL_STATSDEBUG, source_p->name);
1326
1327 DLINK_FOREACH(ptr, callback_list.head)
1328 {
1329 cb = ptr->data;
1330
1331 if (cb->last != 0)
1332 snprintf(lastused, sizeof(lastused), "%d seconds ago",
1333 (int) (CurrentTime - cb->last));
1334 else
1335 strcpy(lastused, "NEVER");
1336
1337 sendto_one(source_p, ":%s %d %s : %-20s %-20s %-8u %d", me.name,
1338 RPL_STATSDEBUG, source_p->name, cb->name, lastused, cb->called,
1339 dlink_list_length(&cb->chain));
1340 }
1341
1342 sendto_one(source_p, ":%s %d %s : ", me.name, RPL_STATSDEBUG,
1343 source_p->name);
1344 }
1345
1346 static void
1347 stats_events(struct Client *source_p)
1348 {
1349 int i;
1350
1351 if (last_event_ran)
1352 {
1353 sendto_one(source_p, ":%s %d %s :Last event to run: %s",
1354 me.name, RPL_STATSDEBUG, source_p->name, last_event_ran);
1355 sendto_one(source_p, ":%s %d %s : ",
1356 me.name, RPL_STATSDEBUG, source_p->name);
1357 }
1358
1359 sendto_one(source_p,
1360 ":%s %d %s : Operation Next Execution",
1361 me.name, RPL_STATSDEBUG, source_p->name);
1362 sendto_one(source_p,
1363 ":%s %d %s : -------------------------------------------",
1364 me.name, RPL_STATSDEBUG, source_p->name);
1365
1366 for (i = 0; i < MAX_EVENTS; ++i)
1367 if (event_table[i].active)
1368 sendto_one(source_p, ":%s %d %s : %-28s %-4d seconds",
1369 me.name, RPL_STATSDEBUG, source_p->name,
1370 event_table[i].name,
1371 (int)(event_table[i].when - CurrentTime));
1372
1373 sendto_one(source_p, ":%s %d %s : ",
1374 me.name, RPL_STATSDEBUG, source_p->name);
1375 }
1376
1377 static void
1378 stats_dns_servers(struct Client *source_p)
1379 {
1380 int i;
1381 char ipaddr[HOSTIPLEN];
1382
1383 for (i = 0; i < irc_nscount; ++i)
1384 {
1385 irc_getnameinfo((struct sockaddr *)&(irc_nsaddr_list[i]),
1386 irc_nsaddr_list[i].ss_len, ipaddr, sizeof(ipaddr), NULL, 0,
1387 NI_NUMERICHOST);
1388 sendto_one(source_p, form_str(RPL_STATSALINE),
1389 me.name, source_p->name, ipaddr);
1390 }
1391 }
1392
1393 static void
1394 fd_dump(struct Client *source_p)
1395 {
1396 int i;
1397 fde_t *F;
1398
1399 for (i = 0; i < FD_HASH_SIZE; ++i)
1400 for (F = fd_hash[i]; F != NULL; F = F->hnext)
1401 sendto_one(source_p, ":%s %d %s :fd %-5d desc '%s'",
1402 me.name, RPL_STATSDEBUG, source_p->name,
1403 F->fd, F->desc);
1404 }
1405
1406 /*
1407 * stats_L
1408 *
1409 * inputs - pointer to client to report to
1410 * - doall flag
1411 * - wild card or not
1412 * output - NONE
1413 * side effects -
1414 */
1415 static void
1416 stats_L(struct Client *source_p,char *name,int doall,
1417 int wilds,char statchar)
1418 {
1419 stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1420 stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1421 stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
1422 }
1423
1424 static void
1425 stats_L_list(struct Client *source_p, char *name, int doall, int wilds,
1426 dlink_list *list, char statchar)
1427 {
1428 dlink_node *ptr = NULL;
1429
1430 /*
1431 * send info about connections which match, or all if the
1432 * mask matches from. Only restrictions are on those who
1433 * are invisible not being visible to 'foreigners' who use
1434 * a wild card based search to list it.
1435 */
1436 DLINK_FOREACH(ptr, list->head)
1437 {
1438 int ip_action = 0;
1439 const struct Client *target_p = ptr->data;
1440
1441 if (IsInvisible(target_p) && (doall || wilds) &&
1442 !(MyConnect(source_p) && IsOper(source_p)) &&
1443 !IsOper(target_p) && (target_p != source_p))
1444 continue;
1445 if (!doall && wilds && !match(name, target_p->name))
1446 continue;
1447 if (!(doall || wilds) && irccmp(name, target_p->name))
1448 continue;
1449
1450 if (IsIPSpoof(target_p) || IsServer(target_p) || IsAdmin(target_p) ||
1451 IsHandshake(target_p) || IsConnecting(target_p))
1452 ip_action = MASK_IP;
1453 else if (IsUpper(statchar))
1454 ip_action = SHOW_IP;
1455 else
1456 ip_action = HIDE_IP;
1457
1458 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1459 from, to, get_client_name(target_p, ip_action),
1460 dbuf_length(&target_p->localClient->buf_sendq),
1461 target_p->localClient->send.messages,
1462 target_p->localClient->send.bytes>>10,
1463 target_p->localClient->recv.messages,
1464 target_p->localClient->recv.bytes>>10,
1465 (unsigned)(CurrentTime - target_p->firsttime),
1466 (CurrentTime > target_p->since) ? (unsigned)(CurrentTime - target_p->since):0,
1467 IsServer(target_p) ? show_capabilities(target_p) : "-");
1468 }
1469 }
1470
1471 /* parse_stats_args()
1472 *
1473 * inputs - arg count
1474 * - args
1475 * - doall flag
1476 * - wild card or not
1477 * output - pointer to name to use
1478 * side effects -
1479 * common parse routine for m_stats args
1480 *
1481 */
1482 static char *
1483 parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1484 {
1485 char *name = NULL;
1486
1487 if (parc > 2)
1488 {
1489 name = parv[2];
1490
1491 if (!irccmp(name, from))
1492 *doall = 2;
1493 else if (match(name, from))
1494 *doall = 1;
1495
1496 *wilds = has_wildcards(name);
1497
1498 return name;
1499 }
1500
1501 return NULL;
1502 }

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision