00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #ifndef lint
00022 static const char rcsid[] = "$Id: main.c,v 1.191 2007-11-06 00:05:40 sven Exp $";
00023 #endif
00024
00025 #include <eggdrop/eggdrop.h>
00026 #include <unistd.h>
00027 #include <fcntl.h>
00028 #include <sys/stat.h>
00029 #include <errno.h>
00030 #include <signal.h>
00031 #include <locale.h>
00032 #include <ltdl.h>
00033
00034 #include "debug.h"
00035 #include "core_config.h"
00036 #include "core_party.h"
00037 #include "core_binds.h"
00038 #include "logfile.h"
00039 #include "terminal.h"
00040 #include "bg.h"
00041 #include "main.h"
00042
00043 #ifdef STOP_UAC
00044 # include <sys/sysinfo.h>
00045 # define UAC_NOPRINT 0x00000001
00046 #endif
00047
00048 #ifdef CYGWIN_HACKS
00049 # include <windows.h>
00050 #endif
00051
00052 #ifndef _POSIX_SOURCE
00053 # define _POSIX_SOURCE 1
00054 #endif
00055
00056 #define RUNMODE_NORMAL 1
00057 #define RUNMODE_SHUTDOWN 2
00058 #define RUNMODE_RESTART 3
00059
00060 int runmode = 1;
00061 int backgrd = 1;
00062 int make_userfile = 0;
00063 int terminal_mode = 0;
00064
00065
00066 int debug_run = 0;
00067
00068 const char *configfile = NULL;
00069 char pid_file[512];
00070
00071 time_t online_since;
00072 time_t now;
00073 egg_timeval_t egg_timeval_now;
00074
00075 int use_stderr = 1;
00076
00077 char version[81];
00078
00079 static int lastmin = 99;
00080 static struct tm nowtm;
00081
00082 void fatal(const char *errmsg)
00083 {
00084 putlog(LOG_MISC, "*", "Fatal: %s", errmsg);
00085 flushlogs();
00086 exit(1);
00087 }
00088
00089 static void got_bus(int z)
00090 {
00091 fatal("BUS ERROR.");
00092 }
00093
00094 static void got_segv(int z)
00095 {
00096 fatal("SEGMENT VIOLATION.");
00097 }
00098
00099 static void got_fpe(int z)
00100 {
00101 fatal("FLOATING POINT ERROR.");
00102 }
00103
00104 static void got_term(int z)
00105 {
00106 eggdrop_event("sigterm");
00107 if (core_config.die_on_sigterm) core_shutdown(SHUTDOWN_SIGTERM, NULL, NULL);
00108 else putlog(LOG_MISC, "*", _("Received TERM signal (ignoring)."));
00109 }
00110
00111 static void got_quit(int z)
00112 {
00113 eggdrop_event("sigquit");
00114 putlog(LOG_MISC, "*", _("Received QUIT signal (ignoring)."));
00115 return;
00116 }
00117
00118 static void got_hup(int z)
00119 {
00120 eggdrop_event("sighup");
00121 putlog(LOG_MISC, "*", _("Received HUP signal (ignoring)."));
00122 return;
00123 }
00124
00125 static void print_version(void)
00126 {
00127 printf("%s\n", version);
00128 }
00129
00130 static void print_help(char *const *argv)
00131 {
00132 print_version();
00133 printf(_("\nUsage: %s [OPTIONS]... [FILE]\n"), argv[0]);
00134 printf(_("\n\
00135 -h, --help Print help and exit\n\
00136 -v, --version Print version and exit\n\
00137 -n, --foreground Don't go into the background (default=off)\n\
00138 -c --channel-stats (with -n) Display channel stats every 10 seconds\n\
00139 -t --terminal (with -n) Use terminal to simulate dcc-chat\n\
00140 -m --make-userfile Userfile creation mode\n\
00141 -d --debug Do a debugging dry-run\n\
00142 FILE optional config filename (default 'config.xml')\n"));
00143 printf("\n");
00144 }
00145
00146 static void do_args(int argc, char **argv)
00147 {
00148 int c;
00149
00150 optarg = 0;
00151 optind = 1;
00152 opterr = 1;
00153 optopt = '?';
00154
00155 while (1) {
00156 int option_index = 0;
00157
00158 static struct option long_options[] = {
00159 { "help", 0, NULL, 'h' },
00160 { "version", 0, NULL, 'v' },
00161 { "load-module", 1, NULL, 'p' },
00162 { "foreground", 0, NULL, 'n' },
00163 { "terminal", 0, NULL, 't' },
00164 { "make-userfile", 0, NULL, 'm' },
00165 { "debug", 0, NULL, 'd' },
00166 {NULL, 0, NULL, 0}
00167 };
00168
00169 c = getopt_long(argc, argv, "hvp:nctmd", long_options, &option_index);
00170 if (c == -1) break;
00171 switch (c) {
00172 case 'n':
00173 backgrd = 0;
00174 break;
00175 case 't':
00176 terminal_mode = 1;
00177 break;
00178 case 'm':
00179 make_userfile = 1;
00180 break;
00181 case 'd':
00182 backgrd = 0;
00183 debug_run = 1;
00184 break;
00185 case 'v':
00186 print_version();
00187 exit(0);
00188 break;
00189 case 'h':
00190 print_help(argv);
00191 exit(0);
00192 break;
00193 case 0:
00194 case '?':
00195
00196 exit(1);
00197 default:
00198 fprintf(stderr, _("%s: option unknown: %c\n"), argv[0], c);
00199 exit(1);
00200 break;
00201 }
00202 }
00203 if (optind < argc) {
00204 configfile = argv[optind++];
00205 eggdrop_set_params((const char **)&argv[optind], argc-optind);
00206 }
00207 else configfile = "config.xml";
00208 }
00209
00210
00211
00212 static int core_secondly()
00213 {
00214 static int cnt = 0;
00215 int miltime;
00216
00217 check_bind_secondly();
00218 cnt++;
00219 memcpy(&nowtm, localtime(&now), sizeof(struct tm));
00220 if (nowtm.tm_min != lastmin) {
00221 int i = 0;
00222
00223
00224 lastmin = (lastmin + 1) % 60;
00225 eggdrop_event("minutely");
00226 check_bind_time(&nowtm);
00227
00228 while (nowtm.tm_min != lastmin) {
00229
00230 putlog(LOG_DEBUG, "*", "timer: drift (lastmin=%d, now=%d)", lastmin, nowtm.tm_min);
00231 i++;
00232 lastmin = (lastmin + 1) % 60;
00233 eggdrop_event("minutely");
00234 }
00235 if (i > 1) putlog(LOG_MISC, "*", _("Warning: timer drift (%d minutes)."), i);
00236
00237 miltime = (nowtm.tm_hour * 100) + (nowtm.tm_min);
00238 if (nowtm.tm_min % 5 == 0) {
00239 eggdrop_event("5minutely");
00240 botnet_autolink();
00241 }
00242 if (nowtm.tm_min == 0) eggdrop_event("hourly");
00243 if (!miltime) {
00244 char s[25];
00245
00246 strlcpy(s, ctime(&now), sizeof s);
00247 putlog(LOG_ALL, "*", "--- %.11s%s", s, s + 20);
00248 eggdrop_event("backup");
00249 eggdrop_event("daily");
00250 }
00251 }
00252 return(0);
00253 }
00254
00255
00256 int file_check(const char *filename)
00257 {
00258 struct stat sbuf = {0};
00259 int r;
00260
00261 r = stat(filename, &sbuf);
00262 if (r) return(-1);
00263 errno = 0;
00264 if (sbuf.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) return(-1);
00265 return(0);
00266 }
00267
00268 static int create_userfile(void)
00269 {
00270 user_t *owner;
00271 char handle[512], password[12];
00272 int len;
00273
00274 printf("\n");
00275 if (user_count() != 0) {
00276 printf("You are trying to create a new userfile, but the old one still exists (%s)!\n", core_config.userfile);
00277 printf("Please remove the userfile, or do not pass the -m option.\n\n");
00278 return(-1);
00279 }
00280
00281 printf("Hello! I see you are creating a new userfile.\n\n");
00282 printf("Let's create the owner account.\n\n");
00283 do {
00284 printf("Enter the owner handle: ");
00285 fflush(stdout);
00286 fgets(handle, sizeof(handle), stdin);
00287 for (len = 0; handle[len]; len++) {
00288 if (!ispunct(handle[len]) && !isalnum(handle[len])) break;
00289 }
00290 if (len == 0) printf("Come on, enter a real handle.\n\n");
00291 } while (len <= 0);
00292 handle[len] = 0;
00293
00294 owner = user_new(handle);
00295 if (!owner) {
00296 printf("Failed to create user record! Out of memory?\n\n");
00297 return(-1);
00298 }
00299
00300 user_rand_pass(password, sizeof(password));
00301 user_set_pass(owner, password);
00302 user_set_flags_str(owner, NULL, "+n");
00303 printf("Your owner handle is '%s' and your password is '%s' (without the quotes).\n\n", handle, password);
00304 memset(password, 0, sizeof(password));
00305 str_redup(&core_config.owner, handle);
00306 core_config_save();
00307 user_save(core_config.userfile);
00308
00309 return(0);
00310 }
00311
00312 static void init_signals(void)
00313 {
00314 struct sigaction sv;
00315
00316
00317 sv.sa_handler = got_bus;
00318 sigemptyset(&sv.sa_mask);
00319 #ifdef SA_RESETHAND
00320 sv.sa_flags = SA_RESETHAND;
00321 #else
00322 sv.sa_flags = 0;
00323 #endif
00324 sigaction(SIGBUS, &sv, NULL);
00325
00326 sv.sa_handler = got_segv;
00327
00328 #ifdef SA_RESETHAND
00329 sv.sa_flags = 0;
00330 #endif
00331
00332 sv.sa_handler = got_fpe;
00333 sigaction(SIGFPE, &sv, NULL);
00334
00335 sv.sa_handler = got_term;
00336 sigaction(SIGTERM, &sv, NULL);
00337
00338 sv.sa_handler = got_hup;
00339 sigaction(SIGHUP, &sv, NULL);
00340
00341 sv.sa_handler = got_quit;
00342 sigaction(SIGQUIT, &sv, NULL);
00343
00344 sv.sa_handler = SIG_IGN;
00345 sigaction(SIGPIPE, &sv, NULL);
00346
00347 sv.sa_handler = SIG_IGN;
00348 sigaction(SIGUSR1, &sv, NULL);
00349 }
00350
00351 static void core_shutdown_or_restart()
00352 {
00353
00354 check_bind_shutdown();
00355
00356 putlog(LOG_MISC, "*", _("Saving user file..."));
00357 user_save(core_config.userfile);
00358
00359
00360 if (terminal_mode)
00361 terminal_shutdown(runmode);
00362
00363
00364
00365
00366
00367 core_binds_shutdown();
00368
00369
00370 logfile_shutdown();
00371
00372 putlog(LOG_MISC, "*", _("Saving config file..."));
00373 core_config_save();
00374
00375
00376 eggdrop_shutdown();
00377
00378
00379 garbage_run();
00380
00381
00382 if (runmode != RUNMODE_RESTART)
00383 unlink(pid_file);
00384 }
00385
00386 int main(int argc, char **argv)
00387 {
00388 int timeout;
00389
00390 #ifdef DEBUG
00391 {
00392 # include <sys/resource.h>
00393 struct rlimit cdlim;
00394
00395 cdlim.rlim_cur = RLIM_INFINITY;
00396 cdlim.rlim_max = RLIM_INFINITY;
00397 setrlimit(RLIMIT_CORE, &cdlim);
00398 }
00399 #endif
00400
00401 init_signals();
00402
00403 #ifdef ENABLE_NLS
00404 setlocale(LC_MESSAGES, "");
00405 bindtextdomain(PACKAGE, LOCALEDIR);
00406 textdomain(PACKAGE);
00407 #endif
00408
00409
00410 LTDL_SET_PRELOADED_SYMBOLS();
00411 if (lt_dlinit()) {
00412 printf("Fatal error initializing ltdl: %s\n", lt_dlerror());
00413 return(-1);
00414 }
00415
00416 snprintf(version, sizeof version, "Eggdrop v%s (C) 1997 Robey Pointer (C) 2004 Eggheads Development Team", VERSION);
00417
00418 #ifdef STOP_UAC
00419 {
00420 int nvpair[2];
00421
00422 nvpair[0] = SSIN_UACPROC;
00423 nvpair[1] = UAC_NOPRINT;
00424 setsysinfo(SSI_NVPAIRS, (char *) nvpair, 1, NULL, 0);
00425 }
00426 #endif
00427
00428 timer_update_now(&egg_timeval_now);
00429 now = egg_timeval_now.sec;
00430 memcpy(&nowtm, localtime(&now), sizeof(struct tm));
00431 lastmin = nowtm.tm_min;
00432
00433 srandom(now % (getpid() + getppid()));
00434
00435 do_args(argc, argv);
00436 printf("\n%s\n", version);
00437 printf("WARNING: Do NOT run this DEVELOPMENT version for any purpose other than testing.\n\n");
00438
00439
00440 if (((int) getuid() == 0) || ((int) geteuid() == 0)) {
00441 fprintf(stderr, "ERROR\n");
00442 fprintf(stderr, "\tEggdrop will not run as root!\n\n");
00443 return -1;
00444 }
00445
00446 init_flag_map();
00447
00448
00449 if (file_check(configfile)) {
00450 fprintf(stderr, "ERROR\n");
00451 if (errno) {
00452 fprintf(stderr, "\tFailed to load config file '%s': %s\n\n", configfile, strerror(errno));
00453 } else {
00454 fprintf(stderr, "\tCheck file permissions on your config file '%s'!\n", configfile);
00455 fprintf(stderr, "\tMake sure other groups and users cannot read/write it.\n\n");
00456 }
00457 return -1;
00458 }
00459
00460
00461 online_since = now;
00462
00463 do {
00464 int tid;
00465 egg_timeval_t howlong;
00466
00467
00468 howlong.sec = 1;
00469 howlong.usec = 0;
00470
00471 tid = timer_create_repeater(&howlong, "main loop", core_secondly);
00472
00473
00474 if (core_init() != 0)
00475 break;
00476
00477
00478 runmode = RUNMODE_NORMAL;
00479
00480
00481 botnet_autolink();
00482
00483 putlog(LOG_DEBUG, "*", "Entering main loop.");
00484
00485
00486 while (!debug_run && runmode == RUNMODE_NORMAL) {
00487
00488 timer_update_now(&egg_timeval_now);
00489 now = egg_timeval_now.sec;
00490
00491
00492 timer_run();
00493
00494
00495 if (timer_get_shortest(&howlong)) timeout = 1000;
00496 else timeout = howlong.sec * 1000 + howlong.usec / 1000;
00497
00498
00499 sockbuf_update_all(timeout);
00500
00501
00502 garbage_run();
00503 }
00504
00505
00506 timer_destroy(tid);
00507
00508
00509 core_shutdown_or_restart();
00510
00511
00512
00513 } while (runmode == RUNMODE_RESTART);
00514
00515 return 0;
00516 }
00517
00518 int core_init()
00519 {
00520 int i;
00521 char *name;
00522 void *config_root, *entry;
00523 char datetime[25];
00524 static int lockfd = -1;
00525 struct flock lock;
00526
00527
00528 eggdrop_init();
00529
00530
00531 if (core_config_init(configfile) != 0)
00532 return (-1);
00533
00534
00535 logfile_init();
00536
00537
00538 if (make_userfile) {
00539 if (create_userfile()) return(-1);
00540 make_userfile = 0;
00541 }
00542
00543
00544 if (runmode != RUNMODE_RESTART) {
00545 if (backgrd) bg_begin_split();
00546 }
00547
00548
00549 if (core_config.lockfile && lockfd == -1) {
00550 lockfd = open(core_config.lockfile, O_WRONLY | O_CREAT, S_IWUSR);
00551 if (lockfd < 0) {
00552 fatal("Could not open lock file!");
00553 }
00554 memset(&lock, 0, sizeof(lock));
00555 lock.l_type = F_WRLCK;
00556 if (fcntl(lockfd, F_SETLK, &lock) != 0) {
00557 fatal("Lock file is already locked! Is eggdrop already running?");
00558 }
00559 }
00560
00561
00562
00563 if (runmode != RUNMODE_RESTART) {
00564 strlcpy(datetime, ctime(&now), sizeof(datetime));
00565 strcpy(&datetime[11], &datetime[20]);
00566 putlog(LOG_ALL, "*", "Loading Eggdrop %s (%s)", VERSION, datetime);
00567 }
00568
00569
00570 if (core_config.userfile)
00571 user_load(core_config.userfile);
00572
00573
00574 core_binds_init();
00575
00576
00577 core_party_init();
00578
00579
00580 help_load_by_module ("core");
00581
00582
00583 if (core_config.module_path) module_add_dir(core_config.module_path);
00584
00585
00586 if (core_config.botname) botnet_set_name(core_config.botname);
00587
00588
00589 if (core_config.help_path) {
00590 help_set_default_path(core_config.help_path);
00591
00592 }
00593
00594
00595 config_root = config_get_root("eggdrop");
00596 for (i = 0; (entry = config_exists(config_root, "eggdrop", 0, "autoload", 0, "module", i, NULL)); i++) {
00597 name = NULL;
00598 config_get_str(&name, entry, NULL);
00599 module_load(name);
00600
00601 help_load_by_module(name);
00602 }
00603 for (i = 0; (entry = config_exists(config_root, "eggdrop", 0, "autoload", 0, "script", i, NULL)); i++) {
00604 name = NULL;
00605 config_get_str(&name, entry, NULL);
00606 script_load(name);
00607 }
00608
00609
00610 check_bind_init();
00611
00612
00613 if (runmode != RUNMODE_RESTART) {
00614 if (backgrd) bg_finish_split();
00615 }
00616 if (terminal_mode) terminal_init();
00617
00618 return (0);
00619 }
00620
00621 int core_restart(const char *nick)
00622 {
00623 putlog(LOG_MISC, "*", "Restarting...");
00624 runmode = RUNMODE_RESTART;
00625 return (0);
00626 }
00627
00628 int core_shutdown(int how, const char *nick, const char *reason)
00629 {
00630 if (how == SHUTDOWN_SIGTERM)
00631 putlog(LOG_MISC, "*", ("Received TERM signal, shutting down."));
00632 else if (how != SHUTDOWN_RESTART)
00633 putlog(LOG_MISC, "*", ("Shutdown requested by %s: %s"), nick,
00634 (reason) ? reason : _("No reason"));
00635
00636
00637 switch (how) {
00638
00639 case (SHUTDOWN_RESTART):
00640 runmode = RUNMODE_RESTART;
00641 break;
00642
00643 case (SHUTDOWN_GRACEFULL):
00644 runmode = RUNMODE_SHUTDOWN;
00645 break;
00646
00647
00648
00649
00650
00651 case (SHUTDOWN_HARD):
00652 case (SHUTDOWN_SIGTERM):
00653 runmode = RUNMODE_SHUTDOWN;
00654 core_shutdown_or_restart();
00655 exit(0);
00656 break;
00657
00658 }
00659
00660 return BIND_RET_LOG;
00661 }