2 * IRC - Internet Relay Chat, ircd/s_stats.c
3 * Copyright (C) 2000 Joseph Bongaarts
5 * See file AUTHORS in IRC package for additional names of
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 1, or (at your option)
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
30 #include "ircd_chattr.h"
31 #include "ircd_events.h"
32 #include "ircd_features.h"
34 #include "ircd_reply.h"
35 #include "ircd_string.h"
64 * Report configuration lines and other statistics from this
67 * Note: The info is reported in the order the server uses
68 * it--not reversed as in ircd.conf!
71 static unsigned int report_array[17][3] = {
72 {CONF_SERVER, RPL_STATSCLINE, 'C'},
73 {CONF_CLIENT, RPL_STATSILINE, 'I'},
74 {CONF_LEAF, RPL_STATSLLINE, 'L'},
75 {CONF_OPERATOR, RPL_STATSOLINE, 'O'},
76 {CONF_HUB, RPL_STATSHLINE, 'H'},
77 {CONF_UWORLD, RPL_STATSULINE, 'U'},
82 stats_configured_links(struct Client *sptr, struct StatDesc* sd, int stat,
85 static char null[] = "<NULL>";
89 unsigned short int port;
90 char c, *host, *pass, *name;
92 mask = sd->sd_funcdata;
94 for (tmp = GlobalConfList; tmp; tmp = tmp->next)
96 if ((tmp->status & mask))
98 for (p = &report_array[0][0]; *p; p += 3)
99 if (*p == tmp->status)
104 host = BadPtr(tmp->host) ? null : tmp->host;
105 pass = BadPtr(tmp->passwd) ? null : tmp->passwd;
106 name = BadPtr(tmp->name) ? null : tmp->name;
109 * On K line the passwd contents can be
110 * displayed on STATS reply. -Vesa
112 /* Special-case 'k' or 'K' lines as appropriate... -Kev */
113 if ((tmp->status & CONF_UWORLD))
114 send_reply(sptr, p[1], c, host, pass, name, port, get_conf_class(tmp));
115 else if ((tmp->status & (CONF_SERVER | CONF_HUB)))
116 send_reply(sptr, p[1], c, "*", name, port, get_conf_class(tmp));
117 else if ((tmp->status & CONF_CLIENT))
119 if(tmp->passwd && IsDigit(*tmp->passwd) && (!tmp->passwd[1] ||
120 (IsDigit(tmp->passwd[1]) && !tmp->passwd[2])))
121 send_reply(sptr, p[1], c, host, pass, name, port, get_conf_class(tmp));
123 send_reply(sptr, p[1], c, host, "*", name, port, get_conf_class(tmp));
126 send_reply(sptr, p[1], c, host, name, port, get_conf_class(tmp));
132 * {CONF_CRULEALL, RPL_STATSDLINE, 'D'},
133 * {CONF_CRULEAUTO, RPL_STATSDLINE, 'd'},
136 stats_crule_list(struct Client* to, struct StatDesc *sd, int stat,
140 const struct CRuleConf* p = conf_get_crule_list();
142 mask = (stat == 'D') ? CRULE_ALL : CRULE_MASK;
144 for ( ; p; p = p->next)
147 send_reply(to, RPL_STATSDLINE, stat, p->hostmask, p->rule);
152 stats_engine(struct Client *to, struct StatDesc *sd, int stat, char *param)
154 send_reply(to, RPL_STATSENGINE, engine_name());
158 stats_access(struct Client *to, struct StatDesc *sd, int stat, char *param)
160 struct ConfItem *aconf;
166 stats_configured_links(to, sd, stat, param);
170 wilds = string_has_wildcards(param);
172 for (aconf = GlobalConfList; aconf; aconf = aconf->next)
174 if (aconf->status != CONF_CLIENT)
176 if ((!wilds && (!match(aconf->host, param) ||
177 !match(aconf->name, param))) ||
178 (wilds && (!mmatch(param, aconf->host) ||
179 !mmatch(param, aconf->name))))
181 send_reply(to, RPL_STATSILINE, 'I', aconf->host, aconf->name,
182 aconf->port, get_conf_class(aconf));
192 * {CONF_KILL, RPL_STATSKLINE, 'K'},
193 * {CONF_IPKILL, RPL_STATSKLINE, 'k'},
196 report_deny_list(struct Client* to)
198 const struct DenyConf* p = conf_get_deny_list();
199 for ( ; p; p = p->next)
200 send_reply(to, RPL_STATSKLINE, (p->flags & DENY_FLAGS_IP) ? 'k' : 'K',
201 p->hostmask, p->message, p->usermask);
205 stats_klines(struct Client *sptr, struct StatDesc *sd, int stat, char *mask)
212 const struct DenyConf* conf;
220 need_more_params(sptr, "STATS K");
222 report_deny_list(sptr);
228 wilds = string_has_wildcards(mask);
231 if ((host = strchr(mask, '@')))
239 for (conf = conf_get_deny_list(); conf; conf = conf->next)
241 if ((!wilds && ((user || conf->hostmask) &&
242 !match(conf->hostmask, host) &&
243 (!user || !match(conf->usermask, user)))) ||
244 (wilds && !mmatch(host, conf->hostmask) &&
245 (!user || !mmatch(user, conf->usermask))))
247 send_reply(sptr, RPL_STATSKLINE,
248 (conf->flags & DENY_FLAGS_IP) ? 'k' : 'K',
249 conf->hostmask, conf->message, conf->usermask);
257 stats_links(struct Client* sptr, struct StatDesc* sd, int stat, char* name)
259 struct Client *acptr;
264 wilds = string_has_wildcards(name);
267 * Send info about connections which match, or all if the
268 * mask matches me.name. Only restrictions are on those who
269 * are invisible not being visible to 'foreigners' who use
270 * a wild card based search to list it.
272 send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ "
273 "SendM SendKBytes RcveM RcveKBytes :Open since");
274 for (i = 0; i <= HighestFd; i++)
276 if (!(acptr = LocalClientArray[i]))
278 /* Don't return clients when this is a request for `all' */
279 if (!name && IsUser(acptr))
281 /* Don't show invisible people to non opers unless they know the nick */
282 if (IsInvisible(acptr) && (!name || wilds) && !IsAnOper(acptr) &&
285 /* Only show the ones that match the given mask - if any */
286 if (name && wilds && match(name, cli_name(acptr)))
288 /* Skip all that do not match the specific query */
289 if (!(!name || wilds) && 0 != ircd_strcmp(name, cli_name(acptr)))
291 send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO,
292 "%s %u %u %u %u %u :%Tu",
293 (*(cli_name(acptr))) ? cli_name(acptr) : "<unregistered>",
294 (int)MsgQLength(&(cli_sendQ(acptr))), (int)cli_sendM(acptr),
295 (int)cli_sendK(acptr), (int)cli_receiveM(acptr),
296 (int)cli_receiveK(acptr), CurrentTime - cli_firsttime(acptr));
301 stats_commands(struct Client* to, struct StatDesc* sd, int stat, char* param)
303 struct Message *mptr;
305 for (mptr = msgtab; mptr->cmd; mptr++)
307 send_reply(to, RPL_STATSCOMMANDS, mptr->cmd, mptr->count, mptr->bytes);
311 stats_quarantine(struct Client* to, struct StatDesc* sd, int stat, char* param)
315 for (qline = GlobalQuarantineList; qline; qline = qline->next)
317 if (param && match(param, qline->chname)) /* narrow search */
319 send_reply(to, RPL_STATSQLINE, qline->chname, qline->reason);
324 stats_mapping(struct Client *to, struct StatDesc* sd, int stat, char* param)
328 send_reply(to, RPL_STATSRLINE, "Command", "Name", "Prepend", "Target");
329 for (map = GlobalServiceMapList; map; map = map->next) {
330 struct nick_host *nh;
331 for (nh = map->services; nh; nh = nh->next) {
332 send_reply(to, RPL_STATSRLINE, map->command, map->name,
333 (map->prepend ? map->prepend : "*"), nh->nick);
339 stats_uptime(struct Client* to, struct StatDesc* sd, int stat, char* param)
343 nowr = CurrentTime - cli_since(&me);
344 send_reply(to, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24,
345 (nowr / 60) % 60, nowr % 60);
346 send_reply(to, RPL_STATSCONN, max_connection_count, max_client_count);
350 stats_servers_verbose(struct Client* sptr, struct StatDesc* sd, int stat,
353 struct Client *acptr;
356 * lowercase 'v' is for human-readable,
357 * uppercase 'V' is for machine-readable
360 send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE,
361 "%-20s %-20s Flags Hops Numeric Lag RTT Up Down "
362 "Clients/Max Proto %-10s :Info", "Servername", "Uplink",
365 for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr))
367 if (!IsServer(acptr) && !IsMe(acptr))
370 if (param && match(param, cli_name(acptr)))
372 send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, stat == 'v' ?
373 "%-20s %-20s %c%c%c%c %4i %s %-4i %5i %4i %4i %4i %5i %5i "
375 "%s %s %c%c%c%c %i %s %i %i %i %i %i %i %i P%i %Tu :%s",
377 cli_name(cli_serv(acptr)->up),
378 IsBurst(acptr) ? 'B' : '-',
379 IsBurstAck(acptr) ? 'A' : '-',
380 IsHub(acptr) ? 'H' : '-',
381 IsService(acptr) ? 'S' : '-',
384 base64toint(cli_yxx(acptr)),
385 cli_serv(acptr)->lag,
386 cli_serv(acptr)->asll_rtt,
387 cli_serv(acptr)->asll_to,
388 cli_serv(acptr)->asll_from,
389 cli_serv(acptr)->clients,
390 cli_serv(acptr)->nn_mask,
391 cli_serv(acptr)->prot,
392 cli_serv(acptr)->timestamp,
399 stats_meminfo(struct Client* to, struct StatDesc* sd, int stat, char* param)
401 class_send_meminfo(to);
402 send_listinfo(to, 0);
407 stats_help(struct Client* to, struct StatDesc* sd, int stat, char* param)
409 struct StatDesc *asd;
411 /* only if it's my user */
413 for (asd = statsinfo; asd->sd_c; asd++)
414 if (asd->sd_c != sd->sd_c) /* don't send the help for us */
415 sendcmdto_one(&me, CMD_NOTICE, to, "%C :%c - %s", to, asd->sd_c,
419 /* This array of structures contains information about all single-character
420 * stats. Struct StatDesc is defined in s_stats.h.
422 struct StatDesc statsinfo[] = {
423 { 'c', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_c,
424 stats_configured_links, CONF_SERVER,
425 "Remote server connection lines." },
426 { 'd', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_d,
428 "Dynamic routing configuration." },
429 { 'e', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_e,
431 "Report server event loop engine." },
432 { 'f', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_f,
434 "Feature settings." },
435 { 'g', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_g,
437 "Global bans (G-lines)." },
438 { 'h', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_h,
439 stats_configured_links, (CONF_HUB | CONF_LEAF),
440 "Hubs information." },
441 { 'i', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_i,
442 stats_access, CONF_CLIENT,
443 "Connection authorization lines." },
444 { 'j', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_j,
446 "Message length histogram." },
447 { 'k', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_k,
449 "Local bans (K-Lines)." },
450 { 'l', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_l,
452 "Current connections information." },
454 { 'M', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_M,
456 "Memory allocation & leak monitoring." },
458 { 'm', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_m,
460 "Message usage information." },
461 { 'o', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_o,
462 stats_configured_links, CONF_OPERATOR,
463 "Operator information." },
464 { 'p', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_p,
466 "Listening ports." },
467 { 'q', (STAT_FLAG_OPERONLY | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_q,
469 "Quarantined channels list." },
470 { 'R', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_R,
472 "Service mappings." },
474 { 'r', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_r,
476 "System resource usage (Debug only)." },
478 { 'T', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
480 "Configured Message Of The Day files." },
481 { 't', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_t,
483 "Local connection statistics (Total SND/RCV, etc)." },
484 { 'U', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_U,
485 stats_configured_links, CONF_UWORLD,
486 "Service server & nick jupes information." },
487 { 'u', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_u,
489 "Current uptime & highest connection count." },
490 { 'v', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_v,
491 stats_servers_verbose, 0,
492 "Verbose server information." },
493 { 'w', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
495 "Userload statistics." },
497 { 'x', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
499 "List usage information (Debug only)." },
501 { 'y', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_y,
503 "Connection classes." },
504 { 'z', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_z,
506 "Memory/Structure allocation information." },
507 { '*', (STAT_FLAG_CASESENS | STAT_FLAG_VARPARAM), FEAT_LAST_F,
509 "Send help for stats." },
510 { '\0', 0, FEAT_LAST_F, 0, 0, 0 }
513 /* This array is for mapping from characters to statistics descriptors */
514 struct StatDesc *statsmap[256];
516 /* Function to build the statsmap from the statsinfo array */
523 /* Make darn sure the statsmap array is initialized to all zeros */
524 for (i = 0; i < 256; i++)
527 /* Build the mapping */
528 for (sd = statsinfo; sd->sd_c; sd++)
530 if (sd->sd_flags & STAT_FLAG_CASESENS)
531 /* case sensitive character... */
532 statsmap[(int)sd->sd_c] = sd;
535 /* case insensitive--make sure to put in two entries */
536 statsmap[(int)ToLower((int)sd->sd_c)] = sd;
537 statsmap[(int)ToUpper((int)sd->sd_c)] = sd;