2 * IRC - Internet Relay Chat, ircd/m_stats.c
3 * Copyright (C) 1990 Jarkko Oikarinen and
4 * University of Oulu, Computing Center
6 * See file AUTHORS in IRC package for additional names of
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 1, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27 * m_functions execute protocol messages on this server:
29 * cptr is always NON-NULL, pointing to a *LOCAL* client
30 * structure (with an open socket connected!). This
31 * identifies the physical socket where the message
32 * originated (or which caused the m_function to be
33 * executed--some m_functions may call others...).
35 * sptr is the source of the message, defined by the
36 * prefix part of the message if present. If not
37 * or prefix not found, then sptr==cptr.
39 * (!IsServer(cptr)) => (cptr == sptr), because
40 * prefixes are taken *only* from servers...
43 * (sptr == cptr) => the message didn't
46 * (sptr != cptr && IsServer(sptr) means
47 * the prefix specified servername. (?)
49 * (sptr != cptr && !IsServer(sptr) means
50 * that message originated from a remote
55 * (!IsServer(sptr)) means that, sptr can safely
56 * taken as defining the target structure of the
57 * message in this server.
59 * *Always* true (if 'parse' and others are working correct):
61 * 1) sptr->from == cptr (note: cptr->from == cptr)
63 * 2) MyConnect(sptr) <=> sptr == cptr (e.g. sptr
64 * *cannot* be a local connection, unless it's
65 * actually cptr!). [MyConnect(x) should probably
66 * be defined as (x == x->from) --msa ]
68 * parc number of variable parameter strings (if zero,
69 * parv is allowed to be NULL)
71 * parv a NULL terminated list of parameter pointers,
73 * parv[0], sender (prefix string), if not present
74 * this points to an empty string.
75 * parv[1]...parv[parc-1]
76 * pointers to additional parameters
77 * parv[parc] == NULL, *always*
79 * note: it is guaranteed that parv[0]..parv[parc-1] are all
84 * No need to include handlers.h here the signatures must match
85 * and we don't need to force a rebuild of all the handlers everytime
86 * we add a new one to the list. --Bleep
99 #include "ircd_alloc.h"
100 #include "ircd_chattr.h"
101 #include "ircd_reply.h"
102 #include "ircd_string.h"
104 #include "listener.h"
108 #include "numnicks.h"
109 #include "opercmds.h"
118 #include "userload.h"
125 * m_stats - generic message handler
127 * parv[0] = sender prefix
128 * parv[1] = statistics selector (defaults to Message frequency)
129 * parv[2] = target server (current server defaulted, if omitted)
130 * And 'stats l' and 'stats' L:
131 * parv[3] = server mask ("*" defaulted, if omitted)
133 * parv[3] = port mask (returns p-lines when its port is matched by this)
134 * Or for stats k,K,i and I:
135 * parv[3] = [user@]host.name (returns which K/I-lines match this)
136 * or [user@]host.mask (returns which K/I-lines are mmatched by this)
137 * (defaults to old reply if ommitted, when local or Oper)
138 * A remote mask (something containing wildcards) is only
139 * allowed for IRC Operators.
141 * parv[3] = time param
142 * parv[4] = time param
143 * (see report_memleak_stats() in runmalloc.c for details)
145 * This function is getting really ugly. -Ghostwolf
147 int m_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
149 static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
150 "RcveM RcveKBytes :Open since";
151 static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
152 struct Message *mptr;
153 struct Client *acptr;
155 struct ConfItem *aconf;
156 char stat = parc > 1 ? parv[1][0] : '\0';
159 /* m_stats is so obnoxiously full of special cases that the different
160 * hunt_server() possiblites were becoming very messy. It now uses a
161 * switch() so as to be easier to read and update as params change.
166 /* open to all, standard # of params */
170 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
176 /* open to all, varying # of params */
186 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
192 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
199 /* oper only, varying # of params */
206 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
212 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
213 parv) != HUNTED_ISME)
216 else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
222 /* oper only, standard # of params */
225 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
237 int doall = 0, wilds = 0;
239 if (parc > 3 && *parv[3])
243 wilds = (*name == '*' || *name == '?');
244 for (p = name + 1; *p; ++p)
245 if ((*p == '*' || *p == '?') && p[-1] != '\\')
254 * Send info about connections which match, or all if the
255 * mask matches me.name. Only restrictions are on those who
256 * are invisible not being visible to 'foreigners' who use
257 * a wild card based search to list it.
259 sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
260 for (i = 0; i <= HighestFd; i++)
262 if (!(acptr = LocalClientArray[i]))
264 /* Don't return clients when this is a request for `all' */
265 if (doall && IsUser(acptr))
267 /* Don't show invisible people to unauthorized people when using
268 * wildcards -- Is this still needed now /stats is oper only ?
269 * Yeah it is -- non opers can /stats l, just not remotely.
271 if (IsInvisible(acptr) && (doall || wilds) &&
272 !(MyConnect(sptr) && IsOper(sptr)) &&
273 !IsAnOper(acptr) && (acptr != sptr))
275 /* Only show the ones that match the given mask - if any */
276 if (!doall && wilds && match(name, acptr->name))
278 /* Skip all that do not match the specific query */
279 if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
281 sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
282 acptr->name, (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
283 (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
284 CurrentTime - acptr->firsttime);
290 report_configured_links(sptr, CONF_SERVER);
293 case 'g': /* send glines */
294 gline_remove_expired(TStime());
295 for (gline = GlobalGlineList; gline; gline = gline->next) {
296 sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
297 sptr->name, 'G', gline->name, gline->host,
298 gline->expire, gline->reason);
307 case 'k': /* display CONF_IPKILL as well
311 char *user, *host, *p;
312 int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
313 if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
315 report_configured_links(sptr, conf_status);
318 if (parc < 4 || *parv[3] == '\0')
319 return need_more_params(sptr,
320 (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
323 for (p = parv[3]; *p; p++)
331 if (*p == '?' || *p == '*')
337 if (!(MyConnect(sptr) || IsOper(sptr)))
345 if (conf_status == CONF_CLIENT)
347 user = 0; /* Not used, but to avoid compiler warning. */
353 if ((host = strchr(parv[3], '@')))
364 for (aconf = GlobalConfList; aconf; aconf = aconf->next)
366 if ((aconf->status & conf_status))
368 if (conf_status == CONF_KLINE)
370 if ((!wilds && ((user || aconf->host[1]) &&
371 !match(aconf->host, host) &&
372 (!user || !match(aconf->name, user)))) ||
373 (wilds && !mmatch(host, aconf->host) &&
374 (!user || !mmatch(user, aconf->name))))
376 sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
377 sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
378 aconf->port, get_conf_class(aconf));
383 else if (conf_status == CONF_CLIENT)
385 if ((!wilds && (!match(aconf->host, host) ||
386 !match(aconf->name, host))) ||
387 (wilds && (!mmatch(host, aconf->host) ||
388 !mmatch(host, aconf->name))))
390 sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
391 sptr->name, 'I', aconf->host, aconf->name,
392 aconf->port, get_conf_class(aconf));
403 sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
404 me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
409 sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
410 me.name, parv[0], get_mem_size(), get_alloc_cnt());
413 report_memleak_stats(sptr, parc, parv);
415 #if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
416 sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
417 "is not enabled on this server", me.name, parv[0]);
422 for (mptr = msgtab; mptr->cmd; mptr++)
424 sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
425 me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
429 report_configured_links(sptr, CONF_OPS);
434 * show listener ports
435 * show hidden ports to opers, if there are more than 3 parameters,
436 * interpret the fourth parameter as the port number, limit non-local
437 * or non-oper results to 8 ports.
439 show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0,
440 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
445 send_usage(sptr, parv[0]);
449 report_configured_links(sptr, CONF_CRULEALL);
452 report_configured_links(sptr, CONF_CRULE);
455 tstats(sptr, parv[0]);
458 report_configured_links(sptr, CONF_TLINES);
461 report_configured_links(sptr, CONF_UWORLD);
467 nowr = CurrentTime - me.since;
468 sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
469 nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
470 sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
471 max_connection_count, max_client_count);
481 send_listinfo(sptr, parv[0]);
486 report_classes(sptr);
490 count_memory(sptr, parv[0]);
496 sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
501 * ms_stats - server message handler
503 * parv[0] = sender prefix
504 * parv[1] = statistics selector (defaults to Message frequency)
505 * parv[2] = target server (current server defaulted, if omitted)
506 * And 'stats l' and 'stats' L:
507 * parv[3] = server mask ("*" defaulted, if omitted)
509 * parv[3] = port mask (returns p-lines when its port is matched by this)
510 * Or for stats k,K,i and I:
511 * parv[3] = [user@]host.name (returns which K/I-lines match this)
512 * or [user@]host.mask (returns which K/I-lines are mmatched by this)
513 * (defaults to old reply if ommitted, when local or Oper)
514 * A remote mask (something containing wildcards) is only
515 * allowed for IRC Operators.
517 * parv[3] = time param
518 * parv[4] = time param
519 * (see report_memleak_stats() in runmalloc.c for details)
521 * This function is getting really ugly. -Ghostwolf
523 int ms_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
525 static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
526 "RcveM RcveKBytes :Open since";
527 static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
528 struct Message *mptr;
529 struct Client *acptr;
531 struct ConfItem *aconf;
532 char stat = parc > 1 ? parv[1][0] : '\0';
535 /* m_stats is so obnoxiously full of special cases that the different
536 * hunt_server() possiblites were becoming very messy. It now uses a
537 * switch() so as to be easier to read and update as params change.
542 /* open to all, standard # of params */
546 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
552 /* open to all, varying # of params */
562 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
568 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
575 /* oper only, varying # of params */
582 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
588 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
589 parv) != HUNTED_ISME)
592 else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
598 /* oper only, standard # of params */
601 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
613 int doall = 0, wilds = 0;
615 if (parc > 3 && *parv[3])
619 wilds = (*name == '*' || *name == '?');
620 for (p = name + 1; *p; ++p)
621 if ((*p == '*' || *p == '?') && p[-1] != '\\')
630 * Send info about connections which match, or all if the
631 * mask matches me.name. Only restrictions are on those who
632 * are invisible not being visible to 'foreigners' who use
633 * a wild card based search to list it.
635 sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
636 for (i = 0; i <= HighestFd; i++)
638 if (!(acptr = LocalClientArray[i]))
640 /* Don't return clients when this is a request for `all' */
641 if (doall && IsUser(acptr))
643 /* Don't show invisible people to unauthorized people when using
644 * wildcards -- Is this still needed now /stats is oper only ? */
645 if (IsInvisible(acptr) && (doall || wilds) &&
646 !(MyConnect(sptr) && IsOper(sptr)) &&
647 !IsAnOper(acptr) && (acptr != sptr))
649 /* Only show the ones that match the given mask - if any */
650 if (!doall && wilds && match(name, acptr->name))
652 /* Skip all that do not match the specific query */
653 if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
655 sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
656 acptr->name, (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
657 (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
658 CurrentTime - acptr->firsttime);
665 report_configured_links(sptr, CONF_SERVER);
668 case 'g': /* send glines */
669 gline_remove_expired(TStime());
670 for (gline = GlobalGlineList; gline; gline = gline->next) {
671 sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
672 sptr->name, 'G', gline->name, gline->host,
673 gline->expire, gline->reason);
678 report_configured_links(sptr, CONF_HUB | CONF_LEAF);
683 case 'k': /* display CONF_IPKILL as well
687 char *user, *host, *p;
688 int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
689 if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
691 report_configured_links(sptr, conf_status);
694 if (parc < 4 || *parv[3] == '\0')
695 return need_more_params(sptr,
696 (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
699 for (p = parv[3]; *p; p++)
707 if (*p == '?' || *p == '*')
713 if (!(MyConnect(sptr) || IsOper(sptr)))
721 if (conf_status == CONF_CLIENT)
723 user = 0; /* Not used, but to avoid compiler warning. */
729 if ((host = strchr(parv[3], '@')))
740 for (aconf = GlobalConfList; aconf; aconf = aconf->next)
742 if ((aconf->status & conf_status))
744 if (conf_status == CONF_KLINE)
746 if ((!wilds && ((user || aconf->host[1]) &&
747 !match(aconf->host, host) &&
748 (!user || !match(aconf->name, user)))) ||
749 (wilds && !mmatch(host, aconf->host) &&
750 (!user || !mmatch(user, aconf->name))))
752 sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
753 sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
754 aconf->port, get_conf_class(aconf));
759 else if (conf_status == CONF_CLIENT)
761 if ((!wilds && (!match(aconf->host, host) ||
762 !match(aconf->name, host))) ||
763 (wilds && (!mmatch(host, aconf->host) ||
764 !mmatch(host, aconf->name))))
766 sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
767 sptr->name, 'I', aconf->host, aconf->name,
768 aconf->port, get_conf_class(aconf));
779 sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
780 me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
785 sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
786 me.name, parv[0], get_mem_size(), get_alloc_cnt());
789 report_memleak_stats(sptr, parc, parv);
791 #if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
792 sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
793 "is not enabled on this server", me.name, parv[0]);
798 for (mptr = msgtab; mptr->cmd; mptr++)
800 sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
801 me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
805 report_configured_links(sptr, CONF_OPS);
810 * show listener ports
811 * show hidden ports to opers, if there are more than 3 parameters,
812 * interpret the fourth parameter as the port number, limit non-local
813 * or non-oper results to 8 ports.
815 show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0,
816 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
821 send_usage(sptr, parv[0]);
825 report_configured_links(sptr, CONF_CRULEALL);
828 report_configured_links(sptr, CONF_CRULE);
831 tstats(sptr, parv[0]);
834 report_configured_links(sptr, CONF_TLINES);
837 report_configured_links(sptr, CONF_UWORLD);
843 nowr = CurrentTime - me.since;
844 sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
845 nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
846 sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
847 max_connection_count, max_client_count);
857 send_listinfo(sptr, parv[0]);
862 report_classes(sptr);
866 count_memory(sptr, parv[0]);
872 sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
877 * mo_stats - oper message handler
879 * parv[0] = sender prefix
880 * parv[1] = statistics selector (defaults to Message frequency)
881 * parv[2] = target server (current server defaulted, if omitted)
882 * And 'stats l' and 'stats' L:
883 * parv[3] = server mask ("*" defaulted, if omitted)
885 * parv[3] = port mask (returns p-lines when its port is matched by this)
886 * Or for stats k,K,i and I:
887 * parv[3] = [user@]host.name (returns which K/I-lines match this)
888 * or [user@]host.mask (returns which K/I-lines are mmatched by this)
889 * (defaults to old reply if ommitted, when local or Oper)
890 * A remote mask (something containing wildcards) is only
891 * allowed for IRC Operators.
893 * parv[3] = time param
894 * parv[4] = time param
895 * (see report_memleak_stats() in runmalloc.c for details)
897 * This function is getting really ugly. -Ghostwolf
899 int mo_stats(struct Client* cptr, struct Client* sptr, int parc, char* parv[])
901 static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
902 "RcveM RcveKBytes :Open since";
903 static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
904 struct Message *mptr;
905 struct Client *acptr;
907 struct ConfItem *aconf;
908 char stat = parc > 1 ? parv[1][0] : '\0';
911 /* m_stats is so obnoxiously full of special cases that the different
912 * hunt_server() possiblites were becoming very messy. It now uses a
913 * switch() so as to be easier to read and update as params change.
918 /* open to all, standard # of params */
922 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
928 /* open to all, varying # of params */
938 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
944 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
951 /* oper only, varying # of params */
958 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
964 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
965 parv) != HUNTED_ISME)
968 else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
974 /* oper only, standard # of params */
977 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
989 int doall = 0, wilds = 0;
991 if (parc > 3 && *parv[3])
995 wilds = (*name == '*' || *name == '?');
996 for (p = name + 1; *p; ++p)
997 if ((*p == '*' || *p == '?') && p[-1] != '\\')
1006 * Send info about connections which match, or all if the
1007 * mask matches me.name. Only restrictions are on those who
1008 * are invisible not being visible to 'foreigners' who use
1009 * a wild card based search to list it.
1011 sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
1012 for (i = 0; i <= HighestFd; i++)
1014 if (!(acptr = LocalClientArray[i]))
1016 /* Don't return clients when this is a request for `all' */
1017 if (doall && IsUser(acptr))
1019 /* Don't show invisible people to unauthorized people when using
1020 * wildcards -- Is this still needed now /stats is oper only ? */
1021 if (IsInvisible(acptr) && (doall || wilds) &&
1022 !(MyConnect(sptr) && IsOper(sptr)) &&
1023 !IsAnOper(acptr) && (acptr != sptr))
1025 /* Only show the ones that match the given mask - if any */
1026 if (!doall && wilds && match(name, acptr->name))
1028 /* Skip all that do not match the specific query */
1029 if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
1031 sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
1032 acptr->name, (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
1033 (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
1034 CurrentTime - acptr->firsttime);
1040 report_configured_links(sptr, CONF_SERVER);
1043 case 'g': /* send glines */
1044 gline_remove_expired(TStime());
1045 for (gline = GlobalGlineList; gline; gline = gline->next) {
1046 sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
1047 sptr->name, 'G', gline->name, gline->host,
1048 gline->expire, gline->reason);
1053 report_configured_links(sptr, CONF_HUB | CONF_LEAF);
1058 case 'k': /* display CONF_IPKILL as well
1059 as CONF_KILL -Kev */
1062 char *user, *host, *p;
1063 int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
1064 if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
1066 report_configured_links(sptr, conf_status);
1069 if (parc < 4 || *parv[3] == '\0')
1070 return need_more_params(sptr,
1071 (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
1074 for (p = parv[3]; *p; p++)
1082 if (*p == '?' || *p == '*')
1088 if (!(MyConnect(sptr) || IsOper(sptr)))
1096 if (conf_status == CONF_CLIENT)
1098 user = 0; /* Not used, but to avoid compiler warning. */
1104 if ((host = strchr(parv[3], '@')))
1115 for (aconf = GlobalConfList; aconf; aconf = aconf->next)
1117 if ((aconf->status & conf_status))
1119 if (conf_status == CONF_KLINE)
1121 if ((!wilds && ((user || aconf->host[1]) &&
1122 !match(aconf->host, host) &&
1123 (!user || !match(aconf->name, user)))) ||
1124 (wilds && !mmatch(host, aconf->host) &&
1125 (!user || !mmatch(user, aconf->name))))
1127 sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
1128 sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
1129 aconf->port, get_conf_class(aconf));
1134 else if (conf_status == CONF_CLIENT)
1136 if ((!wilds && (!match(aconf->host, host) ||
1137 !match(aconf->name, host))) ||
1138 (wilds && (!mmatch(host, aconf->host) ||
1139 !mmatch(host, aconf->name))))
1141 sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
1142 sptr->name, 'I', aconf->host, aconf->name,
1143 aconf->port, get_conf_class(aconf));
1153 #if !defined(NDEBUG)
1154 sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
1155 me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
1160 sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
1161 me.name, parv[0], get_mem_size(), get_alloc_cnt());
1164 report_memleak_stats(sptr, parc, parv);
1166 #if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
1167 sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
1168 "is not enabled on this server", me.name, parv[0]);
1173 for (mptr = msgtab; mptr->cmd; mptr++)
1175 sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
1176 me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
1180 report_configured_links(sptr, CONF_OPS);
1185 * show listener ports
1186 * show hidden ports to opers, if there are more than 3 parameters,
1187 * interpret the fourth parameter as the port number, limit non-local
1188 * or non-oper results to 8 ports.
1190 show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0,
1191 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
1196 send_usage(sptr, parv[0]);
1200 report_configured_links(sptr, CONF_CRULEALL);
1203 report_configured_links(sptr, CONF_CRULE);
1206 tstats(sptr, parv[0]);
1209 report_configured_links(sptr, CONF_TLINES);
1212 report_configured_links(sptr, CONF_UWORLD);
1218 nowr = CurrentTime - me.since;
1219 sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
1220 nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
1221 sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
1222 max_connection_count, max_client_count);
1232 send_listinfo(sptr, parv[0]);
1237 report_classes(sptr);
1241 count_memory(sptr, parv[0]);
1247 sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);
1255 * parv[0] = sender prefix
1256 * parv[1] = statistics selector (defaults to Message frequency)
1257 * parv[2] = target server (current server defaulted, if omitted)
1258 * And 'stats l' and 'stats' L:
1259 * parv[3] = server mask ("*" defaulted, if omitted)
1261 * parv[3] = port mask (returns p-lines when its port is matched by this)
1262 * Or for stats k,K,i and I:
1263 * parv[3] = [user@]host.name (returns which K/I-lines match this)
1264 * or [user@]host.mask (returns which K/I-lines are mmatched by this)
1265 * (defaults to old reply if ommitted, when local or Oper)
1266 * A remote mask (something containing wildcards) is only
1267 * allowed for IRC Operators.
1269 * parv[3] = time param
1270 * parv[4] = time param
1271 * (see report_memleak_stats() in runmalloc.c for details)
1273 * This function is getting really ugly. -Ghostwolf
1275 int m_stats(struct Client *cptr, struct Client *sptr, int parc, char *parv[])
1277 static char Sformat[] = ":%s %d %s Connection SendQ SendM SendKBytes "
1278 "RcveM RcveKBytes :Open since";
1279 static char Lformat[] = ":%s %d %s %s %u %u %u %u %u :" TIME_T_FMT;
1280 struct Message *mptr;
1281 struct Client *acptr;
1282 struct Gline* gline;
1283 struct ConfItem *aconf;
1284 char stat = parc > 1 ? parv[1][0] : '\0';
1287 /* m_stats is so obnoxiously full of special cases that the different
1288 * hunt_server() possiblites were becoming very messy. It now uses a
1289 * switch() so as to be easier to read and update as params change.
1294 /* open to all, standard # of params */
1298 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
1304 /* open to all, varying # of params */
1314 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
1320 if (hunt_server(0, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
1327 /* oper only, varying # of params */
1334 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s :%s", 2, parc, parv)
1340 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s %s %s :%s", 2, parc,
1341 parv) != HUNTED_ISME)
1344 else if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
1350 /* oper only, standard # of params */
1353 if (hunt_server(1, cptr, sptr, "%s%s " TOK_STATS " %s :%s", 2, parc, parv)
1365 int doall = 0, wilds = 0;
1367 if (parc > 3 && *parv[3])
1371 wilds = (*name == '*' || *name == '?');
1372 for (p = name + 1; *p; ++p)
1373 if ((*p == '*' || *p == '?') && p[-1] != '\\')
1382 * Send info about connections which match, or all if the
1383 * mask matches me.name. Only restrictions are on those who
1384 * are invisible not being visible to 'foreigners' who use
1385 * a wild card based search to list it.
1387 sendto_one(sptr, Sformat, me.name, RPL_STATSLINKINFO, parv[0]);
1388 for (i = 0; i <= HighestFd; i++)
1390 if (!(acptr = LocalClientArray[i]))
1392 /* Don't return clients when this is a request for `all' */
1393 if (doall && IsUser(acptr))
1395 /* Don't show invisible people to unauthorized people when using
1396 * wildcards -- Is this still needed now /stats is oper only ? */
1397 if (IsInvisible(acptr) && (doall || wilds) &&
1398 !(MyConnect(sptr) && IsOper(sptr)) &&
1399 !IsAnOper(acptr) && (acptr != sptr))
1401 /* Only show the ones that match the given mask - if any */
1402 if (!doall && wilds && match(name, acptr->name))
1404 /* Skip all that do not match the specific query */
1405 if (!(doall || wilds) && 0 != ircd_strcmp(name, acptr->name))
1407 sendto_one(sptr, Lformat, me.name, RPL_STATSLINKINFO, parv[0],
1409 (int)DBufLength(&acptr->sendQ), (int)acptr->sendM,
1410 (int)acptr->sendK, (int)acptr->receiveM, (int)acptr->receiveK,
1411 CurrentTime - acptr->firsttime);
1417 report_configured_links(sptr, CONF_SERVER);
1420 case 'g': /* send glines */
1421 gline_remove_expired(TStime());
1422 for (gline = GlobalGlineList; gline; gline = gline->next) {
1423 sendto_one(sptr, rpl_str(RPL_STATSGLINE), me.name,
1424 sptr->name, 'G', gline->name, gline->host,
1425 gline->expire, gline->reason);
1430 report_configured_links(sptr, CONF_HUB | CONF_LEAF);
1435 case 'k': /* display CONF_IPKILL as well
1436 as CONF_KILL -Kev */
1439 char *user, *host, *p;
1440 int conf_status = (stat == 'k' || stat == 'K') ? CONF_KLINE : CONF_CLIENT;
1441 if ((MyUser(sptr) || IsOper(sptr)) && parc < 4)
1443 report_configured_links(sptr, conf_status);
1446 if (parc < 4 || *parv[3] == '\0')
1447 return need_more_params(sptr,
1448 (conf_status & CONF_KLINE) ? "STATS K" : "STATS I");
1451 for (p = parv[3]; *p; p++)
1459 if (*p == '?' || *p == '*')
1465 if (!(MyConnect(sptr) || IsOper(sptr)))
1473 if (conf_status == CONF_CLIENT)
1475 user = 0; /* Not used, but to avoid compiler warning. */
1481 if ((host = strchr(parv[3], '@')))
1492 for (aconf = GlobalConfList; aconf; aconf = aconf->next)
1494 if ((aconf->status & conf_status))
1496 if (conf_status == CONF_KLINE)
1498 if ((!wilds && ((user || aconf->host[1]) &&
1499 !match(aconf->host, host) &&
1500 (!user || !match(aconf->name, user)))) ||
1501 (wilds && !mmatch(host, aconf->host) &&
1502 (!user || !mmatch(user, aconf->name))))
1504 sendto_one(sptr, rpl_str(RPL_STATSKLINE), me.name,
1505 sptr->name, 'K', aconf->host, aconf->passwd, aconf->name,
1506 aconf->port, get_conf_class(aconf));
1511 else if (conf_status == CONF_CLIENT)
1513 if ((!wilds && (!match(aconf->host, host) ||
1514 !match(aconf->name, host))) ||
1515 (wilds && (!mmatch(host, aconf->host) ||
1516 !mmatch(host, aconf->name))))
1518 sendto_one(sptr, rpl_str(RPL_STATSILINE), me.name,
1519 sptr->name, 'I', aconf->host, aconf->name,
1520 aconf->port, get_conf_class(aconf));
1530 #if !defined(NDEBUG)
1531 sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
1532 me.name, parv[0], fda_get_byte_count(), fda_get_block_count());
1537 sendto_one(sptr, rpl_str(RPL_STATMEMTOT),
1538 me.name, parv[0], get_mem_size(), get_alloc_cnt());
1541 report_memleak_stats(sptr, parc, parv);
1543 #if !defined(MEMSIZESTATS) && !defined(MEMLEAKSTATS)
1544 sendto_one(sptr, ":%s NOTICE %s :stats M : Memory allocation monitoring "
1545 "is not enabled on this server", me.name, parv[0]);
1550 for (mptr = msgtab; mptr->cmd; mptr++)
1552 sendto_one(sptr, rpl_str(RPL_STATSCOMMANDS),
1553 me.name, parv[0], mptr->cmd, mptr->count, mptr->bytes);
1557 report_configured_links(sptr, CONF_OPS);
1562 * show listener ports
1563 * show hidden ports to opers, if there are more than 3 parameters,
1564 * interpret the fourth parameter as the port number, limit non-local
1565 * or non-oper results to 8 ports.
1567 show_ports(sptr, IsOper(sptr), (parc > 3) ? atoi(parv[3]) : 0,
1568 (MyUser(sptr) || IsOper(sptr)) ? 100 : 8);
1573 send_usage(sptr, parv[0]);
1577 report_configured_links(sptr, CONF_CRULEALL);
1580 report_configured_links(sptr, CONF_CRULE);
1583 tstats(sptr, parv[0]);
1586 report_configured_links(sptr, CONF_TLINES);
1589 report_configured_links(sptr, CONF_UWORLD);
1595 nowr = CurrentTime - me.since;
1596 sendto_one(sptr, rpl_str(RPL_STATSUPTIME), me.name, parv[0],
1597 nowr / 86400, (nowr / 3600) % 24, (nowr / 60) % 60, nowr % 60);
1598 sendto_one(sptr, rpl_str(RPL_STATSCONN), me.name, parv[0],
1599 max_connection_count, max_client_count);
1609 send_listinfo(sptr, parv[0]);
1614 report_classes(sptr);
1618 count_memory(sptr, parv[0]);
1624 sendto_one(sptr, rpl_str(RPL_ENDOFSTATS), me.name, parv[0], stat);