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