ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/ircd-hybrid/trunk/modules/m_stats.c
Revision: 2118
Committed: Sun May 26 11:49:51 2013 UTC (12 years, 3 months ago) by michael
Content type: text/x-csrc
File size: 54224 byte(s)
Log Message:
- Got rid of CONF_HUB enum type

File Contents

# User Rev Content
1 adx 30 /*
2     * ircd-hybrid: an advanced Internet Relay Chat Daemon(ircd).
3     * m_stats.c: Sends the user statistics or config information.
4     *
5     * Copyright (C) 2002 by the past and present ircd coders, and others.
6     *
7     * This program is free software; you can redistribute it and/or modify
8     * it under the terms of the GNU General Public License as published by
9     * the Free Software Foundation; either version 2 of the License, or
10     * (at your option) any later version.
11     *
12     * This program is distributed in the hope that it will be useful,
13     * but WITHOUT ANY WARRANTY; without even the implied warranty of
14     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15     * GNU General Public License for more details.
16     *
17     * You should have received a copy of the GNU General Public License
18     * along with this program; if not, write to the Free Software
19     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20     * USA
21     *
22 knight 31 * $Id$
23 adx 30 */
24    
25     #include "stdinc.h"
26 michael 1011 #include "list.h" /* dlink_node/dlink_list */
27 adx 30 #include "client.h" /* Client */
28     #include "irc_string.h"
29     #include "ircd.h" /* me */
30     #include "listener.h" /* show_ports */
31     #include "s_gline.h"
32 michael 1632 #include "conf.h"
33 michael 1644 #include "conf_class.h"
34 adx 30 #include "hostmask.h"
35     #include "numeric.h" /* ERR_xxx */
36     #include "send.h" /* sendto_one */
37     #include "fdlist.h" /* PF and friends */
38     #include "s_bsd.h" /* highest_fd */
39     #include "s_misc.h" /* serv_info */
40     #include "s_serv.h" /* hunt_server */
41     #include "s_user.h" /* show_opers */
42     #include "event.h" /* events */
43     #include "dbuf.h"
44 michael 1144 #include "hook.h"
45 adx 30 #include "parse.h"
46     #include "modules.h"
47     #include "resv.h" /* report_resv */
48     #include "whowas.h"
49 michael 884 #include "watch.h"
50 michael 1312 #include "irc_res.h"
51 adx 30
52    
53     const char *from, *to;
54    
55 michael 1922 static const struct shared_flags
56     {
57     const unsigned int type;
58     const unsigned char letter;
59     } flag_table[] = {
60     { SHARED_KLINE, 'K' },
61     { SHARED_UNKLINE, 'U' },
62     { SHARED_XLINE, 'X' },
63     { SHARED_UNXLINE, 'Y' },
64     { SHARED_RESV, 'Q' },
65     { SHARED_UNRESV, 'R' },
66     { SHARED_LOCOPS, 'L' },
67     { SHARED_DLINE, 'D' },
68     { SHARED_UNDLINE, 'E' },
69     { 0, '\0' }
70     };
71    
72 adx 30 /*
73 michael 1922 * inputs - pointer to client requesting confitem report
74     * - ConfType to report
75     * output - none
76     * side effects -
77     */
78     static void
79     report_confitem_types(struct Client *source_p, enum maskitem_type type)
80     {
81     dlink_node *ptr = NULL, *dptr = NULL;
82     struct MaskItem *conf = NULL;
83     const struct shared_flags *shared = NULL;
84     char buf[12];
85     char *p = NULL;
86    
87     switch (type)
88     {
89     case CONF_XLINE:
90     DLINK_FOREACH(ptr, xconf_items.head)
91     {
92     conf = ptr->data;
93    
94     sendto_one(source_p, form_str(RPL_STATSXLINE),
95     me.name, source_p->name,
96     conf->until ? 'x': 'X', conf->count,
97     conf->name, conf->reason);
98     }
99     break;
100    
101     case CONF_ULINE:
102     shared = flag_table;
103     DLINK_FOREACH(ptr, uconf_items.head)
104     {
105     conf = ptr->data;
106    
107     p = buf;
108    
109     *p++ = 'c';
110     for (; shared->type; ++shared)
111     if (shared->type & conf->flags)
112     *p++ = shared->letter;
113     else
114     *p++ = ToLower(shared->letter);
115    
116     sendto_one(source_p, form_str(RPL_STATSULINE),
117     me.name, source_p->name, conf->name,
118     conf->user?conf->user: "*",
119     conf->host?conf->host: "*", buf);
120     }
121    
122     shared = flag_table;
123     DLINK_FOREACH(ptr, cluster_items.head)
124     {
125     conf = ptr->data;
126    
127     p = buf;
128    
129     *p++ = 'C';
130     for (; shared->type; ++shared)
131     if (shared->type & conf->flags)
132     *p++ = shared->letter;
133     else
134     *p++ = ToLower(shared->letter);
135    
136     sendto_one(source_p, form_str(RPL_STATSULINE),
137     me.name, source_p->name, conf->name,
138     "*", "*", buf);
139     }
140    
141     break;
142    
143     case CONF_OPER:
144     DLINK_FOREACH(ptr, oconf_items.head)
145     {
146     conf = ptr->data;
147    
148     /* Don't allow non opers to see oper privs */
149     if (HasUMode(source_p, UMODE_OPER))
150     sendto_one(source_p, form_str(RPL_STATSOLINE),
151 michael 1925 me.name, source_p->name, 'O', conf->count, conf->user, conf->host,
152 michael 1922 conf->name, oper_privs_as_string(conf->port),
153     conf->class ? conf->class->name : "<default>");
154     else
155     sendto_one(source_p, form_str(RPL_STATSOLINE),
156 michael 1925 me.name, source_p->name, 'O', conf->count, conf->user, conf->host,
157 michael 1922 conf->name, "0",
158     conf->class ? conf->class->name : "<default>");
159     }
160     break;
161    
162     case CONF_SERVICE:
163     DLINK_FOREACH(ptr, service_items.head)
164     {
165     conf = ptr->data;
166     sendto_one(source_p, form_str(RPL_STATSSERVICE),
167     me.name, source_p->name, 'S', "*", conf->name, 0, 0);
168     }
169     break;
170    
171     case CONF_SERVER:
172     DLINK_FOREACH(ptr, server_items.head)
173     {
174     p = buf;
175     conf = ptr->data;
176    
177     buf[0] = '\0';
178    
179     if (IsConfAllowAutoConn(conf))
180     *p++ = 'A';
181     if (IsConfSSL(conf))
182     *p++ = 'S';
183     if (buf[0] == '\0')
184     *p++ = '*';
185    
186     *p = '\0';
187    
188     /*
189     * Allow admins to see actual ips unless hide_server_ips is enabled
190     */
191     if (!ConfigServerHide.hide_server_ips && HasUMode(source_p, UMODE_ADMIN))
192     sendto_one(source_p, form_str(RPL_STATSCLINE),
193     me.name, source_p->name, 'C', conf->host,
194     buf, conf->name, conf->port,
195     conf->class ? conf->class->name : "<default>");
196     else
197     sendto_one(source_p, form_str(RPL_STATSCLINE),
198     me.name, source_p->name, 'C',
199     "*@127.0.0.1", buf, conf->name, conf->port,
200     conf->class ? conf->class->name : "<default>");
201     }
202     break;
203    
204     default:
205     break;
206     }
207     }
208    
209 michael 1927 /* report_resv()
210     *
211     * inputs - pointer to client pointer to report to.
212     * output - NONE
213     * side effects - report all resvs to client.
214     */
215     static void
216     report_resv(struct Client *source_p)
217     {
218     dlink_node *ptr = NULL;
219     struct MaskItem *conf = NULL;
220    
221     DLINK_FOREACH(ptr, resv_channel_list.head)
222     {
223     conf = ptr->data;
224     sendto_one(source_p, form_str(RPL_STATSQLINE),
225     me.name, source_p->name,
226     conf->until ? 'q' : 'Q', conf->count,
227     conf->name, conf->reason);
228     }
229    
230     DLINK_FOREACH(ptr, nresv_items.head)
231     {
232     conf = ptr->data;
233     sendto_one(source_p, form_str(RPL_STATSQLINE),
234     me.name, source_p->name,
235     conf->until ? 'q' : 'Q', conf->count,
236     conf->name, conf->reason);
237     }
238     }
239    
240 michael 1922 /*
241 adx 30 * This is part of the STATS replies. There is no offical numeric for this
242     * since this isnt an official command, in much the same way as HASH isnt.
243     * It is also possible that some systems wont support this call or have
244     * different field names for "struct rusage".
245     * -avalon
246     */
247     static void
248 michael 1457 stats_usage(struct Client *source_p, int parc, char *parv[])
249 adx 30 {
250     struct rusage rus;
251     time_t secs;
252     time_t rup;
253     #ifdef hz
254     # define hzz hz
255     #else
256     # ifdef HZ
257     # define hzz HZ
258     # else
259     int hzz = 1;
260     # endif
261     #endif
262    
263     if (getrusage(RUSAGE_SELF, &rus) == -1)
264     {
265     sendto_one(source_p, ":%s NOTICE %s :Getruseage error: %s",
266     me.name, source_p->name, strerror(errno));
267     return;
268     }
269    
270     secs = rus.ru_utime.tv_sec + rus.ru_stime.tv_sec;
271    
272     if (secs == 0)
273     secs = 1;
274    
275 michael 1241 rup = (CurrentTime - me.localClient->since) * hzz;
276 adx 30
277     if (rup == 0)
278     rup = 1;
279    
280     sendto_one(source_p,
281 michael 1968 ":%s %d %s R :CPU Secs %d:%02d User %d:%02d System %d:%02d",
282 adx 30 me.name, RPL_STATSDEBUG, source_p->name, (int)(secs/60), (int)(secs%60),
283     (int)(rus.ru_utime.tv_sec/60), (int)(rus.ru_utime.tv_sec%60),
284     (int)(rus.ru_stime.tv_sec/60), (int)(rus.ru_stime.tv_sec%60));
285     sendto_one(source_p, ":%s %d %s R :RSS %ld ShMem %ld Data %ld Stack %ld",
286     me.name, RPL_STATSDEBUG, source_p->name, rus.ru_maxrss,
287     (rus.ru_ixrss / rup), (rus.ru_idrss / rup),
288     (rus.ru_isrss / rup));
289     sendto_one(source_p, ":%s %d %s R :Swaps %d Reclaims %d Faults %d",
290     me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_nswap,
291     (int)rus.ru_minflt, (int)rus.ru_majflt);
292     sendto_one(source_p, ":%s %d %s R :Block in %d out %d",
293     me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_inblock,
294     (int)rus.ru_oublock);
295     sendto_one(source_p, ":%s %d %s R :Msg Rcv %d Send %d",
296     me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_msgrcv,
297     (int)rus.ru_msgsnd);
298     sendto_one(source_p, ":%s %d %s R :Signals %d Context Vol. %d Invol %d",
299     me.name, RPL_STATSDEBUG, source_p->name, (int)rus.ru_nsignals,
300     (int)rus.ru_nvcsw, (int)rus.ru_nivcsw);
301     }
302    
303     static void
304 michael 1457 stats_memory(struct Client *source_p, int parc, char *parv[])
305 adx 30 {
306     const dlink_node *gptr = NULL;
307     const dlink_node *dlink = NULL;
308    
309 michael 948 unsigned int local_client_conf_count = 0; /* local client conf links */
310     unsigned int users_counted = 0; /* user structs */
311 adx 30
312 michael 1017 unsigned int channel_members = 0;
313 michael 948 unsigned int channel_invites = 0;
314     unsigned int channel_bans = 0;
315     unsigned int channel_except = 0;
316     unsigned int channel_invex = 0;
317 adx 30
318 michael 948 unsigned int wwu = 0; /* whowas users */
319     unsigned int class_count = 0; /* classes */
320     unsigned int aways_counted = 0;
321     unsigned int number_ips_stored; /* number of ip addresses hashed */
322 adx 30
323 michael 948 uint64_t channel_memory = 0;
324     uint64_t channel_ban_memory = 0;
325     uint64_t channel_except_memory = 0;
326     uint64_t channel_invex_memory = 0;
327 adx 30
328     unsigned int safelist_count = 0;
329 michael 948 uint64_t safelist_memory = 0;
330 adx 30
331 michael 948 uint64_t wwm = 0; /* whowas array memory used */
332     uint64_t conf_memory = 0; /* memory used by conf lines */
333     uint64_t mem_ips_stored; /* memory used by ip address hash */
334 adx 30
335 michael 948 uint64_t total_channel_memory = 0;
336     uint64_t totww = 0;
337 adx 30
338     unsigned int local_client_count = 0;
339     unsigned int remote_client_count = 0;
340    
341 michael 948 uint64_t local_client_memory_used = 0;
342     uint64_t remote_client_memory_used = 0;
343 adx 30
344 michael 948 uint64_t total_memory = 0;
345 adx 30 unsigned int topic_count = 0;
346    
347 michael 1017 unsigned int watch_list_headers = 0; /* watchlist headers */
348     unsigned int watch_list_entries = 0; /* watchlist entries */
349     uint64_t watch_list_memory = 0; /* watchlist memory used */
350 michael 884
351 adx 30
352     DLINK_FOREACH(gptr, global_client_list.head)
353     {
354     struct Client *target_p = gptr->data;
355    
356     if (MyConnect(target_p))
357     {
358     ++local_client_count;
359     local_client_conf_count += dlink_list_length(&target_p->localClient->confs);
360 michael 1017 watch_list_entries += dlink_list_length(&target_p->localClient->watches);
361 adx 30 }
362     else
363     ++remote_client_count;
364    
365     if (IsClient(target_p))
366     {
367     ++users_counted;
368    
369 michael 1483 if (target_p->away[0])
370 adx 30 ++aways_counted;
371     }
372     }
373    
374     /* Count up all channels, ban lists, except lists, Invex lists */
375     channel_memory = dlink_list_length(&global_channel_list) *
376     sizeof(struct Channel);
377     DLINK_FOREACH(gptr, global_channel_list.head)
378     {
379 michael 948 const struct Ban *actualBan;
380     const struct Channel *chptr = gptr->data;
381 adx 30
382 michael 1017 channel_members += dlink_list_length(&chptr->members);
383 adx 30 channel_invites += dlink_list_length(&chptr->invites);
384    
385 michael 1203 if (chptr->topic[0])
386 adx 30 ++topic_count;
387    
388 michael 1017 channel_bans += dlink_list_length(&chptr->banlist);
389     channel_ban_memory += dlink_list_length(&chptr->banlist) * sizeof(struct Ban);
390    
391     DLINK_FOREACH(dlink, chptr->banlist.head)
392 adx 30 {
393 michael 1017 actualBan = dlink->data;
394     assert(actualBan->who);
395 adx 30
396 michael 1017 channel_ban_memory += actualBan->len + 1;
397     channel_ban_memory += strlen(actualBan->who) + 1;
398 adx 30 }
399    
400 michael 1017 channel_except += dlink_list_length(&chptr->exceptlist);
401     channel_except_memory += dlink_list_length(&chptr->exceptlist) * sizeof(struct Ban);
402    
403     DLINK_FOREACH(dlink, chptr->exceptlist.head)
404 adx 30 {
405 michael 1017 actualBan = dlink->data;
406     assert(actualBan->who);
407 adx 30
408 michael 1017 channel_except_memory += actualBan->len + 1;
409     channel_except_memory += strlen(actualBan->who) + 1;
410 adx 30 }
411    
412 michael 1017 channel_invex += dlink_list_length(&chptr->invexlist);
413     channel_invex_memory += dlink_list_length(&chptr->invexlist) * sizeof(struct Ban);
414    
415     DLINK_FOREACH(dlink, chptr->invexlist.head)
416 adx 30 {
417 michael 1017 actualBan = dlink->data;
418     assert(actualBan->who);
419 adx 30
420 michael 1017 channel_invex_memory += actualBan->len + 1;
421     channel_invex_memory += strlen(actualBan->who) + 1;
422 adx 30 }
423     }
424    
425     if ((safelist_count = dlink_list_length(&listing_client_list)))
426     {
427     safelist_memory = safelist_count * sizeof(struct ListTask);
428     DLINK_FOREACH(gptr, listing_client_list.head)
429     {
430 michael 948 const struct Client *acptr = gptr->data;
431 adx 30
432     DLINK_FOREACH(dlink, acptr->localClient->list_task->show_mask.head)
433     safelist_memory += strlen(dlink->data);
434    
435     DLINK_FOREACH(dlink, acptr->localClient->list_task->hide_mask.head)
436     safelist_memory += strlen(dlink->data);
437     }
438     }
439    
440     #if 0
441     /* XXX THIS has to be fixed !!!! -db */
442     /* count up all config items */
443     DLINK_FOREACH(dlink, ConfigItemList.head)
444     {
445     aconf = dlink->data;
446     conf_memory += aconf->host ? strlen(aconf->host)+1 : 0;
447     conf_memory += aconf->passwd ? strlen(aconf->passwd)+1 : 0;
448     conf_memory += aconf->name ? strlen(aconf->name)+1 : 0;
449     conf_memory += sizeof(struct AccessItem);
450     }
451     #endif
452     /* count up all classes */
453 michael 1644 class_count = dlink_list_length(class_get_list());
454 adx 30
455 michael 1017 count_whowas_memory(&wwu, &wwm);
456     watch_count_memory(&watch_list_headers, &watch_list_memory);
457 michael 884
458 michael 1761 sendto_one(source_p, ":%s %d %s z :WATCH headers %u(%llu) entries %d(%u)",
459 michael 1017 me.name, RPL_STATSDEBUG, source_p->name, watch_list_headers,
460     watch_list_memory, watch_list_entries,
461     watch_list_entries * sizeof(dlink_node) * 2);
462 michael 884
463     sendto_one(source_p, ":%s %d %s z :Clients %u(%u)",
464 adx 30 me.name, RPL_STATSDEBUG, source_p->name, users_counted,
465 michael 884 (users_counted * sizeof(struct Client)));
466 adx 30
467 michael 1483 sendto_one(source_p, ":%s %d %s z :User aways %u",
468 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
469 michael 1483 aways_counted);
470 adx 30
471 michael 948 sendto_one(source_p, ":%s %d %s z :Attached confs %u(%llu)",
472 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
473     local_client_conf_count,
474 michael 948 (unsigned long long)(local_client_conf_count * sizeof(dlink_node)));
475 adx 30
476 michael 1127 sendto_one(source_p, ":%s %d %s z :Resv channels %u(%lu) nicks %u(%lu)",
477 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
478     dlink_list_length(&resv_channel_list),
479 michael 1632 dlink_list_length(&resv_channel_list) * sizeof(struct MaskItem),
480 adx 30 dlink_list_length(&nresv_items),
481 michael 1632 dlink_list_length(&nresv_items) * sizeof(struct MaskItem));
482 adx 30
483 michael 948 sendto_one(source_p, ":%s %d %s z :Classes %u(%llu)",
484 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
485 michael 948 class_count, (unsigned long long)(class_count * sizeof(struct ClassItem)));
486 adx 30
487 michael 1761 sendto_one(source_p, ":%s %d %s z :Channels %u(%llu) Topics %u(%u)",
488 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
489     dlink_list_length(&global_channel_list),
490     channel_memory, topic_count, topic_count *
491     (TOPICLEN + 1 + USERHOST_REPLYLEN));
492    
493 michael 948 sendto_one(source_p, ":%s %d %s z :Bans %u(%llu)",
494 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
495     channel_bans, channel_ban_memory);
496    
497 michael 948 sendto_one(source_p, ":%s %d %s z :Exceptions %u(%llu)",
498 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
499     channel_except, channel_except_memory);
500    
501 michael 948 sendto_one(source_p, ":%s %d %s z :Invex %u(%llu)",
502 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
503     channel_invex, channel_invex_memory);
504    
505 michael 948 sendto_one(source_p, ":%s %d %s z :Channel members %u(%llu) invites %u(%llu)",
506 michael 1017 me.name, RPL_STATSDEBUG, source_p->name, channel_members,
507     (unsigned long long)(channel_members * sizeof(struct Membership)),
508 michael 948 channel_invites, (unsigned long long)channel_invites *
509 michael 884 sizeof(dlink_node) * 2);
510 adx 30
511     total_channel_memory = channel_memory + channel_ban_memory +
512 michael 1017 channel_members * sizeof(struct Membership) +
513 michael 884 (channel_invites * sizeof(dlink_node)*2);
514 adx 30
515 michael 948 sendto_one(source_p, ":%s %d %s z :Safelist %u(%llu)",
516 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
517     safelist_count, safelist_memory);
518    
519 michael 948 sendto_one(source_p, ":%s %d %s z :Whowas users %u(%llu)",
520 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
521 michael 948 wwu, (unsigned long long)(wwu * sizeof(struct Client)));
522 adx 30
523 michael 948 sendto_one(source_p, ":%s %d %s z :Whowas array %u(%llu)",
524 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
525 michael 948 NICKNAMEHISTORYLENGTH, wwm);
526 adx 30
527     totww = wwu * sizeof(struct Client) + wwm;
528    
529     count_ip_hash(&number_ips_stored,&mem_ips_stored);
530 michael 948 sendto_one(source_p, ":%s %d %s z :iphash %u(%llu)",
531 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
532 michael 948 number_ips_stored, mem_ips_stored);
533 adx 30
534     total_memory = totww + total_channel_memory + conf_memory + class_count *
535     sizeof(struct ClassItem);
536 michael 948 sendto_one(source_p, ":%s %d %s z :Total: whowas %llu channel %llu conf %llu",
537     me.name, RPL_STATSDEBUG, source_p->name, totww,
538     total_channel_memory, conf_memory);
539 adx 30
540     local_client_memory_used = local_client_count*(sizeof(struct Client) + sizeof(struct LocalUser));
541     total_memory += local_client_memory_used;
542 michael 1127 sendto_one(source_p, ":%s %d %s z :Local client Memory in use: %u(%llu)",
543 adx 30 me.name, RPL_STATSDEBUG, source_p->name, local_client_count,
544     local_client_memory_used);
545    
546     remote_client_memory_used = remote_client_count * sizeof(struct Client);
547     total_memory += remote_client_memory_used;
548 michael 1127 sendto_one(source_p, ":%s %d %s z :Remote client Memory in use: %u(%llu)",
549 adx 30 me.name, RPL_STATSDEBUG, source_p->name, remote_client_count,
550     remote_client_memory_used);
551    
552     sendto_one(source_p,
553 michael 948 ":%s %d %s z :TOTAL: %llu",
554 adx 30 me.name, RPL_STATSDEBUG, source_p->name,
555 michael 948 total_memory);
556 adx 30 }
557    
558     static void
559     stats_dns_servers(struct Client *source_p)
560     {
561     report_dns_servers(source_p);
562     }
563    
564     static void
565 michael 1457 stats_connect(struct Client *source_p, int parc, char *parv[])
566 adx 30 {
567 michael 1632 report_confitem_types(source_p, CONF_SERVER);
568 adx 30 }
569    
570     /* stats_deny()
571     *
572     * input - client to report to
573     * output - none
574     * side effects - client is given dline list.
575     */
576     static void
577 michael 1457 stats_deny(struct Client *source_p, int parc, char *parv[])
578 adx 30 {
579 michael 1632 struct MaskItem *conf;
580 michael 1367 dlink_node *ptr = NULL;
581     unsigned int i = 0;
582 adx 30
583 michael 1367
584     for (i = 0; i < ATABLE_SIZE; ++i)
585 adx 30 {
586 michael 1367 DLINK_FOREACH(ptr, atable[i].head)
587 adx 30 {
588 michael 1367 struct AddressRec *arec = ptr->data;
589    
590 michael 1632 if (arec->type != CONF_DLINE)
591     continue;
592 adx 30
593 michael 1632 conf = arec->conf;
594 adx 30
595 michael 1632 /* dont report a tdline as a dline */
596 michael 1649 if (conf->until)
597 michael 1632 continue;
598 adx 30
599 michael 1834 sendto_one(source_p, form_str(RPL_STATSDLINE),
600 michael 1632 from, to, 'D', conf->host, conf->reason);
601 adx 30 }
602     }
603     }
604    
605     /* stats_tdeny()
606     *
607     * input - client to report to
608     * output - none
609     * side effects - client is given dline list.
610     */
611     static void
612 michael 1457 stats_tdeny(struct Client *source_p, int parc, char *parv[])
613 adx 30 {
614 michael 1632 struct MaskItem *conf = NULL;
615 michael 1367 dlink_node *ptr = NULL;
616     unsigned int i = 0;
617 adx 30
618 michael 1367
619     for (i = 0; i < ATABLE_SIZE; ++i)
620 adx 30 {
621 michael 1367 DLINK_FOREACH(ptr, atable[i].head)
622 adx 30 {
623 michael 1367 struct AddressRec *arec = ptr->data;
624    
625 michael 1632 if (arec->type != CONF_DLINE)
626     continue;
627 adx 30
628 michael 1632 conf = arec->conf;
629 adx 30
630 michael 1632 /* dont report a permanent dline as a tdline */
631 michael 1649 if (!conf->until)
632 michael 1632 continue;
633 adx 30
634 michael 1834 sendto_one(source_p, form_str(RPL_STATSDLINE),
635 michael 1632 from, to, 'd', conf->host, conf->reason);
636 adx 30 }
637     }
638     }
639    
640     /* stats_exempt()
641     *
642     * input - client to report to
643     * output - none
644     * side effects - client is given list of exempt blocks
645     */
646     static void
647 michael 1457 stats_exempt(struct Client *source_p, int parc, char *parv[])
648 adx 30 {
649 michael 1632 struct MaskItem *conf;
650 michael 1367 dlink_node *ptr = NULL;
651     unsigned int i = 0;
652 adx 30
653 michael 584 if (ConfigFileEntry.stats_e_disabled)
654     {
655 michael 1834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
656 michael 584 from, to);
657     return;
658     }
659    
660 michael 1834
661 michael 1367 for (i = 0; i < ATABLE_SIZE; ++i)
662 adx 30 {
663 michael 1367 DLINK_FOREACH(ptr, atable[i].head)
664 adx 30 {
665 michael 1367 struct AddressRec *arec = ptr->data;
666    
667 michael 1632 if (arec->type != CONF_EXEMPT)
668     continue;
669 adx 30
670 michael 1632 conf = arec->conf;
671 adx 30
672 michael 1842 sendto_one(source_p, form_str(RPL_STATSDLINE), from, to, 'e',
673     conf->host, "");
674 adx 30 }
675     }
676     }
677    
678     static void
679 michael 1457 stats_events(struct Client *source_p, int parc, char *parv[])
680 adx 30 {
681     show_events(source_p);
682     }
683    
684     /* stats_pending_glines()
685     *
686     * input - client pointer
687     * output - none
688     * side effects - client is shown list of pending glines
689     */
690     static void
691 michael 1457 stats_pending_glines(struct Client *source_p, int parc, char *parv[])
692 adx 30 {
693 michael 958 const dlink_node *dn_ptr = NULL;
694 michael 988 const struct gline_pending *glp_ptr = NULL;
695 michael 958 char timebuffer[MAX_DATE_STRING] = { '\0' };
696     struct tm *tmptr = NULL;
697 adx 30
698     if (!ConfigFileEntry.glines)
699     {
700     sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
701     from, to);
702     return;
703     }
704    
705 michael 958 if (dlink_list_length(&pending_glines[GLINE_PENDING_ADD_TYPE]) > 0)
706 adx 30 sendto_one(source_p, ":%s NOTICE %s :Pending G-lines",
707     from, to);
708    
709 michael 958 DLINK_FOREACH(dn_ptr, pending_glines[GLINE_PENDING_ADD_TYPE].head)
710 adx 30 {
711 michael 958 glp_ptr = dn_ptr->data;
712     tmptr = localtime(&glp_ptr->vote_1.time_request);
713 adx 30 strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
714    
715     sendto_one(source_p,
716     ":%s NOTICE %s :1) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
717 michael 958 from, to, glp_ptr->vote_1.oper_nick,
718     glp_ptr->vote_1.oper_user, glp_ptr->vote_1.oper_host,
719     glp_ptr->vote_1.oper_server, timebuffer,
720     glp_ptr->user, glp_ptr->host, glp_ptr->vote_1.reason);
721 adx 30
722 michael 988 if (glp_ptr->vote_2.oper_nick[0] != '\0')
723 adx 30 {
724 michael 958 tmptr = localtime(&glp_ptr->vote_2.time_request);
725 adx 30 strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
726     sendto_one(source_p,
727     ":%s NOTICE %s :2) %s!%s@%s on %s requested gline at %s for %s@%s [%s]",
728 michael 958 from, to, glp_ptr->vote_2.oper_nick,
729     glp_ptr->vote_2.oper_user, glp_ptr->vote_2.oper_host,
730     glp_ptr->vote_2.oper_server, timebuffer,
731     glp_ptr->user, glp_ptr->host, glp_ptr->vote_2.reason);
732 adx 30 }
733     }
734    
735     sendto_one(source_p, ":%s NOTICE %s :End of Pending G-lines",
736     from, to);
737 michael 958
738     if (dlink_list_length(&pending_glines[GLINE_PENDING_DEL_TYPE]) > 0)
739     sendto_one(source_p, ":%s NOTICE %s :Pending UNG-lines",
740     from, to);
741    
742     DLINK_FOREACH(dn_ptr, pending_glines[GLINE_PENDING_DEL_TYPE].head)
743     {
744     glp_ptr = dn_ptr->data;
745     tmptr = localtime(&glp_ptr->vote_1.time_request);
746     strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
747    
748     sendto_one(source_p,
749     ":%s NOTICE %s :1) %s!%s@%s on %s requested ungline at %s for %s@%s [%s]",
750     from, to, glp_ptr->vote_1.oper_nick,
751     glp_ptr->vote_1.oper_user, glp_ptr->vote_1.oper_host,
752     glp_ptr->vote_1.oper_server, timebuffer,
753     glp_ptr->user, glp_ptr->host, glp_ptr->vote_1.reason);
754    
755 michael 988 if (glp_ptr->vote_2.oper_nick[0] != '\0')
756 michael 958 {
757     tmptr = localtime(&glp_ptr->vote_2.time_request);
758     strftime(timebuffer, MAX_DATE_STRING, "%Y/%m/%d %H:%M:%S", tmptr);
759     sendto_one(source_p,
760     ":%s NOTICE %s :2) %s!%s@%s on %s requested ungline at %s for %s@%s [%s]",
761     from, to, glp_ptr->vote_2.oper_nick,
762     glp_ptr->vote_2.oper_user, glp_ptr->vote_2.oper_host,
763     glp_ptr->vote_2.oper_server, timebuffer,
764     glp_ptr->user, glp_ptr->host, glp_ptr->vote_2.reason);
765    
766     }
767     }
768    
769     sendto_one(source_p, ":%s NOTICE %s :End of Pending UNG-lines",
770     from, to);
771 adx 30 }
772    
773     /* stats_glines()
774     *
775     * input - client pointer
776     * output - none
777     * side effects - client is shown list of glines
778     */
779     static void
780 michael 1457 stats_glines(struct Client *source_p, int parc, char *parv[])
781 adx 30 {
782 michael 1367 dlink_node *ptr = NULL;
783     unsigned int i = 0;
784 adx 30
785     if (!ConfigFileEntry.glines)
786     {
787     sendto_one(source_p, ":%s NOTICE %s :This server does not support G-Lines",
788     from, to);
789     return;
790     }
791    
792 michael 1367 for (i = 0; i < ATABLE_SIZE; ++i)
793 adx 30 {
794 michael 1367 DLINK_FOREACH(ptr, atable[i].head)
795 adx 30 {
796 michael 1376 const struct AddressRec *arec = ptr->data;
797 michael 1367
798 adx 30 if (arec->type == CONF_GLINE)
799     {
800 michael 1632 const struct MaskItem *conf = arec->conf;
801 adx 30
802 michael 1834 sendto_one(source_p, form_str(RPL_STATSKLINE),
803 michael 1921 from, to, 'G',
804 michael 1632 conf->host ? conf->host : "*",
805     conf->user ? conf->user : "*",
806 michael 1794 conf->reason ? conf->reason : CONF_NOREASON);
807 adx 30 }
808     }
809     }
810     }
811    
812     static void
813 michael 1457 stats_hubleaf(struct Client *source_p, int parc, char *parv[])
814 adx 30 {
815 michael 2118 const dlink_node *ptr = NULL, *dptr = NULL;
816    
817     DLINK_FOREACH(ptr, server_items.head)
818     {
819     const struct MaskItem *conf = ptr->data;
820    
821     DLINK_FOREACH(dptr, conf->hub_list.head)
822     sendto_one(source_p, form_str(RPL_STATSHLINE), me.name,
823     source_p->name, 'H', dptr->data, conf->name, 0, "*");
824     }
825    
826     DLINK_FOREACH(ptr, server_items.head)
827     {
828     const struct MaskItem *conf = ptr->data;
829    
830     DLINK_FOREACH(dptr, conf->leaf_list.head)
831     sendto_one(source_p, form_str(RPL_STATSLLINE), me.name,
832     source_p->name, 'L', dptr->data, conf->name, 0, "*");
833     }
834 adx 30 }
835    
836 michael 1372 /*
837     * show_iline_prefix()
838     *
839     * inputs - pointer to struct Client requesting output
840 michael 1632 * - pointer to struct MaskItem
841 michael 1372 * - name to which iline prefix will be prefixed to
842     * output - pointer to static string with prefixes listed in ascii form
843     * side effects - NONE
844     */
845     static const char *
846 michael 1632 show_iline_prefix(const struct Client *sptr, const struct MaskItem *conf)
847 michael 1372 {
848 michael 1715 static char prefix_of_host[USERLEN + 15];
849 michael 1372 char *prefix_ptr = prefix_of_host;
850    
851 michael 1715 if (IsConfWebIRC(conf))
852     *prefix_ptr++ = '<';
853 michael 1632 if (IsNoTilde(conf))
854 michael 1372 *prefix_ptr++ = '-';
855 michael 1632 if (IsLimitIp(conf))
856 michael 1372 *prefix_ptr++ = '!';
857 michael 1632 if (IsNeedIdentd(conf))
858 michael 1372 *prefix_ptr++ = '+';
859 michael 1632 if (!IsNeedPassword(conf))
860 michael 1372 *prefix_ptr++ = '&';
861 michael 1632 if (IsConfExemptResv(conf))
862 michael 1372 *prefix_ptr++ = '$';
863 michael 1632 if (IsNoMatchIp(conf))
864 michael 1372 *prefix_ptr++ = '%';
865 michael 1632 if (IsConfDoSpoofIp(conf))
866 michael 1372 *prefix_ptr++ = '=';
867 michael 1632 if (MyOper(sptr) && IsConfExemptKline(conf))
868 michael 1372 *prefix_ptr++ = '^';
869 michael 1632 if (MyOper(sptr) && IsConfExemptGline(conf))
870 michael 1372 *prefix_ptr++ = '_';
871 michael 1632 if (MyOper(sptr) && IsConfExemptLimits(conf))
872 michael 1372 *prefix_ptr++ = '>';
873 michael 1632 if (IsConfCanFlood(conf))
874 michael 1372 *prefix_ptr++ = '|';
875    
876 michael 1632 strlcpy(prefix_ptr, conf->user, USERLEN+1);
877 michael 1372
878     return prefix_of_host;
879     }
880    
881 adx 30 static void
882 michael 1457 report_auth(struct Client *client_p, int parc, char *parv[])
883 michael 1372 {
884 michael 1632 struct MaskItem *conf = NULL;
885 michael 1372 dlink_node *ptr = NULL;
886     unsigned int i;
887    
888    
889     for (i = 0; i < ATABLE_SIZE; ++i)
890     {
891     DLINK_FOREACH(ptr, atable[i].head)
892     {
893     struct AddressRec *arec = ptr->data;
894    
895 michael 1632 if (arec->type != CONF_CLIENT)
896     continue;
897 michael 1372
898 michael 1632 conf = arec->conf;
899 michael 1372
900 michael 1632 if (!MyOper(client_p) && IsConfDoSpoofIp(conf))
901     continue;
902 michael 1372
903 michael 1632 /* We are doing a partial list, based on what matches the u@h of the
904     * sender, so prepare the strings for comparing --fl_
905     */
906     if (ConfigFileEntry.hide_spoof_ips)
907 michael 1834 sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
908 michael 1632 client_p->name, 'I',
909     conf->name == NULL ? "*" : conf->name,
910     show_iline_prefix(client_p, conf),
911     IsConfDoSpoofIp(conf) ? "255.255.255.255" :
912     conf->host, conf->port,
913     conf->class ? conf->class->name : "<default>");
914 michael 1372
915 michael 1632 else
916 michael 1834 sendto_one(client_p, form_str(RPL_STATSILINE), me.name,
917 michael 1632 client_p->name, 'I',
918     conf->name == NULL ? "*" : conf->name,
919     show_iline_prefix(client_p, conf),
920     conf->host, conf->port,
921     conf->class ? conf->class->name : "<default>");
922 michael 1372 }
923     }
924     }
925    
926     static void
927 michael 1457 stats_auth(struct Client *source_p, int parc, char *parv[])
928 adx 30 {
929     /* Oper only, if unopered, return ERR_NOPRIVILEGES */
930 michael 1219 if ((ConfigFileEntry.stats_i_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
931 michael 1834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
932 adx 30 from, to);
933    
934     /* If unopered, Only return matching auth blocks */
935 michael 1219 else if ((ConfigFileEntry.stats_i_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
936 adx 30 {
937 michael 1632 struct MaskItem *conf;
938 adx 30
939     if (MyConnect(source_p))
940 michael 1632 conf = find_conf_by_address(source_p->host,
941 adx 30 &source_p->localClient->ip,
942     CONF_CLIENT,
943     source_p->localClient->aftype,
944     source_p->username,
945 michael 1371 source_p->localClient->passwd, 1);
946 adx 30 else
947 michael 1632 conf = find_conf_by_address(source_p->host, NULL, CONF_CLIENT,
948 michael 1371 0, source_p->username, NULL, 1);
949 adx 30
950 michael 1632 if (conf == NULL)
951 adx 30 return;
952    
953 michael 1834 sendto_one(source_p, form_str(RPL_STATSILINE), from,
954 adx 30 to, 'I',
955 michael 1632 "*", show_iline_prefix(source_p, conf),
956     conf->host, conf->port,
957     conf->class ? conf->class->name : "<default>");
958 adx 30 }
959     /* They are opered, or allowed to see all auth blocks */
960     else
961 michael 1457 report_auth(source_p, 0, NULL);
962 adx 30 }
963    
964 michael 1372 /* report_Klines()
965     * Inputs: Client to report to,
966     * type(==0 for perm, !=0 for temporary)
967     * mask
968     * Output: None
969     * Side effects: Reports configured K(or k)-lines to client_p.
970     */
971 adx 30 static void
972 michael 1372 report_Klines(struct Client *client_p, int tkline)
973     {
974 michael 1632 struct MaskItem *conf = NULL;
975 michael 1372 unsigned int i = 0;
976 michael 1921 char c = '\0';
977 michael 1372 dlink_node *ptr = NULL;
978    
979     if (tkline)
980 michael 1921 c = 'k';
981 michael 1372 else
982 michael 1921 c = 'K';
983 michael 1372
984     for (i = 0; i < ATABLE_SIZE; ++i)
985     {
986     DLINK_FOREACH(ptr, atable[i].head)
987     {
988     struct AddressRec *arec = ptr->data;
989    
990 michael 1632 if (arec->type != CONF_KLINE)
991     continue;
992 michael 1628
993 michael 1632 conf = arec->conf;
994 michael 1372
995 michael 1650 if ((!tkline && conf->until) ||
996     (tkline && !conf->until))
997 michael 1632 continue;
998    
999     if (HasUMode(client_p, UMODE_OPER))
1000 michael 1834 sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
1001 michael 1921 client_p->name, c, conf->host, conf->user,
1002 michael 1632 conf->reason);
1003     else
1004 michael 1834 sendto_one(client_p, form_str(RPL_STATSKLINE), me.name,
1005 michael 1921 client_p->name, c, conf->host, conf->user,
1006 michael 1632 conf->reason);
1007 michael 1372 }
1008     }
1009     }
1010    
1011     static void
1012 michael 1457 stats_tklines(struct Client *source_p, int parc, char *parv[])
1013 adx 30 {
1014     /* Oper only, if unopered, return ERR_NOPRIVILEGES */
1015 michael 1219 if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
1016 michael 1834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1017 adx 30 from, to);
1018    
1019     /* If unopered, Only return matching klines */
1020 michael 1219 else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
1021 adx 30 {
1022 michael 1632 struct MaskItem *conf = NULL;
1023 adx 30
1024     if (MyConnect(source_p))
1025 michael 1632 conf = find_conf_by_address(source_p->host,
1026     &source_p->localClient->ip,
1027 michael 1369 CONF_KLINE,
1028 adx 30 source_p->localClient->aftype,
1029 michael 1371 source_p->username, NULL, 1);
1030 adx 30 else
1031 michael 1632 conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
1032 michael 1371 0, source_p->username, NULL, 1);
1033 adx 30
1034 michael 1632 if (!conf)
1035 adx 30 return;
1036    
1037     /* dont report a permanent kline as a tkline */
1038 michael 1649 if (!conf->until)
1039 adx 30 return;
1040    
1041 michael 1834 sendto_one(source_p, form_str(RPL_STATSKLINE), from,
1042 michael 1921 to, 'k', conf->host, conf->user, conf->reason);
1043 adx 30 }
1044     /* Theyre opered, or allowed to see all klines */
1045     else {
1046     report_Klines(source_p, 1);
1047     }
1048     }
1049    
1050     static void
1051 michael 1457 stats_klines(struct Client *source_p, int parc, char *parv[])
1052 adx 30 {
1053     /* Oper only, if unopered, return ERR_NOPRIVILEGES */
1054 michael 1219 if ((ConfigFileEntry.stats_k_oper_only == 2) && !HasUMode(source_p, UMODE_OPER))
1055 michael 1834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1056 adx 30 from, to);
1057    
1058     /* If unopered, Only return matching klines */
1059 michael 1219 else if ((ConfigFileEntry.stats_k_oper_only == 1) && !HasUMode(source_p, UMODE_OPER))
1060 adx 30 {
1061 michael 1632 struct MaskItem *conf = NULL;
1062 adx 30
1063     /* search for a kline */
1064 michael 560 if (MyConnect(source_p))
1065 michael 1632 conf = find_conf_by_address(source_p->host,
1066 adx 30 &source_p->localClient->ip,
1067 michael 1369 CONF_KLINE,
1068 adx 30 source_p->localClient->aftype,
1069 michael 1371 source_p->username, NULL, 0);
1070 adx 30 else
1071 michael 1632 conf = find_conf_by_address(source_p->host, NULL, CONF_KLINE,
1072 michael 1371 0, source_p->username, NULL, 0);
1073 adx 30
1074 michael 1632 if (!conf)
1075 adx 30 return;
1076    
1077     /* dont report a tkline as a kline */
1078 michael 1649 if (conf->until)
1079 adx 30 return;
1080    
1081 michael 1834 sendto_one(source_p, form_str(RPL_STATSKLINE), from,
1082 michael 1921 to, 'K', conf->host, conf->user, conf->reason);
1083 adx 30 }
1084     /* Theyre opered, or allowed to see all klines */
1085 michael 1921 else
1086 adx 30 report_Klines(source_p, 0);
1087     }
1088    
1089     static void
1090 michael 1457 stats_messages(struct Client *source_p, int parc, char *parv[])
1091 adx 30 {
1092     report_messages(source_p);
1093     }
1094    
1095     static void
1096 michael 1457 stats_oper(struct Client *source_p, int parc, char *parv[])
1097 adx 30 {
1098 michael 1219 if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_o_oper_only)
1099 michael 1834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1100 adx 30 from, to);
1101     else
1102 michael 1632 report_confitem_types(source_p, CONF_OPER);
1103 adx 30 }
1104    
1105     /* stats_operedup()
1106     *
1107     * input - client pointer
1108     * output - none
1109     * side effects - client is shown a list of active opers
1110     */
1111     static void
1112 michael 1457 stats_operedup(struct Client *source_p, int parc, char *parv[])
1113 adx 30 {
1114     dlink_node *ptr;
1115    
1116     DLINK_FOREACH(ptr, oper_list.head)
1117     {
1118     const struct Client *target_p = ptr->data;
1119    
1120 michael 1294 if (HasUMode(target_p, UMODE_HIDDEN) && !HasUMode(source_p, UMODE_OPER))
1121 adx 30 continue;
1122    
1123 michael 1219 if (MyClient(source_p) && HasUMode(source_p, UMODE_OPER))
1124 michael 1783 sendto_one(source_p, ":%s %d %s p :[%c][%s] %s (%s@%s) Idle: %u",
1125 adx 30 from, RPL_STATSDEBUG, to,
1126 michael 1294 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
1127 adx 30 oper_privs_as_string(target_p->localClient->operflags),
1128     target_p->name, target_p->username, target_p->host,
1129 michael 1783 idle_time_get(source_p, target_p));
1130 adx 30 else
1131 michael 1783 sendto_one(source_p, ":%s %d %s p :[%c] %s (%s@%s) Idle: %u",
1132 adx 30 from, RPL_STATSDEBUG, to,
1133 michael 1294 HasUMode(target_p, UMODE_ADMIN) ? 'A' : 'O',
1134 adx 30 target_p->name, target_p->username, target_p->host,
1135 michael 1783 idle_time_get(source_p, target_p));
1136 adx 30 }
1137    
1138 michael 1759 sendto_one(source_p, ":%s %d %s p :%u OPER(s)",
1139 adx 30 from, RPL_STATSDEBUG, to, dlink_list_length(&oper_list));
1140     }
1141    
1142     static void
1143 michael 1457 stats_ports(struct Client *source_p, int parc, char *parv[])
1144 adx 30 {
1145 michael 1219 if (!HasUMode(source_p, UMODE_OPER) && ConfigFileEntry.stats_P_oper_only)
1146 michael 1834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1147 adx 30 from, to);
1148     else
1149     show_ports(source_p);
1150     }
1151    
1152     static void
1153 michael 1457 stats_resv(struct Client *source_p, int parc, char *parv[])
1154 adx 30 {
1155     report_resv(source_p);
1156     }
1157    
1158     static void
1159 michael 1457 stats_service(struct Client *source_p, int parc, char *parv[])
1160 adx 30 {
1161 michael 1632 report_confitem_types(source_p, CONF_SERVICE);
1162 michael 1175 }
1163    
1164     static void
1165 michael 1457 stats_tstats(struct Client *source_p, int parc, char *parv[])
1166 adx 30 {
1167 michael 896 const struct Client *target_p = NULL;
1168     const dlink_node *ptr = NULL;
1169     struct ServerStatistics tmp;
1170 michael 1842 struct ServerStatistics *sp = &tmp;
1171 michael 896
1172     memcpy(sp, &ServerStats, sizeof(struct ServerStatistics));
1173    
1174     /*
1175     * must use the += operator. is_sv is not the number of currently
1176     * active server connections. Note the incrementation in
1177     * s_bsd.c:close_connection.
1178     */
1179     sp->is_sv += dlink_list_length(&serv_list);
1180    
1181     DLINK_FOREACH(ptr, serv_list.head)
1182     {
1183     target_p = ptr->data;
1184    
1185     sp->is_sbs += target_p->localClient->send.bytes;
1186     sp->is_sbr += target_p->localClient->recv.bytes;
1187 michael 1241 sp->is_sti += CurrentTime - target_p->localClient->firsttime;
1188 michael 896 }
1189    
1190     sp->is_cl += dlink_list_length(&local_client_list);
1191    
1192     DLINK_FOREACH(ptr, local_client_list.head)
1193     {
1194     target_p = ptr->data;
1195    
1196     sp->is_cbs += target_p->localClient->send.bytes;
1197     sp->is_cbr += target_p->localClient->recv.bytes;
1198 michael 1241 sp->is_cti += CurrentTime - target_p->localClient->firsttime;
1199 michael 896 }
1200    
1201     sp->is_ni += dlink_list_length(&unknown_list);
1202    
1203     sendto_one(source_p, ":%s %d %s T :accepts %u refused %u",
1204     me.name, RPL_STATSDEBUG, source_p->name, sp->is_ac, sp->is_ref);
1205     sendto_one(source_p, ":%s %d %s T :unknown commands %u prefixes %u",
1206     me.name, RPL_STATSDEBUG, source_p->name, sp->is_unco, sp->is_unpf);
1207     sendto_one(source_p, ":%s %d %s T :nick collisions %u unknown closes %u",
1208     me.name, RPL_STATSDEBUG, source_p->name, sp->is_kill, sp->is_ni);
1209     sendto_one(source_p, ":%s %d %s T :wrong direction %u empty %u",
1210     me.name, RPL_STATSDEBUG, source_p->name, sp->is_wrdi, sp->is_empt);
1211     sendto_one(source_p, ":%s %d %s T :numerics seen %u",
1212     me.name, RPL_STATSDEBUG, source_p->name, sp->is_num);
1213     sendto_one(source_p, ":%s %d %s T :auth successes %u fails %u",
1214     me.name, RPL_STATSDEBUG, source_p->name, sp->is_asuc, sp->is_abad);
1215     sendto_one(source_p, ":%s %d %s T :Client Server",
1216     me.name, RPL_STATSDEBUG, source_p->name);
1217    
1218     sendto_one(source_p, ":%s %d %s T :connected %u %u",
1219     me.name, RPL_STATSDEBUG, source_p->name,
1220     (unsigned int)sp->is_cl,
1221     (unsigned int)sp->is_sv);
1222     sendto_one(source_p, ":%s %d %s T :bytes sent %llu %llu",
1223     me.name, RPL_STATSDEBUG, source_p->name,
1224     sp->is_cbs, sp->is_sbs);
1225     sendto_one(source_p, ":%s %d %s T :bytes recv %llu %llu",
1226     me.name, RPL_STATSDEBUG, source_p->name,
1227     sp->is_cbr, sp->is_sbr);
1228     sendto_one(source_p, ":%s %d %s T :time connected %u %u",
1229     me.name, RPL_STATSDEBUG, source_p->name,
1230     (unsigned int)sp->is_cti,
1231     (unsigned int)sp->is_sti);
1232 adx 30 }
1233    
1234     static void
1235 michael 1457 stats_uptime(struct Client *source_p, int parc, char *parv[])
1236 adx 30 {
1237 michael 1241 time_t now = CurrentTime - me.localClient->since;
1238 michael 1148
1239 michael 1834 sendto_one(source_p, form_str(RPL_STATSUPTIME), from, to,
1240 michael 1148 now / 86400, (now / 3600) % 24, (now / 60) % 60, now % 60);
1241    
1242 michael 1219 if (!ConfigFileEntry.disable_remote || HasUMode(source_p, UMODE_OPER))
1243 michael 1834 sendto_one(source_p, form_str(RPL_STATSCONN), from, to,
1244 michael 1148 Count.max_loc_con, Count.max_loc_cli, Count.totalrestartcount);
1245 adx 30 }
1246    
1247     static void
1248 michael 1457 stats_shared(struct Client *source_p, int parc, char *parv[])
1249 adx 30 {
1250 michael 1632 report_confitem_types(source_p, CONF_ULINE);
1251 adx 30 }
1252    
1253     /* stats_servers()
1254     *
1255     * input - client pointer
1256     * output - none
1257     * side effects - client is shown lists of who connected servers
1258     */
1259     static void
1260 michael 1457 stats_servers(struct Client *source_p, int parc, char *parv[])
1261 adx 30 {
1262 michael 1127 dlink_node *ptr = NULL;
1263 adx 30
1264     DLINK_FOREACH(ptr, serv_list.head)
1265     {
1266 michael 1127 const struct Client *target_p = ptr->data;
1267 adx 30
1268     sendto_one(source_p, ":%s %d %s v :%s (%s!%s@%s) Idle: %d",
1269 michael 1127 from, RPL_STATSDEBUG, to, target_p->name,
1270     (target_p->serv->by[0] ? target_p->serv->by : "Remote."),
1271 michael 1241 "*", "*", (int)(CurrentTime - target_p->localClient->lasttime));
1272 adx 30 }
1273    
1274 michael 1127 sendto_one(source_p, ":%s %d %s v :%u Server(s)",
1275     from, RPL_STATSDEBUG, to, dlink_list_length(&serv_list));
1276 adx 30 }
1277    
1278     static void
1279 michael 1457 stats_gecos(struct Client *source_p, int parc, char *parv[])
1280 adx 30 {
1281 michael 1632 report_confitem_types(source_p, CONF_XLINE);
1282 adx 30 }
1283    
1284     static void
1285 michael 1457 stats_class(struct Client *source_p, int parc, char *parv[])
1286 adx 30 {
1287 michael 2116 const dlink_node *ptr = NULL;
1288    
1289     DLINK_FOREACH(ptr, class_get_list()->head)
1290     {
1291     const struct ClassItem *class = ptr->data;
1292    
1293     sendto_one(source_p, form_str(RPL_STATSYLINE),
1294     me.name, source_p->name, 'Y',
1295     class->name, class->ping_freq,
1296     class->con_freq,
1297     class->max_total, class->max_sendq,
1298     class->max_recvq,
1299     class->ref_count,
1300     class->number_per_cidr, class->cidr_bitlen_ipv4,
1301     class->number_per_cidr, class->cidr_bitlen_ipv6,
1302     class->active ? "active" : "disabled");
1303     }
1304 adx 30 }
1305    
1306     static void
1307 michael 1457 stats_servlinks(struct Client *source_p, int parc, char *parv[])
1308 adx 30 {
1309     uint64_t sendB = 0, recvB = 0;
1310     time_t uptime = 0;
1311 michael 560 dlink_node *ptr = NULL;
1312 adx 30
1313 michael 1219 if (ConfigServerHide.flatten_links && !HasUMode(source_p, UMODE_OPER))
1314 adx 30 {
1315 michael 1834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1316 adx 30 from, to);
1317     return;
1318     }
1319    
1320     DLINK_FOREACH(ptr, serv_list.head)
1321     {
1322 michael 560 struct Client *target_p = ptr->data;
1323 adx 30
1324 michael 1851 if (HasFlag(target_p, FLAGS_SERVICE) && ConfigServerHide.hide_services)
1325     if (!HasUMode(source_p, UMODE_OPER))
1326     continue;
1327    
1328 adx 30 sendB += target_p->localClient->send.bytes;
1329     recvB += target_p->localClient->recv.bytes;
1330    
1331     /* ":%s 211 %s %s %u %u %llu %u %llu :%u %u %s" */
1332 michael 1834 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1333 adx 30 from, to,
1334 michael 1219 get_client_name(target_p, HasUMode(source_p, UMODE_ADMIN) ? SHOW_IP : MASK_IP),
1335 adx 30 dbuf_length(&target_p->localClient->buf_sendq),
1336     target_p->localClient->send.messages,
1337     target_p->localClient->send.bytes >> 10,
1338     target_p->localClient->recv.messages,
1339     target_p->localClient->recv.bytes >> 10,
1340 michael 1241 (unsigned)(CurrentTime - target_p->localClient->firsttime),
1341     (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since): 0,
1342 michael 1219 HasUMode(source_p, UMODE_OPER) ? show_capabilities(target_p) : "TS");
1343 adx 30 }
1344    
1345     sendB >>= 10;
1346     recvB >>= 10;
1347    
1348     sendto_one(source_p, ":%s %d %s ? :%u total server(s)",
1349 michael 560 from, RPL_STATSDEBUG, to, dlink_list_length(&serv_list));
1350 adx 30 sendto_one(source_p, ":%s %d %s ? :Sent total : %7.2f %s",
1351     from, RPL_STATSDEBUG, to,
1352 michael 560 _GMKv(sendB), _GMKs(sendB));
1353 adx 30 sendto_one(source_p, ":%s %d %s ? :Recv total : %7.2f %s",
1354     from, RPL_STATSDEBUG, to,
1355 michael 560 _GMKv(recvB), _GMKs(recvB));
1356 adx 30
1357 michael 1241 uptime = (CurrentTime - me.localClient->since);
1358 adx 30
1359     sendto_one(source_p, ":%s %d %s ? :Server send: %7.2f %s (%4.1f K/s)",
1360     from, RPL_STATSDEBUG, to,
1361 michael 560 _GMKv((me.localClient->send.bytes>>10)),
1362     _GMKs((me.localClient->send.bytes>>10)),
1363     (float)((float)((me.localClient->send.bytes) >> 10) /
1364     (float)uptime));
1365 adx 30 sendto_one(source_p, ":%s %d %s ? :Server recv: %7.2f %s (%4.1f K/s)",
1366     from, RPL_STATSDEBUG, to,
1367 michael 560 _GMKv((me.localClient->recv.bytes>>10)),
1368     _GMKs((me.localClient->recv.bytes>>10)),
1369     (float)((float)((me.localClient->recv.bytes) >> 10) /
1370     (float)uptime));
1371 adx 30 }
1372    
1373 michael 1457 /* parse_stats_args()
1374     *
1375     * inputs - arg count
1376     * - args
1377     * - doall flag
1378     * - wild card or not
1379     * output - pointer to name to use
1380     * side effects -
1381     * common parse routine for m_stats args
1382     *
1383     */
1384     static char *
1385     parse_stats_args(int parc, char *parv[], int *doall, int *wilds)
1386 adx 30 {
1387 michael 1457 char *name;
1388 adx 30
1389 michael 1457 if (parc > 2)
1390 adx 30 {
1391 michael 1457 name = parv[2];
1392 adx 30
1393 michael 1457 if (!irccmp(name, from))
1394     *doall = 2;
1395 michael 1652 else if (!match(name, from))
1396 michael 1457 *doall = 1;
1397    
1398     *wilds = has_wildcards(name);
1399    
1400     return name;
1401 adx 30 }
1402    
1403 michael 1457 return NULL;
1404 adx 30 }
1405    
1406     static void
1407     stats_L_list(struct Client *source_p,char *name, int doall, int wilds,
1408     dlink_list *list,char statchar)
1409     {
1410     dlink_node *ptr;
1411     struct Client *target_p;
1412    
1413     /*
1414     * send info about connections which match, or all if the
1415     * mask matches from. Only restrictions are on those who
1416     * are invisible not being visible to 'foreigners' who use
1417     * a wild card based search to list it.
1418     */
1419     DLINK_FOREACH(ptr, list->head)
1420     {
1421     target_p = ptr->data;
1422    
1423 michael 1219 if (HasUMode(target_p, UMODE_INVISIBLE) && (doall || wilds) &&
1424 michael 1457 !(MyConnect(source_p) && HasUMode(source_p, UMODE_OPER)) &&
1425     !HasUMode(target_p, UMODE_OPER) && (target_p != source_p))
1426 adx 30 continue;
1427 michael 1652 if (!doall && wilds && match(name, target_p->name))
1428 adx 30 continue;
1429     if (!(doall || wilds) && irccmp(name, target_p->name))
1430     continue;
1431    
1432     /* This basically shows ips for our opers if its not a server/admin, or
1433     * its one of our admins. */
1434 michael 1457 if(MyClient(source_p) && HasUMode(source_p, UMODE_OPER) &&
1435 michael 1219 (HasUMode(source_p, UMODE_ADMIN) ||
1436 michael 1457 (!IsServer(target_p) && !HasUMode(target_p, UMODE_ADMIN) &&
1437 adx 30 !IsHandshake(target_p) && !IsConnecting(target_p))))
1438     {
1439 michael 1834 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1440 michael 1457 from, to,
1441 adx 30 (IsUpper(statchar)) ?
1442     get_client_name(target_p, SHOW_IP) :
1443     get_client_name(target_p, HIDE_IP),
1444     dbuf_length(&target_p->localClient->buf_sendq),
1445     target_p->localClient->send.messages,
1446     target_p->localClient->send.bytes>>10,
1447     target_p->localClient->recv.messages,
1448     target_p->localClient->recv.bytes>>10,
1449 michael 1241 (unsigned)(CurrentTime - target_p->localClient->firsttime),
1450     (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1451 adx 30 IsServer(target_p) ? show_capabilities(target_p) : "-");
1452     }
1453     else
1454     {
1455     /* If its a hidden ip, an admin, or a server, mask the real IP */
1456 michael 1219 if(IsIPSpoof(target_p) || IsServer(target_p) || HasUMode(target_p, UMODE_ADMIN)
1457 adx 30 || IsHandshake(target_p) || IsConnecting(target_p))
1458 michael 1834 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1459 adx 30 from, to,
1460 michael 1457 get_client_name(target_p, MASK_IP),
1461     dbuf_length(&target_p->localClient->buf_sendq),
1462     target_p->localClient->send.messages,
1463     target_p->localClient->send.bytes>>10,
1464     target_p->localClient->recv.messages,
1465     target_p->localClient->recv.bytes>>10,
1466     (unsigned)(CurrentTime - target_p->localClient->firsttime),
1467     (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1468     IsServer(target_p) ? show_capabilities(target_p) : "-");
1469 adx 30 else /* show the real IP */
1470 michael 1834 sendto_one(source_p, form_str(RPL_STATSLINKINFO),
1471 adx 30 from, to,
1472 michael 1457 (IsUpper(statchar)) ?
1473     get_client_name(target_p, SHOW_IP) :
1474     get_client_name(target_p, HIDE_IP),
1475     dbuf_length(&target_p->localClient->buf_sendq),
1476     target_p->localClient->send.messages,
1477     target_p->localClient->send.bytes>>10,
1478     target_p->localClient->recv.messages,
1479     target_p->localClient->recv.bytes>>10,
1480     (unsigned)(CurrentTime - target_p->localClient->firsttime),
1481     (CurrentTime > target_p->localClient->since) ? (unsigned)(CurrentTime - target_p->localClient->since):0,
1482     IsServer(target_p) ? show_capabilities(target_p) : "-");
1483 adx 30 }
1484     }
1485     }
1486    
1487 michael 1457 /*
1488     * stats_L
1489 adx 30 *
1490 michael 1457 * inputs - pointer to client to report to
1491     * - doall flag
1492     * - wild card or not
1493     * output - NONE
1494     * side effects -
1495     */
1496     static void
1497     stats_L(struct Client *source_p,char *name,int doall,
1498     int wilds,char statchar)
1499     {
1500     stats_L_list(source_p, name, doall, wilds, &unknown_list, statchar);
1501     stats_L_list(source_p, name, doall, wilds, &local_client_list, statchar);
1502     stats_L_list(source_p, name, doall, wilds, &serv_list, statchar);
1503     }
1504    
1505     static void
1506     stats_ltrace(struct Client *source_p, int parc, char *parv[])
1507     {
1508     int doall = 0;
1509     int wilds = 0;
1510     char *name = NULL;
1511     char statchar;
1512    
1513     if ((name = parse_stats_args(parc, parv, &doall, &wilds)) != NULL)
1514     {
1515     statchar = parv[1][0];
1516    
1517     stats_L(source_p, name, doall, wilds, statchar);
1518     }
1519     else
1520 michael 1834 sendto_one(source_p, form_str(ERR_NEEDMOREPARAMS),
1521 michael 1457 from, to, "STATS");
1522     }
1523    
1524     static const struct StatsStruct
1525     {
1526     const unsigned char letter;
1527     void (*handler)();
1528     const unsigned int need_oper;
1529     const unsigned int need_admin;
1530     } stats_cmd_table[] = {
1531     /* letter function need_oper need_admin */
1532     { 'a', stats_dns_servers, 1, 1 },
1533     { 'A', stats_dns_servers, 1, 1 },
1534     { 'c', stats_connect, 1, 0 },
1535     { 'C', stats_connect, 1, 0 },
1536     { 'd', stats_tdeny, 1, 0 },
1537     { 'D', stats_deny, 1, 0 },
1538     { 'e', stats_exempt, 1, 0 },
1539     { 'E', stats_events, 1, 1 },
1540     { 'f', fd_dump, 1, 1 },
1541     { 'F', fd_dump, 1, 1 },
1542     { 'g', stats_pending_glines, 1, 0 },
1543     { 'G', stats_glines, 1, 0 },
1544     { 'h', stats_hooks, 1, 1 },
1545     { 'H', stats_hubleaf, 1, 0 },
1546     { 'i', stats_auth, 0, 0 },
1547     { 'I', stats_auth, 0, 0 },
1548     { 'k', stats_tklines, 0, 0 },
1549     { 'K', stats_klines, 0, 0 },
1550     { 'l', stats_ltrace, 1, 0 },
1551     { 'L', stats_ltrace, 1, 0 },
1552     { 'm', stats_messages, 0, 0 },
1553     { 'M', stats_messages, 0, 0 },
1554     { 'o', stats_oper, 0, 0 },
1555     { 'O', stats_oper, 0, 0 },
1556     { 'p', stats_operedup, 0, 0 },
1557     { 'P', stats_ports, 0, 0 },
1558     { 'q', stats_resv, 1, 0 },
1559     { 'Q', stats_resv, 1, 0 },
1560     { 'r', stats_usage, 1, 0 },
1561     { 'R', stats_usage, 1, 0 },
1562 michael 1875 { 's', stats_service, 1, 0 },
1563 michael 1457 { 'S', stats_service, 1, 0 },
1564     { 't', stats_tstats, 1, 0 },
1565     { 'T', stats_tstats, 1, 0 },
1566     { 'u', stats_uptime, 0, 0 },
1567     { 'U', stats_shared, 1, 0 },
1568     { 'v', stats_servers, 1, 0 },
1569     { 'x', stats_gecos, 1, 0 },
1570     { 'X', stats_gecos, 1, 0 },
1571     { 'y', stats_class, 1, 0 },
1572     { 'Y', stats_class, 1, 0 },
1573     { 'z', stats_memory, 1, 0 },
1574     { '?', stats_servlinks, 0, 0 },
1575     { '\0', NULL, 0, 0 }
1576     };
1577    
1578     static void
1579     do_stats(struct Client *source_p, int parc, char *parv[])
1580     {
1581     const struct StatsStruct *tab = stats_cmd_table;
1582     const char statchar = *parv[1];
1583    
1584     if (statchar == '\0')
1585     {
1586 michael 1834 sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1587 michael 1457 from, to, '*');
1588     return;
1589     }
1590    
1591     for (; tab->handler; ++tab)
1592     {
1593     if (tab->letter == statchar)
1594     {
1595     /* The stats table says what privs are needed, so check --fl_ */
1596     if ((tab->need_admin && !HasUMode(source_p, UMODE_ADMIN)) ||
1597     (tab->need_oper && !HasUMode(source_p, UMODE_OPER)))
1598     {
1599 michael 1834 sendto_one(source_p, form_str(ERR_NOPRIVILEGES),
1600 michael 1457 from, to);
1601     break;
1602     }
1603    
1604 michael 1618 sendto_realops_flags(UMODE_SPY, L_ALL, SEND_NOTICE,
1605 michael 1532 "STATS %c requested by %s (%s@%s) [%s]",
1606 michael 1457 statchar, source_p->name, source_p->username,
1607     source_p->host, source_p->servptr->name);
1608     tab->handler(source_p, parc, parv);
1609     break;
1610     }
1611     }
1612    
1613 michael 1834 sendto_one(source_p, form_str(RPL_ENDOFSTATS),
1614 michael 1457 from, to, statchar);
1615     }
1616    
1617     /*
1618     * m_stats()
1619     * parv[0] = sender prefix
1620     * parv[1] = stat letter/command
1621     * parv[2] = (if present) server/mask in stats L
1622 adx 30 *
1623 michael 1457 * This will search the tables for the appropriate stats letter/command,
1624     * if found execute it.
1625 adx 30 */
1626 michael 1457 static void
1627     m_stats(struct Client *client_p, struct Client *source_p,
1628     int parc, char *parv[])
1629 adx 30 {
1630 michael 1457 static time_t last_used = 0;
1631 adx 30
1632 michael 1457 /* Is the stats meant for us? */
1633     if (!ConfigFileEntry.disable_remote)
1634     if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1635     parc, parv) != HUNTED_ISME)
1636     return;
1637    
1638     if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1639 adx 30 {
1640 michael 1457 from = me.id;
1641     to = source_p->id;
1642     }
1643     else
1644     {
1645     from = me.name;
1646     to = source_p->name;
1647     }
1648 adx 30
1649 michael 1457 /* Check the user is actually allowed to do /stats, and isnt flooding */
1650     if ((last_used + ConfigFileEntry.pace_wait) > CurrentTime)
1651     {
1652 michael 1834 sendto_one(source_p,form_str(RPL_LOAD2HI),
1653 michael 1457 from, to);
1654     return;
1655     }
1656 adx 30
1657 michael 1457 last_used = CurrentTime;
1658 adx 30
1659 michael 1457 do_stats(source_p, parc, parv);
1660     }
1661    
1662     /*
1663     * mo_stats()
1664     * parv[0] = sender prefix
1665     * parv[1] = stat letter/command
1666     * parv[2] = (if present) server/mask in stats L, or target
1667     *
1668     * This will search the tables for the appropriate stats letter,
1669     * if found execute it.
1670     */
1671     static void
1672     mo_stats(struct Client *client_p, struct Client *source_p,
1673     int parc, char *parv[])
1674     {
1675     if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1676     parc, parv) != HUNTED_ISME)
1677     return;
1678    
1679     if (!MyClient(source_p) && IsCapable(source_p->from, CAP_TS6) && HasID(source_p))
1680     {
1681     from = me.id;
1682     to = source_p->id;
1683 adx 30 }
1684 michael 1457 else
1685     {
1686     from = me.name;
1687     to = source_p->name;
1688     }
1689 michael 1400
1690 michael 1457 do_stats(source_p, parc, parv);
1691 adx 30 }
1692 michael 1230
1693 michael 1457 /*
1694     * ms_stats - STATS message handler
1695     * parv[0] = sender prefix
1696     * parv[1] = statistics selector (defaults to Message frequency)
1697     * parv[2] = server name (current server defaulted, if omitted)
1698     */
1699     static void
1700     ms_stats(struct Client *client_p, struct Client *source_p,
1701     int parc, char *parv[])
1702     {
1703     if (hunt_server(client_p, source_p, ":%s STATS %s :%s", 2,
1704     parc, parv) != HUNTED_ISME)
1705     return;
1706    
1707     if (IsClient(source_p))
1708     mo_stats(client_p, source_p, parc, parv);
1709     }
1710    
1711 michael 1230 static struct Message stats_msgtab = {
1712     "STATS", 0, 0, 2, MAXPARA, MFLG_SLOW, 0,
1713     { m_unregistered, m_stats, ms_stats, m_ignore, mo_stats, m_ignore }
1714     };
1715    
1716     static void
1717     module_init(void)
1718     {
1719     mod_add_cmd(&stats_msgtab);
1720     }
1721    
1722     static void
1723     module_exit(void)
1724     {
1725     mod_del_cmd(&stats_msgtab);
1726     }
1727    
1728     struct module module_entry = {
1729     .node = { NULL, NULL, NULL },
1730     .name = NULL,
1731     .version = "$Revision$",
1732     .handle = NULL,
1733     .modinit = module_init,
1734     .modexit = module_exit,
1735     .flags = 0
1736     };

Properties

Name Value
svn:eol-style native
svn:keywords Id Revision