ManaPlus
process.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2011-2019 The ManaPlus Developers
4  * Copyright (C) 2019-2021 Andrei Karas
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "utils/process.h"
23 
24 #include <unistd.h>
25 
26 #include "localconsts.h"
27 
28 PRAGMA48(GCC diagnostic push)
29 PRAGMA48(GCC diagnostic ignored "-Wshadow")
30 #ifdef USE_SDL2
31 #ifdef ANDROID
32 #include <SDL_system.h>
33 #endif // ANDROID
34 #endif // USE_SDL2
35 PRAGMA48(GCC diagnostic pop)
36 
37 #include "debug.h"
38 
39 #if defined(WIN32) || defined(__linux__) || \
40  defined(__linux) || defined(__APPLE__)
41 const int timeOut = 10;
42 #endif // defined(WIN32) || defined(__linux__) ||
43  // defined(__linux) || defined(__APPLE__)
44 
45 #ifdef WIN32
46 
47 #include "utils/stringutils.h"
48 
49 #include <windows.h>
50 
51 int execFileWait(const std::string &pathName, const std::string &name A_UNUSED,
52  const std::string &arg1, const std::string &arg2,
53  const int waitTime A_UNUSED)
54 {
55 // if (!waitTime)
56 // waitTime = timeOut;
57 
58  STARTUPINFO siStartupInfo;
59  PROCESS_INFORMATION piProcessInfo;
60  memset(&siStartupInfo, 0, sizeof(siStartupInfo));
61  memset(&piProcessInfo, 0, sizeof(piProcessInfo));
62  siStartupInfo.cb = sizeof(siStartupInfo);
63  DWORD ret = -1;
64  std::string args(std::string(pathName).append(" ").append(arg1));
65  if (!arg2.empty())
66  args.append(" ").append(arg2);
67 
68  if (CreateProcess(pathName.c_str(), const_cast<char*>(args.c_str()),
69  nullptr, nullptr, false, CREATE_DEFAULT_ERROR_MODE, nullptr, nullptr,
70  &siStartupInfo, &piProcessInfo) != false)
71  {
72  if (!WaitForSingleObject(piProcessInfo.hProcess, timeOut * 1000))
73  {
74  if (GetExitCodeProcess(piProcessInfo.hProcess, &ret))
75  {
76  CloseHandle(piProcessInfo.hProcess);
77  CloseHandle(piProcessInfo.hThread);
78  return ret;
79  }
80  }
81  TerminateProcess(piProcessInfo.hProcess, -1);
82  }
83 
84  CloseHandle(piProcessInfo.hProcess);
85  CloseHandle(piProcessInfo.hThread);
86  return -1;
87 }
88 
89 bool execFile(const std::string &pathName, const std::string &name A_UNUSED,
90  const std::string &arg1, const std::string &arg2)
91 {
92  STARTUPINFO siStartupInfo;
93  PROCESS_INFORMATION piProcessInfo;
94  memset(&siStartupInfo, 0, sizeof(siStartupInfo));
95  memset(&piProcessInfo, 0, sizeof(piProcessInfo));
96  siStartupInfo.cb = sizeof(siStartupInfo);
97  std::string args(std::string(pathName).append(" ").append(arg1));
98  if (!arg2.empty())
99  args.append(" ").append(arg2);
100 
101  bool res = CreateProcess(pathName.c_str(), const_cast<char*>(
102  args.c_str()), nullptr, nullptr, false,
103  CREATE_DEFAULT_ERROR_MODE, nullptr, nullptr, &siStartupInfo,
104  &piProcessInfo);
105 
106  CloseHandle(piProcessInfo.hProcess);
107  CloseHandle(piProcessInfo.hThread);
108  return res;
109 }
110 
111 
112 #elif defined __linux__ || defined __linux || defined __APPLE__
113 
114 #include <sys/types.h>
115 #include <sys/stat.h>
116 #include <sys/wait.h>
117 #include <csignal>
118 
119 int execFileWait(const std::string &pathName, const std::string &name,
120  const std::string &arg1, const std::string &arg2,
121  int waitTime)
122 {
123  pid_t mon_pid;
124  int status;
125 
126  if (waitTime == 0)
127  waitTime = timeOut;
128 
129  if ((mon_pid = fork()) == -1)
130  { // fork error
131  return -1;
132  }
133  else if (mon_pid == 0)
134  { // monitoring child
135  pid_t pid;
136  if ((pid = fork()) == -1)
137  { // fork error
138  return -1;
139  }
140  else if (pid == 0)
141  { // work child
142  if (arg2.empty())
143  {
144  execl(pathName.c_str(), name.c_str(),
145  arg1.c_str(), static_cast<char *>(nullptr));
146  }
147  else
148  {
149  execl(pathName.c_str(), name.c_str(), arg1.c_str(),
150  arg2.c_str(), static_cast<char *>(nullptr));
151  }
152  _exit(-1);
153  }
154 
155  // monitoring process
156  pid_t sleep_pid;
157  if ((sleep_pid = fork()) == -1)
158  { // fork error
159  return -1;
160  }
161  else if (sleep_pid == 0)
162  { // sleep pid
163  sleep(waitTime);
164  execl("/bin/true", "/bin/true", static_cast<char *>(nullptr));
165  _exit(-1);
166  }
167 
168  // monitoring process
169  const pid_t exited_pid = wait(&status);
170  int ret = -1;
171  if (exited_pid == pid)
172  {
173  kill(sleep_pid, SIGKILL);
174  if (WIFEXITED(status))
175  ret = WEXITSTATUS(status);
176  }
177  else
178  {
179  kill(pid, SIGKILL);
180  ret = -1;
181  }
182  wait(nullptr);
183  execl("/bin/true", "/bin/true", static_cast<char *>(nullptr));
184  _exit(ret);
185  }
186 
187  // monitoring parent
188  waitpid(mon_pid, &status, 0);
189  if (WIFEXITED(status))
190  return WEXITSTATUS(status);
191 
192  return -1;
193 }
194 
195 bool execFile(const std::string &pathName, const std::string &name,
196  const std::string &arg1, const std::string &arg2)
197 {
198  struct stat statbuf;
199  // file not exists
200  if (stat(pathName.c_str(), &statbuf) != 0)
201  return false;
202 
203  pid_t pid;
204  if ((pid = fork()) == -1)
205  { // fork error
206  return false;
207  }
208  else if (pid == 0)
209  { // work child
210  if (arg2.empty())
211  {
212  execl(pathName.c_str(), name.c_str(),
213  arg1.c_str(), static_cast<char *>(nullptr));
214  }
215  else
216  {
217  execl(pathName.c_str(), name.c_str(), arg1.c_str(),
218  arg2.c_str(), static_cast<char *>(nullptr));
219  }
220  _exit(-1);
221  PRAGMACLANG6(GCC diagnostic push)
222  PRAGMACLANG6(GCC diagnostic ignored "-Wunreachable-code-return")
223  return false;
224  PRAGMACLANG6(GCC diagnostic pop)
225  }
226  return true;
227 }
228 
229 #else // OTHER
230 
231 int execFileWait(const std::string &pathName A_UNUSED,
232  const std::string &name A_UNUSED,
233  const std::string &arg1 A_UNUSED,
234  const std::string &arg2 A_UNUSED,
235  int waitTime A_UNUSED)
236 {
237  return -1;
238 }
239 
240 bool execFile(const std::string &pathName A_UNUSED,
241  const std::string &name A_UNUSED,
242  const std::string &arg1 A_UNUSED,
243  const std::string &arg2 A_UNUSED)
244 {
245  return false;
246 }
247 
248 #endif // WIN32
249 
250 #if defined WIN64
251 bool openBrowser(std::string url)
252 {
253  return reinterpret_cast<int64_t>(ShellExecute(nullptr, "open",
254  replaceAll(url, " ", "").c_str(),
255  nullptr, nullptr, SW_SHOWNORMAL)) > 32;
256 }
257 #elif defined WIN32
258 bool openBrowser(std::string url)
259 {
260  return reinterpret_cast<int32_t>(ShellExecute(nullptr, "open",
261  replaceAll(url, " ", "").c_str(),
262  nullptr, nullptr, SW_SHOWNORMAL)) > 32;
263 }
264 #elif defined ANDROID
265 #include "utils/stringutils.h"
266 #ifndef USE_SDL2
267 PRAGMA48(GCC diagnostic push)
268 PRAGMA48(GCC diagnostic ignored "-Wshadow")
269 #include <SDL_screenkeyboard.h>
270 PRAGMA48(GCC diagnostic pop)
271 #endif // USE_SDL2
272 
273 bool openBrowser(std::string url)
274 {
275 #ifdef USE_SDL2
276  SDL_OpenBrowser(replaceAll(url, " ", "").c_str());
277 #else // USE_SDL2
278 
279  SDL_ANDROID_OpenBrowser(replaceAll(url, " ", "").c_str());
280 #endif // USE_SDL2
281 
282  return true;
283 }
284 #elif defined __APPLE__
285 bool openBrowser(std::string url)
286 {
287  return execFile("/usr/bin/open", "/usr/bin/open", url, "");
288 }
289 #elif defined __OpenBSD__ || defined __FreeBSD__ || defined __DragonFly__
290 bool openBrowser(std::string url)
291 {
292  return execFile("/usr/local/bin/xdg-open",
293  "/usr/local/bin/xdg-open", url, "");
294 }
295 #elif defined __linux__ || defined __linux
296 bool openBrowser(std::string url)
297 {
298  return execFile("/usr/bin/xdg-open", "/usr/bin/xdg-open", url, "");
299 }
300 #elif defined __native_client__
301 
302 #include "utils/naclmessages.h"
303 
304 bool openBrowser(std::string url)
305 {
306  naclPostMessage("open-browser", url);
307  return true;
308 }
309 #else // OTHER
310 bool openBrowser(std::string url A_UNUSED)
311 {
312  return false;
313 }
314 
315 #endif // WIN32
316 
317 #ifdef WIN32
318 void setPriority(const bool big)
319 {
320  HANDLE hCurrentProcess = GetCurrentProcess();
321  if (big)
322  SetPriorityClass(hCurrentProcess, ABOVE_NORMAL_PRIORITY_CLASS);
323  else
324  SetPriorityClass(hCurrentProcess, BELOW_NORMAL_PRIORITY_CLASS);
325 }
326 #else // WIN32
327 
328 void setPriority(const bool big A_UNUSED)
329 {
330 }
331 #endif // WIN32
#define PRAGMA48(str)
Definition: localconsts.h:199
#define A_UNUSED
Definition: localconsts.h:160
#define PRAGMACLANG6(str)
Definition: localconsts.h:231
bool wait(InputEvent &event)
Definition: commands.cpp:58
bool url(InputEvent &event)
Definition: commands.cpp:64
void setPriority(const bool big)
Definition: process.cpp:328
int execFileWait(const std::string &pathName, const std::string &name, const std::string &arg1, const std::string &arg2, int waitTime)
Definition: process.cpp:231
bool openBrowser(std::string url)
Definition: process.cpp:310
bool execFile(const std::string &pathName, const std::string &name, const std::string &arg1, const std::string &arg2)
Definition: process.cpp:240
std::string & replaceAll(std::string &context, const std::string &from, const std::string &to)