From d8d2d7509f04822ba3910f8f1acecdff270bfe60 Mon Sep 17 00:00:00 2001 From: pk910 Date: Mon, 30 Jan 2012 23:41:35 +0100 Subject: [PATCH] moving NeonServ into background by default; added a few startup parameters --- src/IRCParser.c | 4 +- src/main.c | 161 +++++++++++++++++++++++++++++++++++++++--------- src/main.h | 16 +++++ src/mysqlConn.c | 6 +- src/signal.c | 19 ++++-- 5 files changed, 167 insertions(+), 39 deletions(-) diff --git a/src/IRCParser.c b/src/IRCParser.c index eed9380..91b4938 100644 --- a/src/IRCParser.c +++ b/src/IRCParser.c @@ -58,9 +58,9 @@ static void parse_line(struct ClientSocket *client, char *line) { int argc = 0; char *argv[MAXNUMPARAMS]; #ifdef HAVE_THREADS - printf("[%d recv %lu] %s\n", getCurrentThreadID(), (unsigned long) strlen(line), line); + putlog(LOGLEVEL_RAW, "[%d recv %lu] %s\n", getCurrentThreadID(), (unsigned long) strlen(line), line); #else - printf("[recv %lu] %s\n", (unsigned long) strlen(line), line); + putlog(LOGLEVEL_RAW, "[recv %lu] %s\n", (unsigned long) strlen(line), line); #endif if(line[0] == ':') line++; diff --git a/src/main.c b/src/main.c index 600c519..1730e38 100644 --- a/src/main.c +++ b/src/main.c @@ -38,6 +38,7 @@ #include "ConfigParser.h" #include "ssl.h" #include "QServer.h" +#include "version.h" time_t start_time; static int running, hard_restart; @@ -45,12 +46,16 @@ static int statistics_requested_lusers = 0; int statistics_enabled; TIMEQ_CALLBACK(main_statistics); TIMEQ_CALLBACK(main_checkauths); +static int daemonized = 0; +static int print_loglevel = 0; +static FILE *log_fptr = NULL; static int process_argc; static char **process_argv; #ifdef HAVE_THREADS int running_threads; pthread_mutex_t cache_sync; pthread_mutex_t whohandler_sync, whohandler_mass_sync; +static pthread_mutex_t log_sync; #endif void cleanup() { @@ -71,32 +76,28 @@ void cleanup() { static int load_mysql_config() { char *mysql_host, *mysql_user, *mysql_pass, *mysql_base; int mysql_serverport; - if(loadConfig("neonserv.conf")) { - mysql_host = get_string_field("MySQL.host"); - if(!mysql_host) { - perror("invalid neonserv.conf: missing MySQL.host"); - return 0; - } - mysql_serverport = get_int_field("MySQL.port"); - if(!mysql_serverport) - mysql_serverport = 3306; - mysql_user = get_string_field("MySQL.user"); - if(!mysql_user) { - perror("invalid neonserv.conf: missing MySQL.user"); - return 0; - } - mysql_pass = get_string_field("MySQL.pass"); - if(!mysql_pass) { - perror("invalid neonserv.conf: missing MySQL.pass"); - return 0; - } - mysql_base = get_string_field("MySQL.base"); - if(!mysql_base) { - perror("invalid neonserv.conf: missing MySQL base"); - return 0; - } - } else { - perror("Unable to load neonserv.conf"); + + mysql_host = get_string_field("MySQL.host"); + if(!mysql_host) { + perror("invalid neonserv.conf: missing MySQL.host"); + return 0; + } + mysql_serverport = get_int_field("MySQL.port"); + if(!mysql_serverport) + mysql_serverport = 3306; + mysql_user = get_string_field("MySQL.user"); + if(!mysql_user) { + perror("invalid neonserv.conf: missing MySQL.user"); + return 0; + } + mysql_pass = get_string_field("MySQL.pass"); + if(!mysql_pass) { + perror("invalid neonserv.conf: missing MySQL.pass"); + return 0; + } + mysql_base = get_string_field("MySQL.base"); + if(!mysql_base) { + perror("invalid neonserv.conf: missing MySQL base"); return 0; } init_mysql(mysql_host, mysql_serverport, mysql_user, mysql_pass, mysql_base); @@ -137,11 +138,76 @@ int getCurrentThreadID() { #endif +void exit_daemon() { + if(daemonized) { + remove(PID_FILE); + } +} + int main(int argc, char *argv[]) { -main: + int run_as_daemon = 1; + int argi; process_argv = argv; process_argc = argc; + printf("NeonServ v%s\n\n", NEONSERV_VERSION); + for(argi = 1; argi < argc; argi++) { + if(!strcmp(argv[argi], "-f") || !strcmp(argv[argi], "--foreground")) { + run_as_daemon = 0; + } else if(!strcmp(argv[argi], "-s") || !strcmp(argv[argi], "--show")) { + if(argi+1 == argc) break; + argi++; + print_loglevel = atoi(argv[argi]); + } else if(!strcmp(argv[argi], "-v") || !strcmp(argv[argi], "--version")) { + printf("Version: %s.%d (%s)\n", NEONSERV_VERSION, patchlevel, (strcmp(revision, "") ? revision : "-")); + printf("Build: #%s %s (%s lines, " COMPILER ")\n", compilation, creation, codelines); + exit(0); + } else if(!strcmp(argv[argi], "-h") || !strcmp(argv[argi], "--help")) { + printf("Usage: ./neonserv [-s loglevel] [-f] [-h|-v]\n"); + printf(" -s, --show show log lines matching loglevel in stdout.\n"); + printf(" -f, --foreground run NeonServ in the foreground.\n"); + printf(" -h, --help prints this usage message.\n"); + printf(" -v, --version prints this program's version.\n"); + exit(0); + } + } + if(geteuid() == 0 || getuid() == 0) { + fprintf(stderr, "NeonServ may not be run with super user privileges.\n"); + exit(0); + } + if(!loadConfig(CONF_FILE)) { + fprintf(stderr, "Unable to load " CONF_FILE "\n"); + exit(0); + } + #if HAVE_THREADS + THREAD_MUTEX_INIT(log_sync); + #endif + if (run_as_daemon) { + /* Attempt to fork into the background if daemon mode is on. */ + pid_t pid = fork(); + if (pid < 0) { + fprintf(stderr, "Unable to fork: %s\n", strerror(errno)); + } else if (pid > 0) { + printf("Forking into the background (pid: %d)...\n", pid); + putlog(LOGLEVEL_INFO, "Forking into the background (pid: %d)...\n", pid); + exit(0); + } + setsid(); + daemonized = 1; + atexit(exit_daemon); + FILE *pidfile = fopen(PID_FILE, "w"); + if (pidfile == NULL) { + fprintf(stderr, "Unable to create PID file: %s", strerror(errno)); + putlog(LOGLEVEL_ERROR, "Unable to create PID file: %s", strerror(errno)); + } else { + fprintf(pidfile, "%i\n", (int)getpid()); + fclose(pidfile); + } + fclose(stdin); + fclose(stdout); + fclose(stderr); + } +main: signal(SIGABRT, sighandler); signal(SIGFPE, sighandler); signal(SIGILL, sighandler); @@ -298,7 +364,7 @@ void stop_bot() { } void reload_config() { - loadConfig("neonserv.conf"); + loadConfig(CONF_FILE); } static int getCurrentSecondsOfDay() { @@ -419,3 +485,42 @@ void statistics_update() { system(command); } } + +void write_log(int loglevel, const char *line, int len) { + SYNCHRONIZE(log_sync); + if(!daemonized && (print_loglevel & loglevel)) { + printf("%s", line); + } else if(!daemonized && loglevel == LOGLEVEL_ERROR) { + fprintf(stderr, "%s", line); + } + if(get_int_field("log.loglevel") & loglevel) { + if(!log_fptr) { + log_fptr = fopen(LOG_FILE, "a"); + if(!log_fptr) goto write_log_end; + } + time_t rawtime; + struct tm *timeinfo; + time(&rawtime); + timeinfo = localtime(&rawtime); + char timestr[20]; + int timepos = strftime(timestr, 20, "%x %X ", timeinfo); + fwrite(timestr, 1, timepos, log_fptr); + fwrite(line, 1, len, log_fptr); + } + write_log_end: + DESYNCHRONIZE(log_sync); +} + +void putlog(int loglevel, const char *text, ...) { + va_list arg_list; + char logBuf[MAXLOGLEN]; + int pos; + logBuf[0] = '\0'; + va_start(arg_list, text); + pos = vsnprintf(logBuf, MAXLOGLEN - 1, text, arg_list); + va_end(arg_list); + if (pos < 0 || pos > (MAXLOGLEN - 1)) pos = MAXLOGLEN - 1; + logBuf[pos] = '\0'; + write_log(loglevel, logBuf, pos); +} + diff --git a/src/main.h b/src/main.h index b8d260b..12c6899 100644 --- a/src/main.h +++ b/src/main.h @@ -105,6 +105,10 @@ #include "memoryDebug.h" #endif +#define PID_FILE "neonserv.pid" +#define CONF_FILE "neonserv.conf" +#define LOG_FILE "neonserv.log" + #define SOCKET_SELECT_TIME 1 #define SOCKET_RECONNECT_TIME 20 @@ -116,6 +120,7 @@ #define TOPICLEN 500 #define CHANNELLEN 200 #define MAXLEN 512 +#define MAXLOGLEN 1024 #define TRIGGERLEN 50 #define MAXNUMPARAMS 200 /* maximum number of parameters in one line */ #define MAXLANGUAGES 5 @@ -136,6 +141,11 @@ #define TEMPUSER_LIST_INDEX VALID_NICK_CHARS_FIRST_LEN +#define LOGLEVEL_INFO 0x01 +#define LOGLEVEL_ERROR 0x02 +#define LOGLEVEL_RAW 0x04 +#define LOGLEVEL_MYSQL 0x08 + #define timeval_is_bigger(x,y) ((x.tv_sec > y.tv_sec) || (x.tv_sec == y.tv_sec && x.tv_usec > y.tv_usec)) extern time_t start_time; @@ -148,6 +158,8 @@ extern pthread_mutex_t whohandler_sync, whohandler_mass_sync; int getCurrentThreadID(); #endif +void exit_daemon(); + int stricmp (const char *s1, const char *s2); int stricmplen (const char *s1, const char *s2, int len); @@ -159,4 +171,8 @@ void reload_config(); void statistics_update(); +void putlog(int loglevel, const char *text, ...) PRINTF_LIKE(2, 3); + +#define perror(errmsg) (putlog(LOGLEVEL_ERROR, "ERROR (%s:%d) %s", __FILE__, __LINE__, errmsg)) + #endif \ No newline at end of file diff --git a/src/mysqlConn.c b/src/mysqlConn.c index 3e5dd19..529e8a4 100644 --- a/src/mysqlConn.c +++ b/src/mysqlConn.c @@ -204,7 +204,7 @@ void free_mysql() { void show_mysql_error() { MYSQL *mysql_conn = get_mysql_conn(); //show mysql_error() - printf("MySQL Error: %s\n", mysql_error(mysql_conn)); + putlog(LOGLEVEL_ERROR, "MySQL Error: %s\n", mysql_error(mysql_conn)); } void printf_mysql_query(const char *text, ...) { @@ -218,7 +218,7 @@ void printf_mysql_query(const char *text, ...) { va_end(arg_list); if (pos < 0 || pos > (MYSQLMAXLEN - 2)) pos = MYSQLMAXLEN - 2; queryBuf[pos] = '\0'; - printf("MySQL: %s\n", queryBuf); + putlog(LOGLEVEL_MYSQL, "MySQL: %s\n", queryBuf); if(mysql_query(mysql_conn, queryBuf)) { check_mysql(); if(mysql_query(mysql_conn, queryBuf)) { @@ -238,7 +238,7 @@ void printf_long_mysql_query(int len, const char *text, ...) { va_end(arg_list); if (pos < 0 || pos > (len - 2)) pos = len - 2; queryBuf[pos] = '\0'; - printf("MySQL: %s\n", queryBuf); + putlog(LOGLEVEL_MYSQL, "MySQL: %s\n", queryBuf); if(mysql_query(mysql_conn, queryBuf)) { check_mysql(); if(mysql_query(mysql_conn, queryBuf)) { diff --git a/src/signal.c b/src/signal.c index d5431da..848828c 100644 --- a/src/signal.c +++ b/src/signal.c @@ -24,6 +24,7 @@ static void sigcrash(); static void sigexit(); void sighandler(int signum) { + putlog(LOGLEVEL_INFO, "Received Signal %d", signum); signal(signum, SIG_DFL); switch(signum) { case SIGABRT: @@ -44,12 +45,6 @@ void sighandler(int signum) { static void sigcrash(int signum) { char *coregen = ""; - #ifndef WIN32 - char gcore[50]; - sprintf(gcore, "gcore %u", getpid()); - system(gcore); //generate core file - coregen = "core file generated."; - #endif char *signame; switch(signum) { case SIGSEGV: @@ -65,6 +60,14 @@ static void sigcrash(int signum) { signame = "SIGUNKNOWN"; break; } + putlog(LOGLEVEL_ERROR, "NeonServ process crashed (%s)", signame); + #ifndef WIN32 + char gcore[50]; + sprintf(gcore, "gcore %u", getpid()); + system(gcore); //generate core file + coregen = "core file generated."; + putlog(LOGLEVEL_ERROR | LOGLEVEL_INFO, "generated core file."); + #endif char *alertchan = get_string_field("General.alertchan"); if(alertchan) { struct ChanNode *channel = getChanByName(alertchan); @@ -81,6 +84,8 @@ static void sigcrash(int signum) { bot->flags &= SOCKET_FLAG_CONNECTED; } } + putlog(LOGLEVEL_INFO, "hard shutdown..."); + exit_daemon(); sleep(1); //hard restart restart_process(); @@ -88,4 +93,6 @@ static void sigcrash(int signum) { static void sigexit(int signum) { cleanup(); + exit_daemon(); + exit(0); } -- 2.20.1