core.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/mmo.h"
  4. #include "../common/showmsg.h"
  5. #include "../common/malloc.h"
  6. #include "core.h"
  7. #ifndef MINICORE
  8. #include "../common/db.h"
  9. #include "../common/socket.h"
  10. #include "../common/timer.h"
  11. #include "../common/thread.h"
  12. #include "../common/mempool.h"
  13. #include "../common/sql.h"
  14. #endif
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <signal.h>
  18. #include <string.h>
  19. #ifndef _WIN32
  20. #include <unistd.h>
  21. #else
  22. #include "../common/winapi.h" // Console close event handling
  23. #endif
  24. /// Called when a terminate signal is received.
  25. void (*shutdown_callback)(void) = NULL;
  26. #if defined(BUILDBOT)
  27. int buildbotflag = 0;
  28. #endif
  29. int runflag = CORE_ST_RUN;
  30. int arg_c = 0;
  31. char **arg_v = NULL;
  32. char *SERVER_NAME = NULL;
  33. char SERVER_TYPE = ATHENA_SERVER_NONE;
  34. #ifndef MINICORE // minimalist Core
  35. // Added by Gabuzomeu
  36. //
  37. // This is an implementation of signal() using sigaction() for portability.
  38. // (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced
  39. // Programming in the UNIX Environment_.
  40. //
  41. #ifdef WIN32 // windows don't have SIGPIPE
  42. #define SIGPIPE SIGINT
  43. #endif
  44. #ifndef POSIX
  45. #define compat_signal(signo, func) signal(signo, func)
  46. #else
  47. sigfunc *compat_signal(int signo, sigfunc *func)
  48. {
  49. struct sigaction sact, oact;
  50. sact.sa_handler = func;
  51. sigemptyset(&sact.sa_mask);
  52. sact.sa_flags = 0;
  53. #ifdef SA_INTERRUPT
  54. sact.sa_flags |= SA_INTERRUPT; /* SunOS */
  55. #endif
  56. if (sigaction(signo, &sact, &oact) < 0)
  57. return (SIG_ERR);
  58. return (oact.sa_handler);
  59. }
  60. #endif
  61. /*======================================
  62. * CORE : Console events for Windows
  63. *--------------------------------------*/
  64. #ifdef _WIN32
  65. static BOOL WINAPI console_handler(DWORD c_event)
  66. {
  67. switch(c_event)
  68. {
  69. case CTRL_CLOSE_EVENT:
  70. case CTRL_LOGOFF_EVENT:
  71. case CTRL_SHUTDOWN_EVENT:
  72. if( shutdown_callback != NULL )
  73. shutdown_callback();
  74. else
  75. runflag = CORE_ST_STOP;// auto-shutdown
  76. break;
  77. default:
  78. return FALSE;
  79. }
  80. return TRUE;
  81. }
  82. static void cevents_init()
  83. {
  84. if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE)
  85. ShowWarning ("Unable to install the console handler!\n");
  86. }
  87. #endif
  88. /*======================================
  89. * CORE : Signal Sub Function
  90. *--------------------------------------*/
  91. static void sig_proc(int sn)
  92. {
  93. static int is_called = 0;
  94. switch (sn) {
  95. case SIGINT:
  96. case SIGTERM:
  97. if (++is_called > 3)
  98. exit(EXIT_SUCCESS);
  99. if( shutdown_callback != NULL )
  100. shutdown_callback();
  101. else
  102. runflag = CORE_ST_STOP;// auto-shutdown
  103. break;
  104. case SIGSEGV:
  105. case SIGFPE:
  106. do_abort();
  107. // Pass the signal to the system's default handler
  108. compat_signal(sn, SIG_DFL);
  109. raise(sn);
  110. break;
  111. #ifndef _WIN32
  112. case SIGXFSZ:
  113. // ignore and allow it to set errno to EFBIG
  114. ShowWarning ("Max file size reached!\n");
  115. //run_flag = 0; // should we quit?
  116. break;
  117. case SIGPIPE:
  118. //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.c
  119. break; // does nothing here
  120. #endif
  121. }
  122. }
  123. void signals_init (void)
  124. {
  125. compat_signal(SIGTERM, sig_proc);
  126. compat_signal(SIGINT, sig_proc);
  127. #ifndef _DEBUG // need unhandled exceptions to debug on Windows
  128. compat_signal(SIGSEGV, sig_proc);
  129. compat_signal(SIGFPE, sig_proc);
  130. #endif
  131. #ifndef _WIN32
  132. compat_signal(SIGILL, SIG_DFL);
  133. compat_signal(SIGXFSZ, sig_proc);
  134. compat_signal(SIGPIPE, sig_proc);
  135. compat_signal(SIGBUS, SIG_DFL);
  136. compat_signal(SIGTRAP, SIG_DFL);
  137. #endif
  138. }
  139. #endif
  140. #ifdef SVNVERSION
  141. const char *get_svn_revision(void)
  142. {
  143. return EXPAND_AND_QUOTE(SVNVERSION);
  144. }
  145. #else// not SVNVERSION
  146. const char* get_svn_revision(void)
  147. {
  148. static char svn_version_buffer[16] = "";
  149. FILE *fp;
  150. if( svn_version_buffer[0] != '\0' )
  151. return svn_version_buffer;
  152. // subversion 1.7 uses a sqlite3 database
  153. // FIXME this is hackish at best...
  154. // - ignores database file structure
  155. // - assumes the data in NODES.dav_cache column ends with "!svn/ver/<revision>/<path>)"
  156. // - since it's a cache column, the data might not even exist
  157. if( (fp = fopen(".svn"PATHSEP_STR"wc.db", "rb")) != NULL || (fp = fopen(".."PATHSEP_STR".svn"PATHSEP_STR"wc.db", "rb")) != NULL )
  158. {
  159. #ifndef SVNNODEPATH
  160. //not sure how to handle branches, so i'll leave this overridable define until a better solution comes up
  161. #define SVNNODEPATH trunk
  162. #endif
  163. const char* prefix = "!svn/ver/";
  164. const char* postfix = "/"EXPAND_AND_QUOTE(SVNNODEPATH)")"; // there should exist only 1 entry like this
  165. size_t prefix_len = strlen(prefix);
  166. size_t postfix_len = strlen(postfix);
  167. size_t i,j,len;
  168. char* buffer;
  169. // read file to buffer
  170. fseek(fp, 0, SEEK_END);
  171. len = ftell(fp);
  172. buffer = (char*)aMalloc(len + 1);
  173. fseek(fp, 0, SEEK_SET);
  174. len = fread(buffer, 1, len, fp);
  175. buffer[len] = '\0';
  176. fclose(fp);
  177. // parse buffer
  178. for( i = prefix_len + 1; i + postfix_len <= len; ++i )
  179. {
  180. if( buffer[i] != postfix[0] || memcmp(buffer + i, postfix, postfix_len) != 0 )
  181. continue; // postfix missmatch
  182. for( j = i; j > 0; --j )
  183. {// skip digits
  184. if( !ISDIGIT(buffer[j - 1]) )
  185. break;
  186. }
  187. if( memcmp(buffer + j - prefix_len, prefix, prefix_len) != 0 )
  188. continue; // prefix missmatch
  189. // done
  190. snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(buffer + j));
  191. break;
  192. }
  193. aFree(buffer);
  194. if( svn_version_buffer[0] != '\0' )
  195. return svn_version_buffer;
  196. }
  197. // subversion 1.6 and older?
  198. if ((fp = fopen(".svn/entries", "r")) != NULL)
  199. {
  200. char line[1024];
  201. int rev;
  202. // Check the version
  203. if (fgets(line, sizeof(line), fp))
  204. {
  205. if(!ISDIGIT(line[0]))
  206. {
  207. // XML File format
  208. while (fgets(line,sizeof(line),fp))
  209. if (strstr(line,"revision=")) break;
  210. if (sscanf(line," %*[^\"]\"%d%*[^\n]", &rev) == 1) {
  211. snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", rev);
  212. }
  213. }
  214. else
  215. {
  216. // Bin File format
  217. if ( fgets(line, sizeof(line), fp) == NULL ) { printf("Can't get bin name\n"); } // Get the name
  218. if ( fgets(line, sizeof(line), fp) == NULL ) { printf("Can't get entries kind\n"); } // Get the entries kind
  219. if(fgets(line, sizeof(line), fp)) // Get the rev numver
  220. {
  221. snprintf(svn_version_buffer, sizeof(svn_version_buffer), "%d", atoi(line));
  222. }
  223. }
  224. }
  225. fclose(fp);
  226. if( svn_version_buffer[0] != '\0' )
  227. return svn_version_buffer;
  228. }
  229. // fallback
  230. snprintf(svn_version_buffer, sizeof(svn_version_buffer), "Unknown");
  231. return svn_version_buffer;
  232. }
  233. #endif
  234. /*======================================
  235. * CORE : Display title
  236. * ASCII By CalciumKid 1/12/2011
  237. *--------------------------------------*/
  238. static void display_title(void) {
  239. //ClearScreen(); // clear screen and go up/left (0, 0 position in text)
  240. ShowMessage("\n");
  241. ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
  242. ShowMessage(""CL_PASS" "CL_BT_WHITE" rAthena Development Team presents "CL_PASS""CL_CLL""CL_NORMAL"\n");
  243. ShowMessage(""CL_PASS" "CL_BOLD" ___ __ __ "CL_PASS""CL_CLL""CL_NORMAL"\n");
  244. ShowMessage(""CL_PASS" "CL_BOLD" _____/ | / /_/ /_ ___ ____ ____ _ "CL_PASS""CL_CLL""CL_NORMAL"\n");
  245. ShowMessage(""CL_PASS" "CL_BOLD" / ___/ /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
  246. ShowMessage(""CL_PASS" "CL_BOLD" / / / ___ / /_/ / / / __/ / / / /_/ / "CL_PASS""CL_CLL""CL_NORMAL"\n");
  247. ShowMessage(""CL_PASS" "CL_BOLD" /_/ /_/ |_\\__/_/ /_/\\___/_/ /_/\\__,_/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
  248. ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
  249. ShowMessage(""CL_PASS" "CL_GREEN" http://rathena.org/board/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
  250. ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
  251. ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision());
  252. }
  253. // Warning if executed as superuser (root)
  254. void usercheck(void)
  255. {
  256. #ifndef _WIN32
  257. if (geteuid() == 0) {
  258. ShowWarning ("You are running rAthena with root privileges, it is not necessary.\n");
  259. }
  260. #endif
  261. }
  262. /*======================================
  263. * CORE : MAINROUTINE
  264. *--------------------------------------*/
  265. int main (int argc, char **argv)
  266. {
  267. {// initialize program arguments
  268. char *p1 = SERVER_NAME = argv[0];
  269. char *p2 = p1;
  270. while ((p1 = strchr(p2, '/')) != NULL || (p1 = strchr(p2, '\\')) != NULL)
  271. {
  272. SERVER_NAME = ++p1;
  273. p2 = p1;
  274. }
  275. arg_c = argc;
  276. arg_v = argv;
  277. }
  278. malloc_init();// needed for Show* in display_title() [FlavioJS]
  279. #ifdef MINICORE // minimalist Core
  280. display_title();
  281. usercheck();
  282. do_init(argc,argv);
  283. do_final();
  284. #else// not MINICORE
  285. set_server_type();
  286. display_title();
  287. usercheck();
  288. Sql_Init();
  289. rathread_init();
  290. mempool_init();
  291. db_init();
  292. signals_init();
  293. #ifdef _WIN32
  294. cevents_init();
  295. #endif
  296. timer_init();
  297. socket_init();
  298. do_init(argc,argv);
  299. {// Main runtime cycle
  300. int next;
  301. while (runflag != CORE_ST_STOP) {
  302. next = do_timer(gettick_nocache());
  303. do_sockets(next);
  304. }
  305. }
  306. do_final();
  307. timer_final();
  308. socket_final();
  309. db_final();
  310. mempool_final();
  311. rathread_final();
  312. #endif
  313. malloc_final();
  314. return 0;
  315. }