1 #include <unistd.h>
2 #include <signal.h>
3 #include <stdlib.h>
4 #include <limits.h>
5 #include <sys/time.h>
6 #include <sys/types.h>
7 #include <unistd.h>
8 #include <fcntl.h>
9 #include <stdarg.h>
10 #include <stdio.h>
11 #include <sys/ipc.h>
12 #include <sys/shm.h>
13 #include <sys/stat.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <sys/wait.h>
17 #include <sys/mman.h>
18 #include <errno.h>
19 #include <execinfo.h>
20 #include <sys/utsname.h>
21 #define __USE_GNU 1
22 #define _GNU_SOURCE
23 #include <link.h>
24 #include <sys/ucontext.h>
25 #include <sys/resource.h>
26 
27 //for old headers
28 #ifndef REG_EIP
29 #ifndef EIP
30 #define EIP 12 //aiee
31 #endif
32 #define REG_EIP EIP
33 #endif
34 
35 //#include <fenv.h>
36 #include <dlfcn.h>
37 
38 #include "../qcommon/qcommon.h"
39 
40 #include "../linux/rw_linux.h"
41 
42 cvar_t *nostdin;
43 cvar_t *nostdout;
44 
45 extern cvar_t *sys_loopstyle;
46 
47 unsigned	sys_frame_time;
48 
49 //uid_t saved_euid;
50 qboolean stdin_active = true;
51 
52 // =======================================================================
53 // General routines
54 // =======================================================================
55 #ifndef NO_SERVER
Sys_ConsoleOutput(const char * string)56 void Sys_ConsoleOutput (const char *string)
57 {
58 	char	text[2048];
59 	int		i, j;
60 
61 	if (nostdout && nostdout->intvalue)
62 		return;
63 
64 	i = 0;
65 	j = 0;
66 
67 	//strip high bits
68 	while (string[j])
69 	{
70 		text[i] = string[j] & 127;
71 
72 		//strip low bits
73 		if (text[i] >= 32 || text[i] == '\n' || text[i] == '\t')
74 			i++;
75 
76 		j++;
77 
78 		if (i == sizeof(text)-2)
79 		{
80 			text[i++] = '\n';
81 			break;
82 		}
83 	}
84 	text[i] = 0;
85 
86 	fputs(text, stdout);
87 }
88 #endif
89 
Sys_FileLength(const char * path)90 int Sys_FileLength (const char *path)
91 {
92 	struct stat st;
93 
94 	if (stat (path, &st) || (st.st_mode & S_IFDIR))
95 		return -1;
96 
97 	return st.st_size;
98 }
99 
Sys_getrusage_f(void)100 void Sys_getrusage_f (void)
101 {
102 	struct rusage usage;
103 
104 	getrusage (RUSAGE_SELF, &usage);
105 
106 	//FIXME
107 	Com_Printf ("user:", LOG_GENERAL);
108 }
109 
Sys_Sleep(int msec)110 void Sys_Sleep (int msec)
111 {
112 	usleep (msec*1000);
113 }
114 
Sys_SetWindowText(char * dummy)115 void Sys_SetWindowText (char *dummy)
116 {
117 }
118 
Sys_Printf(char * fmt,...)119 void Sys_Printf (char *fmt, ...)
120 {
121 	va_list		argptr;
122 	char		text[1024];
123 	unsigned char		*p;
124 
125     if (nostdout && nostdout->intvalue)
126         return;
127 
128 	va_start (argptr,fmt);
129 	vsprintf (text,fmt,argptr);
130 	va_end (argptr);
131 
132 	if (strlen(text) > sizeof(text))
133 		Sys_Error("memory overwrite in Sys_Printf");
134 
135 	for (p = (unsigned char *)text; *p; p++) {
136 		*p &= 0x7f;
137 		if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
138 			printf("[%02x]", *p);
139 		else
140 			putc(*p, stdout);
141 	}
142 }
143 
Sys_Quit(void)144 void Sys_Quit (void)
145 {
146 #ifndef DEDICATED_ONLY
147 	CL_Shutdown ();
148 #endif
149 	Qcommon_Shutdown ();
150     fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
151 	exit(0);
152 }
153 
Sys_KillServer(int sig)154 void Sys_KillServer (int sig)
155 {
156 	signal (SIGTERM, SIG_DFL);
157 	signal (SIGINT, SIG_DFL);
158 
159 	Com_Printf ("Got sig %d, shutting down.\n", LOG_SERVER|LOG_NOTICE, sig);
160 	Cmd_TokenizeString (va("Exiting on signal %d\n", sig), 0);
161 	Com_Quit();
162 }
163 
164 #if R1RELEASE == 3
dlcallback(struct dl_phdr_info * info,size_t size,void * data)165 static int dlcallback (struct dl_phdr_info *info, size_t size, void *data)
166 {
167 	int		j;
168 	int		end;
169 
170 	end = 0;
171 
172 	if (!info->dlpi_name || !info->dlpi_name[0])
173 		return 0;
174 
175 	for (j = 0; j < info->dlpi_phnum; j++)
176 	{
177 		end += info->dlpi_phdr[j].p_memsz;
178 	}
179 
180 	//this is terrible.
181 #if __WORDSIZE == 64
182 	fprintf (stderr, "[0x%lux-0x%lux] %s\n", info->dlpi_addr, info->dlpi_addr + end, info->dlpi_name);
183 #else
184 	fprintf (stderr, "[0x%ux-0x%ux] %s\n", info->dlpi_addr, info->dlpi_addr + end, info->dlpi_name);
185 #endif
186 	return 0;
187 }
188 #endif
189 
190 /* Obtain a backtrace and print it to stderr.
191  * Adapted from http://www.delorie.com/gnu/docs/glibc/libc_665.html
192  */
193 #ifndef __i386__
Sys_Backtrace(int sig)194 void Sys_Backtrace (int sig)
195 #else
196 void Sys_Backtrace (int sig, siginfo_t *siginfo, void *secret)
197 #endif
198 {
199 	void		*array[32];
200 	struct utsname	info;
201 	size_t		size;
202 	size_t		i;
203 	char		**strings;
204 #ifdef __i386__
205 	ucontext_t 	*uc = (ucontext_t *)secret;
206 #endif
207 
208 	signal (SIGSEGV, SIG_DFL);
209 
210 	fprintf (stderr, "=====================================================\n"
211 			 "Segmentation Fault\n"
212 			 "=====================================================\n"
213 			 "A crash has occured within R1Q2 or the Game DLL (mod)\n"
214 			 "that you are running.  This is most  likely caused by\n"
215 			 "using the wrong server binary (eg, r1q2ded instead of\n"
216 			 "r1q2ded-old) for the mod you are running.  The server\n"
217 			 "README on the  R1Q2 forums has more information about\n"
218 			 "which binaries you should be using.\n"
219 			 "\n"
220 			 "If possible, try re-building R1Q2 and the mod you are\n"
221 			 "running from source code to ensure it isn't a compile\n"
222 			 "problem. If the crash still persists, please post the\n"
223 			 "following  debug info on the R1Q2 forums with details\n"
224 			 "including the mod name,  version,  Linux distribution\n"
225 			 "and any other pertinent information.\n"
226 			 "\n");
227 
228 	size = backtrace (array, sizeof(array)/sizeof(void*));
229 
230 #ifdef __i386__
231 #ifdef __FreeBSD__
232 	array[1] = (void *) uc->uc_mcontext.mc_eip;
233 #else	/* __linux__ */
234 	array[1] = (void *) uc->uc_mcontext.gregs[REG_EIP];
235 #endif
236 #endif
237 
238 	strings = backtrace_symbols (array, size);
239 
240 	fprintf (stderr, "Stack dump (%zd frames):\n", size);
241 
242 	for (i = 0; i < size; i++)
243 		fprintf (stderr, "%.2zd: %s\n", i, strings[i]);
244 
245 	fprintf (stderr, "\nVersion: " R1BINARY " " VERSION " (" BUILDSTRING " " CPUSTRING ") " RELEASESTRING "\n");
246 
247 	uname (&info);
248 	fprintf (stderr, "OS Info: %s %s %s %s %s\n\n", info.sysname, info.nodename, info.release, info.version, info.machine);
249 
250 #if R1RELEASE == 3
251 	fprintf (stderr, "Loaded libraries:\n");
252 	dl_iterate_phdr(dlcallback, NULL);
253 #endif
254 
255 	free (strings);
256 
257 	raise (SIGSEGV);
258 }
259 
Sys_ProcessTimes_f(void)260 void Sys_ProcessTimes_f (void)
261 {
262 	struct rusage	usage;
263 	int		days, hours, minutes;
264 	double		seconds;
265 
266 	if (getrusage (RUSAGE_SELF, &usage))
267 	{
268 		Com_Printf ("getrusage(): %s\n", LOG_GENERAL, strerror(errno));
269 		return;
270 	}
271 
272 	//1 second = 1 000 000 microseconds
273 	days = usage.ru_stime.tv_sec / 86400;
274 	usage.ru_stime.tv_sec -= days * 86400;
275 
276 	hours = usage.ru_stime.tv_sec / 3600;
277 	usage.ru_stime.tv_sec -= hours * 3600;
278 
279 	minutes = usage.ru_stime.tv_sec / 60;
280 	usage.ru_stime.tv_sec -= minutes * 60;
281 
282 	seconds = usage.ru_stime.tv_sec + (usage.ru_stime.tv_usec / 1000000);
283 
284 	Com_Printf ("%dd %dh %dm %gs kernel\n", LOG_GENERAL, days, hours, minutes, seconds);
285 
286 	days = usage.ru_utime.tv_sec / 86400;
287 	usage.ru_utime.tv_sec -= days * 86400;
288 
289 	hours = usage.ru_utime.tv_sec / 3600;
290 	usage.ru_utime.tv_sec -= hours * 3600;
291 
292 	minutes = usage.ru_utime.tv_sec / 60;
293 	usage.ru_utime.tv_sec -= minutes * 60;
294 
295 	seconds = usage.ru_utime.tv_sec + (usage.ru_utime.tv_usec / 1000000);
296 
297 	Com_Printf ("%dd %dh %dm %gs user\n", LOG_GENERAL, days, hours, minutes, seconds);
298 }
299 
300 static unsigned int goodspins, badspins;
301 
Sys_Spinstats_f(void)302 void Sys_Spinstats_f (void)
303 {
304 	Com_Printf ("%u fast spins, %u slow spins, %.2f%% slow.\n", LOG_GENERAL, goodspins, badspins, ((float)badspins / (float)(goodspins+badspins)) * 100.0f);
305 }
306 
Sys_GetFPUStatus(void)307 unsigned short Sys_GetFPUStatus (void)
308 {
309 	unsigned short fpuword;
310 	__asm__ __volatile__ ("fnstcw %0" : "=m" (fpuword));
311 	return fpuword;
312 }
313 
314 /*
315  * Round to zero, 24 bit precision
316  */
Sys_SetFPU(void)317 void Sys_SetFPU (void)
318 {
319 	unsigned short fpuword;
320 	fpuword = Sys_GetFPUStatus ();
321 	fpuword &= ~(3 << 8);
322 	fpuword |= (0 << 8);
323 	fpuword &= ~(3 << 10);
324 	fpuword |= (0 << 10);
325 	__asm__ __volatile__ ("fldcw %0" : : "m" (fpuword));
326 }
327 
Sys_Init(void)328 void Sys_Init(void)
329 {
330 #if id386
331 //	Sys_SetFPCW();
332 #endif
333   /* Install our signal handler */
334 #ifdef __i386__
335 	struct sigaction sa;
336 
337 	if (sizeof(uint32) != 4)
338 		Sys_Error ("uint32 != 32 bits");
339 	else if (sizeof(uint64) != 8)
340 		Sys_Error ("uint64 != 64 bits");
341 	else if (sizeof(uint16) != 2)
342 		Sys_Error ("uint16 != 16 bits");
343 
344 //	fesetround (FE_TOWARDZERO);
345 
346 	Sys_SetFPU ();
347 	Sys_CheckFPUStatus ();
348 
349 	sa.sa_sigaction = (void *)Sys_Backtrace;
350 	sigemptyset (&sa.sa_mask);
351 	sa.sa_flags = SA_RESTART | SA_SIGINFO;
352 
353 	sigaction(SIGSEGV, &sa, NULL);
354 #else
355 	signal (SIGSEGV, Sys_Backtrace);
356 #endif
357 
358 	signal (SIGTERM, Sys_KillServer);
359 	signal (SIGINT, Sys_KillServer);
360 
361 	//initialize timer base
362 	Sys_Milliseconds ();
363 }
364 
Sys_Error(const char * error,...)365 void Sys_Error (const char *error, ...)
366 {
367     va_list     argptr;
368     char        string[1024];
369 
370 // change stdin to non blocking
371     fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
372 
373 #ifndef DEDICATED_ONLY
374 	CL_Shutdown ();
375 #endif
376 	Qcommon_Shutdown ();
377 
378     va_start (argptr,error);
379     vsprintf (string,error,argptr);
380     va_end (argptr);
381 	fprintf(stderr, "Error: %s\n", string);
382 
383 	exit (1);
384 
385 }
386 
Sys_Warn(char * warning,...)387 void Sys_Warn (char *warning, ...)
388 {
389     va_list     argptr;
390     char        string[1024];
391 
392     va_start (argptr,warning);
393     vsprintf (string,warning,argptr);
394     va_end (argptr);
395 	fprintf(stderr, "Warning: %s", string);
396 }
397 
398 /*
399 ============
400 Sys_FileTime
401 
402 returns -1 if not present
403 ============
404 */
Sys_FileTime(char * path)405 int	Sys_FileTime (char *path)
406 {
407 	struct	stat	buf;
408 
409 	if (stat (path,&buf) == -1)
410 		return -1;
411 
412 	return buf.st_mtime;
413 }
414 
floating_point_exception_handler(int whatever)415 void floating_point_exception_handler(int whatever)
416 {
417 //	Sys_Warn("floating point exception\n");
418 	signal(SIGFPE, floating_point_exception_handler);
419 }
420 
Sys_ConsoleInput(void)421 char *Sys_ConsoleInput(void)
422 {
423     static char text[1024];
424     int     len;
425 	fd_set	fdset;
426     struct timeval timeout;
427 
428 	if (!dedicated || !dedicated->intvalue)
429 		return NULL;
430 
431 	if (!stdin_active || (nostdin && nostdin->intvalue))
432 		return NULL;
433 
434 	FD_ZERO(&fdset);
435 	FD_SET(0, &fdset); // stdin
436 	timeout.tv_sec = 0;
437 	timeout.tv_usec = 0;
438 	if (select (1, &fdset, NULL, NULL, &timeout) < 1 || !FD_ISSET(0, &fdset))
439 		return NULL;
440 
441 	len = read (0, text, sizeof(text));
442 	if (len == 0)
443 	{ // eof!
444 		//stdin_active = false;
445 		return NULL;
446 	}
447 	else if (len == sizeof(text))
448 	{
449 		Com_Printf ("Sys_ConsoleInput: Line too long, discarded.\n", LOG_SERVER);
450 		return NULL;
451 	}
452 
453 	if (len < 1)
454 		return NULL;
455 
456 	text[len-1] = 0;    // rip off the /n and terminate
457 
458 	return text;
459 }
460 
461 /*****************************************************************************/
462 
463 static void *game_library;
464 
465 /*
466 =================
467 Sys_UnloadGame
468 =================
469 */
Sys_UnloadGame(void)470 void Sys_UnloadGame (void)
471 {
472 	if (game_library)
473 		dlclose (game_library);
474 	game_library = NULL;
475 }
476 
477 /*
478 =================
479 Sys_GetGameAPI
480 
481 Loads the game dll
482 =================
483 */
Sys_GetGameAPI(void * parms,int baseq2)484 void *Sys_GetGameAPI (void *parms, int baseq2)
485 {
486 	void	*(*GetGameAPI) (void *);
487 
488 	char	name[MAX_OSPATH];
489 	char	*path;
490 	const char *gamename = "game.so";
491 
492 	if (game_library)
493 		Com_Error (ERR_FATAL, "Sys_GetGameAPI without Sys_UnloadingGame");
494 
495 	Com_Printf("------- Loading %s -------\n", LOG_SERVER|LOG_NOTICE, gamename);
496 
497 	if (baseq2)
498 	{
499 		Com_sprintf (name, sizeof(name), "%s/%s", BASEDIRNAME, gamename);
500 		game_library = dlopen (name, RTLD_NOW );
501 
502 		if (game_library == NULL) {
503 			Com_Printf ("dlopen(): %s\n", LOG_SERVER, dlerror());
504 			Com_Printf ("Attempting to load with lazy symbols...", LOG_SERVER);
505 			game_library = dlopen(name, RTLD_LAZY);
506 		}
507 	}
508 	else
509 	{
510 		// now run through the search paths
511 		path = NULL;
512 		for (;;)
513 		{
514 			path = FS_NextPath (path);
515 			if (!path)
516 				return NULL;		// couldn't find one anywhere
517 			Com_sprintf (name, sizeof(name), "%s/%s", path, gamename);
518 			game_library = dlopen (name, RTLD_NOW );
519 			if (game_library)
520 			{
521 				Com_DPrintf ("LoadLibrary (%s)\n",name);
522 				break;
523 			}
524 			else
525 			{
526 				Com_Printf ("dlopen(): %s\n", LOG_SERVER, dlerror());
527 				Com_Printf ("Attempting to load with lazy symbols...", LOG_SERVER);
528 				game_library = dlopen(name, RTLD_LAZY);
529 				if (game_library)
530 				{
531 					Com_Printf ("ok\n", LOG_SERVER);
532 					break;
533 				}
534 				else
535 				{
536 					Com_Printf ("dlopen(): %s\n", LOG_SERVER, dlerror());
537 				}
538 			}
539 		}
540 	}
541 
542 	if (!game_library)
543 		return NULL;
544 
545 	GetGameAPI = (void *(*)(void *))dlsym (game_library, "GetGameAPI");
546 	if (!GetGameAPI)
547 	{
548 		Com_Printf ("dlsym(): %s\n", LOG_SERVER, dlerror());
549 		Sys_UnloadGame ();
550 		return NULL;
551 	}
552 
553 	return GetGameAPI (parms);
554 }
555 
556 /*****************************************************************************/
557 
Sys_AppActivate(void)558 void Sys_AppActivate (void)
559 {
560 }
561 
Sys_SendKeyEvents(void)562 void Sys_SendKeyEvents (void)
563 {
564 #ifndef DEDICATED_ONLY
565 	if (KBD_Update_fp)
566 		KBD_Update_fp();
567 #endif
568 
569 	// grab frame time
570 	sys_frame_time = Sys_Milliseconds();
571 }
572 
573 /*****************************************************************************/
574 
Sys_GetClipboardData(void)575 char *Sys_GetClipboardData(void)
576 {
577 	return NULL;
578 }
579 
main(int argc,char ** argv)580 int main (int argc, char **argv)
581 {
582 	unsigned int 	time, oldtime, newtime, spins;
583 
584 	// go back to real user for config loads
585 	//saved_euid = geteuid();
586 	//seteuid(getuid());
587 	//
588 
589 	if (getuid() == 0 || geteuid() == 0)
590 		Sys_Error ("For security reasons, do not run Quake II as root.");
591 
592 	binary_name = argv[0];
593 
594 	Qcommon_Init(argc, argv);
595 
596 	fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
597 
598 	nostdin = Cvar_Get ("nostdin", "0", 0);
599 	nostdout = Cvar_Get("nostdout", "0", 0);
600 	if (!nostdout->intvalue) {
601 		fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
602 //		printf ("Linux Quake -- Version %0.3f\n", LINUX_VERSION);
603 	}
604 
605     oldtime = Sys_Milliseconds ();
606     while (1)
607     {
608 		// find time spent rendering last frame
609 		if (dedicated->intvalue && sys_loopstyle->intvalue)
610 		{
611 			newtime = Sys_Milliseconds ();
612 			time = newtime - oldtime;
613 			spins = 0;
614 		}
615 		else
616 		{
617 			spins = 0;
618 			do
619 			{
620 				newtime = Sys_Milliseconds ();
621 				time = newtime - oldtime;
622 				spins++;
623 			} while (time < 1);
624 		}
625 
626 		if (spins > 500)
627 			badspins++;
628 		else
629 			goodspins++;
630 
631 		Qcommon_Frame (time);
632 		oldtime = newtime;
633     }
634 
635 }
636 
637 //r1 :redundant
Sys_CopyProtect(void)638 void Sys_CopyProtect(void)
639 {
640 }
641 
642 #if 0
643 /*
644 ================
645 Sys_MakeCodeWriteable
646 ================
647 */
648 void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
649 {
650 
651 	int r;
652 	unsigned long addr;
653 	int psize = getpagesize();
654 
655 	addr = (startaddr & ~(psize-1)) - psize;
656 
657 //	fprintf(stderr, "writable code %lx(%lx)-%lx, length=%lx\n", startaddr,
658 //			addr, startaddr+length, length);
659 
660 	r = mprotect((char*)addr, length + startaddr - addr + psize, 7);
661 
662 	if (r < 0)
663     		Sys_Error("Protection change failed\n");
664 
665 }
666 
667 #endif
668 
Sys_CheckFPUStatus(void)669 qboolean Sys_CheckFPUStatus (void)
670 {
671 	static unsigned short	last_word = 0;
672 	unsigned short	fpu_control_word;
673 
674 	fpu_control_word = Sys_GetFPUStatus ();
675 
676 	Com_DPrintf ("Sys_CheckFPUStatus: rounding %d, precision %d\n", (fpu_control_word >> 10) & 3, (fpu_control_word >> 8) & 3);
677 
678 	//check rounding (10) and precision (8) are set properly
679 	if (((fpu_control_word >> 10) & 3) != 0 ||
680 		((fpu_control_word >> 8) & 3) != 0)
681 	{
682 		if (fpu_control_word != last_word)
683 		{
684 			last_word = fpu_control_word;
685 			return false;
686 		}
687 	}
688 
689 	last_word = fpu_control_word;
690 	return true;
691 }
692 
Sys_ShellExec(const char * cmd)693 void Sys_ShellExec (const char *cmd)
694 {
695 	//FIXME
696 }
697 
Sys_OpenURL(void)698 void Sys_OpenURL (void)
699 {
700 	//FIXME
701 }
702 
Sys_UpdateURLMenu(const char * s)703 void Sys_UpdateURLMenu (const char *s)
704 {
705 	//FIXME
706 }
707