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