1 /** \file   archdep_unix.c
2  * \brief   Miscellaneous UNIX-specific stuff
3  *
4  * \author  Marco van den Heuvel <blackystardust68@yahoo.com>
5  * \author  Bas Wassink <b.wassink@ziggo.nl>
6  */
7 
8 /*
9  * This file is part of VICE, the Versatile Commodore Emulator.
10  * See README for copyright notice.
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software
24  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
25  *  02111-1307  USA.
26  *
27  */
28 
29 #include "vice.h"
30 
31 #include <stdio.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <sys/wait.h>
38 #include <glib.h>
39 
40 #include "ioutil.h"
41 #include "lib.h"
42 #include "util.h"
43 
44 #include "debug_gtk3.h"
45 
46 #include "archdep.h"
47 
48 
49 /* fix VICE userdir */
50 #ifdef VICEUSERDIR
51 # undef VICEUSERDIR
52 #endif
53 /** \brief  User directory inside ./config
54  */
55 #define VICEUSERDIR "vice"
56 
57 
58 /** \brief  Write log message to stdout
59  *
60  * param[in]    level_string    log level string
61  * param[in]    txt             log message
62  *
63  * \note    Shamelessly copied from unix/archdep.c
64  *
65  * \return  0 on success, < 0 on failure
66  */
archdep_default_logger(const char * level_string,const char * txt)67 int archdep_default_logger(const char *level_string, const char *txt)
68 {
69     if (fputs(level_string, stdout) == EOF || fprintf(stdout, "%s", txt) < 0 || fputc ('\n', stdout) == EOF) {
70         return -1;
71     }
72     return 0;
73 }
74 
75 
76 /** \brief  Architecture-dependent shutdown hanlder
77  */
archdep_shutdown(void)78 void archdep_shutdown(void)
79 {
80     /* free memory used by the exec path */
81     archdep_program_path_free();
82     /* free memory used by the exec name */
83     archdep_program_name_free();
84     /* free memory used by the boot path */
85     archdep_boot_path_free();
86     /* free memory used by the home path */
87     archdep_home_path_free();
88     /* free memory used by the config files path */
89     archdep_user_config_path_free();
90     /* free memory used by the sysfile pathlist */
91     archdep_default_sysfile_pathlist_free();
92 
93     /* this should be removed soon */
94     if (argv0 != NULL) {
95         lib_free(argv0);
96         argv0 = NULL;
97     }
98 
99     archdep_network_shutdown();
100 }
101 
archdep_mkstemp_fd(char ** filename,const char * mode)102 FILE *archdep_mkstemp_fd(char **filename, const char *mode)
103 {
104 #if defined(HAVE_MKSTEMP)
105     char *tmp;
106     const char template[] = "/vice.XXXXXX";
107     int fildes;
108     FILE *fd;
109     char *tmpdir;
110 
111 #ifdef USE_EXE_RELATIVE_TMP
112     tmp = lib_msprintf("%s/tmp%s", archdep_boot_path(), template);
113 #else
114     tmpdir = getenv("TMPDIR");
115 
116     if (tmpdir != NULL) {
117         tmp = util_concat(tmpdir, template, NULL);
118     } else {
119         tmp = util_concat("/tmp", template, NULL);
120     }
121 #endif
122 
123     fildes = mkstemp(tmp);
124 
125     if (fildes < 0) {
126         lib_free(tmp);
127         return NULL;
128     }
129 
130     fd = fdopen(fildes, mode);
131 
132     if (fd == NULL) {
133         lib_free(tmp);
134         return NULL;
135     }
136 
137     *filename = tmp;
138 
139     return fd;
140 #else
141     char *tmp;
142     FILE *fd;
143 
144     tmp = tmpnam(NULL);
145 
146     if (tmp == NULL) {
147         return NULL;
148     }
149 
150     fd = fopen(tmp, mode);
151 
152     if (fd == NULL) {
153         return NULL;
154     }
155 
156     *filename = lib_stralloc(tmp);
157 
158     return fd;
159 #endif
160 }
161 
archdep_spawn(const char * name,char ** argv,char ** pstdout_redir,const char * stderr_redir)162 int archdep_spawn(const char *name, char **argv,
163                   char **pstdout_redir, const char *stderr_redir)
164 {
165     pid_t child_pid;
166     int child_status;
167     char *stdout_redir;
168 
169 
170     if (pstdout_redir != NULL) {
171         if (*pstdout_redir == NULL) {
172             *pstdout_redir = archdep_tmpnam();
173         }
174         stdout_redir = *pstdout_redir;
175     } else {
176         stdout_redir = NULL;
177     }
178 
179     child_pid = vfork();
180     if (child_pid < 0) {
181         log_error(LOG_DEFAULT, "vfork() failed: %s.", strerror(errno));
182         return -1;
183     } else {
184         if (child_pid == 0) {
185             if (stdout_redir && freopen(stdout_redir, "w", stdout) == NULL) {
186                 log_error(LOG_DEFAULT, "freopen(\"%s\") failed: %s.", stdout_redir, strerror(errno));
187                 _exit(-1);
188             }
189             if (stderr_redir && freopen(stderr_redir, "w", stderr) == NULL) {
190                 log_error(LOG_DEFAULT, "freopen(\"%s\") failed: %s.", stderr_redir, strerror(errno));
191                 _exit(-1);
192             }
193             execvp(name, argv);
194             _exit(-1);
195         }
196     }
197 
198     if (waitpid(child_pid, &child_status, 0) != child_pid) {
199         log_error(LOG_DEFAULT, "waitpid() failed: %s", strerror(errno));
200         return -1;
201     }
202 
203     if (WIFEXITED(child_status)) {
204         return WEXITSTATUS(child_status);
205     } else {
206         return -1;
207     }
208 }
209 
210 #if 0
211 /** \brief  Create a unique temporary filename
212  *
213  * Uses mkstemp(3) when available.
214  *
215  * \return  temporary filename
216  */
217 char *archdep_tmpnam(void)
218 {
219 #ifdef HAVE_MKSTEMP
220     char *tmp_name;
221     const char mkstemp_template[] = "/vice.XXXXXX";
222     int fd;
223     char *tmp;
224     char *final_name;
225 
226     tmp_name = lib_malloc(ioutil_maxpathlen());
227     if ((tmp = getenv("TMPDIR")) != NULL) {
228         strncpy(tmp_name, tmp, ioutil_maxpathlen());
229         tmp_name[ioutil_maxpathlen() - sizeof(mkstemp_template)] = '\0';
230     } else {
231         strcpy(tmp_name, "/tmp");
232     }
233     strcat(tmp_name, mkstemp_template);
234     if ((fd = mkstemp(tmp_name)) < 0) {
235         tmp_name[0] = '\0';
236     } else {
237         close(fd);
238     }
239 
240     final_name = lib_stralloc(tmp_name);
241     lib_free(tmp_name);
242     return final_name;
243 #else
244     return lib_stralloc(tmpnam(NULL));
245 #endif
246 }
247 #endif
248 
break64(int sig)249 static RETSIGTYPE break64(int sig)
250 {
251     log_message(LOG_DEFAULT, "Received signal %d, exiting.", sig);
252     exit (-1);
253 }
254 
archdep_signals_init(int do_core_dumps)255 void archdep_signals_init(int do_core_dumps)
256 {
257     if (do_core_dumps) {
258         signal(SIGPIPE, break64);
259     }
260 }
261 
262 typedef void (*signal_handler_t)(int);
263 
264 static signal_handler_t old_pipe_handler;
265 
266 /*
267     these two are used for socket send/recv. in this case we might
268     get SIGPIPE if the connection is unexpectedly closed.
269 */
archdep_signals_pipe_set(void)270 void archdep_signals_pipe_set(void)
271 {
272     old_pipe_handler = signal(SIGPIPE, SIG_IGN);
273 }
274 
archdep_signals_pipe_unset(void)275 void archdep_signals_pipe_unset(void)
276 {
277     signal(SIGPIPE, old_pipe_handler);
278 }
279 
280