/[cvs]/eggdrop1.9/src/main.c
ViewVC logotype

Contents of /eggdrop1.9/src/main.c

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


Revision 1.78 - (show annotations) (download) (as text)
Fri Sep 28 03:15:34 2001 UTC (17 years, 9 months ago) by stdarg
Branch: MAIN
Changes since 1.77: +4 -13 lines
File MIME type: text/x-chdr

This is a big patch!
Created several new bind tables (raw, msg, msgm, pub, pubm) to see how it
would work. Seems to work well so far, although there could be bugs.
Added most of the new important bind table functions to the global table.

1 /*
2 * main.c -- handles:
3 * core event handling
4 * signal handling
5 * command line arguments
6 * context and assert debugging
7 *
8 * $Id: main.c,v 1.77 2001/09/20 19:50:19 stdarg Exp $
9 */
10 /*
11 * Copyright (C) 1997 Robey Pointer
12 * Copyright (C) 1999, 2000, 2001 Eggheads Development Team
13 *
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28 /*
29 * The author (Robey Pointer) can be reached at: robey@netcom.com
30 * NOTE: Robey is no long working on this code, there is a discussion
31 * list available at eggheads@eggheads.org.
32 */
33
34 #include "main.h"
35 #include <fcntl.h>
36 #include <time.h>
37 #include <errno.h>
38 #include <signal.h>
39 #include <netdb.h>
40 #include <setjmp.h>
41
42 #include <locale.h>
43
44 #ifdef STOP_UAC /* osf/1 complains a lot */
45 #include <sys/sysinfo.h>
46 #define UAC_NOPRINT 0x00000001 /* Don't report unaligned fixups */
47 #endif
48 /* Some systems have a working sys/wait.h even though configure will
49 * decide it's not bsd compatable. Oh well.
50 */
51
52 #include "chan.h"
53 #include "modules.h"
54 #include "tandem.h"
55 #include "bg.h"
56
57 #include "adns/adns.h"
58
59 #ifdef CYGWIN_HACKS
60 #include <windows.h>
61 #endif
62
63 #ifndef _POSIX_SOURCE
64 /* Solaris needs this */
65 #define _POSIX_SOURCE 1
66 #endif
67
68 extern char origbotname[], userfile[], botnetnick[];
69 extern int dcc_total, conmask, cache_hit, cache_miss,
70 max_logs, quick_logs;
71 extern struct dcc_t *dcc;
72 extern struct userrec *userlist;
73 extern struct chanset_t *chanset;
74 extern log_t *logs;
75 extern Tcl_Interp *interp;
76 extern tcl_timer_t *timer,
77 *utimer;
78 extern jmp_buf alarmret;
79
80
81 /*
82 * Please use the PATCH macro instead of directly altering the version
83 * string from now on (it makes it much easier to maintain patches).
84 * Also please read the README file regarding your rights to distribute
85 * modified versions of this bot.
86 */
87
88 char egg_version[1024] = VERSION;
89 int egg_numver = VERSION_NUM;
90
91 char notify_new[121] = ""; /* Person to send a note to for new users */
92 int default_flags = 0; /* Default user flags and */
93 int default_uflags = 0; /* Default userdefinied flags for people
94 who say 'hello' or for .adduser */
95
96 int backgrd = 1; /* Run in the background? */
97 int con_chan = 0; /* Foreground: constantly display channel
98 stats? */
99 int term_z = 0; /* Foreground: use the terminal as a party
100 line? */
101 char configfile[121] = "eggdrop.conf"; /* Name of the config file */
102 char helpdir[121]; /* Directory of help files (if used) */
103 char textdir[121] = ""; /* Directory for text files that get dumped */
104 int keep_all_logs = 0; /* Never erase logfiles, no matter how old
105 they are? */
106 char logfile_suffix[21] = ".%d%b%Y"; /* Format of logfile suffix. */
107 time_t online_since; /* Unix-time that the bot loaded up */
108 int make_userfile = 0; /* Using bot in make-userfile mode? (first
109 user to 'hello' becomes master) */
110 char owner[121] = ""; /* Permanent owner(s) of the bot */
111 char pid_file[HANDLEN + 5]; /* Name of the file for the pid to be
112 stored in */
113 int save_users_at = 0; /* How many minutes past the hour to
114 save the userfile? */
115 int notify_users_at = 0; /* How many minutes past the hour to
116 notify users of notes? */
117 int switch_logfiles_at = 300; /* When (military time) to switch logfiles */
118 char version[81]; /* Version info (long form) */
119 char ver[41]; /* Version info (short form) */
120 char egg_xtra[2048]; /* Patch info */
121 int use_stderr = 1; /* Send stuff to stderr instead of logfiles? */
122 int do_restart = 0; /* .restart has been called, restart asap */
123 int die_on_sighup = 0; /* die if bot receives SIGHUP */
124 int die_on_sigterm = 1; /* die if bot receives SIGTERM */
125 int resolve_timeout = 15; /* hostname/address lookup timeout */
126 char quit_msg[1024]; /* quit message */
127 time_t now; /* duh, now :) */
128
129 /* Traffic stats
130 */
131 unsigned long otraffic_irc = 0;
132 unsigned long otraffic_irc_today = 0;
133 unsigned long otraffic_bn = 0;
134 unsigned long otraffic_bn_today = 0;
135 unsigned long otraffic_dcc = 0;
136 unsigned long otraffic_dcc_today = 0;
137 unsigned long otraffic_filesys = 0;
138 unsigned long otraffic_filesys_today = 0;
139 unsigned long otraffic_trans = 0;
140 unsigned long otraffic_trans_today = 0;
141 unsigned long otraffic_unknown = 0;
142 unsigned long otraffic_unknown_today = 0;
143 unsigned long itraffic_irc = 0;
144 unsigned long itraffic_irc_today = 0;
145 unsigned long itraffic_bn = 0;
146 unsigned long itraffic_bn_today = 0;
147 unsigned long itraffic_dcc = 0;
148 unsigned long itraffic_dcc_today = 0;
149 unsigned long itraffic_trans = 0;
150 unsigned long itraffic_trans_today = 0;
151 unsigned long itraffic_unknown = 0;
152 unsigned long itraffic_unknown_today = 0;
153
154 #ifdef DEBUG_CONTEXT
155 /* Context storage for fatal crashes */
156 char cx_file[16][30];
157 char cx_note[16][256];
158 int cx_line[16];
159 int cx_ptr = 0;
160 #endif
161
162
163 void fatal(const char *s, int recoverable)
164 {
165 int i;
166
167 putlog(LOG_MISC, "*", "* %s", s);
168 flushlogs();
169 for (i = 0; i < dcc_total; i++)
170 if (dcc[i].sock >= 0)
171 killsock(dcc[i].sock);
172 unlink(pid_file);
173 if (!recoverable) {
174 bg_send_quit(BG_ABORT);
175 exit(1);
176 }
177 }
178
179
180 int expmem_chanprog(), expmem_users(), expmem_misc(), expmem_dccutil(),
181 expmem_botnet(), expmem_tcl(), expmem_tclhash(), expmem_net(),
182 expmem_modules(int), expmem_tcldcc();
183
184 /* For mem.c : calculate memory we SHOULD be using
185 */
186 int expected_memory(void)
187 {
188 int tot;
189
190 tot = expmem_chanprog() + expmem_users() + expmem_misc() +
191 expmem_dccutil() + expmem_botnet() + expmem_tcl() + expmem_tclhash() +
192 expmem_net() + expmem_modules(0) + expmem_tcldcc();
193 return tot;
194 }
195
196 static void check_expired_dcc()
197 {
198 int i;
199
200 for (i = 0; i < dcc_total; i++)
201 if (dcc[i].type && dcc[i].type->timeout_val &&
202 ((now - dcc[i].timeval) > *(dcc[i].type->timeout_val))) {
203 if (dcc[i].type->timeout)
204 dcc[i].type->timeout(i);
205 else if (dcc[i].type->eof)
206 dcc[i].type->eof(i);
207 else
208 continue;
209 /* Only timeout 1 socket per cycle, too risky for more */
210 return;
211 }
212 }
213
214 #ifdef DEBUG_CONTEXT
215 static int nested_debug = 0;
216
217 void write_debug()
218 {
219 int x;
220 char s[25];
221 int y;
222
223 if (nested_debug) {
224 /* Yoicks, if we have this there's serious trouble!
225 * All of these are pretty reliable, so we'll try these.
226 *
227 * NOTE: dont try and display context-notes in here, it's
228 * _not_ safe <cybah>
229 */
230 x = creat("DEBUG.DEBUG", 0644);
231 setsock(x, SOCK_NONSOCK);
232 if (x >= 0) {
233 strncpyz(s, ctime(&now), sizeof s);
234 dprintf(-x, "Debug (%s) written %s\n", ver, s);
235 dprintf(-x, "Please report problem to bugs@eggheads.org\n");
236 dprintf(-x, "after a visit to http://www.eggheads.org/bugzilla/\n");
237 dprintf(-x, "Full Patch List: %s\n", egg_xtra);
238 dprintf(-x, "Context: ");
239 cx_ptr = cx_ptr & 15;
240 for (y = ((cx_ptr + 1) & 15); y != cx_ptr; y = ((y + 1) & 15))
241 dprintf(-x, "%s/%d,\n ", cx_file[y], cx_line[y]);
242 dprintf(-x, "%s/%d\n\n", cx_file[y], cx_line[y]);
243 killsock(x);
244 close(x);
245 }
246 bg_send_quit(BG_ABORT);
247 exit(1); /* Dont even try & tell people about, that may
248 have caused the fault last time. */
249 } else
250 nested_debug = 1;
251 putlog(LOG_MISC, "*", "* Last context: %s/%d [%s]", cx_file[cx_ptr],
252 cx_line[cx_ptr], cx_note[cx_ptr][0] ? cx_note[cx_ptr] : "");
253 putlog(LOG_MISC, "*", "* Please REPORT this BUG!");
254 putlog(LOG_MISC, "*", "* Check doc/BUG-REPORT on how to do so.");
255 x = creat("DEBUG", 0644);
256 setsock(x, SOCK_NONSOCK);
257 if (x < 0) {
258 putlog(LOG_MISC, "*", "* Failed to write DEBUG");
259 } else {
260 strncpyz(s, ctime(&now), sizeof s);
261 dprintf(-x, "Debug (%s) written %s\n", ver, s);
262 dprintf(-x, "Full Patch List: %s\n", egg_xtra);
263 #ifdef STATIC
264 dprintf(-x, "STATICALLY LINKED\n");
265 #endif
266
267 /* info library */
268 dprintf(-x, "TCL library: %s\n",
269 ((interp) && (Tcl_Eval(interp, "info library") == TCL_OK)) ?
270 interp->result : "*unknown*");
271
272 /* info tclversion/patchlevel */
273 dprintf(-x, "TCL version: %s (header version %s)\n",
274 ((interp) && (Tcl_Eval(interp, "info patchlevel") == TCL_OK)) ?
275 interp->result : (Tcl_Eval(interp, "info tclversion") == TCL_OK) ?
276 interp->result : "*unknown*", TCL_PATCH_LEVEL ? TCL_PATCH_LEVEL :
277 "*unknown*");
278
279 #if HAVE_TCL_THREADS
280 dprintf(-x, "TCL is threaded\n");
281 #endif
282
283 #ifdef CCFLAGS
284 dprintf(-x, "Compile flags: %s\n", CCFLAGS);
285 #endif
286 #ifdef LDFLAGS
287 dprintf(-x, "Link flags: %s\n", LDFLAGS);
288 #endif
289 #ifdef STRIPFLAGS
290 dprintf(-x, "Strip flags: %s\n", STRIPFLAGS);
291 #endif
292
293 dprintf(-x, "Context: ");
294 cx_ptr = cx_ptr & 15;
295 for (y = ((cx_ptr + 1) & 15); y != cx_ptr; y = ((y + 1) & 15))
296 dprintf(-x, "%s/%d, [%s]\n ", cx_file[y], cx_line[y],
297 (cx_note[y][0]) ? cx_note[y] : "");
298 dprintf(-x, "%s/%d [%s]\n\n", cx_file[cx_ptr], cx_line[cx_ptr],
299 (cx_note[cx_ptr][0]) ? cx_note[cx_ptr] : "");
300 tell_dcc(-x);
301 dprintf(-x, "\n");
302 debug_mem_to_dcc(-x);
303 killsock(x);
304 close(x);
305 putlog(LOG_MISC, "*", "* Wrote DEBUG");
306 }
307 }
308 #endif
309
310 static void got_bus(int z)
311 {
312 #ifdef DEBUG_CONTEXT
313 write_debug();
314 #endif
315 fatal("BUS ERROR -- CRASHING!", 1);
316 #ifdef SA_RESETHAND
317 kill(getpid(), SIGBUS);
318 #else
319 bg_send_quit(BG_ABORT);
320 exit(1);
321 #endif
322 }
323
324 static void got_segv(int z)
325 {
326 #ifdef DEBUG_CONTEXT
327 write_debug();
328 #endif
329 fatal("SEGMENT VIOLATION -- CRASHING!", 1);
330 #ifdef SA_RESETHAND
331 kill(getpid(), SIGSEGV);
332 #else
333 bg_send_quit(BG_ABORT);
334 exit(1);
335 #endif
336 }
337
338 static void got_fpe(int z)
339 {
340 #ifdef DEBUG_CONTEXT
341 write_debug();
342 #endif
343 fatal("FLOATING POINT ERROR -- CRASHING!", 0);
344 }
345
346 static void got_term(int z)
347 {
348 write_userfile(-1);
349 check_tcl_event("sigterm");
350 if (die_on_sigterm) {
351 botnet_send_chat(-1, botnetnick, "ACK, I've been terminated!");
352 fatal("TERMINATE SIGNAL -- SIGNING OFF", 0);
353 } else {
354 putlog(LOG_MISC, "*", "RECEIVED TERMINATE SIGNAL (IGNORING)");
355 }
356 }
357
358 static void got_quit(int z)
359 {
360 check_tcl_event("sigquit");
361 putlog(LOG_MISC, "*", "RECEIVED QUIT SIGNAL (IGNORING)");
362 return;
363 }
364
365 static void got_hup(int z)
366 {
367 write_userfile(-1);
368 check_tcl_event("sighup");
369 if (die_on_sighup) {
370 fatal("HANGUP SIGNAL -- SIGNING OFF", 0);
371 } else
372 putlog(LOG_MISC, "*", "Received HUP signal: rehashing...");
373 do_restart = -2;
374 return;
375 }
376
377 /* A call to resolver (gethostbyname, etc) timed out
378 */
379 static void got_alarm(int z)
380 {
381 longjmp(alarmret, 1);
382
383 /* -Never reached- */
384 }
385
386 /* Got ILL signal -- log context and continue
387 */
388 static void got_ill(int z)
389 {
390 check_tcl_event("sigill");
391 #ifdef DEBUG_CONTEXT
392 putlog(LOG_MISC, "*", "* Context: %s/%d [%s]", cx_file[cx_ptr],
393 cx_line[cx_ptr], (cx_note[cx_ptr][0]) ? cx_note[cx_ptr] : "");
394 #endif
395 }
396
397 #ifdef DEBUG_CONTEXT
398 /* Context */
399 void eggContext(const char *file, int line, const char *module)
400 {
401 char x[31], *p;
402
403 p = strrchr(file, '/');
404 if (!module) {
405 strncpyz(x, p ? p + 1 : file, sizeof x);
406 } else
407 egg_snprintf(x, 31, "%s:%s", module, p ? p + 1 : file);
408 cx_ptr = ((cx_ptr + 1) & 15);
409 strcpy(cx_file[cx_ptr], x);
410 cx_line[cx_ptr] = line;
411 cx_note[cx_ptr][0] = 0;
412 }
413
414 /* Called from the ContextNote macro.
415 */
416 void eggContextNote(const char *file, int line, const char *module,
417 const char *note)
418 {
419 char x[31], *p;
420
421 p = strrchr(file, '/');
422 if (!module) {
423 strncpyz(x, p ? p + 1 : file, sizeof x);
424 } else
425 egg_snprintf(x, 31, "%s:%s", module, p ? p + 1 : file);
426 cx_ptr = ((cx_ptr + 1) & 15);
427 strcpy(cx_file[cx_ptr], x);
428 cx_line[cx_ptr] = line;
429 strncpyz(cx_note[cx_ptr], note, sizeof cx_note[cx_ptr]);
430 }
431 #endif
432
433 #ifdef DEBUG_ASSERT
434 /* Called from the Assert macro.
435 */
436 void eggAssert(const char *file, int line, const char *module)
437 {
438 #ifdef DEBUG_CONTEXT
439 write_debug();
440 #endif
441 if (!module)
442 putlog(LOG_MISC, "*", "* In file %s, line %u", file, line);
443 else
444 putlog(LOG_MISC, "*", "* In file %s:%s, line %u", module, file, line);
445 fatal("ASSERT FAILED -- CRASHING!", 1);
446 }
447 #endif
448
449 static void do_arg(char *s)
450 {
451 char x[1024], *z = x;
452 int i;
453
454 if (s[0] == '-')
455 for (i = 1; i < strlen(s); i++) {
456 switch (s[i]) {
457 case 'n':
458 backgrd = 0;
459 break;
460 case 'c':
461 con_chan = 1;
462 term_z = 0;
463 break;
464 case 't':
465 con_chan = 0;
466 term_z = 1;
467 break;
468 case 'm':
469 make_userfile = 1;
470 break;
471 case 'v':
472 strncpyz(x, egg_version, sizeof x);
473 newsplit(&z);
474 newsplit(&z);
475 printf("%s\n", version);
476 if (z[0])
477 printf(" (patches: %s)\n", z);
478 bg_send_quit(BG_ABORT);
479 exit(0);
480 break; /* this should never be reached */
481 case 'h':
482 printf("\n%s\n\n", version);
483 printf(_("Command line arguments:\n\
484 -h help\n\
485 -v print version and exit\n\
486 -n don't go into the background\n\
487 -c (with -n) display channel stats every 10 seconds\n\
488 -t (with -n) use terminal to simulate dcc-chat\n\
489 -m userfile creation mode\n\
490 optional config filename (default 'eggdrop.conf')\n"));
491 printf("\n");
492 bg_send_quit(BG_ABORT);
493 exit(0);
494 break; /* this should never be reached */
495 }
496 } else
497 strncpyz(configfile, s, sizeof configfile);
498 }
499
500 void backup_userfile(void)
501 {
502 char s[125];
503
504 putlog(LOG_MISC, "*", _("Backing up user file..."));
505 egg_snprintf(s, sizeof s, "%s~bak", userfile);
506 copyfile(userfile, s);
507 }
508
509 /* Timer info */
510 static int lastmin = 99;
511 static time_t then;
512 static struct tm nowtm;
513
514 /* Called once a second.
515 *
516 * Note: Try to not put any Context lines in here (guppy 21Mar2000).
517 */
518 static void core_secondly()
519 {
520 static int cnt = 0;
521 int miltime;
522
523 do_check_timers(&utimer); /* Secondly timers */
524 cnt++;
525 if (cnt >= 10) { /* Every 10 seconds */
526 cnt = 0;
527 check_expired_dcc();
528 if (con_chan && !backgrd) {
529 dprintf(DP_STDOUT, "\033[2J\033[1;1H");
530 tell_verbose_status(DP_STDOUT);
531 do_module_report(DP_STDOUT, 0, "server");
532 do_module_report(DP_STDOUT, 0, "channels");
533 tell_mem_status_dcc(DP_STDOUT);
534 }
535 }
536 egg_memcpy(&nowtm, localtime(&now), sizeof(struct tm));
537 if (nowtm.tm_min != lastmin) {
538 int i = 0;
539
540 /* Once a minute */
541 lastmin = (lastmin + 1) % 60;
542 call_hook(HOOK_MINUTELY);
543 check_expired_ignores();
544 autolink_cycle(NULL); /* Attempt autolinks */
545 /* In case for some reason more than 1 min has passed: */
546 while (nowtm.tm_min != lastmin) {
547 /* Timer drift, dammit */
548 debug2("timer: drift (lastmin=%d, now=%d)", lastmin, nowtm.tm_min);
549 i++;
550 lastmin = (lastmin + 1) % 60;
551 call_hook(HOOK_MINUTELY);
552 }
553 if (i > 1)
554 putlog(LOG_MISC, "*", "(!) timer drift -- spun %d minutes", i);
555 miltime = (nowtm.tm_hour * 100) + (nowtm.tm_min);
556 if (((int) (nowtm.tm_min / 5) * 5) == (nowtm.tm_min)) { /* 5 min */
557 call_hook(HOOK_5MINUTELY);
558 check_botnet_pings();
559 if (!quick_logs) {
560 flushlogs();
561 check_logsize();
562 }
563 if (!miltime) { /* At midnight */
564 char s[25];
565 int j;
566
567 strncpyz(s, ctime(&now), sizeof s);
568 putlog(LOG_ALL, "*", "--- %.11s%s", s, s + 20);
569 call_hook(HOOK_BACKUP);
570 for (j = 0; j < max_logs; j++) {
571 if (logs[j].filename != NULL && logs[j].f != NULL) {
572 fclose(logs[j].f);
573 logs[j].f = NULL;
574 }
575 }
576 }
577 }
578 if (nowtm.tm_min == notify_users_at)
579 call_hook(HOOK_HOURLY);
580 /* These no longer need checking since they are all check vs minutely
581 * settings and we only get this far on the minute.
582 */
583 if (miltime == switch_logfiles_at) {
584 call_hook(HOOK_DAILY);
585 if (!keep_all_logs) {
586 putlog(LOG_MISC, "*", _("Switching logfiles..."));
587 for (i = 0; i < max_logs; i++)
588 if (logs[i].filename) {
589 char s[1024];
590
591 if (logs[i].f) {
592 fclose(logs[i].f);
593 logs[i].f = NULL;
594 }
595 egg_snprintf(s, sizeof s, "%s.yesterday", logs[i].filename);
596 unlink(s);
597 movefile(logs[i].filename, s);
598 }
599 }
600 }
601 }
602 }
603
604 static void core_minutely()
605 {
606 check_tcl_time(&nowtm);
607 do_check_timers(&timer);
608 if (quick_logs != 0) {
609 flushlogs();
610 check_logsize();
611 }
612 }
613
614 static void core_hourly()
615 {
616 write_userfile(-1);
617 }
618
619 static void event_rehash()
620 {
621 check_tcl_event("rehash");
622 }
623
624 static void event_prerehash()
625 {
626 check_tcl_event("prerehash");
627 }
628
629 static void event_save()
630 {
631 check_tcl_event("save");
632 }
633
634 static void event_logfile()
635 {
636 check_tcl_event("logfile");
637 }
638
639 static void event_resettraffic()
640 {
641 otraffic_irc += otraffic_irc_today;
642 itraffic_irc += itraffic_irc_today;
643 otraffic_bn += otraffic_bn_today;
644 itraffic_bn += itraffic_bn_today;
645 otraffic_dcc += otraffic_dcc_today;
646 itraffic_dcc += itraffic_dcc_today;
647 otraffic_unknown += otraffic_unknown_today;
648 itraffic_unknown += itraffic_unknown_today;
649 otraffic_trans += otraffic_trans_today;
650 itraffic_trans += itraffic_trans_today;
651 otraffic_irc_today = otraffic_bn_today = 0;
652 otraffic_dcc_today = otraffic_unknown_today = 0;
653 itraffic_irc_today = itraffic_bn_today = 0;
654 itraffic_dcc_today = itraffic_unknown_today = 0;
655 itraffic_trans_today = otraffic_trans_today = 0;
656 }
657
658 static void event_loaded()
659 {
660 check_tcl_event("loaded");
661 }
662
663 void kill_tcl();
664 extern module_entry *module_list;
665 void restart_chons();
666
667 #ifdef STATIC
668 void check_static(char *, char *(*)());
669
670 #include "mod/static.h"
671 #endif
672 int init_mem(), init_dcc_max(), init_userent(), init_misc(),
673 init_net(), init_modules(), init_tcl(int, char **);
674 void botnet_init();
675
676 void patch(const char *str)
677 {
678 char *p = strchr(egg_version, '+');
679
680 if (!p)
681 p = &egg_version[strlen(egg_version)];
682 sprintf(p, "+%s", str);
683 egg_numver++;
684 sprintf(&egg_xtra[strlen(egg_xtra)], " %s", str);
685 }
686
687 static inline void garbage_collect(void)
688 {
689 static u_8bit_t run_cnt = 0;
690
691 if (run_cnt == 3)
692 garbage_collect_tclhash();
693 else
694 run_cnt++;
695 }
696
697 int main(int argc, char **argv)
698 {
699 int xx, i;
700 char buf[520], s[25];
701 FILE *f;
702 struct sigaction sv;
703 struct chanset_t *chan;
704
705 #ifdef DEBUG_MEM
706 /* Make sure it can write core, if you make debug. Else it's pretty
707 * useless (dw)
708 */
709 {
710 #include <sys/resource.h>
711 struct rlimit cdlim;
712
713 cdlim.rlim_cur = RLIM_INFINITY;
714 cdlim.rlim_max = RLIM_INFINITY;
715 setrlimit(RLIMIT_CORE, &cdlim);
716 }
717 #endif
718
719 /* Initialise context list */
720 for (i = 0; i < 16; i++)
721 Context;
722
723 setlocale(LC_MESSAGES, "");
724 bindtextdomain(PACKAGE, LOCALEDIR);
725 textdomain(PACKAGE);
726
727 #include "patch.h"
728 /* Version info! */
729 egg_snprintf(ver, sizeof ver, "eggdrop v%s", egg_version);
730 egg_snprintf(version, sizeof version, "Eggdrop v%s (C)1997 Robey Pointer (C)2001 Eggheads",
731 egg_version);
732 /* Now add on the patchlevel (for Tcl) */
733 sprintf(&egg_version[strlen(egg_version)], " %u", egg_numver);
734 strcat(egg_version, egg_xtra);
735 #ifdef STOP_UAC
736 {
737 int nvpair[2];
738
739 nvpair[0] = SSIN_UACPROC;
740 nvpair[1] = UAC_NOPRINT;
741 setsysinfo(SSI_NVPAIRS, (char *) nvpair, 1, NULL, 0);
742 }
743 #endif
744
745 /* Set up error traps: */
746 sv.sa_handler = got_bus;
747 sigemptyset(&sv.sa_mask);
748 #ifdef SA_RESETHAND
749 sv.sa_flags = SA_RESETHAND;
750 #else
751 sv.sa_flags = 0;
752 #endif
753 sigaction(SIGBUS, &sv, NULL);
754 sv.sa_handler = got_segv;
755 sigaction(SIGSEGV, &sv, NULL);
756 #ifdef SA_RESETHAND
757 sv.sa_flags = 0;
758 #endif
759 sv.sa_handler = got_fpe;
760 sigaction(SIGFPE, &sv, NULL);
761 sv.sa_handler = got_term;
762 sigaction(SIGTERM, &sv, NULL);
763 sv.sa_handler = got_hup;
764 sigaction(SIGHUP, &sv, NULL);
765 sv.sa_handler = got_quit;
766 sigaction(SIGQUIT, &sv, NULL);
767 sv.sa_handler = SIG_IGN;
768 sigaction(SIGPIPE, &sv, NULL);
769 sv.sa_handler = got_ill;
770 sigaction(SIGILL, &sv, NULL);
771 sv.sa_handler = got_alarm;
772 sigaction(SIGALRM, &sv, NULL);
773
774 /* Initialize variables and stuff */
775 now = time(NULL);
776 chanset = NULL;
777 egg_memcpy(&nowtm, localtime(&now), sizeof(struct tm));
778 lastmin = nowtm.tm_min;
779 srandom(now % (getpid() + getppid()));
780 init_mem();
781 if (argc > 1)
782 for (i = 1; i < argc; i++)
783 do_arg(argv[i]);
784 printf("\n%s\n", version);
785
786 /* Don't allow eggdrop to run as root */
787 if (((int) getuid() == 0) || ((int) geteuid() == 0))
788 fatal(_("ERROR: Eggdrop will not run as root!"), 0);
789
790 init_dcc_max();
791 init_userent();
792 init_misc();
793 botnet_init();
794 init_net();
795 init_modules();
796 if (backgrd)
797 bg_prepare_split();
798 init_tcl(argc, argv);
799 #ifdef STATIC
800 link_statics();
801 #endif
802 strncpyz(s, ctime(&now), sizeof s);
803 strcpy(&s[11], &s[20]);
804 putlog(LOG_ALL, "*", "--- Loading %s (%s)", ver, s);
805 chanprog();
806 if (!encrypt_pass) {
807 printf(_("You have installed modules but have not selected an encryption\n\
808 module, please consult the default config file for info.\n"));
809 bg_send_quit(BG_ABORT);
810 exit(1);
811 }
812 i = 0;
813 for (chan = chanset; chan; chan = chan->next)
814 i++;
815 putlog(LOG_MISC, "*", "=== %s: %d channels, %d users.",
816 botnetnick, i, count_users(userlist));
817 cache_miss = 0;
818 cache_hit = 0;
819 egg_snprintf(pid_file, sizeof pid_file, "pid.%s", botnetnick);
820
821 /* Check for pre-existing eggdrop! */
822 f = fopen(pid_file, "r");
823 if (f != NULL) {
824 fgets(s, 10, f);
825 xx = atoi(s);
826 kill(xx, SIGCHLD); /* Meaningless kill to determine if pid
827 is used */
828 if (errno != ESRCH) {
829 printf(_("I detect %s already running from this directory.\n"), origbotname);
830 printf(_("If this is incorrect, erase the %s\n"), pid_file);
831 bg_send_quit(BG_ABORT);
832 exit(1);
833 }
834 }
835
836 /* Move into background? */
837 if (backgrd) {
838 #ifndef CYGWIN_HACKS
839 bg_do_split();
840 } else { /* !backgrd */
841 #endif
842 xx = getpid();
843 if (xx != 0) {
844 FILE *fp;
845
846 /* Write pid to file */
847 unlink(pid_file);
848 fp = fopen(pid_file, "w");
849 if (fp != NULL) {
850 fprintf(fp, "%u\n", xx);
851 if (fflush(fp)) {
852 /* Let the bot live since this doesn't appear to be a botchk */
853 printf(_("* Warning! Could not write %s file!\n"), pid_file);
854 fclose(fp);
855 unlink(pid_file);
856 } else
857 fclose(fp);
858 } else
859 printf(_("* Warning! Could not write %s file!\n"), pid_file);
860 #ifdef CYGWIN_HACKS
861 printf("Launched into the background (pid: %d)\n\n", xx);
862 #endif
863 }
864 }
865
866 use_stderr = 0; /* Stop writing to stderr now */
867 if (backgrd) {
868 /* Ok, try to disassociate from controlling terminal (finger cross) */
869 #if HAVE_SETPGID && !defined(CYGWIN_HACKS)
870 setpgid(0, 0);
871 #endif
872 /* Tcl wants the stdin, stdout and stderr file handles kept open. */
873 freopen("/dev/null", "r", stdin);
874 freopen("/dev/null", "w", stdout);
875 freopen("/dev/null", "w", stderr);
876 #ifdef CYGWIN_HACKS
877 FreeConsole();
878 #endif
879 }
880
881 /* Terminal emulating dcc chat */
882 if (!backgrd && term_z) {
883 int n = new_dcc(&DCC_CHAT, sizeof(struct chat_info));
884
885 dcc[n].addr[0] = '\0';
886 dcc[n].sock = STDOUT;
887 dcc[n].timeval = now;
888 dcc[n].u.chat->con_flags = conmask;
889 dcc[n].u.chat->strip_flags = STRIP_ALL;
890 dcc[n].status = STAT_ECHO;
891 strcpy(dcc[n].nick, "HQ");
892 strcpy(dcc[n].host, "llama@console");
893 dcc[n].user = get_user_by_handle(userlist, "HQ");
894 /* Make sure there's an innocuous HQ user if needed */
895 if (!dcc[n].user) {
896 userlist = adduser(userlist, "HQ", "none", "-", USER_PARTY);
897 dcc[n].user = get_user_by_handle(userlist, "HQ");
898 }
899 setsock(STDOUT, 0); /* Entry in net table */
900 dprintf(n, "\n### ENTERING DCC CHAT SIMULATION ###\n\n");
901 dcc_chatter(n);
902 }
903
904 then = now;
905 online_since = now;
906 autolink_cycle(NULL); /* Hurry and connect to tandem bots */
907 add_help_reference("cmds1.help");
908 add_help_reference("cmds2.help");
909 add_help_reference("core.help");
910 add_hook(HOOK_SECONDLY, (Function) core_secondly);
911 add_hook(HOOK_MINUTELY, (Function) core_minutely);
912 add_hook(HOOK_HOURLY, (Function) core_hourly);
913 add_hook(HOOK_REHASH, (Function) event_rehash);
914 add_hook(HOOK_PRE_REHASH, (Function) event_prerehash);
915 add_hook(HOOK_USERFILE, (Function) event_save);
916 add_hook(HOOK_BACKUP, (Function) backup_userfile);
917 add_hook(HOOK_DAILY, (Function) event_logfile);
918 add_hook(HOOK_DAILY, (Function) event_resettraffic);
919 add_hook(HOOK_LOADED, (Function) event_loaded);
920
921 call_hook(HOOK_LOADED);
922
923 debug0("main: entering loop");
924 while (1) {
925 int socket_cleanup = 0;
926
927 #if !defined(HAVE_PRE7_5_TCL)
928 /* Process a single tcl event */
929 Tcl_DoOneEvent(TCL_ALL_EVENTS | TCL_DONT_WAIT);
930 #endif
931
932 /* Lets move some of this here, reducing the numer of actual
933 * calls to periodic_timers
934 */
935 now = time(NULL);
936 random(); /* Woop, lets really jumble things */
937 if (now != then) { /* Once a second */
938 call_hook(HOOK_SECONDLY);
939 then = now;
940 }
941
942 /* Only do this every so often. */
943 if (!socket_cleanup) {
944 socket_cleanup = 5;
945
946 /* Remove dead dcc entries. */
947 dcc_remove_lost();
948
949 /* Check for server or dcc activity. */
950 dequeue_sockets();
951 } else
952 socket_cleanup--;
953
954 /* Free unused structures. */
955 garbage_collect();
956
957 xx = sockgets(buf, &i);
958 if (xx >= 0) { /* Non-error */
959 int idx;
960
961 for (idx = 0; idx < dcc_total; idx++)
962 if (dcc[idx].sock == xx) {
963 if (dcc[idx].type && dcc[idx].type->activity) {
964 /* Traffic stats */
965 if (dcc[idx].type->name) {
966 if (!strncmp(dcc[idx].type->name, "BOT", 3))
967 itraffic_bn_today += strlen(buf) + 1;
968 else if (!strcmp(dcc[idx].type->name, "SERVER"))
969 itraffic_irc_today += strlen(buf) + 1;
970 else if (!strncmp(dcc[idx].type->name, "CHAT", 4))
971 itraffic_dcc_today += strlen(buf) + 1;
972 else if (!strncmp(dcc[idx].type->name, "FILES", 5))
973 itraffic_dcc_today += strlen(buf) + 1;
974 else if (!strcmp(dcc[idx].type->name, "SEND"))
975 itraffic_trans_today += strlen(buf) + 1;
976 else if (!strncmp(dcc[idx].type->name, "GET", 3))
977 itraffic_trans_today += strlen(buf) + 1;
978 else
979 itraffic_unknown_today += strlen(buf) + 1;
980 }
981 dcc[idx].type->activity(idx, buf, i);
982 } else
983 putlog(LOG_MISC, "*",
984 "!!! untrapped dcc activity: type %s, sock %d",
985 dcc[idx].type->name, dcc[idx].sock);
986 break;
987 }
988 } else if (xx == -1) { /* EOF from someone */
989 int idx;
990
991 if (i == STDOUT && !backgrd)
992 fatal("END OF FILE ON TERMINAL", 0);
993 for (idx = 0; idx < dcc_total; idx++)
994 if (dcc[idx].sock == i) {
995 if (dcc[idx].type && dcc[idx].type->eof)
996 dcc[idx].type->eof(idx);
997 else {
998 putlog(LOG_MISC, "*",
999 "*** ATTENTION: DEAD SOCKET (%d) OF TYPE %s UNTRAPPED",
1000 i, dcc[idx].type ? dcc[idx].type->name : "*UNKNOWN*");
1001 killsock(i);
1002 lostdcc(idx);
1003 }
1004 idx = dcc_total + 1;
1005 }
1006 if (idx == dcc_total) {
1007 putlog(LOG_MISC, "*",
1008 "(@) EOF socket %d, not a dcc socket, not anything.", i);
1009 close(i);
1010 killsock(i);
1011 }
1012 } else if (xx == -2 && errno != EINTR) { /* select() error */
1013 putlog(LOG_MISC, "*", "* Socket error #%d; recovering.", errno);
1014 for (i = 0; i < dcc_total; i++) {
1015 if ((fcntl(dcc[i].sock, F_GETFD, 0) == -1) && (errno = EBADF)) {
1016 putlog(LOG_MISC, "*",
1017 "DCC socket %d (type %d, name '%s') expired -- pfft",
1018 dcc[i].sock, dcc[i].type, dcc[i].nick);
1019 killsock(dcc[i].sock);
1020 lostdcc(i);
1021 i--;
1022 }
1023 }
1024 } else if (xx == -3) {
1025 call_hook(HOOK_IDLE);
1026 socket_cleanup = 0; /* If we've been idle, cleanup & flush */
1027 }
1028
1029 if (do_restart) {
1030 if (do_restart == -2)
1031 rehash();
1032 else {
1033 /* Unload as many modules as possible */
1034 int f = 1;
1035 module_entry *p;
1036 Function x;
1037 char xx[256];
1038
1039 /* oops, I guess we should call this event before tcl is restarted */
1040 check_tcl_event("prerestart");
1041
1042 while (f) {
1043 f = 0;
1044 for (p = module_list; p != NULL; p = p->next) {
1045 dependancy *d = dependancy_list;
1046 int ok = 1;
1047
1048 while (ok && d) {
1049 if (d->needed == p)
1050 ok = 0;
1051 d = d->next;
1052 }
1053 if (ok) {
1054 strcpy(xx, p->name);
1055 if (module_unload(xx, origbotname) == NULL) {
1056 f = 1;
1057 break;
1058 }
1059 }
1060 }
1061 }
1062 p = module_list;
1063 if (p && p->next && p->next->next)
1064 /* Should be only 2 modules now - blowfish (or some other
1065 encryption module) and eggdrop. */
1066 putlog(LOG_MISC, "*", _("Stagnant module; there WILL be memory leaks!"));
1067 flushlogs();
1068 kill_tcl();
1069 init_tcl(argc, argv);
1070 /* We expect the encryption module as the current module pointed
1071 * to by `module_list'.
1072 */
1073 x = p->funcs[MODCALL_START];
1074 /* `NULL' indicates that we just recently restarted. The module
1075 * is expected to re-initialise as needed.
1076 */
1077 x(NULL);
1078 rehash();
1079 restart_chons();
1080 call_hook(HOOK_LOADED);
1081 }
1082 do_restart = 0;
1083 }
1084 }
1085 }

webmaster@eggheads.org
ViewVC Help
Powered by ViewVC 1.1.23