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_LOCOP, RPL_STATSOLINE, 'o'},
78 {CONF_UWORLD, RPL_STATSULINE, 'U'},
83 stats_configured_links(struct Client *sptr, struct StatDesc* sd, int stat,
86 static char null[] = "<NULL>";
90 unsigned short int port;
91 char c, *host, *pass, *name;
93 mask = sd->sd_funcdata;
95 for (tmp = GlobalConfList; tmp; tmp = tmp->next)
97 if ((tmp->status & mask))
99 for (p = &report_array[0][0]; *p; p += 3)
100 if (*p == tmp->status)
105 host = BadPtr(tmp->host) ? null : tmp->host;
106 pass = BadPtr(tmp->passwd) ? null : tmp->passwd;
107 name = BadPtr(tmp->name) ? null : tmp->name;
110 * On K line the passwd contents can be
111 * displayed on STATS reply. -Vesa
113 /* Special-case 'k' or 'K' lines as appropriate... -Kev */
114 if ((tmp->status & CONF_UWORLD))
115 send_reply(sptr, p[1], c, host, pass, name, port, get_conf_class(tmp));
116 else if ((tmp->status & (CONF_SERVER | CONF_HUB)))
117 send_reply(sptr, p[1], c, "*", name, port, get_conf_class(tmp));
118 else if ((tmp->status & CONF_CLIENT))
120 if(tmp->passwd && IsDigit(*tmp->passwd) && (!tmp->passwd[1] ||
121 (IsDigit(tmp->passwd[1]) && !tmp->passwd[2])))
122 send_reply(sptr, p[1], c, host, pass, name, port, get_conf_class(tmp));
124 send_reply(sptr, p[1], c, host, "*", name, port, get_conf_class(tmp));
127 send_reply(sptr, p[1], c, host, name, port, get_conf_class(tmp));
133 * {CONF_CRULEALL, RPL_STATSDLINE, 'D'},
134 * {CONF_CRULEAUTO, RPL_STATSDLINE, 'd'},
137 stats_crule_list(struct Client* to, struct StatDesc *sd, int stat,
141 const struct CRuleConf* p = conf_get_crule_list();
143 mask = (stat == 'D') ? CRULE_ALL : CRULE_MASK;
145 for ( ; p; p = p->next)
148 send_reply(to, RPL_STATSDLINE, stat, p->hostmask, p->rule);
153 stats_engine(struct Client *to, struct StatDesc *sd, int stat, char *param)
155 send_reply(to, RPL_STATSENGINE, engine_name());
159 stats_access(struct Client *to, struct StatDesc *sd, int stat, char *param)
161 struct ConfItem *aconf;
167 stats_configured_links(to, sd, stat, param);
171 wilds = string_has_wildcards(param);
173 for (aconf = GlobalConfList; aconf; aconf = aconf->next)
175 if (aconf->status != CONF_CLIENT)
177 if ((!wilds && (!match(aconf->host, param) ||
178 !match(aconf->name, param))) ||
179 (wilds && (!mmatch(param, aconf->host) ||
180 !mmatch(param, aconf->name))))
182 send_reply(to, RPL_STATSILINE, 'I', aconf->host, aconf->name,
183 aconf->port, get_conf_class(aconf));
193 * {CONF_KILL, RPL_STATSKLINE, 'K'},
194 * {CONF_IPKILL, RPL_STATSKLINE, 'k'},
197 report_deny_list(struct Client* to)
199 const struct DenyConf* p = conf_get_deny_list();
200 for ( ; p; p = p->next)
201 send_reply(to, RPL_STATSKLINE, (p->flags & DENY_FLAGS_IP) ? 'k' : 'K',
202 p->hostmask, p->message, p->usermask);
206 stats_klines(struct Client *sptr, struct StatDesc *sd, int stat, char *mask)
213 const struct DenyConf* conf;
221 need_more_params(sptr, "STATS K");
223 report_deny_list(sptr);
229 wilds = string_has_wildcards(mask);
232 if ((host = strchr(mask, '@')))
240 for (conf = conf_get_deny_list(); conf; conf = conf->next)
242 if ((!wilds && ((user || conf->hostmask) &&
243 !match(conf->hostmask, host) &&
244 (!user || !match(conf->usermask, user)))) ||
245 (wilds && !mmatch(host, conf->hostmask) &&
246 (!user || !mmatch(user, conf->usermask))))
248 send_reply(sptr, RPL_STATSKLINE,
249 (conf->flags & DENY_FLAGS_IP) ? 'k' : 'K',
250 conf->hostmask, conf->message, conf->usermask);
258 stats_links(struct Client* sptr, struct StatDesc* sd, int stat, char* name)
260 struct Client *acptr;
265 wilds = string_has_wildcards(name);
268 * Send info about connections which match, or all if the
269 * mask matches me.name. Only restrictions are on those who
270 * are invisible not being visible to 'foreigners' who use
271 * a wild card based search to list it.
273 send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ "
274 "SendM SendKBytes RcveM RcveKBytes :Open since");
275 for (i = 0; i <= HighestFd; i++)
277 if (!(acptr = LocalClientArray[i]))
279 /* Don't return clients when this is a request for `all' */
280 if (!name && IsUser(acptr))
282 /* Don't show invisible people to non opers unless they know the nick */
283 if (IsInvisible(acptr) && (!name || wilds) && !IsAnOper(acptr) &&
286 /* Only show the ones that match the given mask - if any */
287 if (name && wilds && match(name, cli_name(acptr)))
289 /* Skip all that do not match the specific query */
290 if (!(!name || wilds) && 0 != ircd_strcmp(name, cli_name(acptr)))
292 send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO,
293 "%s %u %u %u %u %u :%Tu",
294 (*(cli_name(acptr))) ? cli_name(acptr) : "<unregistered>",
295 (int)MsgQLength(&(cli_sendQ(acptr))), (int)cli_sendM(acptr),
296 (int)cli_sendK(acptr), (int)cli_receiveM(acptr),
297 (int)cli_receiveK(acptr), CurrentTime - cli_firsttime(acptr));
302 stats_commands(struct Client* to, struct StatDesc* sd, int stat, char* param)
304 struct Message *mptr;
306 for (mptr = msgtab; mptr->cmd; mptr++)
308 send_reply(to, RPL_STATSCOMMANDS, mptr->cmd, mptr->count, mptr->bytes);
312 stats_quarantine(struct Client* to, struct StatDesc* sd, int stat, char* param)
316 for (qline = GlobalQuarantineList; qline; qline = qline->next)
318 if (param && match(param, qline->chname)) /* narrow search */
320 send_reply(to, RPL_STATSQLINE, qline->chname, qline->reason);
325 stats_mapping(struct Client *to, struct StatDesc* sd, int stat, char* param)
329 send_reply(to, RPL_STATSRLINE, "Command", "Name", "Prepend", "Target");
330 for (map = GlobalServiceMapList; map; map = map->next) {
331 struct nick_host *nh;
332 for (nh = map->services; nh; nh = nh->next) {
333 send_reply(to, RPL_STATSRLINE, map->command, map->name,
334 (map->prepend ? map->prepend : "*"), nh->nick);
340 stats_uptime(struct Client* to, struct StatDesc* sd, int stat, char* param)
344 nowr = CurrentTime - cli_since(&me);
345 send_reply(to, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24,
346 (nowr / 60) % 60, nowr % 60);
347 send_reply(to, RPL_STATSCONN, max_connection_count, max_client_count);
351 stats_servers_verbose(struct Client* sptr, struct StatDesc* sd, int stat,
354 struct Client *acptr;
357 * lowercase 'v' is for human-readable,
358 * uppercase 'V' is for machine-readable
361 send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE,
362 "%-20s %-20s Flags Hops Numeric Lag RTT Up Down "
363 "Clients/Max Proto %-10s :Info", "Servername", "Uplink",
366 for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr))
368 if (!IsServer(acptr) && !IsMe(acptr))
371 if (param && match(param, cli_name(acptr)))
373 send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, stat == 'v' ?
374 "%-20s %-20s %c%c%c%c %4i %s %-4i %5i %4i %4i %4i %5i %5i "
376 "%s %s %c%c%c%c %i %s %i %i %i %i %i %i %i P%i %Tu :%s",
378 cli_name(cli_serv(acptr)->up),
379 IsBurst(acptr) ? 'B' : '-',
380 IsBurstAck(acptr) ? 'A' : '-',
381 IsHub(acptr) ? 'H' : '-',
382 IsService(acptr) ? 'S' : '-',
385 base64toint(cli_yxx(acptr)),
386 cli_serv(acptr)->lag,
387 cli_serv(acptr)->asll_rtt,
388 cli_serv(acptr)->asll_to,
389 cli_serv(acptr)->asll_from,
390 cli_serv(acptr)->clients,
391 cli_serv(acptr)->nn_mask,
392 cli_serv(acptr)->prot,
393 cli_serv(acptr)->timestamp,
400 stats_meminfo(struct Client* to, struct StatDesc* sd, int stat, char* param)
402 class_send_meminfo(to);
403 send_listinfo(to, 0);
408 stats_help(struct Client* to, struct StatDesc* sd, int stat, char* param)
410 struct StatDesc *asd;
412 /* only if it's my user */
414 for (asd = statsinfo; asd->sd_c; asd++)
415 if (asd->sd_c != sd->sd_c) /* don't send the help for us */
416 sendcmdto_one(&me, CMD_NOTICE, to, "%C :%c - %s", to, asd->sd_c,
420 /* This array of structures contains information about all single-character
421 * stats. Struct StatDesc is defined in s_stats.h.
423 struct StatDesc statsinfo[] = {
424 { 'c', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_c,
425 stats_configured_links, CONF_SERVER,
426 "Remote server connection lines." },
427 { 'd', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_d,
429 "Dynamic routing configuration." },
430 { 'e', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_e,
432 "Report server event loop engine." },
433 { 'f', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_f,
435 "Feature settings." },
436 { 'g', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_g,
438 "Global bans (G-lines)." },
439 { 'h', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_h,
440 stats_configured_links, (CONF_HUB | CONF_LEAF),
441 "Hubs information." },
442 { 'i', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_i,
443 stats_access, CONF_CLIENT,
444 "Connection authorization lines." },
445 { 'j', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_j,
447 "Message length histogram." },
448 { 'k', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_k,
450 "Local bans (K-Lines)." },
451 { 'l', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_l,
453 "Current connections information." },
455 { 'M', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_M,
457 "Memory allocation & leak monitoring." },
459 { 'm', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_m,
461 "Message usage information." },
462 { 'o', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_o,
463 stats_configured_links, CONF_OPS,
464 "Operator information." },
465 { 'p', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_p,
467 "Listening ports." },
468 { 'q', (STAT_FLAG_OPERONLY | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_q,
470 "Quarantined channels list." },
471 { 'R', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_R,
473 "Service mappings." },
475 { 'r', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_r,
477 "System resource usage (Debug only)." },
479 { 'T', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
481 "Configured Message Of The Day files." },
482 { 't', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_t,
484 "Local connection statistics (Total SND/RCV, etc)." },
485 { 'U', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_U,
486 stats_configured_links, CONF_UWORLD,
487 "Service server & nick jupes information." },
488 { 'u', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_u,
490 "Current uptime & highest connection count." },
491 { 'v', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_v,
492 stats_servers_verbose, 0,
493 "Verbose server information." },
494 { 'w', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
496 "Userload statistics." },
498 { 'x', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
500 "List usage information (Debug only)." },
502 { 'y', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_y,
504 "Connection classes." },
505 { 'z', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_z,
507 "Memory/Structure allocation information." },
508 { '*', (STAT_FLAG_CASESENS | STAT_FLAG_VARPARAM), FEAT_LAST_F,
510 "Send help for stats." },
511 { '\0', 0, FEAT_LAST_F, 0, 0, 0 }
514 /* This array is for mapping from characters to statistics descriptors */
515 struct StatDesc *statsmap[256];
517 /* Function to build the statsmap from the statsinfo array */
524 /* Make darn sure the statsmap array is initialized to all zeros */
525 for (i = 0; i < 256; i++)
528 /* Build the mapping */
529 for (sd = statsinfo; sd->sd_c; sd++)
531 if (sd->sd_flags & STAT_FLAG_CASESENS)
532 /* case sensitive character... */
533 statsmap[(int)sd->sd_c] = sd;
536 /* case insensitive--make sure to put in two entries */
537 statsmap[(int)ToLower((int)sd->sd_c)] = sd;
538 statsmap[(int)ToUpper((int)sd->sd_c)] = sd;