core.c 10 KB

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