/* sys_unix.c $Id: sys_unix.c,v 1.43 2007/09/22 15:27:34 sezero Exp $ Unix system interface code */ #include "quakedef.h" #include "userdir.h" // whether to use the password file to determine // the path to the home directory #define USE_PASSWORD_FILE 0 #include #include #include #include #include #include #if USE_PASSWORD_FILE #include #endif // heapsize: minimum 8 mb, standart 16 mb, max is 32 mb. // -heapsize argument will abide by these min/max settings // unless the -forcemem argument is used #define MIN_MEM_ALLOC 0x0800000 #define STD_MEM_ALLOC 0x1000000 #define MAX_MEM_ALLOC 0x2000000 cvar_t sys_nostdout = {"sys_nostdout", "0", CVAR_NONE}; int devlog; /* log the Con_DPrintf and Sys_DPrintf content when !developer.integer */ static double starttime; static qboolean first = true; /* ================ Sys_GetUserdir ================ */ static int Sys_GetUserdir (char *buff, size_t path_len) { char *home_dir = NULL; #if USE_PASSWORD_FILE struct passwd *pwent; pwent = getpwuid( getuid() ); if (pwent == NULL) perror("getpwuid"); else home_dir = pwent->pw_dir; #endif if (home_dir == NULL) home_dir = getenv("HOME"); if (home_dir == NULL) return 1; // what would be a maximum path for a file in the user's directory... // $HOME/AOT_USERDIR/game_dir/dirname1/dirname2/dirname3/filename.ext // still fits in the MAX_OSPATH == 256 definition, but just in case : if (strlen(home_dir) + strlen(AOT_USERDIR) + 50 > path_len) return 1; q_snprintf (buff, path_len, "%s/%s", home_dir, AOT_USERDIR); return Sys_mkdir(buff); } /* ================ Sys_mkdir ================ */ int Sys_mkdir (const char *path) { int rc; rc = mkdir (path, 0777); if (rc != 0 && errno == EEXIST) rc = 0; return rc; } /* ================================================= simplified findfirst/findnext implementation: Sys_FindFirstFile and Sys_FindNextFile return filenames only, not a dirent struct. this is what we presently need in this engine. ================================================= */ static DIR *finddir; static struct dirent *finddata; static char *findpath, *findpattern; char *Sys_FindFirstFile (const char *path, const char *pattern) { size_t tmp_len; if (finddir) Sys_Error ("Sys_FindFirst without FindClose"); finddir = opendir (path); if (!finddir) return NULL; tmp_len = strlen (pattern); findpattern = (char *) Z_Malloc (tmp_len + 1, Z_MAINZONE); // if (!findpattern) // return NULL; strcpy (findpattern, pattern); findpattern[tmp_len] = '\0'; tmp_len = strlen (path); findpath = (char *) Z_Malloc (tmp_len + 1, Z_MAINZONE); // if (!findpath) // return NULL; strcpy (findpath, path); findpath[tmp_len] = '\0'; return Sys_FindNextFile(); } char *Sys_FindNextFile (void) { struct stat test; if (!finddir) return NULL; do { finddata = readdir(finddir); if (finddata != NULL) { if (!fnmatch (findpattern, finddata->d_name, FNM_PATHNAME)) { if ( (stat(va("%s/%s", findpath, finddata->d_name), &test) == 0) && S_ISREG(test.st_mode) ) return finddata->d_name; } } } while (finddata != NULL); return NULL; } void Sys_FindClose (void) { if (finddir != NULL) closedir(finddir); if (findpath != NULL) Z_Free (findpath); if (findpattern != NULL) Z_Free (findpattern); finddir = NULL; findpath = NULL; findpattern = NULL; } /* ================ Sys_Error ================ */ void Sys_Error (const char *error, ...) { va_list argptr; char text[MAX_PRINTMSG]; va_start (argptr, error); q_vsnprintf (text, sizeof(text), error, argptr); va_end (argptr); printf ("\nFATAL ERROR: %s\n\n", text); if (sv_logfile) { fprintf (sv_logfile, "\nFATAL ERROR: %s\n\n", text); fflush (sv_logfile); } exit (1); } /* ================ Sys_DoubleTime ================ */ double Sys_DoubleTime (void) { struct timeval tp; struct timezone tzp; double now; gettimeofday (&tp, &tzp); now = tp.tv_sec + tp.tv_usec / 1e6; if (first) { first = false; starttime = now; return 0.0; } return now - starttime; } /* ================ Sys_ConsoleInput ================ */ char *Sys_ConsoleInput (void) { static char con_text[256]; static int textlen; char c; fd_set set; struct timeval timeout; FD_ZERO (&set); FD_SET (0, &set); // stdin timeout.tv_sec = 0; timeout.tv_usec = 0; while (select (1, &set, NULL, NULL, &timeout)) { read (0, &c, 1); if (c == '\n' || c == '\r') { con_text[textlen] = 0; textlen = 0; return con_text; } else if (c == 8) { if (textlen) { textlen--; con_text[textlen] = 0; } continue; } con_text[textlen] = c; textlen++; con_text[textlen] = 0; if (textlen == sizeof(con_text)) textlen = 0; } return NULL; } /* ================ Sys_PrintTerm ================ */ void Sys_PrintTerm (const char *msgtxt) { unsigned char *p; if (sys_nostdout.integer) return; for (p = (unsigned char *) msgtxt; *p; p++) putc (*p, stdout); } /* ================ Sys_Quit ================ */ void Sys_Quit (void) { exit (0); } static void PrintVersion (void) { printf ("HexenWorld server %4.2f (%s)\n", ENGINE_VERSION, PLATFORM_STRING); #if HOT_VERSION_BETA printf ("Hammer of Thyrion, %s-%s (%s) pre-release\n", HOT_VERSION_STR, HOT_VERSION_BETA_STR, HOT_VERSION_REL_DATE); #else printf ("Hammer of Thyrion, release %s (%s)\n", HOT_VERSION_STR, HOT_VERSION_REL_DATE); #endif } /* =============================================================================== MAIN =============================================================================== */ static quakeparms_t parms; static char cwd[MAX_OSPATH], userdir[MAX_OSPATH]; int main (int argc, char **argv) { int i; double newtime, time, oldtime; char *tmp; struct timeval timeout; fd_set fdset; PrintVersion(); if (argc > 1) { for (i = 1; i < argc; i++) { if ( !(strcmp(argv[i], "-v")) || !(strcmp(argv[i], "-version" )) || !(strcmp(argv[i], "--version")) ) { exit(0); } else if ( !(strcmp(argv[i], "-h")) || !(strcmp(argv[i], "-help" )) || !(strcmp(argv[i], "-?")) || !(strcmp(argv[i], "--help")) ) { printf ("See the documentation for details\n"); exit (0); } } } memset (cwd, 0, sizeof(cwd)); if ( getcwd (cwd, sizeof(cwd)-1) == NULL ) Sys_Error ("Couldn't determine current directory"); tmp = cwd; while (*tmp != 0) tmp++; while (*tmp == 0) { --tmp; if (*tmp == '/') *tmp = 0; } memset (userdir, 0, sizeof(userdir)); if (Sys_GetUserdir(userdir,sizeof(userdir)) != 0) Sys_Error ("Couldn't determine userspace directory"); /* initialize the host params */ memset (&parms, 0, sizeof(parms)); parms.basedir = cwd; parms.userdir = userdir; parms.argc = argc; parms.argv = argv; host_parms = &parms; devlog = COM_CheckParm("-devlog"); Sys_Printf("basedir is: %s\n", parms.basedir); Sys_Printf("userdir is: %s\n", parms.userdir); parms.memsize = STD_MEM_ALLOC; i = COM_CheckParm ("-heapsize"); if (i && i < com_argc-1) { parms.memsize = atoi (com_argv[i+1]) * 1024; if ((parms.memsize > MAX_MEM_ALLOC) && !(COM_CheckParm ("-forcemem"))) { Sys_Printf ("Requested memory (%d Mb) too large, using the default maximum.\n", parms.memsize/(1024*1024)); Sys_Printf ("If you are sure, use the -forcemem switch.\n"); parms.memsize = MAX_MEM_ALLOC; } else if ((parms.memsize < MIN_MEM_ALLOC) && !(COM_CheckParm ("-forcemem"))) { Sys_Printf ("Requested memory (%d Mb) too little, using the default minimum.\n", parms.memsize/(1024*1024)); Sys_Printf ("If you are sure, use the -forcemem switch.\n"); parms.memsize = MIN_MEM_ALLOC; } } parms.membase = malloc (parms.memsize); if (!parms.membase) Sys_Error ("Insufficient memory.\n"); SV_Init(); // report the filesystem to the user Sys_Printf("fs_gamedir is: %s\n", fs_gamedir); Sys_Printf("fs_userdir is: %s\n", fs_userdir); // run one frame immediately for first heartbeat SV_Frame (HX_FRAME_TIME); // // main loop // oldtime = Sys_DoubleTime () - HX_FRAME_TIME; while (1) { // select on the net socket and stdin // the only reason we have a timeout at all is so that if the last // connected client times out, the message would not otherwise // be printed until the next event. FD_ZERO(&fdset); FD_SET(net_socket, &fdset); timeout.tv_sec = 0; timeout.tv_usec = 10000; if (select (net_socket+1, &fdset, NULL, NULL, &timeout) == -1) continue; // find time passed since last cycle newtime = Sys_DoubleTime (); time = newtime - oldtime; oldtime = newtime; SV_Frame (time); } return 0; }