1 // Emacs style mode select   -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: i_main.cpp 4469 2014-01-03 23:38:29Z dr_sean $
5 //
6 // Copyright (C) 1993-1996 by id Software, Inc.
7 // Copyright (C) 2006-2014 by The Odamex Team.
8 //
9 // This program is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU General Public License
11 // as published by the Free Software Foundation; either version 2
12 // of the License, or (at your option) any later version.
13 //
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 // GNU General Public License for more details.
18 //
19 // DESCRIPTION:
20 //	Main program, simply calls D_DoomMain high level loop.
21 //
22 //-----------------------------------------------------------------------------
23 
24 #include <stack>
25 #include <iostream>
26 #include <map>
27 #include <string>
28 
29 #include "win32inc.h"
30 #ifdef _WIN32
31     #include "resource.h"
32 	#include "mmsystem.h"
33 #endif
34 
35 #ifdef UNIX
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <signal.h>
39 #endif
40 
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <stdarg.h>
44 #include <math.h>
45 #include <time.h>
46 
47 #include "m_argv.h"
48 #include "d_main.h"
49 #include "i_system.h"
50 #include "c_console.h"
51 #include "z_zone.h"
52 #include "errors.h"
53 #include "i_net.h"
54 #include "sv_main.h"
55 #include "m_ostring.h"
56 
57 using namespace std;
58 
59 void AddCommandString(std::string cmd);
60 
61 DArgs Args;
62 
63 #ifdef _WIN32
64 extern UINT TimerPeriod;
65 #endif
66 
67 // functions to be called at shutdown are stored in this stack
68 typedef void (STACK_ARGS *term_func_t)(void);
69 std::stack< std::pair<term_func_t, std::string> > TermFuncs;
70 
addterm(void (STACK_ARGS * func)(),const char * name)71 void addterm (void (STACK_ARGS *func) (), const char *name)
72 {
73 	TermFuncs.push(std::pair<term_func_t, std::string>(func, name));
74 }
75 
call_terms(void)76 void STACK_ARGS call_terms (void)
77 {
78 	while (!TermFuncs.empty())
79 		TermFuncs.top().first(), TermFuncs.pop();
80 }
81 
PrintString(int printlevel,char const * outline)82 int PrintString (int printlevel, char const *outline)
83 {
84 	int ret = printf("%s", outline);
85 	fflush(stdout);
86 	return ret;
87 }
88 
89 #ifdef _WIN32
90 static HANDLE hEvent;
91 
ShutdownNow()92 int ShutdownNow()
93 {
94     return (WaitForSingleObject(hEvent, 1) == WAIT_OBJECT_0);
95 }
96 
ConsoleHandlerRoutine(DWORD dwCtrlType)97 BOOL WINAPI ConsoleHandlerRoutine(DWORD dwCtrlType)
98 {
99     SetEvent(hEvent);
100     return TRUE;
101 }
102 
main(int argc,char * argv[])103 int __cdecl main(int argc, char *argv[])
104 {
105     try
106     {
107         // Handle ctrl-c, close box, shutdown and logoff events
108         if (!SetConsoleCtrlHandler(ConsoleHandlerRoutine, TRUE))
109             throw CDoomError("Could not set console control handler!\n");
110 
111         if (!(hEvent = CreateEvent(NULL, FALSE, FALSE, NULL)))
112             throw CDoomError("Could not create console control event!\n");
113 
114         #ifdef _WIN32
115         // Fixes icon not showing in titlebar and alt-tab menu under windows 7
116         HANDLE hIcon;
117 
118         hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON1));
119 
120         if(hIcon)
121         {
122             SendMessage(GetConsoleWindow(), WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
123             SendMessage(GetConsoleWindow(), WM_SETICON, ICON_BIG, (LPARAM)hIcon);
124         }
125         #endif
126 
127 		// [ML] 2007/9/3: From Eternity (originally chocolate Doom) Thanks SoM & fraggle!
128 		Args.SetArgs (argc, argv);
129 
130 		const char *CON_FILE = Args.CheckValue("-confile");
131 		if(CON_FILE)CON.open(CON_FILE, std::ios::in);
132 
133 		// Set the timer to be as accurate as possible
134 		TIMECAPS tc;
135 		if (timeGetDevCaps (&tc, sizeof(tc) != TIMERR_NOERROR))
136 			TimerPeriod = 1;	// Assume minimum resolution of 1 ms
137 		else
138 			TimerPeriod = tc.wPeriodMin;
139 
140 		timeBeginPeriod (TimerPeriod);
141 
142         // Don't call this on windows!
143 		//atexit (call_terms);
144 
145 		Z_Init();
146 
147 		atterm (I_Quit);
148 		atterm (DObject::StaticShutdown);
149 
150 		progdir = I_GetBinaryDir();
151 		startdir = I_GetCWD();
152 
153 		C_InitConsole (80*8, 25*8, false);
154 
155 		D_DoomMain ();
156     }
157     catch (CDoomError &error)
158     {
159 		if (LOG.is_open())
160         {
161             LOG << error.GetMsg() << std::endl;
162             LOG << std::endl;
163         }
164         else
165         {
166             MessageBox(NULL, error.GetMsg().c_str(), "Odasrv Error", MB_OK);
167         }
168 
169 		exit(EXIT_FAILURE);
170     }
171     catch (...)
172     {
173 		call_terms ();
174 		throw;
175     }
176     return 0;
177 }
178 #else
179 
180 // cleanup handling -- killough:
handler(int s)181 static void handler (int s)
182 {
183     char buf[64];
184 
185     signal(s,SIG_IGN);  // Ignore future instances of this signal.
186 
187     strcpy(buf,
188 		   s==SIGSEGV ? "Segmentation Violation" :
189 		   s==SIGINT  ? "Interrupted by User" :
190 		   s==SIGILL  ? "Illegal Instruction" :
191 		   s==SIGFPE  ? "Floating Point Exception" :
192 		   s==SIGTERM ? "Killed" : "Terminated by signal %s");
193 
194     I_FatalError (buf, s);
195 }
196 
197 //
198 // daemon_init
199 //
daemon_init(void)200 void daemon_init(void)
201 {
202     int     pid;
203     FILE   *fpid;
204     string  pidfile;
205 
206     Printf(PRINT_HIGH, "Launched into the background\n");
207 
208     if ((pid = fork()) != 0)
209     {
210     	call_terms();
211     	exit(EXIT_SUCCESS);
212     }
213 
214 	const char *forkargs = Args.CheckValue("-fork");
215 	if (forkargs)
216 		pidfile = string(forkargs);
217 
218     if(!pidfile.size() || pidfile[0] == '-')
219     	pidfile = "doomsv.pid";
220 
221     pid = getpid();
222     fpid = fopen(pidfile.c_str(), "w");
223     fprintf(fpid, "%d\n", pid);
224     fclose(fpid);
225 }
226 
main(int argc,char ** argv)227 int main (int argc, char **argv)
228 {
229     try
230     {
231 		if(!getuid() || !geteuid())
232 			I_FatalError("root user detected, quitting odamex immediately");
233 
234 	    seteuid (getuid ());
235 
236 		// ensure OString's string table is properly initialized and shutdown
237 		OString::startup();
238 		atterm(OString::shutdown);
239 
240 		Args.SetArgs (argc, argv);
241 
242 		const char *CON_FILE = Args.CheckValue("-confile");
243 		if(CON_FILE)CON.open(CON_FILE, std::ios::in);
244 
245 		/*
246 		  killough 1/98:
247 
248 		  This fixes some problems with exit handling
249 		  during abnormal situations.
250 
251 		  The old code called I_Quit() to end program,
252 		  while now I_Quit() is installed as an exit
253 		  handler and exit() is called to exit, either
254 		  normally or abnormally. Seg faults are caught
255 		  and the error handler is used, to prevent
256 		  being left in graphics mode or having very
257 		  loud SFX noise because the sound card is
258 		  left in an unstable state.
259 		*/
260 
261         // Don't use this on other platforms either
262 		//atexit (call_terms);
263 		Z_Init();					// 1/18/98 killough: start up memory stuff first
264 
265 		atterm (I_Quit);
266 		atterm (DObject::StaticShutdown);
267 
268 		signal(SIGSEGV, handler);
269 		signal(SIGTERM, handler);
270 		signal(SIGILL,  handler);
271 		signal(SIGFPE,  handler);
272 		signal(SIGINT,  handler);	// killough 3/6/98: allow CTRL-BRK during init
273 		signal(SIGABRT, handler);
274 
275 		progdir = I_GetBinaryDir();
276 
277 		C_InitConsole (80*8, 25*8, false);
278 
279 		D_DoomMain ();
280     }
281     catch (CDoomError &error)
282     {
283 	fprintf (stderr, "%s\n", error.GetMsg().c_str());
284 
285 	if (LOG.is_open())
286         {
287             LOG << error.GetMsg() << std::endl;
288             LOG << std::endl;
289         }
290 
291 	call_terms();
292 	exit(EXIT_FAILURE);
293     }
294     catch (...)
295     {
296 		call_terms ();
297 		throw;
298     }
299     return 0;
300 }
301 
302 #endif
303 
304 VERSION_CONTROL (i_main_cpp, "$Id: i_main.cpp 4469 2014-01-03 23:38:29Z dr_sean $")
305 
306