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