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