core.c 10 KB

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