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