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_uptime(struct Client* to, struct StatDesc* sd, int stat, char* param)
329 nowr = CurrentTime - cli_since(&me);
330 send_reply(to, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24,
331 (nowr / 60) % 60, nowr % 60);
332 send_reply(to, RPL_STATSCONN, max_connection_count, max_client_count);
336 stats_servers_verbose(struct Client* sptr, struct StatDesc* sd, int stat,
339 struct Client *acptr;
342 * lowercase 'v' is for human-readable,
343 * uppercase 'V' is for machine-readable
346 send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE,
347 "%-20s %-20s Flags Hops Numeric Lag RTT Up Down "
348 "Clients/Max Proto %-10s :Info", "Servername", "Uplink",
351 for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr))
353 if (!IsServer(acptr) && !IsMe(acptr))
356 if (param && match(param, cli_name(acptr)))
358 send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, stat == 'v' ?
359 "%-20s %-20s %c%c%c%c %4i %s %-4i %5i %4i %4i %4i %5i %5i "
361 "%s %s %c%c%c%c %i %s %i %i %i %i %i %i %i P%i %Tu :%s",
363 cli_name(cli_serv(acptr)->up),
364 IsBurst(acptr) ? 'B' : '-',
365 IsBurstAck(acptr) ? 'A' : '-',
366 IsHub(acptr) ? 'H' : '-',
367 IsService(acptr) ? 'S' : '-',
370 base64toint(cli_yxx(acptr)),
371 cli_serv(acptr)->lag,
372 cli_serv(acptr)->asll_rtt,
373 cli_serv(acptr)->asll_to,
374 cli_serv(acptr)->asll_from,
375 cli_serv(acptr)->clients,
376 cli_serv(acptr)->nn_mask,
377 cli_serv(acptr)->prot,
378 cli_serv(acptr)->timestamp,
385 stats_meminfo(struct Client* to, struct StatDesc* sd, int stat, char* param)
387 class_send_meminfo(to);
388 send_listinfo(to, 0);
393 stats_help(struct Client* to, struct StatDesc* sd, int stat, char* param)
395 struct StatDesc *asd;
397 /* only if it's my user */
399 for (asd = statsinfo; asd->sd_c; asd++)
400 if (asd->sd_c != sd->sd_c) /* don't send the help for us */
401 sendcmdto_one(&me, CMD_NOTICE, to, "%C :%c - %s", to, asd->sd_c,
405 /* This array of structures contains information about all single-character
406 * stats. Struct StatDesc is defined in s_stats.h.
408 struct StatDesc statsinfo[] = {
409 { 'c', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_c,
410 stats_configured_links, CONF_SERVER,
411 "Remote server connection lines." },
412 { 'd', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_d,
414 "Dynamic routing configuration." },
415 { 'e', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_e,
417 "Report server event loop engine." },
418 { 'f', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_f,
420 "Feature settings." },
421 { 'g', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_g,
423 "Global bans (G-lines)." },
424 { 'h', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_h,
425 stats_configured_links, (CONF_HUB | CONF_LEAF),
426 "Hubs information." },
427 { 'i', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_i,
428 stats_access, CONF_CLIENT,
429 "Connection authorization lines." },
430 { 'j', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_j,
432 "Message length histogram." },
433 { 'k', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_k,
435 "Local bans (K-Lines)." },
436 { 'l', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_l,
438 "Current connections information." },
440 { 'M', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_M,
442 "Memory allocation & leak monitoring." },
444 { 'm', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_m,
446 "Message usage information." },
447 { 'o', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_o,
448 stats_configured_links, CONF_OPS,
449 "Operator information." },
450 { 'p', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_p,
452 "Listening ports." },
453 { 'q', (STAT_FLAG_OPERONLY | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_q,
455 "Quarantined channels list." },
457 { 'r', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_r,
459 "System resource usage (Debug only)." },
461 { 'T', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T,
463 "Configured Message Of The Day files." },
464 { 't', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_t,
466 "Local connection statistics (Total SND/RCV, etc)." },
467 { 'U', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_U,
468 stats_configured_links, CONF_UWORLD,
469 "Service server & nick jupes information." },
470 { 'u', (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_u,
472 "Current uptime & highest connection count." },
473 { 'v', (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_v,
474 stats_servers_verbose, 0,
475 "Verbose server information." },
476 { 'w', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w,
478 "Userload statistics." },
480 { 'x', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x,
482 "List usage information (Debug only)." },
484 { 'y', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_y,
486 "Connection classes." },
487 { 'z', STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_z,
489 "Memory/Structure allocation information." },
490 { '*', (STAT_FLAG_CASESENS | STAT_FLAG_VARPARAM), FEAT_LAST_F,
492 "Send help for stats." },
493 { '\0', 0, FEAT_LAST_F, 0, 0, 0 }
496 /* This array is for mapping from characters to statistics descriptors */
497 struct StatDesc *statsmap[256];
499 /* Function to build the statsmap from the statsinfo array */
506 /* Make darn sure the statsmap array is initialized to all zeros */
507 for (i = 0; i < 256; i++)
510 /* Build the mapping */
511 for (sd = statsinfo; sd->sd_c; sd++)
513 if (sd->sd_flags & STAT_FLAG_CASESENS)
514 /* case sensitive character... */
515 statsmap[(int)sd->sd_c] = sd;
518 /* case insensitive--make sure to put in two entries */
519 statsmap[(int)ToLower((int)sd->sd_c)] = sd;
520 statsmap[(int)ToUpper((int)sd->sd_c)] = sd;