1 #include "command.h"
2 
3 #include "config.h"
4 #include "log.h"
5 #include "str_util.h"
6 
7 static int
build_cmd(char * cmd,size_t len,const char * const argv[])8 build_cmd(char *cmd, size_t len, const char *const argv[]) {
9     // Windows command-line parsing is WTF:
10     // <http://daviddeley.com/autohotkey/parameters/parameters.htm#WINPASS>
11     // only make it work for this very specific program
12     // (don't handle escaping nor quotes)
13     size_t ret = xstrjoin(cmd, argv, ' ', len);
14     if (ret >= len) {
15         LOGE("Command too long (%" PRIsizet " chars)", len - 1);
16         return -1;
17     }
18     return 0;
19 }
20 
21 enum process_result
cmd_execute(const char * path,const char * const argv[],HANDLE * handle)22 cmd_execute(const char *path, const char *const argv[], HANDLE *handle) {
23     STARTUPINFOW si;
24     PROCESS_INFORMATION pi;
25     memset(&si, 0, sizeof(si));
26     si.cb = sizeof(si);
27 
28     char cmd[256];
29     if (build_cmd(cmd, sizeof(cmd), argv)) {
30         *handle = NULL;
31         return PROCESS_ERROR_GENERIC;
32     }
33 
34     wchar_t *wide = utf8_to_wide_char(cmd);
35     if (!wide) {
36         LOGC("Cannot allocate wide char string");
37         return PROCESS_ERROR_GENERIC;
38     }
39 
40 #ifdef WINDOWS_NOCONSOLE
41     int flags = CREATE_NO_WINDOW;
42 #else
43     int flags = 0;
44 #endif
45     if (!CreateProcessW(NULL, wide, NULL, NULL, FALSE, flags, NULL, NULL, &si,
46                         &pi)) {
47         SDL_free(wide);
48         *handle = NULL;
49         if (GetLastError() == ERROR_FILE_NOT_FOUND) {
50             return PROCESS_ERROR_MISSING_BINARY;
51         }
52         return PROCESS_ERROR_GENERIC;
53     }
54 
55     SDL_free(wide);
56     *handle = pi.hProcess;
57     return PROCESS_SUCCESS;
58 }
59 
60 bool
cmd_terminate(HANDLE handle)61 cmd_terminate(HANDLE handle) {
62     return TerminateProcess(handle, 1) && CloseHandle(handle);
63 }
64 
65 bool
cmd_simple_wait(HANDLE handle,DWORD * exit_code)66 cmd_simple_wait(HANDLE handle, DWORD *exit_code) {
67     DWORD code;
68     if (WaitForSingleObject(handle, INFINITE) != WAIT_OBJECT_0
69             || !GetExitCodeProcess(handle, &code)) {
70         // cannot wait or retrieve the exit code
71         code = -1; // max value, it's unsigned
72     }
73     if (exit_code) {
74         *exit_code = code;
75     }
76     return !code;
77 }
78 
79 char *
get_executable_path(void)80 get_executable_path(void) {
81     HMODULE hModule = GetModuleHandleW(NULL);
82     if (!hModule) {
83         return NULL;
84     }
85     WCHAR buf[MAX_PATH + 1]; // +1 for the null byte
86     int len = GetModuleFileNameW(hModule, buf, MAX_PATH);
87     if (!len) {
88         return NULL;
89     }
90     buf[len] = '\0';
91     return utf8_from_wide_char(buf);
92 }
93