621 lines
18 KiB
C
621 lines
18 KiB
C
/* NeoStats - IRC Statistical Services k
|
|
** Copyright (c) 1999-2004 Adam Rutter, Justin Hammond
|
|
** http://www.neostats.net/
|
|
**
|
|
** Portions Copyright (c) 2000-2001 ^Enigma^
|
|
**
|
|
** Portions Copyright (c) 1999 Johnathan George net@lite.net
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation; either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
|
|
** USA
|
|
**
|
|
** NeoStats CVS Identification
|
|
** $Id$
|
|
*/
|
|
|
|
#include <setjmp.h>
|
|
#include <stdio.h>
|
|
#include "stats.h"
|
|
#include "ircd.h"
|
|
#ifdef HAVE_BACKTRACE
|
|
#include <execinfo.h>
|
|
#endif
|
|
#include "signal.h"
|
|
#include "dl.h"
|
|
#include "conf.h"
|
|
#include "keeper.h"
|
|
#include "log.h"
|
|
#include "sock.h"
|
|
#include "users.h"
|
|
#include "server.h"
|
|
#include "chans.h"
|
|
#include "dns.h"
|
|
#include "dotconf.h"
|
|
#include "transfer.h"
|
|
#include "exclude.h"
|
|
#include "bans.h"
|
|
#ifdef SQLSRV
|
|
#include "sqlsrv/rta.h"
|
|
#endif
|
|
|
|
|
|
/* this is the name of the services bot */
|
|
char s_Services[MAXNICK] = "NeoStats";
|
|
/*! Date when we were compiled */
|
|
const char version_date[] = __DATE__;
|
|
/*! Time we were compiled */
|
|
const char version_time[] = __TIME__;
|
|
|
|
static void start (void);
|
|
static void setup_signals (void);
|
|
static int get_options (int argc, char **argv);
|
|
|
|
/*! have we forked */
|
|
int forked = 0;
|
|
static int attempts = 0;
|
|
jmp_buf sigvbuf;
|
|
|
|
/** @brief Main Entry point into program
|
|
*
|
|
* Sets up defaults, and parses the config file.
|
|
* Also initializes different parts of NeoStats
|
|
*
|
|
* @return Exits the program!
|
|
*
|
|
* @todo Close STDIN etc correctly
|
|
*/
|
|
int
|
|
main (int argc, char *argv[])
|
|
{
|
|
FILE *fp;
|
|
|
|
/* initialise version */
|
|
strlcpy(me.version, NEOSTATS_VERSION, VERSIONSIZE);
|
|
strlcpy(me.versionfull, NEOSTATS_VERSION, VERSIONSIZE);
|
|
strlcat(me.versionfull, ircd_version, VERSIONSIZE);
|
|
|
|
/* get our commandline options */
|
|
if(get_options (argc, argv)!=NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
|
|
/* Change to the working Directory */
|
|
if (chdir (NEO_PREFIX) < 0) {
|
|
printf ("NeoStats Could not change to %s\n", NEO_PREFIX);
|
|
printf ("Did you 'make install' after compiling?\n");
|
|
printf ("Error Was: %s\n", strerror (errno));
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* before we do anything, make sure logging is setup */
|
|
if(init_logs () != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
|
|
/* our crash trace variables */
|
|
SET_SEGV_LOCATION();
|
|
CLEAR_SEGV_INMODULE();
|
|
|
|
/* keep quiet if we are told to :) */
|
|
if (!config.quiet) {
|
|
printf ("NeoStats %s Loading...\n", me.versionfull);
|
|
printf ("-----------------------------------------------\n");
|
|
printf ("Copyright: NeoStats Group. 2000-2004\n");
|
|
printf ("Justin Hammond (fish@neostats.net)\n");
|
|
printf ("Adam Rutter (shmad@neostats.net)\n");
|
|
printf ("Mark (m@neostats.net)\n");
|
|
printf ("-----------------------------------------------\n\n");
|
|
}
|
|
/* set some defaults before we parse the config file */
|
|
me.t_start = time(NULL);
|
|
me.now = time(NULL);
|
|
ircsnprintf (me.strnow, STR_TIME_T_SIZE, "%ld", (long)me.now);
|
|
me.want_privmsg = 0;
|
|
me.want_nickip = 0;
|
|
me.die = 0;
|
|
me.local[0] = '\0';
|
|
#ifndef DEBUG
|
|
me.debug_mode = 0;
|
|
#else
|
|
me.debug_mode = 1;
|
|
#endif
|
|
me.r_time = 10;
|
|
me.numeric = 1;
|
|
me.setservertimes = 0;
|
|
me.SendM = me.SendBytes = me.RcveM = me.RcveBytes = 0;
|
|
/* for modules, let them know we are not ready */
|
|
me.synced = 0;
|
|
me.onchan = 0;
|
|
me.maxsocks = getmaxsock ();
|
|
#ifdef ULTIMATE3
|
|
me.client = 0;
|
|
#endif
|
|
#ifdef SQLSRV
|
|
me.sqlport = 8888;
|
|
#endif
|
|
/* if we are doing recv.log, remove the previous version */
|
|
if (config.recvlog)
|
|
remove (RECV_LOG);
|
|
|
|
/* prepare to catch errors */
|
|
setup_signals ();
|
|
|
|
/* init the sql subsystem if used */
|
|
#ifdef SQLSRV
|
|
rta_init(sqlsrvlog);
|
|
#endif
|
|
|
|
/* initilze our Module subsystem */
|
|
if(InitModuleHash () != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
|
|
/* load the config files */
|
|
if(ConfLoad () != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
|
|
/* init NeoStats bot */
|
|
if(init_services () != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
|
|
#ifdef EXTAUTH
|
|
/* load extauth if we need to */
|
|
load_module ("extauth", NULL);
|
|
InitExtAuth();
|
|
#endif
|
|
|
|
if (me.die) {
|
|
printf ("\n-----> ERROR: Read the README file then edit %s! <-----\n\n",CONFIG_NAME);
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Read the README file and edit your %s",CONFIG_NAME);
|
|
/* we are exiting the parent, not the program, so just return */
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* initialize the rest of the subsystems */
|
|
if(init_dns () != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
if (init_exclude_list() != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
if(init_server_hash () != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
if(init_user_hash () != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
if(init_chan_hash () != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
if(InitBans () != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
/* initilize out transfer subsystem */
|
|
if (init_curl () != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
init_ircd ();
|
|
|
|
|
|
#ifndef DEBUG
|
|
/* if we are compiled with debug, or forground switch was specified, DONT FORK */
|
|
if (!config.foreground) {
|
|
/* fix the double log message problem by closing logs prior to fork() */
|
|
close_logs();
|
|
forked = fork ();
|
|
/* Error check fork() */
|
|
if (forked<0) {
|
|
perror("fork");
|
|
return EXIT_FAILURE; /* fork error */
|
|
}
|
|
#endif
|
|
/* we are the parent */
|
|
if (forked>0) {
|
|
/* write out our PID */
|
|
fp = fopen (PID_FILENAME, "w");
|
|
fprintf (fp, "%i", forked);
|
|
fclose (fp);
|
|
if (!config.quiet) {
|
|
printf ("\n");
|
|
printf ("NeoStats %s Successfully Launched into Background\n", me.versionfull);
|
|
printf ("PID: %i - Wrote to %s\n", forked, PID_FILENAME);
|
|
}
|
|
return EXIT_SUCCESS; /* parent exits */
|
|
}
|
|
#ifndef DEBUG
|
|
/* child (daemon) continues */
|
|
/* reopen logs for child */
|
|
if(init_logs () != NS_SUCCESS)
|
|
return EXIT_FAILURE;
|
|
/* detach from parent process */
|
|
if (setpgid (0, 0) < 0) {
|
|
nlog (LOG_WARNING, LOG_CORE, "setpgid() failed");
|
|
}
|
|
}
|
|
#endif
|
|
nlog (LOG_NOTICE, LOG_CORE, "NeoStats started (Version %s).", me.versionfull);
|
|
|
|
/* don't init_modules till after we fork. This fixes the load->fork-exit->call _fini problems when we fork */
|
|
ConfLoadModules ();
|
|
|
|
/* we are ready to start now Duh! */
|
|
start ();
|
|
|
|
/* We should never reach here but the compiler does not realise and may
|
|
complain about not all paths control returning values without the return
|
|
Since it should never happen, treat as an error condition! */
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/** @brief Process Commandline Options
|
|
*
|
|
* Processes commandline options
|
|
*
|
|
* returns 0 on success, -1 on error
|
|
*/
|
|
static int
|
|
get_options (int argc, char **argv)
|
|
{
|
|
int c;
|
|
int dbg;
|
|
|
|
/* set some defaults first */
|
|
#ifdef DEBUG
|
|
config.debug = 10;
|
|
config.foreground = 1;
|
|
#else
|
|
config.debug = 5;
|
|
config.foreground = 0;
|
|
#endif
|
|
|
|
while ((c = getopt (argc, argv, "hvrd:nqf")) != -1) {
|
|
switch (c) {
|
|
case 'h':
|
|
printf ("NeoStats: Usage: \"neostats [options]\"\n");
|
|
printf (" -h (Show this screen)\n");
|
|
printf (" -v (Show version number)\n");
|
|
printf (" -r (Enable recv.log)\n");
|
|
printf (" -d 1-10 (Enable debugging output 1= lowest, 10 = highest)\n");
|
|
printf (" -n (Do not load any modules on startup)\n");
|
|
printf (" -q (Quiet start - for cron scripts)\n");
|
|
printf (" -f (Do not fork into background\n");
|
|
return NS_FAILURE;
|
|
case 'v':
|
|
printf ("NeoStats Version %s\n", me.versionfull);
|
|
printf ("Compiled: %s at %s\n", version_date, version_time);
|
|
printf ("Flag after version number indicates what IRCd NeoStats is compiled for:\n");
|
|
printf ("(U31)- Unreal 3.1.x IRCd\n");
|
|
printf ("(U32)- Unreal 3.2.x IRCd\n");
|
|
printf ("(UL3)- Ultimate 3.x.x IRCd\n");
|
|
printf ("(UL) - Ultimate 2.x.x IRCd (Depreciated)\n");
|
|
printf ("(H) - Hybrid 7.x IRCd\n");
|
|
printf ("(N) - NeoIRCd IRCd\n");
|
|
printf ("(M) - Mystic IRCd\n");
|
|
printf ("(Q) - Quantum IRCd\n");
|
|
printf ("(B) - Bahamut IRCd\n");
|
|
printf ("(IRCu) - IRCu (P10) IRCd\n");
|
|
printf ("(V) - Viagra IRCd\n");
|
|
printf ("\nNeoStats: http://www.neostats.net\n");
|
|
return NS_FAILURE;
|
|
case 'r':
|
|
printf ("recv.log enabled. Watch your DiskSpace\n");
|
|
config.recvlog = 1;
|
|
break;
|
|
case 'n':
|
|
config.modnoload = 1;
|
|
break;
|
|
case 'q':
|
|
config.quiet = 1;
|
|
break;
|
|
case 'd':
|
|
dbg = atoi (optarg);
|
|
if ((dbg > 10) || (dbg < 1)) {
|
|
printf ("Invalid Debug Level %d\n", dbg);
|
|
return NS_FAILURE;
|
|
}
|
|
config.debug = dbg;
|
|
break;
|
|
case 'f':
|
|
config.foreground = 1;
|
|
break;
|
|
default:
|
|
printf ("Unknown command line switch %c\n", optopt);
|
|
}
|
|
}
|
|
return NS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
/** @brief Sigterm Signal handler
|
|
*
|
|
* Called by the signal handler if we get a SIGTERM
|
|
* This shutsdown NeoStats and exits
|
|
*
|
|
* @return Exits the program!
|
|
*
|
|
* @todo Do a nice shutdown, no thtis crap :)
|
|
*/
|
|
char msg_sigterm[]="SIGTERM received, shutting down server.";
|
|
|
|
RETSIGTYPE
|
|
serv_die ()
|
|
{
|
|
#ifdef VALGRIND
|
|
exit(NS_SUCCESS);
|
|
#else /* VALGRIND */
|
|
User *u;
|
|
|
|
u = finduser (s_Services);
|
|
nlog (LOG_CRITICAL, LOG_CORE, msg_sigterm);
|
|
globops (s_Services, msg_sigterm);
|
|
do_exit (NS_EXIT_NORMAL, msg_sigterm);
|
|
#endif /* VALGRIND */
|
|
}
|
|
|
|
/** @brief Sighup Signal handler
|
|
*
|
|
* Called by the signal handler if we get a SIGHUP
|
|
* and rehashes the config file.
|
|
*
|
|
* @return Nothing
|
|
*
|
|
* @todo Implement a Rehash function. What can we actually rehash?
|
|
*/
|
|
RETSIGTYPE
|
|
conf_rehash ()
|
|
{
|
|
chanalert (s_Services, "SIGHUP received, attempting to rehash");
|
|
globops (me.name, "SIGHUP received, attempted to rehash");
|
|
/* at the moment, the reshash just checks for a the SQL port is opened, if enabled */
|
|
#ifdef SQLSRV
|
|
check_sql_sock();
|
|
#endif
|
|
}
|
|
|
|
|
|
/** @brief Sigsegv Signal handler
|
|
*
|
|
* This function is called when we get a SEGV
|
|
* and will send some debug into to the logs and to IRC
|
|
* to help us track down where the problem occured.
|
|
* if the platform we are using supports backtrace
|
|
* also print out the backtrace.
|
|
* if the segv happened inside a module, try to unload the module
|
|
* and continue on our merry way :)
|
|
*
|
|
* @return Nothing
|
|
*
|
|
*/
|
|
#ifndef HAVE_BACKTRACE
|
|
static char backtrace_unavailable[]="Backtrace not available on this platform";
|
|
#endif
|
|
static
|
|
void do_backtrace(void)
|
|
{
|
|
#ifdef HAVE_BACKTRACE
|
|
void *array[50];
|
|
size_t size;
|
|
char **strings;
|
|
int i;
|
|
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Backtrace:");
|
|
chanalert (s_Services, "Backtrace: %s", segv_location);
|
|
size = backtrace (array, 10);
|
|
strings = backtrace_symbols (array, size);
|
|
for (i = 1; i < size; i++) {
|
|
chanalert (s_Services, "Backtrace(%d): %s", i, strings[i]);
|
|
nlog (LOG_CRITICAL, LOG_CORE, "BackTrace(%d): %s", i - 1, strings[i]);
|
|
}
|
|
free (strings);
|
|
#else
|
|
chanalert (s_Services, backtrace_unavailable);
|
|
nlog (LOG_CRITICAL, LOG_CORE, backtrace_unavailable);
|
|
#endif
|
|
}
|
|
|
|
RETSIGTYPE
|
|
serv_segv ()
|
|
{
|
|
char name[MAX_MOD_NAME];
|
|
/** if the segv happened while we were inside a module, unload and try to restore
|
|
* the stack to where we were before we jumped into the module
|
|
* and continue on
|
|
*/
|
|
if (segvinmodule[0] != 0) {
|
|
globops (me.name, "Segmentation Fault in %s. Refer to log file for details.", segvinmodule);
|
|
chanalert (s_Services, "Segmentation Fault in %s. Refer to log file for details.", segvinmodule);
|
|
nlog (LOG_CRITICAL, LOG_CORE, "------------------------SEGFAULT REPORT-------------------------");
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Please view the README for how to submit a bug report");
|
|
nlog (LOG_CRITICAL, LOG_CORE, "and include this segfault report in your submission.");
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Module: %s", segvinmodule);
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Location: %s", segv_location);
|
|
nlog (LOG_CRITICAL, LOG_CORE, "recbuf: %s", recbuf);
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Unloading Module and restoring stacks. Backtrace:");
|
|
chanalert (s_Services, "Location *could* be %s.", segv_location);
|
|
do_backtrace();
|
|
nlog (LOG_CRITICAL, LOG_CORE, "-------------------------END OF REPORT--------------------------");
|
|
strlcpy (name, segvinmodule, MAX_MOD_NAME);
|
|
CLEAR_SEGV_INMODULE();
|
|
unload_module (name, NULL);
|
|
chanalert (s_Services, "Restoring Stack to before Crash");
|
|
/* flush the logs out */
|
|
close_logs();
|
|
longjmp (sigvbuf, -1);
|
|
chanalert (s_Services, "Done");
|
|
return;
|
|
}
|
|
/** The segv happened in our core, damn it */
|
|
/* Thanks to Stskeeps and Unreal for this stuff :) */
|
|
/* Broadcast it out! */
|
|
globops (me.name, "Segmentation Fault. Server Terminating. Refer to log file for details.");
|
|
chanalert (s_Services, "Segmentation Fault. Server Terminating. Refer to log file for details.");
|
|
globops (me.name, "Buffer: %s, Approx Location %s", recbuf, segv_location);
|
|
chanalert (s_Services, "NeoStats (%s) Buffer: %s, Approx Location: %s Backtrace:", me.versionfull, recbuf, segv_location);
|
|
nlog (LOG_CRITICAL, LOG_CORE, "------------------------SEGFAULT REPORT-------------------------");
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Please view the README for how to submit a bug report");
|
|
nlog (LOG_CRITICAL, LOG_CORE, "and include this segfault report in your submission.");
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Location: %s", segv_location);
|
|
nlog (LOG_CRITICAL, LOG_CORE, "recbuf: %s", recbuf);
|
|
do_backtrace();
|
|
nlog (LOG_CRITICAL, LOG_CORE, "-------------------------END OF REPORT--------------------------");
|
|
close_logs();
|
|
/* clean up */
|
|
do_exit (NS_EXIT_SEGFAULT, NULL);
|
|
}
|
|
|
|
/** @brief Sets up the signal handlers
|
|
*
|
|
* Sets up the signal handlers for SIGHUP (rehash)
|
|
* SIGTERM (die) and SIGSEGV (segv fault)
|
|
* and ignore the others (Such as SIGPIPE)
|
|
*
|
|
* @return Nothing
|
|
*
|
|
*/
|
|
static void
|
|
setup_signals (void)
|
|
{
|
|
struct sigaction act;
|
|
act.sa_handler = SIG_IGN;
|
|
act.sa_flags = 0;
|
|
|
|
/* SIGPIPE/SIGALRM */
|
|
(void) sigemptyset (&act.sa_mask);
|
|
(void) sigaddset (&act.sa_mask, SIGPIPE);
|
|
(void) sigaddset (&act.sa_mask, SIGALRM);
|
|
(void) sigaction (SIGPIPE, &act, NULL);
|
|
(void) sigaction (SIGALRM, &act, NULL);
|
|
|
|
/* SIGHUP */
|
|
act.sa_handler = conf_rehash;
|
|
(void) sigemptyset (&act.sa_mask);
|
|
(void) sigaddset (&act.sa_mask, SIGHUP);
|
|
(void) sigaction (SIGHUP, &act, NULL);
|
|
|
|
/* SIGTERM/SIGINT */
|
|
act.sa_handler = serv_die;
|
|
(void) sigaddset (&act.sa_mask, SIGTERM);
|
|
(void) sigaction (SIGTERM, &act, NULL);
|
|
(void) sigaddset (&act.sa_mask, SIGINT);
|
|
(void) sigaction (SIGINT, &act, NULL);
|
|
|
|
/* SIGSEGV */
|
|
act.sa_handler = serv_segv;
|
|
(void) sigaddset (&act.sa_mask, SIGSEGV);
|
|
(void) sigaction (SIGSEGV, &act, NULL);
|
|
|
|
(void) signal (SIGHUP, conf_rehash);
|
|
(void) signal (SIGTERM, serv_die);
|
|
(void) signal (SIGSEGV, serv_segv);
|
|
(void) signal (SIGINT, serv_die);
|
|
}
|
|
|
|
/** @brief Connects to IRC and starts the main loop
|
|
*
|
|
* Connects to the IRC server and attempts to login
|
|
* If it connects and logs in, then starts the main program loop
|
|
* if control is returned to this function, restart
|
|
*
|
|
* @return Nothing
|
|
*
|
|
* @todo make the restart code nicer so it doesn't go mad when we can't connect
|
|
*/
|
|
static void
|
|
start (void)
|
|
{
|
|
SET_SEGV_LOCATION();
|
|
nlog (LOG_NOTICE, LOG_CORE, "Connecting to %s:%d", me.uplink, me.port);
|
|
|
|
servsock = ConnectTo (me.uplink, me.port);
|
|
|
|
if (servsock <= 0) {
|
|
nlog (LOG_WARNING, LOG_CORE, "Unable to connect to %s", me.uplink);
|
|
} else {
|
|
/* Call the IRC specific function send_server_connect to login as a server to IRC */
|
|
send_server_connect (me.name, me.numeric, me.infoline, me.pass, (unsigned long)me.t_start, (unsigned long)me.now);
|
|
read_loop ();
|
|
}
|
|
|
|
do_exit (NS_EXIT_RECONNECT, NULL);
|
|
}
|
|
|
|
/** @brief before exiting call this function. It flushes log files and tidy's up.
|
|
*
|
|
* Cleans up before exiting
|
|
* @parm segv 1 = we are exiting because of a segv fault, 0, we are not.
|
|
* if 1, we don't prompt to save data
|
|
*/
|
|
void
|
|
do_exit (NS_EXIT_TYPE exitcode, char* quitmsg)
|
|
{
|
|
/* Initialise exit code to OK */
|
|
int return_code=EXIT_SUCCESS;
|
|
|
|
switch (exitcode) {
|
|
case NS_EXIT_NORMAL:
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Normal shut down subsystems");
|
|
break;
|
|
case NS_EXIT_RELOAD:
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Reloading NeoStats");
|
|
break;
|
|
case NS_EXIT_RECONNECT:
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Restarting NeoStats subsystems");
|
|
break;
|
|
case NS_EXIT_ERROR:
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Exiting due to error");
|
|
return_code=EXIT_FAILURE; /* exit code to error */
|
|
break;
|
|
case NS_EXIT_SEGFAULT:
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Shutting down subsystems without saving data due to core");
|
|
return_code=EXIT_FAILURE; /* exit code to error */
|
|
break;
|
|
}
|
|
|
|
if (exitcode != NS_EXIT_SEGFAULT) {
|
|
unload_modules();
|
|
if(quitmsg)
|
|
{
|
|
squit_cmd (s_Services, quitmsg);
|
|
ssquit_cmd (me.name, quitmsg);
|
|
}
|
|
sleep(1);
|
|
if (servsock > 0)
|
|
close (servsock);
|
|
if (exitcode == NS_EXIT_RECONNECT) {
|
|
if(me.r_time>0) {
|
|
nlog (LOG_NOTICE, LOG_CORE, "Reconnecting to the server in %d seconds (Attempt %i)", me.r_time, attempts);
|
|
sleep (me.r_time);
|
|
}
|
|
else {
|
|
nlog (LOG_NOTICE, LOG_CORE, "Reconnect time is zero, shutting down");
|
|
}
|
|
}
|
|
|
|
/* now free up the users and servers memory */
|
|
FreeUsers();
|
|
FreeServers();
|
|
FreeBans();
|
|
fini_adns();
|
|
finiModuleHash();
|
|
}
|
|
|
|
kp_flush();
|
|
kp_exit();
|
|
fini_logs ();
|
|
|
|
if ((exitcode == NS_EXIT_RECONNECT && me.r_time > 0) || exitcode == NS_EXIT_RELOAD) {
|
|
execve ("./neostats", NULL, NULL);
|
|
return_code=EXIT_FAILURE; /* exit code to error */
|
|
}
|
|
remove (PID_FILENAME);
|
|
exit (return_code);
|
|
}
|
|
|
|
void fatal_error(char* file, int line, char* func, char* error_text)
|
|
{
|
|
nlog (LOG_CRITICAL, LOG_CORE, "Fatal Error: %s %d %s %s", file, line, func, error_text);
|
|
do_exit (NS_EXIT_ERROR, "Fatal Error - check log file");
|
|
}
|