1 /** \file coproc.c
2 * \brief co-process fork
3 *
4 * \author Andre Fachat <a.fachat@physik.tu-chemnitz.de>
5 */
6
7 /*
8 * This file is part of VICE, the Versatile Commodore Emulator.
9 * See README for copyright notice.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 * 02111-1307 USA.
25 *
26 */
27
28 /*
29 * This is modelled after some examples in Stevens, "Advanced Progamming
30 * in the Unix environment", Addison Wesley.
31 *
32 * It simply opens two uni-directional pipes and forks a process to
33 * use the pipes as bidirectional connection for the stdin/out of the
34 * child.
35 * This, however, implies that the child knows its being piped and _buffers_
36 * all stdio. To avoid that one has to open a pseudo terminal device,
37 * which is too heavily system dependant to be included here.
38 * Instead a wrapper like the program "pty" described in the book mentioned
39 * above could be used.
40 *
41 * Technicalities: It does not store the PID of the forked child but
42 * instead it relies on the child being killed when the parent terminates
43 * prematurely or the child terminates itself on EOF on stdin.
44 *
45 * The command string is given to "/bin/sh -c cmdstring" such that
46 * the shell can do fileexpansion.
47 *
48 * We ignore all SIGCHLD and SIGPIPE signals that may occur here by
49 * installing an ignoring handler.
50 */
51
52 #include "vice.h"
53
54 #ifdef UNIX_COMPILE
55
56 /* to be removed later */
57 #if !defined(OPENSTEP_COMPILE) && !defined(RHAPSODY_COMPILE) \
58 && !defined(NEXTSTEP_COMPILE)
59
60 #ifdef __svr4__
61 #define _POSIX_SOURCE
62 #endif
63
64 #include <sys/types.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <unistd.h>
68 #include <errno.h>
69 #include <signal.h>
70
71 #ifdef OPENSERVER6_COMPILE
72 #include <sys/signal.h>
73 #endif
74
75 #include "archdep.h"
76
77 #include "coproc.h"
78
79 #include "log.h"
80
81 #define SHELL "/bin/sh"
82
83 #ifndef sigset_t
84 #define sigset_t int
85 #endif
86
87 /* HP-UX 9 fix */
88 #ifndef SA_RESTART
89 #define SA_RESTART 0
90 #endif
91
92 #ifdef __NeXT__
sigaction(int sig,const struct sigaction * act,struct sigaction * oact)93 int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
94 {
95 struct sigvec vec, ovec;
96 int st;
97
98 vec.sv_handler = act->sa_handler;
99 vec.sv_mask = act->sa_mask;
100 vec.sv_flags = act->sa_flags;
101
102 st = sigvec(sig, &vec, &ovec);
103
104 if (oact) {
105 oact->sa_handler = ovec.sv_handler;
106 oact->sa_mask = ovec.sv_mask;
107 oact->sa_flags = ovec.sv_flags;
108 }
109 return st;
110 }
111
sigemptyset(sigset_t * set)112 int sigemptyset(sigset_t *set)
113 {
114 *set = 0;
115 return 0;
116 }
117 #endif
118
119 static struct sigaction ignore;
120
fork_coproc(int * fd_wr,int * fd_rd,char * cmd)121 int fork_coproc(int *fd_wr, int *fd_rd, char *cmd)
122 {
123 int fd1[2], fd2[2];
124 pid_t pid;
125
126 ignore.sa_handler = SIG_IGN;
127 sigemptyset(&ignore.sa_mask);
128 ignore.sa_flags = SA_NOCLDSTOP | SA_RESTART;
129
130 sigaction(SIGCHLD, &ignore, NULL);
131 sigaction(SIGPIPE, &ignore, NULL);
132
133 if (pipe(fd1) < 0) {
134 log_error(LOG_DEFAULT, "Coproc: Couldn't open pipe!");
135 return -1;
136 }
137 if (pipe(fd2) < 0) {
138 log_error(LOG_DEFAULT, "Coproc: Couldn't open pipe!");
139 close(fd1[0]);
140 close(fd1[1]);
141 return -1;
142 }
143 if ((pid = fork()) < 0) {
144 log_error(LOG_DEFAULT, "Coproc: Couldn't fork()!");
145 close(fd1[0]);
146 close(fd1[1]);
147 close(fd2[0]);
148 close(fd2[1]);
149 return -1;
150 } else if (pid == 0) { /* child */
151 close(fd1[0]);
152 if (fd1[1] != STDOUT_FILENO) {
153 dup2(fd1[1], STDOUT_FILENO);
154 close(fd1[1]);
155 }
156 close(fd2[1]);
157 if (fd2[0] != STDIN_FILENO) {
158 dup2(fd2[0], STDIN_FILENO);
159 close(fd2[0]);
160 }
161 /* Hm, we have to close all other files that are currently
162 open now... */
163 execl(SHELL, "sh", "-c", cmd, NULL);
164
165 archdep_vice_exit(127); /* child dies on error */
166 } else { /* parent */
167 close(fd1[1]);
168 close(fd2[0]);
169
170 *fd_rd = fd1[0];
171 *fd_wr = fd2[1];
172 }
173 return 0;
174 }
175 #endif
176 #endif
177
178