OpenClonk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros
ClonkMain.cpp
Go to the documentation of this file.
1 /*
2  * OpenClonk, http://www.openclonk.org
3  *
4  * Copyright (c) 1998-2000, Matthes Bender
5  * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de/
6  * Copyright (c) 2009-2016, The OpenClonk Team and contributors
7  *
8  * Distributed under the terms of the ISC license; see accompanying file
9  * "COPYING" for details.
10  *
11  * "Clonk" is a registered trademark of Matthes Bender, used with permission.
12  * See accompanying file "TRADEMARK" for details.
13  *
14  * To redistribute this file separately, substitute the full license texts
15  * for the above references.
16  */
17 
18 /* Main program entry point */
19 
20 #include "C4Include.h"
21 #include "game/C4Application.h"
22 
23 #include "lib/C4Log.h"
24 #include "game/C4Game.h"
25 #include "C4Version.h"
26 #include "network/C4Network2.h"
27 
28 #ifdef _WIN32
29 #include <shellapi.h>
30 
31 void InstallCrashHandler();
32 
33 int WINAPI WinMain (HINSTANCE hInst,
34  HINSTANCE hPrevInstance,
35  LPSTR lpszCmdParam,
36  int nCmdShow)
37 {
38 #if defined(_DEBUG) && defined(_MSC_VER)
39  // enable debugheap!
40  _CrtSetDbgFlag( _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG ) | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
41 #endif
42 
43  // This should be handled in an application manifest, but that is
44  // decidedly non-trivial to do portably across compilers and compiler
45  // versions, so we do it in code instead.
46  // Also we aren't really DPI aware (we'd have to default ingame zoom
47  // differently and scale the menus), but this is better than clipping.
48  // Fixes #891.
49  HMODULE user32 = LoadLibrary(L"user32");
50  if (user32)
51  {
52  typedef BOOL (WINAPI *SETPROCESSDPIAWAREPROC)();
53  SETPROCESSDPIAWAREPROC SetProcessDPIAware =
54  reinterpret_cast<SETPROCESSDPIAWAREPROC>(GetProcAddress(user32, "SetProcessDPIAware"));
55  if (SetProcessDPIAware)
56  SetProcessDPIAware();
57  FreeLibrary(user32);
58  }
59 
61 
62  // Split wide command line to wide argv array
63  std::vector<char*> argv;
64  int argc = 0;
65  LPWSTR *wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
66  if (!wargv)
67  {
68  const char *error = "Internal error: Unable to split command line! Exiting.";
69  Log(error);
71  return C4XRV_Failure;
72  }
73  argv.reserve(argc);
74 
75  // Convert args to UTF-8
76  LPWSTR *curwarg = wargv;
77  while(argc--)
78  {
79  int arglen = WideCharToMultiByte(CP_UTF8, 0, *curwarg, -1, nullptr, 0, 0, 0);
80  char *utf8arg = new char[arglen ? arglen : 1];
81  WideCharToMultiByte(CP_UTF8, 0, *curwarg, -1, utf8arg, arglen, 0, 0);
82  argv.push_back(utf8arg);
83  ++curwarg;
84  }
85  LocalFree(wargv);
86 
87  // Init application
88  Application.SetInstance(hInst);
89  if (!Application.Init(argv.size(), &argv[0]))
90  {
92  return C4XRV_Failure;
93  }
94 
95  // Run it
96  Application.Run();
98 
99  // delete arguments
100  for(std::vector<char*>::const_iterator it = argv.begin(); it != argv.end(); ++it)
101  delete[] *it;
102  argv.clear();
103  // Return exit code
104  if (!Game.GameOver) return C4XRV_Aborted;
105  return C4XRV_Completed;
106 }
107 
108 int main()
109 {
110  return WinMain(GetModuleHandle(nullptr), 0, 0, 0);
111 }
112 
113 #else // _WIN32
114 
115 #include <unistd.h>
116 #include <fcntl.h>
117 
118 #ifdef HAVE_SYS_TYPES_H
119 #include <sys/types.h>
120 #endif
121 
122 #ifdef HAVE_BACKWARD
123 #include <backward-cpp/backward.hpp>
124 
125 #elif defined(HAVE_SIGNAL_H)
126 #include <signal.h>
127 
128 #ifdef HAVE_EXECINFO_H
129 #include <execinfo.h>
130 #endif
131 
132 static void crash_handler(int signo, siginfo_t * si, void *)
133 {
134  static unsigned signal_count = 0;
135  ++signal_count;
136  switch (signo)
137  {
138  case SIGINT: case SIGTERM: case SIGHUP:
139  if (signal_count < 2) {
140  Application.Quit();
141  break;
142  } // else/fallthrough
143  default:
144  int logfd = STDERR_FILENO;
145  for (;;)
146  {
147  // Print out the signal
148  write(logfd, C4VERSION ": Caught signal ", sizeof (C4VERSION ": Caught signal ") - 1);
149  switch (signo)
150  {
151  case SIGBUS: write(logfd, "SIGBUS", sizeof ("SIGBUS") - 1); break;
152  case SIGILL: write(logfd, "SIGILL", sizeof ("SIGILL") - 1); break;
153  case SIGSEGV: write(logfd, "SIGSEGV", sizeof ("SIGSEGV") - 1); break;
154  case SIGABRT: write(logfd, "SIGABRT", sizeof ("SIGABRT") - 1); break;
155  case SIGINT: write(logfd, "SIGINT", sizeof ("SIGINT") - 1); break;
156  case SIGHUP: write(logfd, "SIGHUP", sizeof ("SIGHUP") - 1); break;
157  case SIGFPE: write(logfd, "SIGFPE", sizeof ("SIGFPE") - 1); break;
158  case SIGTERM: write(logfd, "SIGTERM", sizeof ("SIGTERM") - 1); break;
159  }
160  char hex[sizeof(void *) * 2];
161  intptr_t x = reinterpret_cast<intptr_t>(si->si_addr);
162  switch (signo)
163  {
164  case SIGILL: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGTRAP:
165  write(logfd, " (0x", sizeof (" (0x") - 1);
166  for (int i = sizeof(void *) * 2 - 1; i >= 0; --i)
167  {
168  if ((x & 0xf) > 9)
169  hex[i] = 'a' + (x & 0xf) - 9;
170  else
171  hex[i] = '0' + (x & 0xf);
172  x >>= 4;
173  }
174  write(logfd, hex, sizeof (hex));
175  write(logfd, ")", sizeof (")") - 1);
176  break;
177  }
178  write(logfd, "\n", sizeof ("\n") - 1);
179  if (logfd == STDERR_FILENO) logfd = GetLogFD();
180  else break;
181  if (logfd < 0) break;
182  }
183 #ifdef HAVE_EXECINFO_H
184  // Get the backtrace
185  void *stack[100];
186  int count = backtrace(stack, 100);
187  // Print it out
188  backtrace_symbols_fd (stack, count, STDERR_FILENO);
189  // Also to the log file
190  if (logfd >= 0)
191  backtrace_symbols_fd (stack, count, logfd);
192 #endif
193  // Bye.
194  _exit(C4XRV_Failure);
195  }
196 }
197 #endif // HAVE_SIGNAL_H
198 
199 static void restart(char * argv[])
200 {
201  // Close all file descriptors except stdin, stdout, stderr
202  int open_max = sysconf (_SC_OPEN_MAX);
203  for (int fd = 4; fd < open_max; fd++)
204  fcntl (fd, F_SETFD, FD_CLOEXEC);
205  // Execute the new engine
206  execlp(argv[0], argv[0], static_cast<char *>(0));
207 }
208 
209 int main (int argc, char * argv[])
210 {
211  if (!geteuid())
212  {
213  printf("Do not run %s as root!\n", argc ? argv[0] : "this program");
214  return C4XRV_Failure;
215  }
216 #ifdef HAVE_BACKWARD
217  backward::SignalHandling sh;
218 #elif defined(HAVE_SIGNAL_H)
219  struct sigaction sa;
220  sa.sa_sigaction = crash_handler;
221  sigemptyset(&sa.sa_mask);
222  sa.sa_flags = SA_SIGINFO;
223  // Quit the program when asked
224  sigaction(SIGINT, &sa, nullptr);
225  sigaction(SIGTERM, &sa, nullptr);
226  sigaction(SIGHUP, &sa, nullptr);
227  // Set up debugging facilities
228  sa.sa_flags |= SA_RESETHAND;
229  sigaction(SIGBUS, &sa, nullptr);
230  sigaction(SIGILL, &sa, nullptr);
231  sigaction(SIGSEGV, &sa, nullptr);
232  sigaction(SIGABRT, &sa, nullptr);
233  sigaction(SIGFPE, &sa, nullptr);
234 #endif
235 
236  // Init application
237  if (!Application.Init(argc, argv))
238  {
239  Application.Clear();
240  return C4XRV_Failure;
241  }
242  // Execute application
243  Application.Run();
244  // free app stuff
245  Application.Clear();
246  if (Application.restartAtEnd) restart(argv);
247  // Return exit code
248  if (!Game.GameOver) return C4XRV_Aborted;
249  return C4XRV_Completed;
250 }
251 #endif
C4Game Game
Definition: C4Globals.cpp:52
void MessageDialog(const char *message)
Definition: C4AppMac.mm:63
int GetLogFD()
Definition: C4Log.cpp:109
int main(int argc, char *argv[])
Definition: ClonkMain.cpp:209
virtual void Quit()
bool GameOver
Definition: C4Game.h:116
const int C4XRV_Failure
Definition: C4Constants.h:71
void Run()
Definition: C4App.cpp:26
const int C4XRV_Aborted
Definition: C4Constants.h:72
bool Init(int argc, char *argv[])
Definition: C4AppSDL.cpp:91
bool Log(const char *szMessage)
Definition: C4Log.cpp:195
const int C4XRV_Completed
Definition: C4Constants.h:70
void InstallCrashHandler()
C4Application Application
Definition: C4Globals.cpp:44