/[cvs]/eggdrop1.8/src/chanprog.c
ViewVC logotype

Annotation of /eggdrop1.8/src/chanprog.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.2 - (hide annotations) (download) (as text)
Sun Oct 10 18:22:47 2010 UTC (9 years, 1 month ago) by pseudo
Branch: MAIN
Changes since 1.1: +30 -23 lines
File MIME type: text/x-chdr
Added the process and parent pids to .status output. Increased the precision of cpu time reporting.
Added a new Tcl command status to provide access to cpu/memory/cache information now and some more in the future.

1 simple 1.1 /*
2     * chanprog.c -- handles:
3     * rmspace()
4     * maintaining the server list
5     * revenge punishment
6     * timers, utimers
7     * telling the current programmed settings
8     * initializing a lot of stuff and loading the tcl scripts
9     *
10 pseudo 1.2 * $Id: chanprog.c,v 1.1.1.1 2010/07/26 21:11:06 simple Exp $
11 simple 1.1 */
12     /*
13     * Copyright (C) 1997 Robey Pointer
14     * Copyright (C) 1999 - 2010 Eggheads Development Team
15     *
16     * This program is free software; you can redistribute it and/or
17     * modify it under the terms of the GNU General Public License
18     * as published by the Free Software Foundation; either version 2
19     * of the License, or (at your option) any later version.
20     *
21     * This program is distributed in the hope that it will be useful,
22     * but WITHOUT ANY WARRANTY; without even the implied warranty of
23     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24     * GNU General Public License for more details.
25     *
26     * You should have received a copy of the GNU General Public License
27     * along with this program; if not, write to the Free Software
28     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
29     */
30    
31     #include "main.h"
32    
33     #ifdef HAVE_GETRUSAGE
34     # include <sys/resource.h>
35     # ifdef HAVE_SYS_RUSAGE_H
36     # include <sys/rusage.h>
37     # endif
38     #endif
39    
40     #ifdef HAVE_UNAME
41     # include <sys/utsname.h>
42     #endif
43    
44     #include "modules.h"
45    
46     extern struct userrec *userlist;
47     extern log_t *logs;
48     extern Tcl_Interp *interp;
49     extern char ver[], botnetnick[], firewall[], motdfile[], userfile[], helpdir[],
50     tempdir[], moddir[], notify_new[], owner[], configfile[];
51     extern time_t now, online_since;
52     extern int backgrd, term_z, con_chan, cache_hit, cache_miss, firewallport,
53     default_flags, max_logs, conmask, protect_readonly, make_userfile,
54     noshare, ignore_time, max_socks;
55    
56     tcl_timer_t *timer = NULL; /* Minutely timer */
57     tcl_timer_t *utimer = NULL; /* Secondly timer */
58     unsigned long timer_id = 1; /* Next timer of any sort will
59     * have this number */
60     struct chanset_t *chanset = NULL; /* Channel list */
61     char admin[121] = ""; /* Admin info */
62     char origbotname[NICKLEN + 1];
63     char botname[NICKLEN + 1]; /* Primary botname */
64    
65    
66     /* Remove leading and trailing whitespaces.
67     */
68     void rmspace(char *s)
69     {
70     register char *p = NULL, *q = NULL;
71    
72     if (!s || !*s)
73     return;
74    
75     /* Remove trailing whitespaces. */
76     for (q = s + strlen(s) - 1; q >= s && egg_isspace(*q); q--);
77     *(q + 1) = 0;
78    
79     /* Remove leading whitespaces. */
80     for (p = s; egg_isspace(*p); p++);
81    
82     if (p != s)
83     memmove(s, p, q - p + 2);
84     }
85    
86    
87     /* Returns memberfields if the nick is in the member list.
88     */
89     memberlist *ismember(struct chanset_t *chan, char *nick)
90     {
91     register memberlist *x;
92    
93     for (x = chan->channel.member; x && x->nick[0]; x = x->next)
94     if (!rfc_casecmp(x->nick, nick))
95     return x;
96     return NULL;
97     }
98    
99     /* Find a chanset by channel name as the server knows it (ie !ABCDEchannel)
100     */
101     struct chanset_t *findchan(const char *name)
102     {
103     register struct chanset_t *chan;
104    
105     for (chan = chanset; chan; chan = chan->next)
106     if (!rfc_casecmp(chan->name, name))
107     return chan;
108     return NULL;
109     }
110    
111     /* Find a chanset by display name (ie !channel)
112     */
113     struct chanset_t *findchan_by_dname(const char *name)
114     {
115     register struct chanset_t *chan;
116    
117     for (chan = chanset; chan; chan = chan->next)
118     if (!rfc_casecmp(chan->dname, name))
119     return chan;
120     return NULL;
121     }
122    
123    
124     /*
125     * "caching" functions
126     */
127    
128     /* Shortcut for get_user_by_host -- might have user record in one
129     * of the channel caches.
130     */
131     struct userrec *check_chanlist(const char *host)
132     {
133     char *nick, *uhost, buf[UHOSTLEN];
134     register memberlist *m;
135     register struct chanset_t *chan;
136    
137     strncpyz(buf, host, sizeof buf);
138     uhost = buf;
139     nick = splitnick(&uhost);
140     for (chan = chanset; chan; chan = chan->next)
141     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
142     if (!rfc_casecmp(nick, m->nick) && !egg_strcasecmp(uhost, m->userhost))
143     return m->user;
144     return NULL;
145     }
146    
147     /* Shortcut for get_user_by_handle -- might have user record in channels
148     */
149     struct userrec *check_chanlist_hand(const char *hand)
150     {
151     register struct chanset_t *chan;
152     register memberlist *m;
153    
154     for (chan = chanset; chan; chan = chan->next)
155     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
156     if (m->user && !egg_strcasecmp(m->user->handle, hand))
157     return m->user;
158     return NULL;
159     }
160    
161     /* Clear the user pointers in the chanlists.
162     *
163     * Necessary when a hostmask is added/removed, a user is added or a new
164     * userfile is loaded.
165     */
166     void clear_chanlist(void)
167     {
168     register memberlist *m;
169     register struct chanset_t *chan;
170    
171     for (chan = chanset; chan; chan = chan->next)
172     for (m = chan->channel.member; m && m->nick[0]; m = m->next) {
173     m->user = NULL;
174     m->tried_getuser = 0;
175     }
176     }
177    
178     /* Clear the user pointer of a specific nick in the chanlists.
179     *
180     * Necessary when a hostmask is added/removed, a nick changes, etc.
181     * Does not completely invalidate the channel cache like clear_chanlist().
182     */
183     void clear_chanlist_member(const char *nick)
184     {
185     register memberlist *m;
186     register struct chanset_t *chan;
187    
188     for (chan = chanset; chan; chan = chan->next)
189     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
190     if (!rfc_casecmp(m->nick, nick)) {
191     m->user = NULL;
192     m->tried_getuser = 0;
193     break;
194     }
195     }
196    
197     /* If this user@host is in a channel, set it (it was null)
198     */
199     void set_chanlist(const char *host, struct userrec *rec)
200     {
201     char *nick, *uhost, buf[UHOSTLEN];
202     register memberlist *m;
203     register struct chanset_t *chan;
204    
205     strncpyz(buf, host, sizeof buf);
206     uhost = buf;
207     nick = splitnick(&uhost);
208     for (chan = chanset; chan; chan = chan->next)
209     for (m = chan->channel.member; m && m->nick[0]; m = m->next)
210     if (!rfc_casecmp(nick, m->nick) && !egg_strcasecmp(uhost, m->userhost))
211     m->user = rec;
212     }
213    
214     /* Calculate the memory we should be using
215     */
216     int expmem_chanprog()
217     {
218     register int tot = 0;
219     register tcl_timer_t *t;
220    
221     for (t = timer; t; t = t->next)
222     tot += sizeof(tcl_timer_t) + strlen(t->cmd) + 1;
223     for (t = utimer; t; t = t->next)
224     tot += sizeof(tcl_timer_t) + strlen(t->cmd) + 1;
225     return tot;
226     }
227    
228 pseudo 1.2 float getcputime()
229     {
230     #ifdef HAVE_GETRUSAGE
231     float stime, utime;
232     struct rusage ru;
233    
234     getrusage(RUSAGE_SELF, &ru);
235     utime = ru.ru_utime.tv_sec + (ru.ru_utime.tv_usec / 1000000.00);
236     stime = ru.ru_stime.tv_sec + (ru.ru_stime.tv_usec / 1000000.00);
237     return (utime + stime);
238     #else
239     # ifdef HAVE_CLOCK
240     return (clock() / (CLOCKS_PER_SEC * 1.00));
241     # else
242     return -1.00;
243     # endif
244     #endif
245     }
246    
247 simple 1.1 /* Dump uptime info out to dcc (guppy 9Jan99)
248     */
249     void tell_verbose_uptime(int idx)
250     {
251     char s[256], s1[121];
252     time_t now2, hr, min;
253    
254     now2 = now - online_since;
255     s[0] = 0;
256     if (now2 > 86400) {
257     /* days */
258     sprintf(s, "%d day", (int) (now2 / 86400));
259     if ((int) (now2 / 86400) >= 2)
260     strcat(s, "s");
261     strcat(s, ", ");
262     now2 -= (((int) (now2 / 86400)) * 86400);
263     }
264     hr = (time_t) ((int) now2 / 3600);
265     now2 -= (hr * 3600);
266     min = (time_t) ((int) now2 / 60);
267     sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
268     s1[0] = 0;
269     if (backgrd)
270     strcpy(s1, MISC_BACKGROUND);
271     else {
272     if (term_z)
273     strcpy(s1, MISC_TERMMODE);
274     else if (con_chan)
275     strcpy(s1, MISC_STATMODE);
276     else
277     strcpy(s1, MISC_LOGMODE);
278     }
279     dprintf(idx, "%s %s (%s)\n", MISC_ONLINEFOR, s, s1);
280     }
281    
282     /* Dump status info out to dcc
283     */
284     void tell_verbose_status(int idx)
285     {
286     char s[256], s1[121], s2[81];
287     char *vers_t, *uni_t;
288     int i;
289     time_t now2 = now - online_since, hr, min;
290 pseudo 1.2 float cputime;
291 simple 1.1 #ifdef HAVE_UNAME
292     struct utsname un;
293    
294     if (!uname(&un) < 0) {
295     #endif
296     vers_t = " ";
297     uni_t = "*unknown*";
298     #ifdef HAVE_UNAME
299     } else {
300     vers_t = un.release;
301     uni_t = un.sysname;
302     }
303     #endif
304    
305     i = count_users(userlist);
306     dprintf(idx, "I am %s, running %s: %d user%s (mem: %uk).\n",
307     botnetnick, ver, i, i == 1 ? "" : "s",
308     (int) (expected_memory() / 1024));
309    
310     s[0] = 0;
311     if (now2 > 86400) {
312     /* days */
313     sprintf(s, "%d day", (int) (now2 / 86400));
314     if ((int) (now2 / 86400) >= 2)
315     strcat(s, "s");
316     strcat(s, ", ");
317     now2 -= (((int) (now2 / 86400)) * 86400);
318     }
319     hr = (time_t) ((int) now2 / 3600);
320     now2 -= (hr * 3600);
321     min = (time_t) ((int) now2 / 60);
322     sprintf(&s[strlen(s)], "%02d:%02d", (int) hr, (int) min);
323     s1[0] = 0;
324     if (backgrd)
325     strcpy(s1, MISC_BACKGROUND);
326     else {
327     if (term_z)
328     strcpy(s1, MISC_TERMMODE);
329     else if (con_chan)
330     strcpy(s1, MISC_STATMODE);
331     else
332     strcpy(s1, MISC_LOGMODE);
333     }
334 pseudo 1.2 cputime = getcputime();
335     if (cputime < 0)
336     sprintf(s2, "CPU: unknown");
337     else {
338     hr = cputime / 60;
339     cputime -= hr * 60;
340     sprintf(s2, "CPU: %02d:%05.2f", (int) hr, cputime); /* Actally min/sec */
341     }
342 simple 1.1 dprintf(idx, "%s %s (%s) - %s - %s: %4.1f%%\n", MISC_ONLINEFOR,
343     s, s1, s2, MISC_CACHEHIT,
344     100.0 * ((float) cache_hit) / ((float) (cache_hit + cache_miss)));
345    
346     if (admin[0])
347     dprintf(idx, "Admin: %s\n", admin);
348    
349     dprintf(idx, "Config file: %s\n", configfile);
350     dprintf(idx, "OS: %s %s\n", uni_t, vers_t);
351 pseudo 1.2 dprintf(idx, "Process ID: %d (parent %d)\n", getpid(), getppid());
352 simple 1.1
353     /* info library */
354     dprintf(idx, "%s %s\n", MISC_TCLLIBRARY,
355     ((interp) && (Tcl_Eval(interp, "info library") == TCL_OK)) ?
356     tcl_resultstring() : "*unknown*");
357    
358     /* info tclversion/patchlevel */
359     dprintf(idx, "%s %s (%s %s)\n", MISC_TCLVERSION,
360     ((interp) && (Tcl_Eval(interp, "info patchlevel") == TCL_OK)) ?
361     tcl_resultstring() : (Tcl_Eval(interp, "info tclversion") == TCL_OK) ?
362     tcl_resultstring() : "*unknown*", MISC_TCLHVERSION,
363     TCL_PATCH_LEVEL ? TCL_PATCH_LEVEL : "*unknown*");
364    
365     if (tcl_threaded())
366     dprintf(idx, "Tcl is threaded.\n");
367     dprintf(idx, "Socket table: %d/%d\n", threaddata()->MAXSOCKS, max_socks);
368     }
369    
370     /* Show all internal state variables
371     */
372     void tell_settings(int idx)
373     {
374     char s[1024];
375     int i;
376     struct flag_record fr = { FR_GLOBAL, 0, 0, 0, 0, 0 };
377    
378     dprintf(idx, "Botnet nickname: %s\n", botnetnick);
379     if (firewall[0])
380     dprintf(idx, "Firewall: %s:%d\n", firewall, firewallport);
381     dprintf(idx, "Userfile: %s\n", userfile);
382     dprintf(idx, "Motd: %s\n", motdfile);
383     dprintf(idx, "Directories:\n");
384     #ifndef STATIC
385     dprintf(idx, " Help : %s\n", helpdir);
386     dprintf(idx, " Temp : %s\n", tempdir);
387     dprintf(idx, " Modules: %s\n", moddir);
388     #else
389     dprintf(idx, " Help: %s\n", helpdir);
390     dprintf(idx, " Temp: %s\n", tempdir);
391     #endif
392     fr.global = default_flags;
393    
394     build_flags(s, &fr, NULL);
395     dprintf(idx, "%s [%s], %s: %s\n", MISC_NEWUSERFLAGS, s,
396     MISC_NOTIFY, notify_new);
397     if (owner[0])
398     dprintf(idx, "%s: %s\n", MISC_PERMOWNER, owner);
399     for (i = 0; i < max_logs; i++)
400     if (logs[i].filename != NULL) {
401     dprintf(idx, "Logfile #%d: %s on %s (%s: %s)\n", i + 1,
402     logs[i].filename, logs[i].chname,
403     masktype(logs[i].mask), maskname(logs[i].mask));
404     }
405     dprintf(idx, "Ignores last %d minute%s.\n", ignore_time,
406     (ignore_time != 1) ? "s" : "");
407     }
408    
409     void reaffirm_owners()
410     {
411     char *p, *q, s[121];
412     struct userrec *u;
413    
414     /* Please stop breaking this function. */
415     if (owner[0]) {
416     q = owner;
417     p = strchr(q, ',');
418     while (p) {
419     strncpyz(s, q, (p - q) + 1);
420     rmspace(s);
421     u = get_user_by_handle(userlist, s);
422     if (u)
423     u->flags = sanity_check(u->flags | USER_OWNER);
424     q = p + 1;
425     p = strchr(q, ',');
426     }
427     strcpy(s, q);
428     rmspace(s);
429     u = get_user_by_handle(userlist, s);
430     if (u)
431     u->flags = sanity_check(u->flags | USER_OWNER);
432     }
433     }
434    
435     void chanprog()
436     {
437     int i;
438     FILE *f;
439     char s[161], rands[8];
440    
441     admin[0] = 0;
442     helpdir[0] = 0;
443     tempdir[0] = 0;
444     conmask = 0;
445    
446     for (i = 0; i < max_logs; i++)
447     logs[i].flags |= LF_EXPIRING;
448    
449     /* Turn off read-only variables (make them write-able) for rehash */
450     protect_readonly = 0;
451    
452     /* Now read it */
453     if (!readtclprog(configfile))
454     fatal(MISC_NOCONFIGFILE, 0);
455    
456     for (i = 0; i < max_logs; i++) {
457     if (logs[i].flags & LF_EXPIRING) {
458     if (logs[i].filename != NULL) {
459     nfree(logs[i].filename);
460     logs[i].filename = NULL;
461     }
462     if (logs[i].chname != NULL) {
463     nfree(logs[i].chname);
464     logs[i].chname = NULL;
465     }
466     if (logs[i].f != NULL) {
467     fclose(logs[i].f);
468     logs[i].f = NULL;
469     }
470     logs[i].mask = 0;
471     logs[i].flags = 0;
472     }
473     }
474    
475     /* We should be safe now */
476     call_hook(HOOK_REHASH);
477     protect_readonly = 1;
478    
479     if (!botnetnick[0])
480     strncpyz(botnetnick, origbotname, HANDLEN + 1);
481    
482     if (!botnetnick[0])
483     fatal("I don't have a botnet nick!!\n", 0);
484    
485     if (!userfile[0])
486     fatal(MISC_NOUSERFILE2, 0);
487    
488     if (!readuserfile(userfile, &userlist)) {
489     if (!make_userfile) {
490     char tmp[178];
491    
492     egg_snprintf(tmp, sizeof tmp, MISC_NOUSERFILE, configfile);
493     fatal(tmp, 0);
494     }
495     printf("\n\n%s\n", MISC_NOUSERFILE2);
496     if (module_find("server", 0, 0))
497     printf(MISC_USERFCREATE1, origbotname);
498     printf("%s\n\n", MISC_USERFCREATE2);
499     } else if (make_userfile) {
500     make_userfile = 0;
501     printf("%s\n", MISC_USERFEXISTS);
502     }
503    
504     if (helpdir[0])
505     if (helpdir[strlen(helpdir) - 1] != '/')
506     strcat(helpdir, "/");
507    
508     if (tempdir[0])
509     if (tempdir[strlen(tempdir) - 1] != '/')
510     strcat(tempdir, "/");
511    
512     /* Test tempdir: it's vital. */
513    
514     /* Possible file race condition solved by using a random string
515     * and the process id in the filename.
516     * FIXME: This race is only partitially fixed. We could still be
517     * overwriting an existing file / following a malicious
518     * link.
519     */
520     make_rand_str(rands, 7); /* create random string */
521     sprintf(s, "%s.test-%u-%s", tempdir, getpid(), rands);
522     f = fopen(s, "w");
523     if (f == NULL)
524     fatal(MISC_CANTWRITETEMP, 0);
525     fclose(f);
526     unlink(s);
527     reaffirm_owners();
528     check_tcl_event("userfile-loaded");
529     }
530    
531     /* Reload the user file from disk
532     */
533     void reload()
534     {
535     if (!file_readable(userfile)) {
536     putlog(LOG_MISC, "*", MISC_CANTRELOADUSER);
537     return;
538     }
539    
540     noshare = 1;
541     clear_userlist(userlist);
542     noshare = 0;
543     userlist = NULL;
544     if (!readuserfile(userfile, &userlist))
545     fatal(MISC_MISSINGUSERF, 0);
546     reaffirm_owners();
547     check_tcl_event("userfile-loaded");
548     call_hook(HOOK_READ_USERFILE);
549     }
550    
551     void rehash()
552     {
553     call_hook(HOOK_PRE_REHASH);
554     noshare = 1;
555     clear_userlist(userlist);
556     noshare = 0;
557     userlist = NULL;
558     chanprog();
559     }
560    
561     /*
562     * Brief venture into timers
563     */
564    
565     /* Add a timer
566     */
567     unsigned long add_timer(tcl_timer_t ** stack, int elapse, char *cmd,
568     unsigned long prev_id)
569     {
570     tcl_timer_t *old = (*stack);
571    
572     *stack = nmalloc(sizeof **stack);
573     (*stack)->next = old;
574     (*stack)->mins = elapse;
575     (*stack)->cmd = nmalloc(strlen(cmd) + 1);
576     strcpy((*stack)->cmd, cmd);
577     /* If it's just being added back and already had an id,
578     * don't create a new one.
579     */
580     if (prev_id > 0)
581     (*stack)->id = prev_id;
582     else
583     (*stack)->id = timer_id++;
584     return (*stack)->id;
585     }
586    
587     /* Remove a timer, by id
588     */
589     int remove_timer(tcl_timer_t ** stack, unsigned long id)
590     {
591     tcl_timer_t *old;
592     int ok = 0;
593    
594     while (*stack) {
595     if ((*stack)->id == id) {
596     ok++;
597     old = *stack;
598     *stack = ((*stack)->next);
599     nfree(old->cmd);
600     nfree(old);
601     } else
602     stack = &((*stack)->next);
603     }
604     return ok;
605     }
606    
607     /* Check timers, execute the ones that have expired.
608     */
609     void do_check_timers(tcl_timer_t ** stack)
610     {
611     tcl_timer_t *mark = *stack, *old = NULL;
612     char x[16];
613    
614     /* New timers could be added by a Tcl script inside a current timer
615     * so i'll just clear out the timer list completely, and add any
616     * unexpired timers back on.
617     */
618     *stack = NULL;
619     while (mark) {
620     if (mark->mins > 0)
621     mark->mins--;
622     old = mark;
623     mark = mark->next;
624     if (!old->mins) {
625     egg_snprintf(x, sizeof x, "timer%lu", old->id);
626     do_tcl(x, old->cmd);
627     nfree(old->cmd);
628     nfree(old);
629     } else {
630     old->next = *stack;
631     *stack = old;
632     }
633     }
634     }
635    
636     /* Wipe all timers.
637     */
638     void wipe_timers(Tcl_Interp *irp, tcl_timer_t **stack)
639     {
640     tcl_timer_t *mark = *stack, *old;
641    
642     while (mark) {
643     old = mark;
644     mark = mark->next;
645     nfree(old->cmd);
646     nfree(old);
647     }
648     *stack = NULL;
649     }
650    
651     /* Return list of timers
652     */
653     void list_timers(Tcl_Interp *irp, tcl_timer_t *stack)
654     {
655     char mins[10], id[16], *x;
656     EGG_CONST char *argv[3];
657     tcl_timer_t *mark;
658    
659     for (mark = stack; mark; mark = mark->next) {
660     egg_snprintf(mins, sizeof mins, "%u", mark->mins);
661     egg_snprintf(id, sizeof id, "timer%lu", mark->id);
662     argv[0] = mins;
663     argv[1] = mark->cmd;
664     argv[2] = id;
665     x = Tcl_Merge(3, argv);
666     Tcl_AppendElement(irp, x);
667     Tcl_Free((char *) x);
668     }
669     }
670    
671     /* Oddly enough, written by Sup (former(?) Eggdrop coder)
672     */
673     int isowner(char *name)
674     {
675     register char *ptr = NULL, *s = NULL, *n = NULL;
676    
677     if (!name)
678     return 0;
679    
680     ptr = owner - 1;
681    
682     do {
683     ptr++;
684     if (*ptr && !egg_isspace(*ptr) && *ptr != ',') {
685     if (!s)
686     s = ptr;
687     } else if (s) {
688     for (n = name; *n && *s && s < ptr &&
689     tolower((unsigned) *n) == tolower((unsigned) *s); n++, s++);
690    
691     if (s == ptr && !*n)
692     return 1;
693    
694     s = NULL;
695     }
696     } while (*ptr);
697    
698     return 0;
699     }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23