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