core.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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/plugins.h"
  12. #endif
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <signal.h>
  16. #include <string.h>
  17. #ifndef _WIN32
  18. #include <unistd.h>
  19. #else
  20. #include <windows.h> // Console close event handling
  21. #endif
  22. /// Called when a terminate signal is received.
  23. void (*shutdown_callback)(void) = NULL;
  24. #if defined(BUILDBOT)
  25. int buildbotflag = 0;
  26. #endif
  27. int runflag = CORE_ST_RUN;
  28. int arg_c = 0;
  29. char **arg_v = NULL;
  30. char *SERVER_NAME = NULL;
  31. char SERVER_TYPE = ATHENA_SERVER_NONE;
  32. static char rA_svn_version[10] = "";
  33. #ifndef MINICORE // minimalist Core
  34. // Added by Gabuzomeu
  35. //
  36. // This is an implementation of signal() using sigaction() for portability.
  37. // (sigaction() is POSIX; signal() is not.) Taken from Stevens' _Advanced
  38. // Programming in the UNIX Environment_.
  39. //
  40. #ifdef WIN32 // windows don't have SIGPIPE
  41. #define SIGPIPE SIGINT
  42. #endif
  43. #ifndef POSIX
  44. #define compat_signal(signo, func) signal(signo, func)
  45. #else
  46. sigfunc *compat_signal(int signo, sigfunc *func)
  47. {
  48. struct sigaction sact, oact;
  49. sact.sa_handler = func;
  50. sigemptyset(&sact.sa_mask);
  51. sact.sa_flags = 0;
  52. #ifdef SA_INTERRUPT
  53. sact.sa_flags |= SA_INTERRUPT; /* SunOS */
  54. #endif
  55. if (sigaction(signo, &sact, &oact) < 0)
  56. return (SIG_ERR);
  57. return (oact.sa_handler);
  58. }
  59. #endif
  60. /*======================================
  61. * CORE : Console events for Windows
  62. *--------------------------------------*/
  63. #ifdef _WIN32
  64. static BOOL WINAPI console_handler(DWORD c_event)
  65. {
  66. switch(c_event)
  67. {
  68. case CTRL_CLOSE_EVENT:
  69. case CTRL_LOGOFF_EVENT:
  70. case CTRL_SHUTDOWN_EVENT:
  71. if( shutdown_callback != NULL )
  72. shutdown_callback();
  73. else
  74. runflag = CORE_ST_STOP;// auto-shutdown
  75. break;
  76. default:
  77. break;
  78. }
  79. return TRUE;
  80. }
  81. static void cevents_init()
  82. {
  83. if (SetConsoleCtrlHandler(console_handler,TRUE)==FALSE)
  84. ShowWarning ("Unable to install the console handler!\n");
  85. }
  86. #endif
  87. /*======================================
  88. * CORE : Signal Sub Function
  89. *--------------------------------------*/
  90. static void sig_proc(int sn)
  91. {
  92. static int is_called = 0;
  93. switch (sn) {
  94. case SIGINT:
  95. case SIGTERM:
  96. if (++is_called > 3)
  97. exit(EXIT_SUCCESS);
  98. if( shutdown_callback != NULL )
  99. shutdown_callback();
  100. else
  101. runflag = CORE_ST_STOP;// auto-shutdown
  102. break;
  103. case SIGSEGV:
  104. case SIGFPE:
  105. do_abort();
  106. // Pass the signal to the system's default handler
  107. compat_signal(sn, SIG_DFL);
  108. raise(sn);
  109. break;
  110. #ifndef _WIN32
  111. case SIGXFSZ:
  112. // ignore and allow it to set errno to EFBIG
  113. ShowWarning ("Max file size reached!\n");
  114. //run_flag = 0; // should we quit?
  115. break;
  116. case SIGPIPE:
  117. //ShowInfo ("Broken pipe found... closing socket\n"); // set to eof in socket.c
  118. break; // does nothing here
  119. #endif
  120. }
  121. }
  122. void signals_init (void)
  123. {
  124. compat_signal(SIGTERM, sig_proc);
  125. compat_signal(SIGINT, sig_proc);
  126. #ifndef _DEBUG // need unhandled exceptions to debug on Windows
  127. compat_signal(SIGSEGV, sig_proc);
  128. compat_signal(SIGFPE, sig_proc);
  129. #endif
  130. #ifndef _WIN32
  131. compat_signal(SIGILL, SIG_DFL);
  132. compat_signal(SIGXFSZ, sig_proc);
  133. compat_signal(SIGPIPE, sig_proc);
  134. compat_signal(SIGBUS, SIG_DFL);
  135. compat_signal(SIGTRAP, SIG_DFL);
  136. #endif
  137. }
  138. #endif
  139. const char* get_svn_revision(void)
  140. {
  141. FILE *fp;
  142. if(*rA_svn_version)
  143. return rA_svn_version;
  144. if ((fp = fopen(".svn/entries", "r")) != NULL)
  145. {
  146. char line[1024];
  147. int rev;
  148. // Check the version
  149. if (fgets(line, sizeof(line), fp))
  150. {
  151. if(!ISDIGIT(line[0]))
  152. {
  153. // XML File format
  154. while (fgets(line,sizeof(line),fp))
  155. if (strstr(line,"revision=")) break;
  156. if (sscanf(line," %*[^\"]\"%d%*[^\n]", &rev) == 1) {
  157. snprintf(rA_svn_version, sizeof(rA_svn_version), "%d", rev);
  158. }
  159. } else {
  160. // Bin File format
  161. bool fgresult;
  162. fgresult = ( fgets(line, sizeof(line), fp) != NULL ); // Get the name
  163. fgresult = ( fgets(line, sizeof(line), fp) != NULL ); // Get the entries kind
  164. if(fgets(line, sizeof(line), fp)) // Get the rev numver
  165. {
  166. snprintf(rA_svn_version, sizeof(rA_svn_version), "%d", atoi(line));
  167. }
  168. }
  169. }
  170. fclose(fp);
  171. }
  172. /**
  173. * subversion 1.7 introduces the use of a .db file to store it, and we go through it
  174. * TODO: In some cases it may be not accurate
  175. **/
  176. if(!(*rA_svn_version) && ((fp = fopen(".svn/wc.db", "rb")) != NULL || (fp = fopen("../.svn/wc.db", "rb")) != NULL)) {
  177. char lines[64];
  178. int revision,last_known = 0;
  179. while(fread(lines, sizeof(char), sizeof(lines), fp)) {
  180. if( strstr(lines,"!svn/ver/") ) {
  181. if (sscanf(strstr(lines,"!svn/ver/"),"!svn/ver/%d/%*s", &revision) == 1) {
  182. if( revision > last_known ) {
  183. last_known = revision;
  184. }
  185. }
  186. }
  187. }
  188. fclose(fp);
  189. if( last_known != 0 )
  190. snprintf(rA_svn_version, sizeof(rA_svn_version), "%d", last_known);
  191. }
  192. /**
  193. * we definitely didn't find it.
  194. **/
  195. if(!(*rA_svn_version))
  196. snprintf(rA_svn_version, sizeof(rA_svn_version), "Unknown");
  197. return rA_svn_version;
  198. }
  199. /*======================================
  200. * CORE : Display title
  201. * ASCII By CalciumKid 1/12/2011
  202. *--------------------------------------*/
  203. static void display_title(void)
  204. {
  205. //ClearScreen(); // clear screen and go up/left (0, 0 position in text)
  206. ShowMessage("\n");
  207. ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
  208. ShowMessage(""CL_PASS" "CL_BT_WHITE" RAthena Development Team presents "CL_PASS""CL_CLL""CL_NORMAL"\n");
  209. ShowMessage(""CL_PASS" "CL_BOLD" ____ ___ __ __ "CL_PASS""CL_CLL""CL_NORMAL"\n");
  210. ShowMessage(""CL_PASS" "CL_BOLD" / __ \\/ | / /_/ /_ ___ ____ ____ _ "CL_PASS""CL_CLL""CL_NORMAL"\n");
  211. ShowMessage(""CL_PASS" "CL_BOLD" / /_/ / /| |/ __/ __ \\/ _ \\/ __ \\/ __ `/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
  212. ShowMessage(""CL_PASS" "CL_BOLD" / _, _/ ___ / /_/ / / / __/ / / / /_/ / "CL_PASS""CL_CLL""CL_NORMAL"\n");
  213. ShowMessage(""CL_PASS" "CL_BOLD" /_/ |_/_/ |_\\__/_/ /_/\\___/_/ /_/\\___,_/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
  214. ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
  215. ShowMessage(""CL_PASS" "CL_GREEN" http://rathena.org/board/ "CL_PASS""CL_CLL""CL_NORMAL"\n");
  216. ShowMessage(""CL_PASS" "CL_BOLD" "CL_PASS""CL_CLL""CL_NORMAL"\n");
  217. ShowInfo("SVN Revision: '"CL_WHITE"%s"CL_RESET"'.\n", get_svn_revision());
  218. }
  219. // Warning if executed as superuser (root)
  220. void usercheck(void)
  221. {
  222. #ifndef _WIN32
  223. if (geteuid() == 0) {
  224. ShowWarning ("You are running rAthena with root privileges, it is not necessary.\n");
  225. }
  226. #endif
  227. }
  228. /*======================================
  229. * CORE : MAINROUTINE
  230. *--------------------------------------*/
  231. int main (int argc, char **argv)
  232. {
  233. {// initialize program arguments
  234. char *p1 = SERVER_NAME = argv[0];
  235. char *p2 = p1;
  236. while ((p1 = strchr(p2, '/')) != NULL || (p1 = strchr(p2, '\\')) != NULL)
  237. {
  238. SERVER_NAME = ++p1;
  239. p2 = p1;
  240. }
  241. arg_c = argc;
  242. arg_v = argv;
  243. }
  244. malloc_init();// needed for Show* in display_title() [FlavioJS]
  245. #ifdef MINICORE // minimalist Core
  246. display_title();
  247. usercheck();
  248. do_init(argc,argv);
  249. do_final();
  250. #else// not MINICORE
  251. set_server_type();
  252. display_title();
  253. usercheck();
  254. db_init();
  255. signals_init();
  256. #ifdef _WIN32
  257. cevents_init();
  258. #endif
  259. timer_init();
  260. socket_init();
  261. plugins_init();
  262. do_init(argc,argv);
  263. plugin_event_trigger(EVENT_ATHENA_INIT);
  264. {// Main runtime cycle
  265. int next;
  266. while (runflag != CORE_ST_STOP) {
  267. next = do_timer(gettick_nocache());
  268. do_sockets(next);
  269. }
  270. }
  271. plugin_event_trigger(EVENT_ATHENA_FINAL);
  272. do_final();
  273. timer_final();
  274. plugins_final();
  275. socket_final();
  276. db_final();
  277. #endif
  278. malloc_final();
  279. return 0;
  280. }