]>
Commit | Line | Data |
---|---|---|
189935b1 | 1 | /* |
2 | * IRC - Internet Relay Chat, ircd/s_stats.c | |
3 | * Copyright (C) 2000 Joseph Bongaarts | |
4 | * | |
5 | * See file AUTHORS in IRC package for additional names of | |
6 | * the programmers. | |
7 | * | |
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) | |
11 | * any later version. | |
12 | * | |
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. | |
17 | * | |
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. | |
21 | */ | |
22 | #include "config.h" | |
23 | ||
24 | #include "class.h" | |
25 | #include "client.h" | |
26 | #include "gline.h" | |
27 | #include "hash.h" | |
28 | #include "ircd.h" | |
29 | #include "ircd_chattr.h" | |
30 | #include "ircd_events.h" | |
31 | #include "ircd_features.h" | |
32 | #include "ircd_crypt.h" | |
33 | #include "ircd_log.h" | |
34 | #include "ircd_reply.h" | |
35 | #include "ircd_string.h" | |
36 | #include "listener.h" | |
37 | #include "list.h" | |
38 | #include "match.h" | |
39 | #include "motd.h" | |
40 | #include "msg.h" | |
41 | #include "msgq.h" | |
42 | #include "numeric.h" | |
43 | #include "numnicks.h" | |
44 | #include "querycmds.h" | |
45 | #include "res.h" | |
9f8856e9 | 46 | #include "s_auth.h" |
189935b1 | 47 | #include "s_bsd.h" |
48 | #include "s_conf.h" | |
49 | #include "s_debug.h" | |
50 | #include "s_misc.h" | |
51 | #include "s_serv.h" | |
52 | #include "s_stats.h" | |
53 | #include "s_user.h" | |
54 | #include "send.h" | |
55 | #include "struct.h" | |
56 | #include "userload.h" | |
57 | ||
58 | #include <stdio.h> | |
59 | #include <stdlib.h> | |
60 | #include <string.h> | |
61 | #include <sys/time.h> | |
62 | ||
63 | /** @file | |
64 | * @brief Report configuration lines and other statistics from this | |
65 | * server. | |
9f8856e9 | 66 | * @version $Id: s_stats.c,v 1.44.2.4 2006/03/14 14:56:50 entrope Exp $ |
189935b1 | 67 | * |
68 | * Note: The info is reported in the order the server uses | |
69 | * it--not reversed as in ircd.conf! | |
70 | */ | |
71 | ||
72 | /* The statsinfo array should only be used in this file, but just TRY | |
73 | * telling the compiler that you want to forward declare a static | |
74 | * array without specifying a length, and see how it responds. So we | |
75 | * forward declare it "extern". | |
76 | */ | |
77 | extern struct StatDesc statsinfo[]; | |
78 | ||
79 | /** Report items from #GlobalConfList. | |
80 | * Uses sd->sd_funcdata as a filter for ConfItem::status. | |
81 | * @param[in] sptr Client requesting statistics. | |
82 | * @param[in] sd Stats descriptor for request. | |
83 | * @param[in] param Extra parameter from user (ignored). | |
84 | */ | |
85 | static void | |
86 | stats_configured_links(struct Client *sptr, const struct StatDesc* sd, | |
87 | char* param) | |
88 | { | |
89 | static char null[] = "<NULL>"; | |
90 | struct ConfItem *tmp; | |
91 | unsigned short int port; | |
92 | int maximum; | |
93 | char *host, *pass, *name, *username, *hub_limit; | |
94 | ||
95 | for (tmp = GlobalConfList; tmp; tmp = tmp->next) | |
96 | { | |
97 | if ((tmp->status & sd->sd_funcdata)) | |
98 | { | |
99 | host = BadPtr(tmp->host) ? null : tmp->host; | |
100 | pass = BadPtr(tmp->passwd) ? null : tmp->passwd; | |
101 | name = BadPtr(tmp->name) ? null : tmp->name; | |
102 | username = BadPtr(tmp->username) ? null : tmp->username; | |
103 | hub_limit = BadPtr(tmp->hub_limit) ? null : tmp->hub_limit; | |
104 | maximum = tmp->maximum; | |
105 | port = tmp->address.port; | |
106 | ||
107 | if (tmp->status & CONF_UWORLD) | |
108 | send_reply(sptr, RPL_STATSULINE, host); | |
109 | else if (tmp->status & CONF_SERVER) | |
110 | send_reply(sptr, RPL_STATSCLINE, name, port, maximum, hub_limit, get_conf_class(tmp)); | |
111 | else if (tmp->status & CONF_CLIENT) | |
112 | send_reply(sptr, RPL_STATSILINE, | |
9f8856e9 | 113 | (tmp->username ? tmp->username : ""), (tmp->username ? "@" : ""), |
189935b1 | 114 | (tmp->host ? tmp->host : "*"), maximum, |
115 | (name[0] == ':' ? "0" : ""), (tmp->name ? tmp->name : "*"), | |
116 | port, get_conf_class(tmp)); | |
117 | else if (tmp->status & CONF_OPERATOR) | |
118 | send_reply(sptr, RPL_STATSOLINE, | |
119 | ((FlagHas(&tmp->privs_dirty, PRIV_PROPAGATE) | |
120 | && FlagHas(&tmp->privs, PRIV_PROPAGATE)) | |
121 | || (FlagHas(&tmp->conn_class->privs_dirty, PRIV_PROPAGATE) | |
122 | && FlagHas(&tmp->conn_class->privs, PRIV_PROPAGATE))) | |
123 | ? 'O' : 'o', username, host, name, get_conf_class(tmp)); | |
124 | } | |
125 | } | |
126 | } | |
127 | ||
128 | /** Report connection rules from conf_get_crule_list(). | |
129 | * Uses sd->sd_funcdata as a filter for CRuleConf::type. | |
130 | * @param[in] to Client requesting statistics. | |
131 | * @param[in] sd Stats descriptor for request. | |
132 | * @param[in] param Extra parameter from user (ignored). | |
133 | */ | |
134 | static void | |
135 | stats_crule_list(struct Client* to, const struct StatDesc *sd, | |
136 | char *param) | |
137 | { | |
138 | const struct CRuleConf* p = conf_get_crule_list(); | |
139 | ||
140 | for ( ; p; p = p->next) | |
141 | { | |
142 | if (p->type & sd->sd_funcdata) | |
143 | send_reply(to, RPL_STATSDLINE, (p->type & CRULE_ALL ? 'D' : 'd'), p->hostmask, p->rule); | |
144 | } | |
145 | } | |
146 | ||
147 | /** Report active event engine name. | |
148 | * @param[in] to Client requesting statistics. | |
149 | * @param[in] sd Stats descriptor for request (ignored). | |
150 | * @param[in] param Extra parameter from user (ignored). | |
151 | */ | |
152 | static void | |
153 | stats_engine(struct Client *to, const struct StatDesc *sd, char *param) | |
154 | { | |
155 | send_reply(to, RPL_STATSENGINE, engine_name()); | |
156 | } | |
157 | ||
158 | /** Report client access lists. | |
159 | * @param[in] to Client requesting statistics. | |
160 | * @param[in] sd Stats descriptor for request. | |
161 | * @param[in] param Filter for hostname or IP (NULL to show all). | |
162 | */ | |
163 | static void | |
164 | stats_access(struct Client *to, const struct StatDesc *sd, char *param) | |
165 | { | |
166 | struct ConfItem *aconf; | |
167 | int wilds = 0; | |
168 | int count = 1000; | |
169 | ||
170 | if (!param) | |
171 | { | |
172 | stats_configured_links(to, sd, param); | |
173 | return; | |
174 | } | |
175 | ||
176 | wilds = string_has_wildcards(param); | |
177 | ||
178 | for (aconf = GlobalConfList; aconf; aconf = aconf->next) | |
179 | { | |
180 | if (aconf->status != CONF_CLIENT) | |
181 | continue; | |
182 | if (wilds ? ((aconf->host && !mmatch(aconf->host, param)) | |
183 | || (aconf->name && !mmatch(aconf->name, param))) | |
184 | : ((aconf->host && !match(param, aconf->host)) | |
185 | || (aconf->name && !match(param, aconf->name)))) | |
186 | { | |
187 | send_reply(to, RPL_STATSILINE, | |
9f8856e9 | 188 | (aconf->username ? aconf->username : ""), (aconf->username ? "@" : ""), |
189935b1 | 189 | (aconf->host ? aconf->host : "*"), aconf->maximum, |
190 | (aconf->name && aconf->name[0] == ':' ? "0":""), | |
191 | aconf->name ? aconf->name : "*", | |
192 | aconf->address.port, get_conf_class(aconf)); | |
193 | if (--count == 0) | |
194 | break; | |
195 | } | |
196 | } | |
197 | } | |
198 | ||
199 | ||
200 | /** Report DenyConf entries. | |
201 | * @param[in] to Client requesting list. | |
202 | */ | |
203 | static void | |
204 | report_deny_list(struct Client* to) | |
205 | { | |
206 | const struct DenyConf* p = conf_get_deny_list(); | |
207 | for ( ; p; p = p->next) | |
208 | send_reply(to, RPL_STATSKLINE, p->bits > 0 ? 'k' : 'K', | |
209 | p->usermask ? p->usermask : "*", | |
210 | p->hostmask ? p->hostmask : "*", | |
211 | p->message ? p->message : "(none)", | |
212 | p->realmask ? p->realmask : "*"); | |
213 | } | |
214 | ||
215 | /** Report K/k-lines to a user. | |
216 | * @param[in] sptr Client requesting statistics. | |
217 | * @param[in] sd Stats descriptor for request (ignored). | |
218 | * @param[in] mask Filter for hostmasks to show. | |
219 | */ | |
220 | static void | |
221 | stats_klines(struct Client *sptr, const struct StatDesc *sd, char *mask) | |
222 | { | |
223 | int wilds = 0; | |
224 | int count = 3; | |
225 | int limit_query = 0; | |
226 | char *user = 0; | |
227 | char *host; | |
228 | const struct DenyConf* conf; | |
229 | ||
230 | if (!IsAnOper(sptr)) | |
231 | limit_query = 1; | |
232 | ||
233 | if (!mask) | |
234 | { | |
235 | if (limit_query) | |
236 | need_more_params(sptr, "STATS K"); | |
237 | else | |
238 | report_deny_list(sptr); | |
239 | return; | |
240 | } | |
241 | ||
242 | if (!limit_query) | |
243 | { | |
244 | wilds = string_has_wildcards(mask); | |
245 | count = 1000; | |
246 | } | |
247 | if ((host = strchr(mask, '@'))) | |
248 | { | |
249 | user = mask; | |
250 | *host++ = '\0'; | |
251 | } | |
252 | else | |
253 | host = mask; | |
254 | ||
255 | for (conf = conf_get_deny_list(); conf; conf = conf->next) | |
256 | { | |
257 | /* Skip this block if the user is searching for a user-matching | |
258 | * mask but the current Kill doesn't have a usermask, or if user | |
259 | * is searching for a host-matching mask but the Kill has no | |
260 | * hostmask, or if the user mask is specified and doesn't match, | |
261 | * or if the host mask is specified and doesn't match. | |
262 | */ | |
263 | if ((user && !conf->usermask) | |
264 | || (host && !conf->hostmask) | |
265 | || (user && conf->usermask | |
266 | && (wilds | |
267 | ? mmatch(user, conf->usermask) | |
268 | : match(conf->usermask, user))) | |
269 | || (host && conf->hostmask | |
270 | && (wilds | |
271 | ? mmatch(host, conf->hostmask) | |
272 | : match(conf->hostmask, host)))) | |
273 | continue; | |
274 | send_reply(sptr, RPL_STATSKLINE, conf->bits > 0 ? 'k' : 'K', | |
275 | conf->usermask ? conf->usermask : "*", | |
276 | conf->hostmask ? conf->hostmask : "*", | |
277 | conf->message ? conf->message : "(none)", | |
278 | conf->realmask ? conf->realmask : "*"); | |
279 | if (--count == 0) | |
280 | return; | |
281 | } | |
282 | } | |
283 | ||
284 | /** Report on servers and/or clients connected to the network. | |
285 | * @param[in] sptr Client requesting statistics. | |
286 | * @param[in] sd Stats descriptor for request (ignored). | |
287 | * @param[in] name Filter for client names to show. | |
288 | */ | |
289 | static void | |
290 | stats_links(struct Client* sptr, const struct StatDesc* sd, char* name) | |
291 | { | |
292 | struct Client *acptr; | |
293 | int i; | |
294 | int wilds = 0; | |
295 | ||
296 | if (name) | |
297 | wilds = string_has_wildcards(name); | |
298 | ||
299 | /* | |
300 | * Send info about connections which match, or all if the | |
301 | * mask matches me.name. Only restrictions are on those who | |
302 | * are invisible not being visible to 'foreigners' who use | |
303 | * a wild card based search to list it. | |
304 | */ | |
305 | send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, "Connection SendQ " | |
306 | "SendM SendKBytes RcveM RcveKBytes :Open since"); | |
307 | for (i = 0; i <= HighestFd; i++) | |
308 | { | |
309 | if (!(acptr = LocalClientArray[i])) | |
310 | continue; | |
311 | /* Don't return clients when this is a request for `all' */ | |
312 | if (!name && IsUser(acptr)) | |
313 | continue; | |
314 | /* Don't show invisible people to non opers unless they know the nick */ | |
315 | if (IsInvisible(acptr) && (!name || wilds) && !IsAnOper(acptr) && | |
316 | (acptr != sptr)) | |
317 | continue; | |
318 | /* Only show the ones that match the given mask - if any */ | |
319 | if (name && wilds && match(name, cli_name(acptr))) | |
320 | continue; | |
321 | /* Skip all that do not match the specific query */ | |
322 | if (!(!name || wilds) && 0 != ircd_strcmp(name, cli_name(acptr))) | |
323 | continue; | |
324 | send_reply(sptr, SND_EXPLICIT | RPL_STATSLINKINFO, | |
325 | "%s %u %u %Lu %u %Lu :%Tu", | |
326 | (*(cli_name(acptr))) ? cli_name(acptr) : "<unregistered>", | |
327 | (int)MsgQLength(&(cli_sendQ(acptr))), (int)cli_sendM(acptr), | |
328 | (cli_sendB(acptr) >> 10), (int)cli_receiveM(acptr), | |
329 | (cli_receiveB(acptr) >> 10), CurrentTime - cli_firsttime(acptr)); | |
330 | } | |
331 | } | |
332 | ||
333 | /** Report on loaded modules. | |
334 | * @param[in] to Client requesting statistics. | |
335 | * @param[in] sd Stats descriptor for request (ignored). | |
336 | * @param[in] param Extra parameter from user (ignored). | |
337 | */ | |
338 | static void | |
339 | stats_modules(struct Client* to, const struct StatDesc* sd, char* param) | |
340 | { | |
341 | crypt_mechs_t* mechs; | |
342 | ||
343 | send_reply(to, SND_EXPLICIT | RPL_STATSLLINE, | |
344 | "Module Description Entry Point"); | |
345 | ||
346 | /* atm the only "modules" we have are the crypto mechanisms, | |
347 | eventualy they'll be part of a global dl module list, for now | |
348 | i'll just output data about them -- hikari */ | |
349 | ||
350 | if(crypt_mechs_root == NULL) | |
351 | return; | |
352 | ||
353 | mechs = crypt_mechs_root->next; | |
354 | ||
355 | for(;;) | |
356 | { | |
357 | if(mechs == NULL) | |
358 | return; | |
359 | ||
360 | send_reply(to, SND_EXPLICIT | RPL_STATSLLINE, | |
361 | "%s %s 0x%X", | |
362 | mechs->mech->shortname, mechs->mech->description, | |
363 | mechs->mech->crypt_function); | |
364 | ||
365 | mechs = mechs->next; | |
366 | } | |
367 | ||
368 | } | |
369 | ||
370 | /** Report how many times each command has been used. | |
371 | * @param[in] to Client requesting statistics. | |
372 | * @param[in] sd Stats descriptor for request (ignored). | |
373 | * @param[in] param Extra parameter from user (ignored). | |
374 | */ | |
375 | static void | |
376 | stats_commands(struct Client* to, const struct StatDesc* sd, char* param) | |
377 | { | |
378 | struct Message *mptr; | |
379 | ||
380 | for (mptr = msgtab; mptr->cmd; mptr++) | |
381 | if (mptr->count) | |
382 | send_reply(to, RPL_STATSCOMMANDS, mptr->cmd, mptr->count, mptr->bytes); | |
383 | } | |
384 | ||
385 | /** List channel quarantines. | |
386 | * @param[in] to Client requesting statistics. | |
387 | * @param[in] sd Stats descriptor for request (ignored). | |
388 | * @param[in] param Filter for quarantined channel names. | |
389 | */ | |
390 | static void | |
391 | stats_quarantine(struct Client* to, const struct StatDesc* sd, char* param) | |
392 | { | |
393 | struct qline *qline; | |
394 | ||
395 | for (qline = GlobalQuarantineList; qline; qline = qline->next) | |
396 | { | |
397 | if (param && match(param, qline->chname)) /* narrow search */ | |
398 | continue; | |
399 | send_reply(to, RPL_STATSQLINE, qline->chname, qline->reason); | |
400 | } | |
401 | } | |
402 | ||
d8e74551 | 403 | static void |
404 | stats_sline(struct Client* to, const struct StatDesc* sd, char* param) | |
405 | { | |
406 | int y = 1, i = 1; | |
407 | struct sline *sline; | |
408 | ||
409 | if (IsAnOper(to)) | |
410 | send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost Realhost Ident"); | |
411 | else | |
412 | send_reply(to, SND_EXPLICIT | RPL_TEXT, "# Type Spoofhost"); | |
413 | ||
414 | for (sline = GlobalSList; sline; sline = sline->next) { | |
415 | if (param && match(param, sline->spoofhost)) { /* narrow search */ | |
416 | if (IsAnOper(to)) | |
417 | y++; | |
418 | else | |
419 | if (!EmptyString(sline->passwd)) | |
420 | y++; | |
421 | continue; | |
422 | } | |
423 | ||
424 | if (IsAnOper(to)) { | |
425 | send_reply(to, RPL_STATSSLINE, (param) ? y : i, | |
426 | (EmptyString(sline->passwd)) ? "oper" : "user", | |
427 | sline->spoofhost, | |
428 | (EmptyString(sline->realhost)) ? "" : sline->realhost, | |
429 | (EmptyString(sline->username)) ? "" : sline->username); | |
430 | i++; | |
431 | } else { | |
432 | if (!EmptyString(sline->passwd)) { | |
433 | send_reply(to, RPL_STATSSLINE, (param) ? y : i, "user", sline->spoofhost, | |
434 | "", "", ""); | |
435 | i++; | |
436 | } | |
437 | } | |
438 | } | |
439 | } | |
440 | ||
189935b1 | 441 | /** List service pseudo-command mappings. |
442 | * @param[in] to Client requesting statistics. | |
443 | * @param[in] sd Stats descriptor for request (ignored). | |
444 | * @param[in] param Extra parameter from user (ignored). | |
445 | */ | |
446 | static void | |
447 | stats_mapping(struct Client *to, const struct StatDesc* sd, char* param) | |
448 | { | |
449 | struct s_map *map; | |
450 | ||
451 | send_reply(to, RPL_STATSRLINE, "Command", "Name", "Prepend", "Target"); | |
452 | for (map = GlobalServiceMapList; map; map = map->next) { | |
453 | struct nick_host *nh; | |
454 | for (nh = map->services; nh; nh = nh->next) { | |
455 | send_reply(to, RPL_STATSRLINE, map->command, map->name, | |
456 | (map->prepend ? map->prepend : "*"), nh->nick); | |
457 | } | |
458 | } | |
459 | } | |
460 | ||
461 | /** Report server uptime and maximum connection/client counts. | |
462 | * @param[in] to Client requesting statistics. | |
463 | * @param[in] sd Stats descriptor for request (ignored). | |
464 | * @param[in] param Extra parameter from user (ignored). | |
465 | */ | |
466 | static void | |
467 | stats_uptime(struct Client* to, const struct StatDesc* sd, char* param) | |
468 | { | |
469 | time_t nowr; | |
470 | ||
471 | nowr = CurrentTime - cli_since(&me); | |
472 | send_reply(to, RPL_STATSUPTIME, nowr / 86400, (nowr / 3600) % 24, | |
473 | (nowr / 60) % 60, nowr % 60); | |
474 | send_reply(to, RPL_STATSCONN, max_connection_count, max_client_count); | |
475 | } | |
476 | ||
477 | /** Verbosely report on servers connected to the network. | |
478 | * If sd->sd_funcdata != 0, then display in a more human-friendly format. | |
479 | * @param[in] sptr Client requesting statistics. | |
480 | * @param[in] sd Stats descriptor for request. | |
481 | * @param[in] param Filter for server names to display. | |
482 | */ | |
483 | static void | |
484 | stats_servers_verbose(struct Client* sptr, const struct StatDesc* sd, | |
485 | char* param) | |
486 | { | |
487 | struct Client *acptr; | |
488 | const char *fmt; | |
489 | ||
490 | /* | |
491 | * lowercase 'v' is for human-readable, | |
492 | * uppercase 'V' is for machine-readable | |
493 | */ | |
494 | if (sd->sd_funcdata) { | |
495 | send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, | |
496 | "%-20s %-20s Flags Hops Numeric Lag RTT Up Down " | |
497 | "Clients/Max Proto %-10s :Info", "Servername", "Uplink", | |
498 | "LinkTS"); | |
052b069e | 499 | fmt = "%-20s %-20s %c%c%c%c%c %4i %s %-4i %5i %4i %4i %4i %5i %5i P%-2i %Tu :%s"; |
189935b1 | 500 | } else { |
052b069e | 501 | fmt = "%s %s %c%c%c%c%c %i %s %i %i %i %i %i %i %i P%i %Tu :%s"; |
189935b1 | 502 | } |
503 | ||
504 | for (acptr = GlobalClientList; acptr; acptr = cli_next(acptr)) | |
505 | { | |
506 | if (!IsServer(acptr) && !IsMe(acptr)) | |
507 | continue; | |
508 | /* narrow search */ | |
509 | if (param && match(param, cli_name(acptr))) | |
510 | continue; | |
511 | send_reply(sptr, SND_EXPLICIT | RPL_STATSVERBOSE, fmt, | |
512 | cli_name(acptr), | |
513 | cli_name(cli_serv(acptr)->up), | |
514 | IsBurst(acptr) ? 'B' : '-', | |
515 | IsBurstAck(acptr) ? 'A' : '-', | |
516 | IsHub(acptr) ? 'H' : '-', | |
517 | IsService(acptr) ? 'S' : '-', | |
052b069e | 518 | IsIPv6(acptr) ? '6' : '-', |
189935b1 | 519 | cli_hopcount(acptr), |
520 | NumServ(acptr), | |
521 | base64toint(cli_yxx(acptr)), | |
522 | cli_serv(acptr)->lag, | |
523 | cli_serv(acptr)->asll_rtt, | |
524 | cli_serv(acptr)->asll_to, | |
525 | cli_serv(acptr)->asll_from, | |
526 | (acptr == &me ? UserStats.local_clients : cli_serv(acptr)->clients), | |
527 | cli_serv(acptr)->nn_mask, | |
528 | cli_serv(acptr)->prot, | |
529 | cli_serv(acptr)->timestamp, | |
530 | cli_info(acptr)); | |
531 | } | |
532 | } | |
533 | ||
534 | /** Display objects allocated (and total memory used by them) for | |
535 | * several types of structures. | |
536 | * @param[in] to Client requesting statistics. | |
537 | * @param[in] sd Stats descriptor for request (ignored). | |
538 | * @param[in] param Extra parameter from user (ignored). | |
539 | */ | |
540 | static void | |
541 | stats_meminfo(struct Client* to, const struct StatDesc* sd, char* param) | |
542 | { | |
543 | extern void bans_send_meminfo(struct Client *cptr); | |
544 | ||
545 | class_send_meminfo(to); | |
546 | bans_send_meminfo(to); | |
547 | send_listinfo(to, 0); | |
548 | } | |
549 | ||
550 | /** Send a list of available statistics. | |
551 | * @param[in] to Client requesting statistics. | |
552 | * @param[in] sd Stats descriptor for request. | |
553 | * @param[in] param Extra parameter from user (ignored). | |
554 | */ | |
555 | static void | |
556 | stats_help(struct Client* to, const struct StatDesc* sd, char* param) | |
557 | { | |
558 | struct StatDesc *asd; | |
559 | ||
560 | /* only if it's my user */ | |
561 | if (MyUser(to)) | |
562 | for (asd = statsinfo; asd->sd_name; asd++) | |
563 | if (asd != sd) /* don't send the help for us */ | |
564 | sendcmdto_one(&me, CMD_NOTICE, to, "%C :%c (%s) - %s", to, asd->sd_c, | |
565 | asd->sd_name, asd->sd_desc); | |
566 | } | |
567 | ||
568 | /** Contains information about all statistics. */ | |
569 | struct StatDesc statsinfo[] = { | |
570 | { 'a', "nameservers", STAT_FLAG_OPERFEAT|STAT_FLAG_LOCONLY, FEAT_HIS_STATS_a, | |
571 | report_dns_servers, 0, | |
572 | "DNS servers." }, | |
573 | { 'c', "connect", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_c, | |
574 | stats_configured_links, CONF_SERVER, | |
575 | "Remote server connection lines." }, | |
576 | { 'd', "maskrules", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_d, | |
577 | stats_crule_list, CRULE_MASK, | |
578 | "Dynamic routing configuration." }, | |
579 | { 'D', "crules", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_d, | |
580 | stats_crule_list, CRULE_ALL, | |
581 | "Dynamic routing configuration." }, | |
582 | { 'e', "engine", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_e, | |
583 | stats_engine, 0, | |
584 | "Report server event loop engine." }, | |
585 | { 'f', "features", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_f, | |
586 | feature_report, 0, | |
587 | "Feature settings." }, | |
588 | { 'g', "glines", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_g, | |
589 | gline_stats, 0, | |
590 | "Global bans (G-lines)." }, | |
591 | { 'i', "access", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_i, | |
592 | stats_access, CONF_CLIENT, | |
593 | "Connection authorization lines." }, | |
594 | { 'j', "histogram", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_j, | |
595 | msgq_histogram, 0, | |
596 | "Message length histogram." }, | |
597 | { 'J', "jupes", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_J, | |
598 | stats_nickjupes, 0, | |
599 | "Nickname jupes." }, | |
600 | { 'k', "klines", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_k, | |
601 | stats_klines, 0, | |
602 | "Local bans (K-Lines)." }, | |
603 | { 'l', "links", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), | |
604 | FEAT_HIS_STATS_l, | |
605 | stats_links, 0, | |
606 | "Current connections information." }, | |
607 | { 'L', "modules", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), | |
608 | FEAT_HIS_STATS_L, | |
609 | stats_modules, 0, | |
610 | "Dynamically loaded modules." }, | |
611 | { 'm', "commands", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_m, | |
612 | stats_commands, 0, | |
613 | "Message usage information." }, | |
614 | { 'o', "operators", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_o, | |
615 | stats_configured_links, CONF_OPERATOR, | |
616 | "Operator information." }, | |
617 | { 'p', "ports", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_p, | |
618 | show_ports, 0, | |
619 | "Listening ports." }, | |
620 | { 'q', "quarantines", (STAT_FLAG_OPERONLY | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_q, | |
621 | stats_quarantine, 0, | |
622 | "Quarantined channels list." }, | |
623 | { 'R', "mappings", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_R, | |
624 | stats_mapping, 0, | |
625 | "Service mappings." }, | |
626 | #ifdef DEBUGMODE | |
627 | { 'r', "usage", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_r, | |
628 | send_usage, 0, | |
629 | "System resource usage (Debug only)." }, | |
630 | #endif | |
d8e74551 | 631 | { 's', "spoofhosts", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM), FEAT_HIS_STATS_s, |
632 | stats_sline, 0, | |
633 | "Spoofed hosts information." }, | |
189935b1 | 634 | { 'T', "motds", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_T, |
635 | motd_report, 0, | |
636 | "Configured Message Of The Day files." }, | |
637 | { 't', "locals", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_t, | |
638 | tstats, 0, | |
639 | "Local connection statistics (Total SND/RCV, etc)." }, | |
640 | { 'U', "uworld", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_U, | |
641 | stats_configured_links, CONF_UWORLD, | |
642 | "Service server information." }, | |
643 | { 'u', "uptime", (STAT_FLAG_OPERFEAT | STAT_FLAG_CASESENS), FEAT_HIS_STATS_u, | |
644 | stats_uptime, 0, | |
645 | "Current uptime & highest connection count." }, | |
646 | { 'v', "vservers", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v, | |
647 | stats_servers_verbose, 1, | |
648 | "Verbose server information." }, | |
649 | { 'V', "vserversmach", (STAT_FLAG_OPERFEAT | STAT_FLAG_VARPARAM | STAT_FLAG_CASESENS), FEAT_HIS_STATS_v, | |
650 | stats_servers_verbose, 0, | |
651 | "Verbose server information." }, | |
652 | { 'w', "userload", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_w, | |
653 | calc_load, 0, | |
654 | "Userload statistics." }, | |
655 | { 'x', "memusage", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_x, | |
656 | stats_meminfo, 0, | |
657 | "List usage information." }, | |
658 | { 'y', "classes", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_y, | |
659 | report_classes, 0, | |
660 | "Connection classes." }, | |
661 | { 'z', "memory", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_z, | |
662 | count_memory, 0, | |
663 | "Memory/Structure allocation information." }, | |
9f8856e9 | 664 | { ' ', "iauth", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_IAUTH, |
665 | report_iauth_stats, 0, | |
666 | "IAuth statistics." }, | |
667 | { ' ', "iauthconf", STAT_FLAG_OPERFEAT, FEAT_HIS_STATS_IAUTH, | |
668 | report_iauth_conf, 0, | |
669 | "IAuth configuration." }, | |
189935b1 | 670 | { '*', "help", STAT_FLAG_CASESENS, FEAT_LAST_F, |
671 | stats_help, 0, | |
672 | "Send help for stats." }, | |
673 | { '\0', 0, FEAT_LAST_F, 0, 0, 0 } | |
674 | }; | |
675 | ||
676 | /** Maps from characters to statistics descriptors. | |
677 | * Statistics descriptors with no single-character alias are not included. | |
678 | */ | |
679 | static struct StatDesc *statsmap[256]; | |
680 | /** Number of statistics descriptors. */ | |
681 | static int statscount; | |
682 | ||
683 | /** Compare two StatDesc structures by long name (StatDesc::sd_name). | |
684 | * @param[in] a_ Pointer to a StatDesc. | |
685 | * @param[in] b_ Pointer to a StatDesc. | |
686 | * @return Less than, equal to, or greater than zero if \a a_ is | |
687 | * lexicographically less than, equal to, or greater than \a b_. | |
688 | */ | |
689 | static int | |
690 | stats_cmp(const void *a_, const void *b_) | |
691 | { | |
692 | const struct StatDesc *a = a_; | |
693 | const struct StatDesc *b = b_; | |
694 | return ircd_strcmp(a->sd_name, b->sd_name); | |
695 | } | |
696 | ||
697 | /** Compare a StatDesc's name against a string. | |
698 | * @param[in] key Pointer to a null-terminated string. | |
699 | * @param[in] sd_ Pointer to a StatDesc. | |
700 | * @return Less than, equal to, or greater than zero if \a key is | |
701 | * lexicographically less than, equal to, or greater than \a | |
702 | * sd_->sd_name. | |
703 | */ | |
704 | static int | |
705 | stats_search(const void *key, const void *sd_) | |
706 | { | |
707 | const struct StatDesc *sd = sd_; | |
708 | return ircd_strcmp(key, sd->sd_name); | |
709 | } | |
710 | ||
711 | /** Look up a stats handler. If name_or_char is just one character | |
712 | * long, use that as a character index; otherwise, look it up by name | |
713 | * in #statsinfo. | |
714 | * @param[in] name_or_char Null-terminated string to look up. | |
715 | * @return The statistics descriptor for \a name_or_char (NULL if none). | |
716 | */ | |
717 | const struct StatDesc * | |
718 | stats_find(const char *name_or_char) | |
719 | { | |
720 | if (!name_or_char[1]) | |
721 | return statsmap[name_or_char[0] - CHAR_MIN]; | |
722 | else | |
723 | return bsearch(name_or_char, statsinfo, statscount, sizeof(statsinfo[0]), stats_search); | |
724 | } | |
725 | ||
726 | /** Build statsmap from the statsinfo array. */ | |
727 | void | |
728 | stats_init(void) | |
729 | { | |
730 | struct StatDesc *sd; | |
731 | ||
732 | /* Count number of stats entries and sort them. */ | |
733 | for (statscount = 0, sd = statsinfo; sd->sd_name; sd++, statscount++) {} | |
734 | qsort(statsinfo, statscount, sizeof(statsinfo[0]), stats_cmp); | |
735 | ||
736 | /* Build the mapping */ | |
737 | for (sd = statsinfo; sd->sd_name; sd++) | |
738 | { | |
739 | if (!sd->sd_c) | |
740 | continue; | |
741 | else if (sd->sd_flags & STAT_FLAG_CASESENS) | |
742 | /* case sensitive character... */ | |
743 | statsmap[sd->sd_c - CHAR_MIN] = sd; | |
744 | else | |
745 | { | |
746 | /* case insensitive--make sure to put in two entries */ | |
747 | statsmap[ToLower(sd->sd_c) - CHAR_MIN] = sd; | |
748 | statsmap[ToUpper(sd->sd_c) - CHAR_MIN] = sd; | |
749 | } | |
750 | } | |
751 | } |