diff --git a/dedicated.c b/dedicated.c --- a/dedicated.c +++ b/dedicated.c @@ -26,8 +26,44 @@ static void *_dedicated_video_mem; #ifdef UNIX +/* We want to fork our dedicated server */ +void DedicatedFork() +{ + /* Fork the program */ + _dedicated_pid = fork(); + switch (_dedicated_pid) { + case -1: + perror("Unable to fork"); + exit(1); + case 0: + // We're the child + + /* Open the log-file to log all stuff too */ + _log_file_fd = fopen(_log_file, "a"); + if (!_log_file_fd) { + perror("Unable to open logfile"); + exit(1); + } + /* Redirect stdout and stderr to log-file */ + if (dup2(fileno(_log_file_fd), fileno(stdout)) == -1) { + perror("Re-routing stdout"); + exit(1); + } + if (dup2(fileno(_log_file_fd), fileno(stderr)) == -1) { + perror("Re-routing stderr"); + exit(1); + } + break; + default: + // We're the parent + printf("Loading dedicated server...\n"); + printf(" - Forked to background with pid %d\n", _dedicated_pid); + exit(0); + } +} + /* Signal handlers */ -void DedicatedSignalHandler(int sig) +static void DedicatedSignalHandler(int sig) { _exit_game = true; signal(sig, DedicatedSignalHandler); @@ -57,7 +93,7 @@ static bool DedicatedVideoChangeRes(int #ifdef UNIX -bool InputWaiting() +static bool InputWaiting() { struct timeval tv; fd_set readfds; @@ -77,21 +113,48 @@ bool InputWaiting() return false; } #else -bool InputWaiting() +static bool InputWaiting() { return kbhit(); } #endif -static int DedicatedVideoMainLoop() { +static void DedicatedHandleKeyInput() +{ +#ifdef WIN32 + char input; +#endif + char input_line[200]; + +#ifdef UNIX + if (InputWaiting()) { + fgets(input_line, 200, stdin); + // Forget about the final \n (or \r) + strtok(input_line, "\r\n"); + IConsoleCmdExec(input_line); + } +#else + if (InputWaiting()) { + input = getch(); + printf("%c", input); + if (input != '\r') + snprintf(input_line, 200, "%s%c", input_line, input); + else { + printf("\n"); + IConsoleCmdExec(input_line); + sprintf(input_line, ""); + } + } +#endif +} + +static int DedicatedVideoMainLoop() +{ #ifndef WIN32 struct timeval tim; -#else - char input; #endif uint32 next_tick; uint32 cur_ticks; - char input_line[200]; #ifdef WIN32 next_tick = GetTickCount() + 30; @@ -125,26 +188,8 @@ static int DedicatedVideoMainLoop() { if (_exit_game) return ML_QUIT; -#ifdef UNIX - if (InputWaiting()) { - fgets(input_line, 200, stdin); - // Forget about the final \n (or \r) - strtok(input_line, "\r\n"); - IConsoleCmdExec(input_line); - } -#else - if (InputWaiting()) { - input = getch(); - printf("%c", input); - if (input != '\r') - snprintf(input_line, 200, "%s%c", input_line, input); - else { - printf("\n"); - IConsoleCmdExec(input_line); - sprintf(input_line, ""); - } - } -#endif + if (!_dedicated_forks) + DedicatedHandleKeyInput(); #ifdef WIN32 cur_ticks = GetTickCount(); diff --git a/ttd.c b/ttd.c --- a/ttd.c +++ b/ttd.c @@ -314,6 +314,7 @@ static void showhelp() " -G seed = Set random seed\n" " -n [ip#player:port] = Start networkgame\n" " -D = Start dedicated server\n" + " -f = Fork into the background (dedicated only)\n" " -i = Force to use the DOS palette (use this if you see a lot of pink)\n" " -p #player = Player as #player (deprecated) (network only)\n" ); @@ -516,6 +517,8 @@ void LoadIntroGame() if (_music_driver->is_song_playing()) ResetMusic(); } +extern void DedicatedFork(); + int ttd_main(int argc, char* argv[]) { MyGetOptData mgo; @@ -531,12 +534,14 @@ int ttd_main(int argc, char* argv[]) _game_mode = GM_MENU; _switch_mode = SM_MENU; _switch_mode_errorstr = INVALID_STRING_ID; + _dedicated_forks = false; + _dedicated_enabled = false; // The last param of the following function means this: // a letter means: it accepts that param (e.g.: -h) // a ':' behind it means: it need a param (e.g.: -m) // a '::' behind it means: it can optional have a param (e.g.: -d) - MyGetOptInit(&mgo, argc-1, argv+1, "m:s:v:hDn::l:eit:d::r:g::G:p:"); + MyGetOptInit(&mgo, argc-1, argv+1, "m:s:v:hDfn::l:eit:d::r:g::G:p:"); while ((i = MyGetOpt(&mgo)) != -1) { switch(i) { case 'm': ttd_strlcpy(musicdriver, mgo.opt, sizeof(musicdriver)); break; @@ -546,7 +551,11 @@ int ttd_main(int argc, char* argv[]) sprintf(musicdriver,"null"); sprintf(sounddriver,"null"); sprintf(videodriver,"dedicated"); + _dedicated_enabled = true; } break; + case 'f': { + _dedicated_forks = true; + }; break; case 'n': { network = true; if (mgo.opt) @@ -595,6 +604,13 @@ int ttd_main(int argc, char* argv[]) } DeterminePaths(); + +#ifdef UNIX + // We must fork here, or we'll end up without some resources we need (like sockets) + if (_dedicated_forks) + DedicatedFork(); +#endif + LoadFromConfig(); // override config? @@ -604,6 +620,9 @@ int ttd_main(int argc, char* argv[]) if (resolution[0]) { _cur_resolution[0] = resolution[0]; _cur_resolution[1] = resolution[1]; } if (startdate != -1) _patches.starting_date = startdate; + if (_dedicated_forks && !_dedicated_enabled) + _dedicated_forks = false; + // enumerate language files InitializeLanguagePacks(); diff --git a/unix.c b/unix.c --- a/unix.c +++ b/unix.c @@ -500,6 +500,7 @@ void DeterminePaths() _path.gm_dir = str_fmt("%sgm/", _path.game_data_dir); _path.data_dir = str_fmt("%sdata/", _path.game_data_dir); _config_file = str_fmt("%sopenttd.cfg", _path.personal_dir); + _log_file = str_fmt("%sopenttd.log", _path.personal_dir); #if defined CUSTOM_LANG_DIR // sets the search path for lng files to the custom one diff --git a/variables.h b/variables.h --- a/variables.h +++ b/variables.h @@ -322,6 +322,8 @@ VARDEF int _num_screenshot_formats, _cur VARDEF char _savegame_format[8]; VARDEF char *_config_file; +VARDEF char *_log_file; +VARDEF FILE *_log_file_fd; // NOSAVE: These can be recalculated from InitializeLandscapeVariables typedef struct { @@ -419,6 +421,11 @@ VARDEF int _debug_grf_level; VARDEF int _debug_ai_level; VARDEF int _debug_net_level; +/* Forking stuff */ +VARDEF bool _dedicated_forks; +VARDEF bool _dedicated_enabled; +VARDEF pid_t _dedicated_pid; + void CDECL debug(const char *s, ...); #ifdef NO_DEBUG_MESSAGES #define DEBUG(name, level) diff --git a/win32.c b/win32.c --- a/win32.c +++ b/win32.c @@ -2061,6 +2061,7 @@ void DeterminePaths() _path.lang_dir = str_fmt("%slang\\", cfg); _config_file = str_fmt("%sopenttd.cfg", _path.personal_dir); + _log_file = str_fmt("%sopenttd.log", _path.personal_dir); // make (auto)save and scenario folder CreateDirectory(_path.save_dir, NULL);