123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
- // For more information, see LICENCE in the main folder
- #include "../common/mmo.h"
- #include "../common/showmsg.h"
- #include "../common/malloc.h"
- #include "core.h"
- #ifndef MINICORE
- #include "../common/db.h"
- #include "../common/socket.h"
- #include "../common/timer.h"
- #include "../common/thread.h"
- #include "../common/mempool.h"
- #include "../common/sql.h"
- #endif
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <string.h>
- #ifndef _WIN32
- #include <unistd.h>
- #else
- #include "../common/winapi.h" // Console close event handling
- #endif
- /// Called when a terminate signal is received.
- void (*shutdown_callback)(void) = NULL;
- #if defined(BUILDBOT)
- int buildbotflag = 0;
- #endif
- int runflag = CORE_ST_RUN;
- int arg_c = 0;
- char **arg_v = NULL;
- char *SERVER_NAME = NULL;
- char SERVER_TYPE = ATHENA_SERVER_NONE;
- #ifndef MINICORE // minimalist Core
- // Added by Gabuzomeu
- //
- // This is an implementation of signal() using sigaction() for portability.
- // (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced
- // Programming in the UNIX Environment_.
- //
- #ifdef WIN32 // windows don't have SIGPIPE
- #define SIGPIPE SIGINT
- #endif
- #ifndef POSIX
- #define compat_signal(signo, func) signal(signo, func)
- #else
- sigfunc *compat_signal(int signo, sigfunc *func)
- {
- struct sigaction sact, oact;
- sact.sa_handler = func;
- sigemptyset(&sact.sa_mask);
- sact.sa_flags = 0;
- #ifdef SA_INTERRUPT
- sact.sa_flags |= SA_INTERRUPT; /* SunOS */
- #endif
- if (sigaction(signo, &sact, &oact) < 0)
- return (SIG_ERR);
- return (oact.sa_handler);
- }
- #endif
- /*======================================
- * CORE : Console events for Windows
- *--------------------------------------*/
- #ifdef _WIN32
- static BOOL WINAPI console_handler(DWORD c_event)
- {
- switch(c_event)
- {
- case CTRL_CLOSE_EVENT:
- case CTRL_LOGOFF_EVENT:
- case CTRL_SHUTDOWN_EVENT:
- if( shutdown_callback != NULL )
- shutdown_callback();
- else
- runflag = CORE_ST_STOP;// auto-shutdown
- break;
- default:
- return FALSE;
- }
- return TRUE;
- }
- static void cevents_init()
- {
- if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE)
- ShowWarning ("Unable to install the console handler!\n");
- }
- #endif
- /*======================================
- * CORE : Signal Sub Function
- *--------------------------------------*/
- static void sig_proc(int sn)
- {
- static int is_called = 0;
- switch (sn) {
- case SIGINT:
- case SIGTERM:
- if (++is_called > 3)
- exit(EXIT_SUCCESS);
- if( shutdown_callback != NULL )
- shutdown_callback();
- else
- runflag = CORE_ST_STOP;// auto-shutdown
- break;
- case SIGSEGV:
- case SIGFPE:
- do_abort();
- // Pass the signal to the system's default handler
- compat_signal(sn, SIG_DFL);
- raise(sn);
- break;
- #ifndef _WIN32
- case SIGXFSZ:
- // ignore and allow it to set errno to EFBIG
- ShowWarning ("Max file size reached!\n");
- //run_flag = 0; // should we quit?
- break;
- case SIGPIPE:
- //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.c
- break; // does nothing here
- #endif
- }
- }
- void signals_init (void)
- {
- compat_signal(SIGTERM, sig_proc);
- compat_signal(SIGINT, sig_proc);
- #ifndef _DEBUG // need unhandled exceptions to debug on Windows
- compat_signal(SIGSEGV, sig_proc);
- compat_signal(SIGFPE, sig_proc);
- #endif
- #ifndef _WIN32
- compat_signal(SIGILL, SIG_DFL);
- compat_signal(SIGXFSZ, sig_proc);
- compat_signal(SIGPIPE, sig_proc);
- compat_signal(SIGBUS, SIG_DFL);
- compat_signal(SIGTRAP, SIG_DFL);
- #endif
- }
- #endif
- #ifdef SVNVERSION
- const char *get_svn_revision(void)
- {
- return EXPAND_AND_QUOTE(SVNVERSION);
- }
- #else// not SVNVERSION
- const char* get_svn_revision(void)
- {
- static char svn_version_buffer[16] = "";
- FILE *fp;
- if( svn_version_buffer[0] != '\0' )
- return svn_version_buffer;
- // subversion 1.7 uses a sqlite3 database
- // FIXME this is hackish at best...
- // - ignores database file structure
- // - assumes the data in NODES.dav_cache column ends with "!svn/ver/<revision>/<path>)"
- // - since it's a cache column, the data might not even exist
- if( (fp = fopen(".svn"PATHSEP_STR"wc.db", "rb")) != NULL || (fp = fopen(".."PATHSEP_STR".svn"PATHSEP_STR"wc.db", "rb")) != NULL )
- {
- #ifndef SVNNODEPATH
- //not sure how to handle branches, so i'll leave this overridable define until a better solution comes up
- #define SVNNODEPATH trunk
- #endif
- const char* prefix = "!svn/ver/";
- const char* postfix = "/"EXPAND_AND_QUOTE(SVNNODEPATH)")"; // there should exist only 1 entry like this
- size_t prefix_len = strlen(prefix);
- size_t postfix_len = strlen(postfix);
- size_t i,j,len;
- char* buffer;
- // read file to buffer
- fseek(fp, 0, SEEK_END);
- len = ftell(fp);
- buffer = (char*)aMalloc(len + 1);
- fseek(fp, 0, SEEK_SET);
- len = fread(buffer, 1, len, fp);
- buffer[len] = '\0';
- fclose(fp);
- // parse buffer
- for( i = prefix_len + 1; i + postfix_len <= len; ++i )
- {
- if( buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0 )
- continue; // postfix missmatch
- for( j = i; j > 0; --j )
- {// skip digits
- if( !ISDIGIT(buffer[j - 1]) )
- break;
- }
- if( memcmp(buffer + j - prefix_len, prefix, prefix_len) != 0 )
- continue; // prefix missmatch
- // done
- snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(buffer + j));
- break;
- }
- aFree(buffer);
- if( svn_version_buffer[0] != '\0' )
- return svn_version_buffer;
- }
- // subversion 1.6 and older?
- if ((fp = fopen(".svn/entries", "r")) != NULL)
- {
- char line[1024];
- int rev;
- // Check the version
- if (fgets(line, sizeof(line), fp))
- {
- if(!ISDIGIT(line[0]))
- {
- // XML File format
- while (fgets(line,sizeof(line),fp))
- if (strstr(line,"revision=")) break;
- if (sscanf(line," %*[^\"]\"%d%*[^\n]", &rev) == 1) {
- snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", rev);
- }
- }
- else
- {
- // Bin File format
- if ( fgets(line, sizeof(line), fp) == NULL ) { printf("Can't get bin name\n"); } // Get the name
- if ( fgets(line, sizeof(line), fp) == NULL ) { printf("Can't get entries kind\n"); } // Get the entries kind
- if(fgets(line, sizeof(line), fp)) // Get the rev numver
- {
- snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(line));
- }
- }
- }
- fclose(fp);
- if( svn_version_buffer[0] != '\0' )
- return svn_version_buffer;
- }
- // fallback
- snprintf(svn_version_buffer, sizeof(svn_version_buffer), "Unknown");
- return svn_version_buffer;
- }
- #endif
- /*======================================
- * CORE : Display title
- * ASCII By CalciumKid 1/12/2011
- *--------------------------------------*/
- static void display_title(void) {
- //ClearScreen(); // clear screen and go up/left (0, 0 position in text)
- ShowMessage("\n");
- ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_PASS" "CL_BT_WHITE" rAthena Development Team presents "CL_PASS""CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_PASS" "CL_BOLD" ___ __ __ "CL_PASS""CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_PASS" "CL_BOLD" _____/ | / /_/ /_ ___ ____ ____ _ "CL_PASS""CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_PASS" "CL_BOLD" / ___/ /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_PASS" "CL_BOLD" / / / ___ / /_/ / / / __/ / / / /_/ / "CL_PASS""CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_PASS" "CL_BOLD" /_/ /_/ |_\\__/_/ /_/\\___/_/ /_/\\__,_/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_PASS" "CL_GREEN" http://rathena.org/board/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
- ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
- ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision());
- }
- // Warning if executed as superuser (root)
- void usercheck(void)
- {
- #ifndef _WIN32
- if (geteuid() == 0) {
- ShowWarning ("You are running rAthena with root privileges, it is not necessary.\n");
- }
- #endif
- }
- /*======================================
- * CORE : MAINROUTINE
- *--------------------------------------*/
- int main (int argc, char **argv)
- {
- {// initialize program arguments
- char *p1 = SERVER_NAME = argv[0];
- char *p2 = p1;
- while ((p1 = strchr(p2, '/')) != NULL || (p1 = strchr(p2, '\\')) != NULL)
- {
- SERVER_NAME = ++p1;
- p2 = p1;
- }
- arg_c = argc;
- arg_v = argv;
- }
- malloc_init();// needed for Show* in display_title() [FlavioJS]
- #ifdef MINICORE // minimalist Core
- display_title();
- usercheck();
- do_init(argc,argv);
- do_final();
- #else// not MINICORE
- set_server_type();
- display_title();
- usercheck();
- Sql_Init();
- rathread_init();
- mempool_init();
- db_init();
- signals_init();
- #ifdef _WIN32
- cevents_init();
- #endif
- timer_init();
- socket_init();
- do_init(argc,argv);
- {// Main runtime cycle
- int next;
- while (runflag != CORE_ST_STOP) {
- next = do_timer(gettick_nocache());
- do_sockets(next);
- }
- }
- do_final();
- timer_final();
- socket_final();
- db_final();
- mempool_final();
- rathread_final();
- #endif
- malloc_final();
- return 0;
- }
|