1 | /* |
2 | Simple DirectMedia Layer |
3 | Copyright (C) 1997-2025 Sam Lantinga <slouken@libsdl.org> |
4 | |
5 | This software is provided 'as-is', without any express or implied |
6 | warranty. In no event will the authors be held liable for any damages |
7 | arising from the use of this software. |
8 | |
9 | Permission is granted to anyone to use this software for any purpose, |
10 | including commercial applications, and to alter it and redistribute it |
11 | freely, subject to the following restrictions: |
12 | |
13 | 1. The origin of this software must not be misrepresented; you must not |
14 | claim that you wrote the original software. If you use this software |
15 | in a product, an acknowledgment in the product documentation would be |
16 | appreciated but is not required. |
17 | 2. Altered source versions must be plainly marked as such, and must not be |
18 | misrepresented as being the original software. |
19 | 3. This notice may not be removed or altered from any source distribution. |
20 | */ |
21 | #include "SDL_internal.h" |
22 | |
23 | #include "SDL_sysprocess.h" |
24 | |
25 | |
26 | SDL_Process *SDL_CreateProcess(const char * const *args, bool pipe_stdio) |
27 | { |
28 | if (!args || !args[0] || !args[0][0]) { |
29 | SDL_InvalidParamError("args" ); |
30 | return NULL; |
31 | } |
32 | |
33 | SDL_Process *process; |
34 | SDL_PropertiesID props = SDL_CreateProperties(); |
35 | SDL_SetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, (void *)args); |
36 | if (pipe_stdio) { |
37 | SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDIN_NUMBER, SDL_PROCESS_STDIO_APP); |
38 | SDL_SetNumberProperty(props, SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER, SDL_PROCESS_STDIO_APP); |
39 | } |
40 | process = SDL_CreateProcessWithProperties(props); |
41 | SDL_DestroyProperties(props); |
42 | return process; |
43 | } |
44 | |
45 | SDL_Process *SDL_CreateProcessWithProperties(SDL_PropertiesID props) |
46 | { |
47 | const char * const *args = SDL_GetPointerProperty(props, SDL_PROP_PROCESS_CREATE_ARGS_POINTER, NULL); |
48 | if (!args || !args[0] || !args[0][0]) { |
49 | SDL_InvalidParamError("SDL_PROP_PROCESS_CREATE_ARGS_POINTER" ); |
50 | return NULL; |
51 | } |
52 | |
53 | SDL_Process *process = (SDL_Process *)SDL_calloc(1, sizeof(*process)); |
54 | if (!process) { |
55 | return NULL; |
56 | } |
57 | process->background = SDL_GetBooleanProperty(props, SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN, false); |
58 | |
59 | process->props = SDL_CreateProperties(); |
60 | if (!process->props) { |
61 | SDL_DestroyProcess(process); |
62 | return NULL; |
63 | } |
64 | SDL_SetBooleanProperty(process->props, SDL_PROP_PROCESS_BACKGROUND_BOOLEAN, process->background); |
65 | |
66 | if (!SDL_SYS_CreateProcessWithProperties(process, props)) { |
67 | SDL_DestroyProcess(process); |
68 | return NULL; |
69 | } |
70 | process->alive = true; |
71 | return process; |
72 | } |
73 | |
74 | SDL_PropertiesID SDL_GetProcessProperties(SDL_Process *process) |
75 | { |
76 | if (!process) { |
77 | return SDL_InvalidParamError("process" ); |
78 | } |
79 | return process->props; |
80 | } |
81 | |
82 | void *SDL_ReadProcess(SDL_Process *process, size_t *datasize, int *exitcode) |
83 | { |
84 | void *result; |
85 | |
86 | if (datasize) { |
87 | *datasize = 0; |
88 | } |
89 | if (exitcode) { |
90 | *exitcode = -1; |
91 | } |
92 | |
93 | if (!process) { |
94 | SDL_InvalidParamError("process" ); |
95 | return NULL; |
96 | } |
97 | |
98 | SDL_IOStream *io = (SDL_IOStream *)SDL_GetPointerProperty(process->props, SDL_PROP_PROCESS_STDOUT_POINTER, NULL); |
99 | if (!io) { |
100 | SDL_SetError("Process not created with I/O enabled" ); |
101 | return NULL; |
102 | } |
103 | |
104 | result = SDL_LoadFile_IO(io, datasize, false); |
105 | |
106 | SDL_WaitProcess(process, true, exitcode); |
107 | |
108 | return result; |
109 | } |
110 | |
111 | SDL_IOStream *SDL_GetProcessInput(SDL_Process *process) |
112 | { |
113 | if (!process) { |
114 | SDL_InvalidParamError("process" ); |
115 | return NULL; |
116 | } |
117 | |
118 | SDL_IOStream *io = (SDL_IOStream *)SDL_GetPointerProperty(process->props, SDL_PROP_PROCESS_STDIN_POINTER, NULL); |
119 | if (!io) { |
120 | SDL_SetError("Process not created with standard input available" ); |
121 | return NULL; |
122 | } |
123 | |
124 | return io; |
125 | } |
126 | |
127 | SDL_IOStream *SDL_GetProcessOutput(SDL_Process *process) |
128 | { |
129 | if (!process) { |
130 | SDL_InvalidParamError("process" ); |
131 | return NULL; |
132 | } |
133 | |
134 | SDL_IOStream *io = (SDL_IOStream *)SDL_GetPointerProperty(process->props, SDL_PROP_PROCESS_STDOUT_POINTER, NULL); |
135 | if (!io) { |
136 | SDL_SetError("Process not created with standard output available" ); |
137 | return NULL; |
138 | } |
139 | |
140 | return io; |
141 | } |
142 | |
143 | bool SDL_KillProcess(SDL_Process *process, bool force) |
144 | { |
145 | if (!process) { |
146 | return SDL_InvalidParamError("process" ); |
147 | } |
148 | |
149 | if (!process->alive) { |
150 | return SDL_SetError("Process isn't running" ); |
151 | } |
152 | |
153 | return SDL_SYS_KillProcess(process, force); |
154 | } |
155 | |
156 | bool SDL_WaitProcess(SDL_Process *process, bool block, int *exitcode) |
157 | { |
158 | if (!process) { |
159 | return SDL_InvalidParamError("process" ); |
160 | } |
161 | |
162 | if (!process->alive) { |
163 | if (exitcode) { |
164 | *exitcode = process->exitcode; |
165 | } |
166 | return true; |
167 | } |
168 | |
169 | if (SDL_SYS_WaitProcess(process, block, &process->exitcode)) { |
170 | process->alive = false; |
171 | if (exitcode) { |
172 | if (process->background) { |
173 | process->exitcode = 0; |
174 | } |
175 | *exitcode = process->exitcode; |
176 | } |
177 | return true; |
178 | } |
179 | return false; |
180 | } |
181 | |
182 | void SDL_DestroyProcess(SDL_Process *process) |
183 | { |
184 | if (!process) { |
185 | return; |
186 | } |
187 | |
188 | // Check to see if the process has exited, will reap zombies on POSIX platforms |
189 | if (process->alive) { |
190 | SDL_WaitProcess(process, false, NULL); |
191 | } |
192 | |
193 | SDL_SYS_DestroyProcess(process); |
194 | SDL_DestroyProperties(process->props); |
195 | SDL_free(process); |
196 | } |
197 | |