1
2
3
4
5
6 #include <soulng/util/System.hpp>
7 #include <soulng/util/Handle.hpp>
8 #include <soulng/util/TextUtils.hpp>
9 #include <sys/stat.h>
10 #include <fcntl.h>
11 #include <cstring>
12 #include <memory>
13 #ifdef _WIN32
14 #include <process.h>
15 #include <windows.h>
16 #include <io.h>
17 #include <Psapi.h>
18 #elif defined(__linux) || defined(__posix) || defined(__unix)
19 #include <unistd.h>
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 #include <sys/time.h>
23 #include <sys/select.h>
24 #endif
25
26 namespace soulng { namespace util {
27
28 bool disableConsoleWindow = false;
29
30 void DisableConsoleWindow()
31 {
32 disableConsoleWindow = true;
33 }
34
35 ProcessFailure::ProcessFailure(const std::string& errorMessage_, int exitCode_) : std::runtime_error(errorMessage_), exitCode(exitCode_)
36 {
37 }
38
39 #ifdef _WIN32
40
41
42
43
44
45
46
47
48
49
50
51
52
53 #endif
54
55 int get_default_pmode()
56 {
57 #if defined(_WIN32)
58
59
60
61 #elif defined(__linux) || defined(__unix) || defined(__posix)
62
63
64
65 #else
66
67 #error unknown platform
68
69 #endif
70 }
71
72 std::std::vector<std::string>ParseCommand(conststd::string&command)
73 {
74 std::vector<std::string> args;
75 int state = 0;
76 std::string arg;
77 for (char c : command)
78 {
79 switch (state)
80 {
81 case 0:
82 {
83 if (c == '"')
84 {
85 arg.append(1, '"');
86 state = 1;
87 }
88 else if (c == ' ')
89 {
90 args.push_back(arg);
91 arg.clear();
92 state = 2;
93 }
94 else
95 {
96 arg.append(1, c);
97 }
98 break;
99 }
100 case 1:
101 {
102 if (c == '"')
103 {
104 arg.append(1, '"');
105 state = 0;
106 }
107 else
108 {
109 arg.append(1, c);
110 }
111 break;
112 }
113 case 2:
114 {
115 if (c != ' ')
116 {
117 arg.append(1, c);
118 state = 0;
119 }
120 break;
121 }
122 }
123 }
124 if (!arg.empty())
125 {
126 args.push_back(arg);
127 }
128 return args;
129 }
130
131 void System(const std::string& command, bool ignoreReturnValue)
132 {
133 int retVal = 0;
134 if (!disableConsoleWindow)
135 {
136 retVal = system(command.c_str());
137 }
138 else
139 {
140 #ifdef _WIN32
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173 #elif defined(__linux) || defined(__unix) || defined(__posix)
174
175 #else
176
177 #error unknown platform
178
179 #endif
180 }
181 if (!ignoreReturnValue)
182 {
183 if (retVal != 0)
184 {
185 #ifdef _WIN32
186
187
188
189 #elif defined(__linux) || defined(__unix) || defined(__posix)
190
191
192
193
194
195
196
197
198
199 #else
200
201 #error unknown platform
202
203 #endif
204 }
205 }
206 }
207
208 void System(const std::string& command)
209 {
210 return System(command, false);
211 }
212
213 void System(const std::string& command, int redirectFd, const std::string& toFile, bool ignoreReturnValue)
214 {
215 Handle old = dup(redirectFd);
216 if (old == -1)
217 {
218 throw std::runtime_error("System redirect: could not duplicate handle " + std::to_string(redirectFd));
219 }
220 Handle fd = creat(toFile.c_str(), get_default_pmode());
221 if (fd == -1)
222 {
223 throw std::runtime_error("System: could not create file '" + toFile + "'");
224 }
225 if (dup2(fd, redirectFd) == -1)
226 {
227 throw std::runtime_error("System redirect: dup2 failed");
228 }
229 try
230 {
231 System(command, ignoreReturnValue);
232 dup2(old, redirectFd);
233 }
234 catch (...)
235 {
236 dup2(old, redirectFd);
237 throw ;
238 }
239 }
240
241 void System(const std::string& command, int redirectFd, const std::string& toFile)
242 {
243 System(command, redirectFd, toFile, false);
244 }
245
246 void System(const std::string& command, const std::std::vector<std::std::pair<int, std::string>>&redirections)
247 {
248 std::vector<std::std::pair<int, Handle>>toRestore;
249 for (const std::std::pair<int, std::string>&redirection : redirections)
250 {
251 int handle = redirection.first;
252 std::string toFile = redirection.second;
253 Handle oldHandle = dup(handle);
254 if (oldHandle == -1)
255 {
256 throw std::runtime_error("System redirect: could not duplicate handle " + std::to_string(handle));
257 }
258 toRestore.push_back(std::make_pair(handle, std::move(oldHandle)));
259 Handle fd = creat(toFile.c_str(), get_default_pmode());
260 if (fd == -1)
261 {
262 throw std::runtime_error("System: could not create file '" + toFile + "'");
263 }
264 if (dup2(fd, handle) == -1)
265 {
266 throw std::runtime_error("System redirect: dup2 failed");
267 }
268 }
269 try
270 {
271 System(command);
272 for (std::std::pair<int, Handle>&r : toRestore)
273 {
274 int handle = r.first;
275 Handle old = std::move(r.second);
276 dup2(old, handle);
277 }
278 }
279 catch (...)
280 {
281 for (std::std::pair<int, Handle>&r : toRestore)
282 {
283 int handle = r.first;
284 Handle old = std::move(r.second);
285 dup2(old, handle);
286 }
287 throw ;
288 }
289 }
290
291 #ifdef _WIN32
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328 #elif defined(__linux) || defined(__posix) || defined(__unix)
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366 #endif
367
368 int ReadFromPipe(int pipeHandle, void* buffer, unsigned int count)
369 {
370 return read(pipeHandle, buffer, count);
371 }
372
373 int WriteToPipe(int pipeHandle, void* buffer, unsigned int count)
374 {
375 return write(pipeHandle, buffer, count);
376 }
377
378 void RedirectStdHandlesToPipes(std::std::vector<int>&oldHandles, std::std::vector<int>&pipeHandles)
379 {
380 int phRead[2];
381 if (pipe(phRead) == -1)
382 {
383 throw std::runtime_error("RedirectStdHandlesToPipes: pipe failed");
384 }
385 int old0 = dup(0);
386 if (old0 == -1)
387 {
388 throw std::runtime_error("RedirectStdHandlesToPipes: dup(0) failed");
389 }
390 oldHandles.push_back(old0);
391 if (dup2(phRead[0], 0) == -1)
392 {
393 throw std::runtime_error("RedirectStdHandlesToPipes: dup2(p0, 0) failed");
394 }
395 pipeHandles.push_back(phRead[1]);
396 close(phRead[0]);
397 int phWrite[2];
398 if (pipe(phWrite) == -1)
399 {
400 throw std::runtime_error("RedirectStdHandlesToPipes: pipe failed");
401 }
402 int old1 = dup(1);
403 if (old1 == -1)
404 {
405 throw std::runtime_error("RedirectStdHandlesToPipes: dup(1) failed");
406 }
407 oldHandles.push_back(old1);
408 if (dup2(phWrite[1], 1) == -1)
409 {
410 throw std::runtime_error("RedirectStdHandlesToPipes: dup2(p1, 1) failed");
411 }
412 pipeHandles.push_back(phWrite[0]);
413 close(phWrite[1]);
414 int phError[2];
415 if (pipe(phError) == -1)
416 {
417 throw std::runtime_error("RedirectStdHandlesToPipes: pipe failed");
418 }
419 int old2 = dup(2);
420 if (old2 == -1)
421 {
422 throw std::runtime_error("RedirectStdHandlesToPipes: dup(2) failed");
423 }
424 oldHandles.push_back(old2);
425 if (dup2(phError[1], 2) == -1)
426 {
427 throw std::runtime_error("RedirectStdHandlesToPipes: dup2(p2, 2) failed");
428 }
429 pipeHandles.push_back(phError[0]);
430 close(phError[1]);
431 }
432
433 void RestoreStdHandles(const std::std::vector<int>&oldHandles)
434 {
435 if (oldHandles.size() != 3)
436 {
437 throw std::runtime_error("3 old handles expected ");
438 }
439 if (dup2(oldHandles[0], 0) == -1)
440 {
441 throw std::runtime_error("RestoreStdHandles: dup2 0, old0 failed");
442 }
443 if (dup2(oldHandles[1], 1) == -1)
444 {
445 throw std::runtime_error("RestoreStdHandles: dup2 1, old1 failed");
446 }
447 if (dup2(oldHandles[2], 2) == -1)
448 {
449 throw std::runtime_error("RestoreStdHandles: dup2 2, old2 failed");
450 }
451 }
452
453 std::string GetPathToExecutable()
454 {
455 char buf[4096];
456 #ifdef _WIN32
457
458
459
460
461
462
463
464 #elif defined(__linux) || defined(__unix) || defined(__posix)
465
466
467
468
469
470
471
472
473
474
475
476
477 #else
478
479 #error unknown platform
480
481 #endif
482 }
483
484 } }