1 /** \file archdep_spawn.c
2 * \brief Process spawning
3 *
4 * Hopefully at some point this won't be required anymore.
5 *
6 * \author Marco van den Heuvel <blackystardust68@yahoo.com>
7 * \author Bas Wassink <b.wassink@ziggo.nl>
8 */
9
10 /*
11 * This file is part of VICE, the Versatile Commodore Emulator.
12 * See README for copyright notice.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
27 * 02111-1307 USA.
28 *
29 */
30
31 #include "vice.h"
32
33 #include "archdep_defs.h"
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <errno.h>
38
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 # include <fcntl.h>
43
44 #ifdef ARCHDEP_OS_UNIX
45 # include <sys/wait.h>
46 #endif
47
48 #ifdef ARCHDEP_OS_WINDOWS
49 # include <windows.h>
50 # include <io.h>
51 # include <process.h>
52 #endif
53
54 #include "ioutil.h"
55 #include "lib.h"
56 #include "log.h"
57 #include "util.h"
58
59 /* #include "debug_gtk3.h" */
60
61 #include "archdep.h"
62 #include "archdep_defs.h"
63
64 /* WTF? */
65 /* fix VICE userdir */
66 #ifdef VICEUSERDIR
67 # undef VICEUSERDIR
68 #endif
69 /** \brief User directory inside ./config
70 */
71 #define VICEUSERDIR "vice"
72
73
74 #include "archdep_spawn.h"
75
76
77 #ifdef ARCHDEP_OS_UNIX
78
archdep_spawn(const char * name,char ** argv,char ** pstdout_redir,const char * stderr_redir)79 int archdep_spawn(const char *name, char **argv,
80 char **pstdout_redir, const char *stderr_redir)
81 {
82 pid_t child_pid;
83 int child_status;
84 char *stdout_redir;
85
86
87 if (pstdout_redir != NULL) {
88 if (*pstdout_redir == NULL) {
89 *pstdout_redir = archdep_tmpnam();
90 }
91 stdout_redir = *pstdout_redir;
92 } else {
93 stdout_redir = NULL;
94 }
95
96 child_pid = vfork();
97 if (child_pid < 0) {
98 log_error(LOG_DEFAULT, "vfork() failed: %s.", strerror(errno));
99 return -1;
100 } else {
101 if (child_pid == 0) {
102 if (stdout_redir && freopen(stdout_redir, "w", stdout) == NULL) {
103 log_error(LOG_DEFAULT, "freopen(\"%s\") failed: %s.", stdout_redir, strerror(errno));
104 _exit(-1);
105 }
106 if (stderr_redir && freopen(stderr_redir, "w", stderr) == NULL) {
107 log_error(LOG_DEFAULT, "freopen(\"%s\") failed: %s.", stderr_redir, strerror(errno));
108 _exit(-1);
109 }
110 execvp(name, argv);
111 _exit(-1);
112 }
113 }
114
115 if (waitpid(child_pid, &child_status, 0) != child_pid) {
116 log_error(LOG_DEFAULT, "waitpid() failed: %s", strerror(errno));
117 return -1;
118 }
119
120 if (WIFEXITED(child_status)) {
121 return WEXITSTATUS(child_status);
122 } else {
123 return -1;
124 }
125 }
126
127 #elif defined(ARCHDEP_OS_WINDOWS)
128
129 /** \brief Spawn new process
130 *
131 * Shamelessly stolen from arch/sdl/archdep_win32.c
132 */
archdep_spawn(const char * name,char ** argv,char ** pstdout_redir,const char * stderr_redir)133 int archdep_spawn(const char *name, char **argv, char **pstdout_redir, const char *stderr_redir)
134 {
135 int new_stdout, new_stderr;
136 int old_stdout_mode, old_stderr_mode;
137 int old_stdout, old_stderr;
138 int retval;
139 char *stdout_redir = NULL;
140
141 if (pstdout_redir != NULL) {
142 if (*pstdout_redir == NULL) {
143 *pstdout_redir = archdep_tmpnam();
144 }
145 stdout_redir = *pstdout_redir;
146 }
147
148 new_stdout = new_stderr = old_stdout = old_stderr = -1;
149
150 /* Make sure we are in binary mode. */
151 old_stdout_mode = _setmode(STDOUT_FILENO, _O_BINARY);
152 old_stderr_mode = _setmode(STDERR_FILENO, _O_BINARY);
153
154 /* Redirect stdout and stderr as requested, saving the old
155 descriptors. */
156 if (stdout_redir != NULL) {
157 old_stdout = _dup(STDOUT_FILENO);
158 new_stdout = _open(stdout_redir,
159 _O_WRONLY | _O_TRUNC | _O_CREAT, _S_IWRITE | _S_IREAD);
160 if (new_stdout == -1) {
161 log_error(LOG_DEFAULT,
162 "open(\"%s\") failed: %s.", stdout_redir, strerror(errno));
163 retval = -1;
164 goto cleanup;
165 }
166 _dup2(new_stdout, STDOUT_FILENO);
167 }
168 if (stderr_redir != NULL) {
169 old_stderr = _dup(STDERR_FILENO);
170 new_stderr = _open(stderr_redir,
171 _O_WRONLY | _O_TRUNC | _O_CREAT, _S_IWRITE | _S_IREAD);
172 if (new_stderr == -1) {
173 log_error(LOG_DEFAULT,
174 "open(\"%s\") failed: %s.", stderr_redir, strerror(errno));
175 retval = -1;
176 goto cleanup;
177 }
178 _dup2(new_stderr, STDERR_FILENO);
179 }
180
181 /* Spawn the child process. */
182 retval = (int)_spawnvp(_P_WAIT, name, (const char * const *)argv);
183
184 cleanup:
185 if (old_stdout >= 0) {
186 _dup2(old_stdout, STDOUT_FILENO);
187 _close(old_stdout);
188 }
189 if (old_stderr >= 0) {
190 _dup2(old_stderr, STDERR_FILENO);
191 _close(old_stderr);
192 }
193 if (old_stdout_mode >= 0) {
194 _setmode(STDOUT_FILENO, old_stdout_mode);
195 }
196 if (old_stderr_mode >= 0) {
197 _setmode(STDERR_FILENO, old_stderr_mode);
198 }
199 if (new_stdout >= 0) {
200 _close(new_stdout);
201 }
202 if (new_stderr >= 0) {
203 _close(new_stderr);
204 }
205
206 return retval;
207 }
208
209 #elif defined(ARCHDEP_OS_BEOS)
210
archdep_spawn(const char * name,char ** argv,char ** pstdout_redir,const char * stderr_redir)211 int archdep_spawn(const char *name, char **argv,
212 char **pstdout_redir, const char *stderr_redir)
213 {
214 pid_t child_pid;
215 int child_status;
216 char *stdout_redir = NULL;
217
218 if (pstdout_redir != NULL) {
219 if (*pstdout_redir == NULL) {
220 *pstdout_redir = archdep_tmpnam();
221 }
222 stdout_redir = *pstdout_redir;
223 }
224
225 #ifdef WORDS_BIGENDIAN
226 child_pid = -1;
227 #else
228 child_pid = vfork();
229 #endif
230
231 if (child_pid < 0) {
232 log_error(LOG_DEFAULT, "vfork() failed: %s.", strerror(errno));
233 return -1;
234 } else {
235 if (child_pid == 0) {
236 if (stdout_redir && freopen(stdout_redir, "w", stdout) == NULL) {
237 log_error(LOG_DEFAULT, "freopen(\"%s\") failed: %s.", stdout_redir, strerror(errno));
238 _exit(-1);
239 }
240 if (stderr_redir && freopen(stderr_redir, "w", stderr) == NULL) {
241 log_error(LOG_DEFAULT, "freopen(\"%s\") failed: %s.", stderr_redir, strerror(errno));
242 _exit(-1);
243 }
244 execvp(name, argv);
245 _exit(-1);
246 }
247 }
248
249 if (waitpid(child_pid, &child_status, 0) != child_pid) {
250 log_error(LOG_DEFAULT, "waitpid() failed: %s", strerror(errno));
251 return -1;
252 }
253
254 if (WIFEXITED(child_status)) {
255 return WEXITSTATUS(child_status);
256 } else {
257 return -1;
258 }
259 }
260
261 #else
262 /* Unsupported OS's */
archdep_spawn(const char * name,char ** argv,char ** stdout_redir,const char * stderr_redir)263 int archdep_spawn(const char *name, char **argv,
264 char **stdout_redir, const char *stderr_redir)
265 {
266 return -1;
267 }
268
269 #endif
270