1 |
/* main.c |
2 |
* |
3 |
* Copyright (C) 1997 Robey Pointer |
4 |
* Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 Eggheads Development Team |
5 |
* |
6 |
* This program is free software; you can redistribute it and/or |
7 |
* modify it under the terms of the GNU General Public License |
8 |
* as published by the Free Software Foundation; either version 2 |
9 |
* of the License, or (at your option) any later version. |
10 |
* |
11 |
* This program is distributed in the hope that it will be useful, |
12 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 |
* GNU General Public License for more details. |
15 |
* |
16 |
* You should have received a copy of the GNU General Public License |
17 |
* along with this program; if not, write to the Free Software |
18 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
19 |
*/ |
20 |
|
21 |
#ifndef lint |
22 |
static const char rcsid[] = "$Id: main.c,v 1.171 2004/06/20 13:33:48 wingman Exp $"; |
23 |
#endif |
24 |
|
25 |
#if HAVE_CONFIG_H |
26 |
# include <config.h> |
27 |
#endif |
28 |
|
29 |
#include <eggdrop/eggdrop.h> |
30 |
#include <ctype.h> |
31 |
#include <unistd.h> |
32 |
#include <fcntl.h> |
33 |
#include <string.h> |
34 |
#include <stdlib.h> |
35 |
#include <sys/stat.h> |
36 |
#include <errno.h> |
37 |
#include <signal.h> |
38 |
#include <netdb.h> |
39 |
#include <setjmp.h> |
40 |
#include <locale.h> |
41 |
#include <ctype.h> |
42 |
#include <ltdl.h> |
43 |
|
44 |
#include <eggdrop/stat.h> |
45 |
|
46 |
#ifdef TIME_WITH_SYS_TIME |
47 |
# include <sys/time.h> |
48 |
# include <time.h> |
49 |
#else |
50 |
# ifdef HAVE_SYS_TIME_H |
51 |
# include <sys/time.h> |
52 |
# else |
53 |
# include <time.h> |
54 |
# endif |
55 |
#endif |
56 |
|
57 |
#include "lib/compat/compat.h" |
58 |
#include "debug.h" |
59 |
#include "core_config.h" |
60 |
#include "core_party.h" |
61 |
#include "core_binds.h" |
62 |
#include "logfile.h" |
63 |
#include "terminal.h" |
64 |
#include "bg.h" |
65 |
#include "main.h" |
66 |
|
67 |
#ifdef STOP_UAC /* OSF/1 complains a lot */ |
68 |
# include <sys/sysinfo.h> |
69 |
# define UAC_NOPRINT 0x00000001 /* Don't report unaligned fixups */ |
70 |
#endif |
71 |
|
72 |
#ifdef CYGWIN_HACKS |
73 |
# include <windows.h> |
74 |
#endif |
75 |
|
76 |
#ifndef _POSIX_SOURCE |
77 |
# define _POSIX_SOURCE 1 /* Solaris needs this */ |
78 |
#endif |
79 |
|
80 |
#define RUNMODE_NORMAL 1 |
81 |
#define RUNMODE_SHUTDOWN 2 |
82 |
#define RUNMODE_RESTART 3 |
83 |
|
84 |
int runmode = 1; /* The most important variable ever! */ |
85 |
int backgrd = 1; /* Run in the background? */ |
86 |
int make_userfile = 0; /* Start bot in make-userfile mode? */ |
87 |
int terminal_mode = 0; /* Terminal mode */ |
88 |
|
89 |
const char *configfile = NULL; /* Name of the config file */ |
90 |
char pid_file[512]; /* Name of Eggdrop's pid file */ |
91 |
|
92 |
time_t online_since; /* Time the bot was started */ |
93 |
time_t now; /* Current time */ |
94 |
egg_timeval_t egg_timeval_now; /* Current time in seconds and microseconds. */ |
95 |
|
96 |
int use_stderr = 1; /* Send stuff to stderr instead of logfiles? */ |
97 |
|
98 |
char version[81]; |
99 |
|
100 |
static int lastmin = 99; |
101 |
static struct tm nowtm; |
102 |
|
103 |
void core_config_init(); |
104 |
|
105 |
void fatal(const char *s, int recoverable) |
106 |
{ |
107 |
putlog(LOG_MISC, "*", "Fatal: %s", s); |
108 |
flushlogs(); |
109 |
unlink(pid_file); |
110 |
if (!recoverable) { |
111 |
bg_send_quit(BG_ABORT); |
112 |
exit(1); |
113 |
} |
114 |
} |
115 |
|
116 |
static void got_bus(int z) |
117 |
{ |
118 |
fatal("BUS ERROR.", 1); |
119 |
#ifdef SA_RESETHAND |
120 |
kill(getpid(), SIGBUS); |
121 |
#else |
122 |
bg_send_quit(BG_ABORT); |
123 |
exit(1); |
124 |
#endif |
125 |
} |
126 |
|
127 |
static void got_segv(int z) |
128 |
{ |
129 |
fatal("SEGMENT VIOLATION.", 1); |
130 |
#ifdef SA_RESETHAND |
131 |
kill(getpid(), SIGSEGV); |
132 |
#else |
133 |
bg_send_quit(BG_ABORT); |
134 |
exit(1); |
135 |
#endif |
136 |
} |
137 |
|
138 |
static void got_fpe(int z) |
139 |
{ |
140 |
fatal("FLOATING POINT ERROR.", 0); |
141 |
} |
142 |
|
143 |
static void got_term(int z) |
144 |
{ |
145 |
eggdrop_event("sigterm"); |
146 |
if (core_config.die_on_sigterm) |
147 |
core_shutdown(SHUTDOWN_SIGTERM, NULL, NULL); |
148 |
else |
149 |
putlog(LOG_MISC, "*", _("Received TERM signal (ignoring).")); |
150 |
} |
151 |
|
152 |
static void got_quit(int z) |
153 |
{ |
154 |
eggdrop_event("sigquit"); |
155 |
putlog(LOG_MISC, "*", _("Received QUIT signal (ignoring).")); |
156 |
return; |
157 |
} |
158 |
|
159 |
static void got_hup(int z) |
160 |
{ |
161 |
eggdrop_event("sighup"); |
162 |
putlog(LOG_MISC, "*", _("Received HUP signal (ignoring).")); |
163 |
return; |
164 |
} |
165 |
|
166 |
#if 0 |
167 |
static void got_ill(int z) |
168 |
{ |
169 |
eggdrop_event("sigill"); |
170 |
putlog(LOG_MISC, "*", _("Received ILL signal (ignoring).")); |
171 |
} |
172 |
#endif |
173 |
|
174 |
|
175 |
static void print_version(void) |
176 |
{ |
177 |
printf("%s\n", version); |
178 |
} |
179 |
|
180 |
static void print_help(char *const *argv) |
181 |
{ |
182 |
print_version(); |
183 |
printf(_("\nUsage: %s [OPTIONS]... [FILE]\n"), argv[0]); |
184 |
printf(_("\n\ |
185 |
-h, --help Print help and exit\n\ |
186 |
-v, --version Print version and exit\n\ |
187 |
-n, --foreground Don't go into the background (default=off)\n\ |
188 |
-c --channel-stats (with -n) Display channel stats every 10 seconds\n\ |
189 |
-t --terminal (with -n) Use terminal to simulate dcc-chat\n\ |
190 |
-m --make-userfile Userfile creation mode\n\ |
191 |
FILE optional config filename (default 'config.xml')\n")); |
192 |
printf("\n"); |
193 |
} |
194 |
|
195 |
static void do_args(int argc, char *const *argv) |
196 |
{ |
197 |
int c; |
198 |
|
199 |
optarg = 0; |
200 |
optind = 1; |
201 |
opterr = 1; |
202 |
optopt = '?'; |
203 |
|
204 |
while (1) { |
205 |
int option_index = 0; |
206 |
|
207 |
static struct option long_options[] = { |
208 |
{"help", 0, NULL, 'h'}, |
209 |
{"version", 0, NULL, 'v'}, |
210 |
{"load-module", 1, NULL, 'p'}, |
211 |
{"foreground", 0, NULL, 'n'}, |
212 |
{"terminal", 0, NULL, 't'}, |
213 |
{"make-userfile", 0, NULL, 'm'}, |
214 |
{NULL, 0, NULL, 0} |
215 |
}; |
216 |
|
217 |
c = getopt_long(argc, argv, "hvp:nctm", long_options, &option_index); |
218 |
if (c == -1) break; |
219 |
switch (c) { |
220 |
case 'n': |
221 |
backgrd = 0; |
222 |
break; |
223 |
case 't': |
224 |
terminal_mode = 1; |
225 |
break; |
226 |
case 'm': |
227 |
make_userfile = 1; |
228 |
break; |
229 |
case 'v': |
230 |
print_version(); |
231 |
bg_send_quit(BG_ABORT); |
232 |
exit(0); |
233 |
break; /* this should never be reached */ |
234 |
case 'h': |
235 |
print_help(argv); |
236 |
bg_send_quit(BG_ABORT); |
237 |
exit(0); |
238 |
break; /* this should never be reached */ |
239 |
case 0: /* Long option with no short option */ |
240 |
case '?': /* Invalid option. */ |
241 |
/* getopt_long() already printed an error message. */ |
242 |
bg_send_quit(BG_ABORT); |
243 |
exit(1); |
244 |
default: /* bug: option not considered. */ |
245 |
fprintf(stderr, _("%s: option unknown: %c\n"), argv[0], c); |
246 |
bg_send_quit(BG_ABORT); |
247 |
exit(1); |
248 |
break; /* this should never be reached */ |
249 |
} |
250 |
} |
251 |
if (optind < argc) configfile = argv[optind]; |
252 |
else configfile = "config.xml"; |
253 |
} |
254 |
|
255 |
/* Called once a second. |
256 |
*/ |
257 |
static int core_secondly() |
258 |
{ |
259 |
static int cnt = 0; |
260 |
int miltime; |
261 |
|
262 |
check_bind_secondly(); |
263 |
cnt++; |
264 |
memcpy(&nowtm, localtime(&now), sizeof(struct tm)); |
265 |
if (nowtm.tm_min != lastmin) { |
266 |
int i = 0; |
267 |
|
268 |
/* Once a minute */ |
269 |
lastmin = (lastmin + 1) % 60; |
270 |
eggdrop_event("minutely"); |
271 |
check_bind_time(&nowtm); |
272 |
/* In case for some reason more than 1 min has passed: */ |
273 |
while (nowtm.tm_min != lastmin) { |
274 |
/* Timer drift, dammit */ |
275 |
putlog(LOG_DEBUG, "*", "timer: drift (lastmin=%d, now=%d)", lastmin, nowtm.tm_min); |
276 |
i++; |
277 |
lastmin = (lastmin + 1) % 60; |
278 |
eggdrop_event("minutely"); |
279 |
} |
280 |
if (i > 1) putlog(LOG_MISC, "*", _("Warning: timer drift (%d minutes)."), i); |
281 |
|
282 |
miltime = (nowtm.tm_hour * 100) + (nowtm.tm_min); |
283 |
if (nowtm.tm_min % 5 == 0) { /* 5 minutes */ |
284 |
eggdrop_event("5minutely"); |
285 |
if (!miltime) { /* At midnight */ |
286 |
char s[25]; |
287 |
|
288 |
strlcpy(s, ctime(&now), sizeof s); |
289 |
putlog(LOG_ALL, "*", "--- %.11s%s", s, s + 20); |
290 |
eggdrop_event("backup"); |
291 |
eggdrop_event("daily"); |
292 |
} |
293 |
} |
294 |
} |
295 |
return(0); |
296 |
} |
297 |
|
298 |
|
299 |
int file_check(const char *filename) |
300 |
{ |
301 |
struct stat sbuf = {0}; |
302 |
int r; |
303 |
|
304 |
r = stat(filename, &sbuf); |
305 |
if (r) return(-1); |
306 |
errno = 0; |
307 |
if (sbuf.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) return(-1); |
308 |
return(0); |
309 |
} |
310 |
|
311 |
static int create_userfile(void) |
312 |
{ |
313 |
user_t *owner; |
314 |
char handle[512], password[12]; |
315 |
int len; |
316 |
|
317 |
printf("\n"); |
318 |
if (user_count() != 0) { |
319 |
printf("You are trying to create a new userfile, but the old one still exists (%s)!\n", core_config.userfile); |
320 |
printf("Please remove the userfile, or do not pass the -m option.\n\n"); |
321 |
return(-1); |
322 |
} |
323 |
|
324 |
printf("Hello! I see you are creating a new userfile.\n\n"); |
325 |
printf("Let's create the owner account.\n\n"); |
326 |
do { |
327 |
printf("Enter the owner handle: "); |
328 |
fflush(stdout); |
329 |
fgets(handle, sizeof(handle), stdin); |
330 |
for (len = 0; handle[len]; len++) { |
331 |
if (!ispunct(handle[len]) && !isalnum(handle[len])) break; |
332 |
} |
333 |
if (len == 0) printf("Come on, enter a real handle.\n\n"); |
334 |
} while (len <= 0); |
335 |
handle[len] = 0; |
336 |
|
337 |
owner = user_new(handle); |
338 |
if (!owner) { |
339 |
printf("Failed to create user record! Out of memory?\n\n"); |
340 |
return(-1); |
341 |
} |
342 |
|
343 |
user_rand_pass(password, sizeof(password)); |
344 |
user_set_pass(owner, password); |
345 |
user_set_flags_str(owner, NULL, "+n"); |
346 |
printf("Your owner handle is '%s' and your password is '%s' (without the quotes).\n\n", handle, password); |
347 |
memset(password, 0, sizeof(password)); |
348 |
str_redup(&core_config.owner, handle); |
349 |
core_config_save(); |
350 |
user_save(core_config.userfile); |
351 |
|
352 |
return(0); |
353 |
} |
354 |
|
355 |
static void init_signals(void) |
356 |
{ |
357 |
struct sigaction sv; |
358 |
|
359 |
|
360 |
sv.sa_handler = got_bus; |
361 |
sigemptyset(&sv.sa_mask); |
362 |
#ifdef SA_RESETHAND |
363 |
sv.sa_flags = SA_RESETHAND; |
364 |
#else |
365 |
sv.sa_flags = 0; |
366 |
#endif |
367 |
sigaction(SIGBUS, &sv, NULL); |
368 |
|
369 |
sv.sa_handler = got_segv; |
370 |
sigaction(SIGSEGV, &sv, NULL); |
371 |
#ifdef SA_RESETHAND |
372 |
sv.sa_flags = 0; |
373 |
#endif |
374 |
|
375 |
sv.sa_handler = got_fpe; |
376 |
sigaction(SIGFPE, &sv, NULL); |
377 |
|
378 |
sv.sa_handler = got_term; |
379 |
sigaction(SIGTERM, &sv, NULL); |
380 |
|
381 |
sv.sa_handler = got_hup; |
382 |
sigaction(SIGHUP, &sv, NULL); |
383 |
|
384 |
sv.sa_handler = got_quit; |
385 |
sigaction(SIGQUIT, &sv, NULL); |
386 |
|
387 |
sv.sa_handler = SIG_IGN; |
388 |
sigaction(SIGPIPE, &sv, NULL); |
389 |
|
390 |
/* XXX: why is this disabled? */ |
391 |
#if 0 |
392 |
sv.sa_handler = got_ill; |
393 |
sigaction(SIGILL, &sv, NULL); |
394 |
#endif |
395 |
} |
396 |
|
397 |
static int init_bg_and_pid (void) |
398 |
{ |
399 |
FILE *f; |
400 |
int xx; |
401 |
char s[25]; |
402 |
|
403 |
if (backgrd) |
404 |
bg_prepare_split(); |
405 |
|
406 |
/* XXX: what shall we do if we've restarted and one changed our |
407 |
* XXX: botname? Remove old pid_file and create new one? Then this |
408 |
* XXX: is the wrong place. */ |
409 |
snprintf(pid_file, sizeof pid_file, "pid.%s", core_config.botname); |
410 |
|
411 |
f = fopen(pid_file, "r"); |
412 |
if (f != NULL) { |
413 |
fgets(s, 10, f); |
414 |
xx = atoi(s); |
415 |
kill(xx, SIGCHLD); /* Meaningless kill to determine if pid is used */ |
416 |
if (errno != ESRCH) { |
417 |
printf("I detect %s already running from this directory.\n", core_config.botname); |
418 |
printf("If this is incorrect, please erase '%s'.\n", pid_file); |
419 |
bg_send_quit(BG_ABORT); |
420 |
return 0; |
421 |
} |
422 |
} |
423 |
|
424 |
if (backgrd) { /* Move into background? */ |
425 |
#ifndef CYGWIN_HACKS |
426 |
bg_do_split(); |
427 |
} |
428 |
else { |
429 |
#endif |
430 |
xx = getpid(); |
431 |
if (xx != 0) { |
432 |
FILE *fp; |
433 |
|
434 |
unlink(pid_file); |
435 |
fp = fopen(pid_file, "w"); |
436 |
if (fp != NULL) { |
437 |
fprintf(fp, "%u\n", xx); |
438 |
if (fflush(fp)) { |
439 |
/* Let the bot live since this doesn't appear to be a botchk */ |
440 |
printf("WARNING: Could not write pid file '%s'.\n", pid_file); |
441 |
fclose(fp); |
442 |
unlink(pid_file); |
443 |
} |
444 |
else fclose(fp); |
445 |
} |
446 |
else printf("WARNING: Could not write pid file '%s'.\n", pid_file); |
447 |
#ifdef CYGWIN_HACKS |
448 |
printf("Launched into the background (pid: %d).\n\n", xx); |
449 |
#endif |
450 |
} |
451 |
} |
452 |
|
453 |
use_stderr = 0; /* Stop writing to stderr now */ |
454 |
|
455 |
if (backgrd) { |
456 |
/* Try to disassociate from controlling terminal (finger cross) */ |
457 |
#if HAVE_SETPGID && !defined(CYGWIN_HACKS) |
458 |
setpgid(0, 0); |
459 |
#endif |
460 |
/* Tcl wants the stdin, stdout and stderr file handles kept open. */ |
461 |
freopen("/dev/null", "r", stdin); |
462 |
freopen("/dev/null", "w", stdout); |
463 |
freopen("/dev/null", "w", stderr); |
464 |
#ifdef CYGWIN_HACKS |
465 |
FreeConsole(); |
466 |
#endif |
467 |
} |
468 |
|
469 |
return 1; |
470 |
} |
471 |
|
472 |
static void core_shutdown_or_restart() |
473 |
{ |
474 |
/* notifiy shutdown listeners */ |
475 |
check_bind_shutdown(); |
476 |
|
477 |
putlog(LOG_MISC, "*", _("Saving user file...")); |
478 |
user_save(core_config.userfile); |
479 |
|
480 |
putlog(LOG_MISC, "*", _("Saving config file...")); |
481 |
core_config_save(); |
482 |
|
483 |
/* shutdown logging */ |
484 |
logfile_shutdown(); |
485 |
|
486 |
/* shutdown libeggdrop */ |
487 |
eggdrop_shutdown(); |
488 |
|
489 |
/* force a garbage run */ |
490 |
garbage_run(); |
491 |
|
492 |
/* just remove pid file if didn't restart */ |
493 |
if (runmode != RUNMODE_RESTART) |
494 |
unlink(pid_file); |
495 |
} |
496 |
|
497 |
int main(int argc, char **argv) |
498 |
{ |
499 |
int timeout; |
500 |
|
501 |
#ifdef DEBUG |
502 |
{ |
503 |
# include <sys/resource.h> |
504 |
struct rlimit cdlim; |
505 |
|
506 |
cdlim.rlim_cur = RLIM_INFINITY; |
507 |
cdlim.rlim_max = RLIM_INFINITY; |
508 |
setrlimit(RLIMIT_CORE, &cdlim); |
509 |
} |
510 |
#endif |
511 |
|
512 |
init_signals(); |
513 |
|
514 |
#ifdef ENABLE_NLS |
515 |
setlocale(LC_MESSAGES, ""); |
516 |
bindtextdomain(PACKAGE, LOCALEDIR); |
517 |
textdomain(PACKAGE); |
518 |
#endif |
519 |
|
520 |
/* Initialize ltdl. */ |
521 |
LTDL_SET_PRELOADED_SYMBOLS(); |
522 |
if (lt_dlinit()) { |
523 |
printf("Fatal error initializing ltdl: %s\n", lt_dlerror()); |
524 |
return(-1); |
525 |
} |
526 |
|
527 |
snprintf(version, sizeof version, "Eggdrop v%s (C) 1997 Robey Pointer (C) 2004 Eggheads Development Team", VERSION); |
528 |
|
529 |
#ifdef STOP_UAC |
530 |
{ |
531 |
int nvpair[2]; |
532 |
|
533 |
nvpair[0] = SSIN_UACPROC; |
534 |
nvpair[1] = UAC_NOPRINT; |
535 |
setsysinfo(SSI_NVPAIRS, (char *) nvpair, 1, NULL, 0); |
536 |
} |
537 |
#endif |
538 |
|
539 |
timer_update_now(&egg_timeval_now); |
540 |
now = egg_timeval_now.sec; |
541 |
memcpy(&nowtm, localtime(&now), sizeof(struct tm)); |
542 |
lastmin = nowtm.tm_min; |
543 |
|
544 |
srandom(now % (getpid() + getppid())); |
545 |
|
546 |
do_args(argc, argv); |
547 |
printf("\n%s\n", version); |
548 |
printf("WARNING: Do NOT run this DEVELOPMENT version for any purpose other than testing.\n\n"); |
549 |
|
550 |
/* we may not run as root */ |
551 |
if (((int) getuid() == 0) || ((int) geteuid() == 0)) { |
552 |
fatal("Eggdrop will not run as root!", 0); |
553 |
return -1; |
554 |
} |
555 |
|
556 |
/* config file may not be world read/writeable */ |
557 |
if (file_check(configfile)) { |
558 |
if (errno) perror(configfile); |
559 |
else { |
560 |
fprintf(stderr, "ERROR\n"); |
561 |
fprintf(stderr, "\tCheck file permissions on your config file!"); |
562 |
fprintf(stderr, "\tMake sure other groups and users cannot read/write it.\n"); |
563 |
return -1; |
564 |
} |
565 |
} |
566 |
|
567 |
/* set uptime */ |
568 |
online_since = now; |
569 |
|
570 |
do { |
571 |
egg_timeval_t howlong; |
572 |
|
573 |
/* default select timeout is 1 sec */ |
574 |
howlong.sec = 1; |
575 |
howlong.usec = 0; |
576 |
|
577 |
timer_create_repeater(&howlong, "main loop", core_secondly); |
578 |
|
579 |
/* init core */ |
580 |
core_init(); |
581 |
|
582 |
/* set normal running mode */ |
583 |
runmode = RUNMODE_NORMAL; |
584 |
|
585 |
putlog(LOG_DEBUG, "*", "Entering main loop."); |
586 |
|
587 |
/* main loop */ |
588 |
while (runmode == RUNMODE_NORMAL) { |
589 |
timer_update_now(&egg_timeval_now); |
590 |
now = egg_timeval_now.sec; |
591 |
random(); /* Woop, lets really jumble things */ |
592 |
timer_run(); |
593 |
if (timer_get_shortest(&howlong)) timeout = 1000; |
594 |
else timeout = howlong.sec * 1000 + howlong.usec / 1000; |
595 |
sockbuf_update_all(timeout); |
596 |
garbage_run(); |
597 |
} |
598 |
|
599 |
/* Save user file, config file, ... */ |
600 |
core_shutdown_or_restart(); |
601 |
|
602 |
/* the only chance to loop again is that running = 2, meaning |
603 |
we have a restart */ |
604 |
} while (runmode == RUNMODE_RESTART); |
605 |
|
606 |
return 1; |
607 |
} |
608 |
|
609 |
int core_init() |
610 |
{ |
611 |
int i; |
612 |
char *name; |
613 |
void *config_root, *entry; |
614 |
char s[25]; |
615 |
|
616 |
/* init libeggdrop */ |
617 |
eggdrop_init(); |
618 |
|
619 |
/* load config */ |
620 |
core_config_init(configfile); |
621 |
|
622 |
/* did the user specify -m? */ |
623 |
if (make_userfile) { |
624 |
if (create_userfile()) return(-1); |
625 |
make_userfile = 0; |
626 |
} |
627 |
|
628 |
/* init background mode and pid file */ |
629 |
if (runmode != RUNMODE_RESTART) |
630 |
init_bg_and_pid(); |
631 |
|
632 |
/* init logging */ |
633 |
logfile_init(); |
634 |
|
635 |
/* just issue this "Loading Eggdrop" message if we are not |
636 |
* restarting */ |
637 |
if (runmode != RUNMODE_RESTART) { |
638 |
strlcpy(s, ctime(&now), sizeof s); |
639 |
strcpy(&s[11], &s[20]); |
640 |
putlog(LOG_ALL, "*", "Loading Eggdrop %s (%s)", VERSION, s); |
641 |
} |
642 |
|
643 |
/* load userlist */ |
644 |
if (core_config.userfile) |
645 |
user_load(core_config.userfile); |
646 |
|
647 |
/* init core bindings */ |
648 |
core_binds_init(); |
649 |
|
650 |
/* init core partyline */ |
651 |
core_party_init(); |
652 |
|
653 |
/* Load core help */ |
654 |
help_load_by_module ("core"); |
655 |
|
656 |
/* Put the module directory in the ltdl search path. */ |
657 |
if (core_config.module_path) |
658 |
module_add_dir(core_config.module_path); |
659 |
|
660 |
/* Scan the autoload section of config. */ |
661 |
config_root = config_get_root("eggdrop"); |
662 |
for (i = 0; (entry = config_exists(config_root, "eggdrop", 0, "autoload", 0, "module", i, NULL)); i++) { |
663 |
name = NULL; |
664 |
config_get_str(&name, entry, NULL); |
665 |
module_load(name); |
666 |
} |
667 |
for (i = 0; (entry = config_exists(config_root, "eggdrop", 0, "autoload", 0, "script", i, NULL)); i++) { |
668 |
name = NULL; |
669 |
config_get_str(&name, entry, NULL); |
670 |
script_load(name); |
671 |
} |
672 |
|
673 |
/* notify init listeners */ |
674 |
check_bind_init(); |
675 |
|
676 |
/* start terminal */ |
677 |
if (runmode != RUNMODE_RESTART) |
678 |
if (terminal_mode) |
679 |
terminal_init(); |
680 |
|
681 |
return 1; |
682 |
} |
683 |
|
684 |
int core_restart(const char *nick) |
685 |
{ |
686 |
putlog(LOG_MISC, "*", "Restarting..."); |
687 |
runmode = RUNMODE_RESTART; |
688 |
return 1; |
689 |
} |
690 |
|
691 |
int core_shutdown(int how, const char *nick, const char *reason) |
692 |
{ |
693 |
if (how == SHUTDOWN_SIGTERM) |
694 |
putlog(LOG_MISC, "*", ("Received TERM signal, shutting down.")); |
695 |
else if (how != SHUTDOWN_RESTART) |
696 |
putlog(LOG_MISC, "*", ("Shutdown requested by %s: %s"), nick, |
697 |
(reason) ? reason : _("No reason")); |
698 |
|
699 |
/* check how to shut down */ |
700 |
switch (how) { |
701 |
|
702 |
case (SHUTDOWN_RESTART): |
703 |
runmode = RUNMODE_RESTART; |
704 |
break; |
705 |
|
706 |
case (SHUTDOWN_GRACEFULL): |
707 |
runmode = RUNMODE_SHUTDOWN; |
708 |
break; |
709 |
|
710 |
/* These two cases are treaded special because something |
711 |
* unusual happened and we're better off if we exit() NOW |
712 |
* than doing a gracefull shutdown with freeing all |
713 |
* memory, closing all sockets, ... */ |
714 |
case (SHUTDOWN_HARD): |
715 |
case (SHUTDOWN_SIGTERM): |
716 |
runmode = RUNMODE_SHUTDOWN; |
717 |
core_shutdown_or_restart(); |
718 |
exit(0); |
719 |
break; |
720 |
|
721 |
} |
722 |
|
723 |
return BIND_RET_LOG; |
724 |
} |