00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "services.h"
00029 #include "timeout.h"
00030 #include "version.h"
00031 #include "datafiles.h"
00032
00033
00034
00035
00036 char *services_dir = SERVICES_DIR;
00037 char *log_filename = LOG_FILENAME;
00038 int debug = 0;
00039 int readonly = 0;
00040 int logchan = 0;
00041 int skeleton = 0;
00042 int nofork = 0;
00043 int forceload = 0;
00044 int nothird = 0;
00045 int noexpire = 0;
00046 int protocoldebug = 0;
00047
00048 #ifdef _WIN32
00049 char *binary_dir;
00050 #endif
00051
00052 #ifdef USE_RDB
00053 int do_mysql = 0;
00054 #endif
00055
00056
00057 int quitting = 0;
00058
00059
00060 int delayed_quit = 0;
00061
00062
00063 char *quitmsg = NULL;
00064
00065
00066 char inbuf[BUFSIZE];
00067
00068
00069 int servsock = -1;
00070
00071
00072 int save_data = 0;
00073
00074
00075 time_t start_time;
00076
00077
00078 char **my_av, **my_envp;
00079
00080
00081 const char version_number[] = VERSION_STRING;
00082 const char version_number_dotted[] = VERSION_STRING_DOTTED;
00083 const char version_build[] =
00084 "build #" BUILD ", compiled " __DATE__ " " __TIME__;
00085
00086 const char version_flags[] = " " VER_DEBUG VER_OS VER_MYSQL VER_MODULE;
00087
00088 extern char *mod_current_buffer;
00089
00090
00091
00092
00093 static int waiting = 0;
00094
00095
00096 static int started = 0;
00097
00098
00099
00100
00101
00102 extern void expire_all(void)
00103 {
00104 if (noexpire || readonly)
00105 {
00106
00107 return;
00108 }
00109
00110 waiting = -30;
00111 send_event(EVENT_DB_EXPIRE, 1, EVENT_START);
00112 waiting = -3;
00113 if (debug)
00114 alog("debug: Running expire routines");
00115 if (!skeleton) {
00116 waiting = -21;
00117 expire_nicks();
00118 waiting = -22;
00119 expire_chans();
00120 waiting = -23;
00121 expire_requests();
00122 }
00123 waiting = -25;
00124 expire_akills();
00125 if (ircd->sgline) {
00126 waiting = -26;
00127 expire_sglines();
00128 }
00129 if (ircd->sqline) {
00130 waiting = -28;
00131 expire_sqlines();
00132 }
00133 if (ircd->szline) {
00134 waiting = -27;
00135 expire_szlines();
00136 }
00137 waiting = -29;
00138 expire_exceptions();
00139 waiting = -31;
00140 send_event(EVENT_DB_EXPIRE, 1, EVENT_STOP);
00141 }
00142
00143
00144
00145 void save_databases(void)
00146 {
00147 if (readonly)
00148 return;
00149 waiting = -19;
00150 send_event(EVENT_DB_SAVING, 1, EVENT_START);
00151 waiting = -2;
00152 if (debug)
00153 alog("debug: Saving FFF databases");
00154 waiting = -10;
00155 backup_databases();
00156 if (!skeleton) {
00157 waiting = -11;
00158 save_ns_dbase();
00159 waiting = -12;
00160 if (PreNickDBName) {
00161 save_ns_req_dbase();
00162 waiting = -13;
00163 }
00164 save_cs_dbase();
00165 if (s_BotServ) {
00166 waiting = -14;
00167 save_bs_dbase();
00168 }
00169 if (s_HostServ) {
00170 waiting = -15;
00171 save_hs_dbase();
00172 }
00173 }
00174 waiting = -16;
00175 save_os_dbase();
00176 waiting = -17;
00177 save_news();
00178 waiting = -18;
00179 save_exceptions();
00180
00181 #ifdef USE_RDB
00182 if (do_mysql) {
00183 if (debug)
00184 alog("debug: Saving RDB databases");
00185 waiting = -10;
00186 if (!skeleton) {
00187 waiting = -11;
00188 save_ns_rdb_dbase();
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198 if (serv_uplink)
00199 anope_cmd_pong(ServerName, ServerName);
00200 waiting = -12;
00201 save_cs_rdb_dbase();
00202 if (serv_uplink)
00203 anope_cmd_pong(ServerName, ServerName);
00204 if (PreNickDBName) {
00205 save_ns_req_rdb_dbase();
00206 if (serv_uplink)
00207 anope_cmd_pong(ServerName, ServerName);
00208 waiting = -13;
00209 }
00210 if (s_BotServ) {
00211 waiting = -14;
00212 save_bs_rdb_dbase();
00213 if (serv_uplink)
00214 anope_cmd_pong(ServerName, ServerName);
00215 }
00216 if (s_HostServ) {
00217 waiting = -15;
00218 save_hs_rdb_dbase();
00219 if (serv_uplink)
00220 anope_cmd_pong(ServerName, ServerName);
00221 }
00222 waiting = -16;
00223 save_os_rdb_dbase();
00224 if (serv_uplink)
00225 anope_cmd_pong(ServerName, ServerName);
00226 waiting = -17;
00227 save_rdb_news();
00228 if (serv_uplink)
00229 anope_cmd_pong(ServerName, ServerName);
00230 waiting = -18;
00231 save_rdb_exceptions();
00232 if (serv_uplink)
00233 anope_cmd_pong(ServerName, ServerName);
00234
00235 } else {
00236 alog("!WARNING! Both MySQL and SKELETON are enabled, however SKELETON mode overrides MySQL dumping so databases will NOT be saved to MySQL. Keep this in mind next time you start Anope with UseRDB!");
00237 }
00238 }
00239 #endif
00240 waiting = -20;
00241 send_event(EVENT_DB_SAVING, 1, EVENT_STOP);
00242 }
00243
00244
00245
00246
00247
00248 static void services_restart(void)
00249 {
00250 alog("Restarting");
00251 send_event(EVENT_RESTART, 1, EVENT_START);
00252 if (!quitmsg)
00253 quitmsg = "Restarting";
00254 anope_cmd_squit(ServerName, quitmsg);
00255 disconn(servsock);
00256 close_log();
00257
00258 modules_unload_all(true, false);
00259 modules_unload_all(true, true);
00260 #ifdef _WIN32
00261
00262
00263 if (binary_dir)
00264 chdir(binary_dir);
00265 #endif
00266 execve(SERVICES_BIN, my_av, my_envp);
00267 if (!readonly) {
00268 open_log();
00269 log_perror("Restart failed");
00270 close_log();
00271 }
00272 }
00273
00274
00279 void do_restart_services(void)
00280 {
00281 if (!readonly) {
00282 expire_all();
00283 save_databases();
00284 }
00285 services_restart();
00286 exit(1);
00287 }
00288
00289
00290
00291
00292
00293 static void services_shutdown(void)
00294 {
00295 User *u, *next;
00296
00297 send_event(EVENT_SHUTDOWN, 1, EVENT_START);
00298
00299 if (!quitmsg)
00300 quitmsg = "Terminating, reason unknown";
00301 alog("%s", quitmsg);
00302 if (started) {
00303 anope_cmd_squit(ServerName, quitmsg);
00304 Anope_Free(uplink);
00305 Anope_Free(mod_current_buffer);
00306 if (ircd->chanmodes) {
00307 Anope_Free(ircd->chanmodes);
00308 }
00309 u = firstuser();
00310 while (u) {
00311 next = nextuser();
00312 delete_user(u);
00313 u = next;
00314 }
00315 }
00316 send_event(EVENT_SHUTDOWN, 1, EVENT_STOP);
00317 disconn(servsock);
00318
00319 modules_unload_all(true, false);
00320 modules_unload_all(true, true);
00321
00322 ModuleRunTimeDirCleanUp();
00323 }
00324
00325
00326
00327
00328
00329 void sighandler(int signum)
00330 {
00331
00332
00333
00334
00335 quitmsg = "Signal Received";
00336 if (started) {
00337 #ifndef _WIN32
00338 if (signum == SIGHUP) {
00339 signal(SIGHUP, SIG_IGN);
00340 signal(SIGUSR2, SIG_IGN);
00341 alog("Received SIGHUP, restarting.");
00342
00343 expire_all();
00344 save_databases();
00345
00346 if (!quitmsg)
00347 quitmsg = "Restarting on SIGHUP";
00348
00349 #ifdef SERVICES_BIN
00350 services_restart();
00351 exit(1);
00352 #else
00353 quitmsg =
00354 "Restart attempt failed--SERVICES_BIN not defined (rerun configure)";
00355 #endif
00356 } else if (signum == SIGQUIT) {
00357
00358 } else if (signum == SIGUSR2) {
00359
00360 alog("Received SIGUSR2: Saving Databases & Rehash Configuration");
00361
00362 expire_all();
00363 save_databases();
00364
00365 if (!read_config(1)) {
00366 static char *buf = "Error Reading Configuration File (Received SIGUSR2)";
00367 quitmsg = buf;
00368 quitting = 1;
00369 }
00370 send_event(EVENT_RELOAD, 1, EVENT_START);
00371 return;
00372
00373 } else
00374 #endif
00375 if (signum == SIGTERM) {
00376 signal(SIGTERM, SIG_IGN);
00377 #ifndef _WIN32
00378 signal(SIGHUP, SIG_IGN);
00379 #endif
00380
00381 alog("Received SIGTERM, exiting.");
00382
00383 expire_all();
00384 save_databases();
00385 quitmsg = "Shutting down on SIGTERM";
00386 services_shutdown();
00387 exit(0);
00388 } else if (signum == SIGINT) {
00389 if (nofork) {
00390 signal(SIGINT, SIG_IGN);
00391 alog("Received SIGINT, exiting.");
00392 expire_all();
00393 save_databases();
00394 quitmsg = "Shutting down on SIGINT";
00395 services_shutdown();
00396 exit(0);
00397 }
00398 } else if (!waiting) {
00399 alog("PANIC! buffer = %s", inbuf);
00400
00401 if (strlen(inbuf) > 448) {
00402 inbuf[446] = '>';
00403 inbuf[447] = '>';
00404 inbuf[448] = 0;
00405 }
00406 wallops(NULL, "PANIC! buffer = %s\r\n", inbuf);
00407 modules_unload_all(false, true);
00408 } else if (waiting < 0) {
00409
00410 static char buf[BUFSIZE];
00411 switch (waiting) {
00412 case -1:
00413 snprintf(buf, sizeof(buf), "in timed_update");
00414 break;
00415 case -10:
00416 snprintf(buf, sizeof(buf), "backing up databases");
00417 break;
00418 case -11:
00419 snprintf(buf, sizeof(buf), "saving %s", NickDBName);
00420 break;
00421 case -12:
00422 snprintf(buf, sizeof(buf), "saving %s", ChanDBName);
00423 break;
00424 case -13:
00425 snprintf(buf, sizeof(buf), "saving %s", PreNickDBName);
00426 break;
00427 case -14:
00428 snprintf(buf, sizeof(buf), "saving %s", BotDBName);
00429 break;
00430 case -15:
00431 snprintf(buf, sizeof(buf), "saving %s", HostDBName);
00432 break;
00433 case -16:
00434 snprintf(buf, sizeof(buf), "saving %s", OperDBName);
00435 break;
00436 case -17:
00437 snprintf(buf, sizeof(buf), "saving %s", NewsDBName);
00438 break;
00439 case -18:
00440 snprintf(buf, sizeof(buf), "saving %s", ExceptionDBName);
00441 break;
00442 case -19:
00443 snprintf(buf, sizeof(buf), "Sending event %s %s",
00444 EVENT_DB_SAVING, EVENT_START);
00445 break;
00446 case -20:
00447 snprintf(buf, sizeof(buf), "Sending event %s %s",
00448 EVENT_DB_SAVING, EVENT_STOP);
00449 break;
00450 case -21:
00451 snprintf(buf, sizeof(buf), "expiring nicknames");
00452 break;
00453 case -22:
00454 snprintf(buf, sizeof(buf), "expiring channels");
00455 break;
00456 case -25:
00457 snprintf(buf, sizeof(buf), "expiring autokills");
00458 break;
00459 case -26:
00460 snprintf(buf, sizeof(buf), "expiring SGLINEs");
00461 break;
00462 case -27:
00463 snprintf(buf, sizeof(buf), "expiring SZLINEs");
00464 break;
00465 case -28:
00466 snprintf(buf, sizeof(buf), "expiring SQLINEs");
00467 break;
00468 case -29:
00469 snprintf(buf, sizeof(buf), "expiring Exceptions");
00470 break;
00471 case -30:
00472 snprintf(buf, sizeof(buf), "Sending event %s %s",
00473 EVENT_DB_EXPIRE, EVENT_START);
00474 break;
00475 case -31:
00476 snprintf(buf, sizeof(buf), "Sending event %s %s",
00477 EVENT_DB_EXPIRE, EVENT_STOP);
00478 break;
00479 default:
00480 snprintf(buf, sizeof(buf), "waiting=%d", waiting);
00481 }
00482 wallops(NULL, "PANIC! %s (%s)", buf, strsignal(signum));
00483 alog("PANIC! %s (%s)", buf, strsignal(signum));
00484 modules_unload_all(false, true);
00485 }
00486 }
00487
00488 if (
00489 #ifndef _WIN32
00490 signum == SIGUSR1 ||
00491 #endif
00492 !(quitmsg = calloc(BUFSIZE, 1))) {
00493 quitmsg = "Out of memory!";
00494 } else {
00495 #if HAVE_STRSIGNAL
00496 snprintf(quitmsg, BUFSIZE, "Services terminating: %s",
00497 strsignal(signum));
00498 #else
00499 snprintf(quitmsg, BUFSIZE, "Services terminating on signal %d",
00500 signum);
00501 #endif
00502 }
00503
00504 if (signum == SIGSEGV) {
00505 do_backtrace(1);
00506 modules_unload_all(false, true);
00507 }
00508
00509 send_event(EVENT_SIGNAL, 1, quitmsg);
00510
00511 if (started) {
00512 services_shutdown();
00513 exit(0);
00514 } else {
00515 if (isatty(2)) {
00516 fprintf(stderr, "%s\n", quitmsg);
00517 } else {
00518 alog("%s", quitmsg);
00519 }
00520 exit(1);
00521 }
00522 }
00523
00524
00525
00526
00527
00528 int main(int ac, char **av, char **envp)
00529 {
00530 volatile time_t last_update;
00531 volatile time_t last_expire;
00532 volatile time_t last_check;
00533 volatile time_t last_DefCon;
00534
00535 int i;
00536 char *progname;
00537
00538 my_av = av;
00539 my_envp = envp;
00540
00541 #ifndef _WIN32
00542
00543 if ((getuid() == 0) && (getgid() == 0)) {
00544 fprintf(stderr,
00545 "WARNING: You are currently running Anope as the root superuser. Anope does not\n");
00546 fprintf(stderr,
00547 " require root privileges to run, and it is discouraged that you run Anope\n");
00548 fprintf(stderr, " as the root superuser.\n");
00549 }
00550 #else
00551
00552
00553
00554
00555
00556
00557 binary_dir = smalloc(MAX_PATH);
00558 if (!getcwd(binary_dir, MAX_PATH)) {
00559 fprintf(stderr, "error: getcwd() error\n");
00560 return -1;
00561 }
00562 #endif
00563
00564
00565 ModuleRunTimeDirCleanUp();
00566
00567
00568 if ((i = init_primary(ac, av)) != 0)
00569 return i;
00570
00571
00572 if ((progname = strrchr(av[0], '/')) != NULL)
00573 progname++;
00574 else
00575 progname = av[0];
00576
00577 #ifdef _WIN32
00578 if (strcmp(progname, "listnicks.exe") == 0)
00579 #else
00580 if (strcmp(progname, "listnicks") == 0)
00581 #endif
00582 {
00583 do_listnicks(ac, av);
00584 modules_unload_all(1, 0);
00585 modules_unload_all(1, 1);
00586 ModuleRunTimeDirCleanUp();
00587 return 0;
00588 }
00589 #ifdef _WIN32
00590 else if (strcmp(progname, "listchans.exe") == 0)
00591 #else
00592 else if (strcmp(progname, "listchans") == 0)
00593 #endif
00594 {
00595 do_listchans(ac, av);
00596 modules_unload_all(1, 0);
00597 modules_unload_all(1, 1);
00598 ModuleRunTimeDirCleanUp();
00599 return 0;
00600 }
00601
00602
00603 if ((i = init_secondary(ac, av)) != 0)
00604 return i;
00605
00606
00607
00608 process();
00609
00610
00611 last_update = time(NULL);
00612 last_expire = time(NULL);
00613 last_check = time(NULL);
00614 last_DefCon = time(NULL);
00615
00616 started = 1;
00617
00618
00619
00620 while (!quitting) {
00621 time_t t = time(NULL);
00622
00623 if (debug >= 2)
00624 alog("debug: Top of main loop");
00625
00626 if (save_data || t - last_expire >= ExpireTimeout) {
00627 expire_all();
00628 last_expire = t;
00629 }
00630
00631 if (!readonly && (save_data || t - last_update >= UpdateTimeout)) {
00632 if (delayed_quit)
00633 anope_cmd_global(NULL,
00634 "Updating databases on shutdown, please wait.");
00635
00636 save_databases();
00637
00638 if (save_data < 0)
00639 break;
00640
00641 save_data = 0;
00642 last_update = t;
00643 }
00644
00645 if ((DefConTimeOut) && (t - last_DefCon >= dotime(DefConTimeOut))) {
00646 resetDefCon(5);
00647 last_DefCon = t;
00648 }
00649
00650 if (delayed_quit)
00651 break;
00652
00653 moduleCallBackRun();
00654
00655 waiting = -1;
00656 if (t - last_check >= TimeoutCheck) {
00657 check_timeouts();
00658 last_check = t;
00659 }
00660
00661 waiting = 1;
00662
00663
00664 i = (int) (long) sgets2(inbuf, sizeof(inbuf), servsock);
00665 waiting = 0;
00666 if ((i > 0) || (i < (-1))) {
00667 process();
00668 } else if (i == 0) {
00669 int errno_save = errno;
00670 quitmsg = scalloc(BUFSIZE, 1);
00671 if (quitmsg) {
00672 snprintf(quitmsg, BUFSIZE,
00673 "Read error from server: %s (error num: %d)",
00674 strerror(errno_save), errno_save);
00675 } else {
00676 quitmsg = "Read error from server";
00677 }
00678 quitting = 1;
00679
00680
00681 if (!readonly)
00682 save_databases();
00683 }
00684 waiting = -4;
00685 }
00686
00687
00688
00689 if (save_data == -2) {
00690 #ifdef SERVICES_BIN
00691 alog("Restarting");
00692 if (!quitmsg)
00693 quitmsg = "Restarting";
00694 anope_cmd_squit(ServerName, quitmsg);
00695 disconn(servsock);
00696 close_log();
00697 #ifdef _WIN32
00698
00699
00700 if (binary_dir)
00701 chdir(binary_dir);
00702 #endif
00703 execve(SERVICES_BIN, av, envp);
00704 if (!readonly) {
00705 open_log();
00706 log_perror("Restart failed");
00707 close_log();
00708 }
00709 return 1;
00710 #else
00711 quitmsg =
00712 "Restart attempt failed--SERVICES_BIN not defined (rerun configure)";
00713 #endif
00714 }
00715
00716
00717 services_shutdown();
00718
00719 #ifdef _WIN32
00720 if (binary_dir)
00721 free(binary_dir);
00722 #endif
00723
00724 return 0;
00725 }
00726
00727
00728
00729 void do_backtrace(int show_segheader)
00730 {
00731 #ifndef _WIN32
00732 #ifdef HAVE_BACKTRACE
00733 void *array[50];
00734 size_t size;
00735 char **strings;
00736 int i;
00737
00738 if (show_segheader) {
00739 alog("Backtrace: Segmentation fault detected");
00740 alog("Backtrace: report the following lines");
00741 }
00742 alog("Backtrace: Anope version %s %s %s", version_number,
00743 version_build, version_flags);
00744 size = backtrace(array, 10);
00745 strings = backtrace_symbols(array, size);
00746 for (i = 0; i < size; i++) {
00747 alog("Backtrace(%d): %s", i, strings[i]);
00748 }
00749 free(strings);
00750 alog("Backtrace: complete");
00751 #else
00752 alog("Backtrace: not available on this platform");
00753 #endif
00754 #else
00755 char *winver;
00756 winver = GetWindowsVersion();
00757 alog("Backtrace: not available on Windows");
00758 alog("Running %S", winver);
00759 free(winver);
00760 #endif
00761 }