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