Updated copyright notice to 2011
[xboard.git] / childio.c
1 /*
2  * childio.c -- set up communication with child processes 
3  *
4  * Copyright 1991 by Digital Equipment Corporation, Maynard,
5  * Massachusetts. 
6  *
7  * Enhancements Copyright 1992-2001, 2002, 2003, 2004, 2005, 2006,
8  * 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
9  *
10  * The following terms apply to Digital Equipment Corporation's copyright
11  * interest in XBoard:
12  * ------------------------------------------------------------------------
13  * All Rights Reserved
14  *
15  * Permission to use, copy, modify, and distribute this software and its
16  * documentation for any purpose and without fee is hereby granted,
17  * provided that the above copyright notice appear in all copies and that
18  * both that copyright notice and this permission notice appear in
19  * supporting documentation, and that the name of Digital not be
20  * used in advertising or publicity pertaining to distribution of the
21  * software without specific, written prior permission.
22  *
23  * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
24  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
25  * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
26  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
27  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
28  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
29  * SOFTWARE.
30  * ------------------------------------------------------------------------
31  *
32  * The following terms apply to the enhanced version of XBoard
33  * distributed by the Free Software Foundation:
34  * ------------------------------------------------------------------------
35  *
36  * GNU XBoard is free software: you can redistribute it and/or modify
37  * it under the terms of the GNU General Public License as published by
38  * the Free Software Foundation, either version 3 of the License, or (at
39  * your option) any later version.
40  *
41  * GNU XBoard is distributed in the hope that it will be useful, but
42  * WITHOUT ANY WARRANTY; without even the implied warranty of
43  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
44  * General Public License for more details.
45  *
46  * You should have received a copy of the GNU General Public License
47  * along with this program. If not, see http://www.gnu.org/licenses/.  *
48  *
49  *------------------------------------------------------------------------
50  ** See the file ChangeLog for a revision history.  */
51
52 /* This file splits into two entirely different pieces of code
53    depending on whether USE_PTYS is 1.  The whole reason for all
54    the pty nonsense is that select() does not work on pipes in System-V
55    derivatives (at least some of them).  This is a problem because
56    XtAppAddInput works by adding its argument to a select that is done
57    deep inside Xlib.
58 */
59
60 #include "config.h"
61
62 #include <signal.h>
63 #if HAVE_UNISTD_H
64 # include <unistd.h>
65 #endif
66
67 #include "common.h"
68 #include "frontend.h"
69 #include "backend.h" /* for safeStrCpy */
70
71 #if !USE_PTYS
72 /* This code is for systems where pipes work properly */
73
74 void SetUpChildIO(to_prog, from_prog)
75      int to_prog[2], from_prog[2];
76 {
77     signal(SIGPIPE, SIG_IGN);
78     pipe(to_prog);
79     pipe(from_prog);
80 }
81
82 #else /* USE_PTYS == 1 */
83 /* This code is for all systems where we must use ptys */
84
85 #include <errno.h>
86 #include <sys/stat.h>
87 #include <sys/ioctl.h>
88 #if HAVE_STROPTS_H
89 # include <stropts.h>
90 #endif /* HAVE_STROPTS_H */
91 #if HAVE_SYS_FCNTL_H
92 # include <sys/fcntl.h>
93 #else /* not HAVE_SYS_FCNTL_H */
94 # if HAVE_FCNTL_H
95 #  include <fcntl.h>
96 # endif /* HAVE_FCNTL_H */
97 #endif /* not HAVE_SYS_FCNTL_H */
98
99 int PseudoTTY P((char pty_name[]));
100
101 int SetUpChildIO(to_prog, from_prog)
102      int to_prog[2], from_prog[2];
103 {
104     char pty_name[MSG_SIZ];
105
106     if ((to_prog[1] = PseudoTTY(pty_name)) == -1) {
107         DisplayFatalError("Can't open pseudo-tty", errno, 1);
108         ExitEvent(1);
109     }
110     from_prog[0] = to_prog[1];
111     to_prog[0] = from_prog[1] = open(pty_name, O_RDWR, 0);
112
113 #if HAVE_STROPTS_H /* do we really need this??  pipe-like behavior is fine */
114     if (ioctl (to_prog[0], I_PUSH, "ptem") == -1 ||
115         ioctl (to_prog[0], I_PUSH, "ldterm") == -1 ||
116         ioctl (to_prog[0], I_PUSH, "ttcompat") == -1) {
117 # ifdef NOTDEF /* seems some systems don't have or need ptem and ttcompat */
118         DisplayFatalError("Can't ioctl pseudo-tty", errno, 1);
119         ExitEvent(1);
120 # endif /*NOTDEF*/
121     }
122 #endif /* HAVE_STROPTS_H */
123
124 }
125
126 #if HAVE_GRANTPT
127 /* This code is for SVR4 */
128
129 int PseudoTTY(pty_name)
130      char pty_name[];
131 {
132     extern char *ptsname();
133     char *ptss;
134     int fd;
135     
136     fd = open("/dev/ptmx", O_RDWR);
137     if (fd < 0) return fd;
138     if (grantpt(fd) == -1) return -1;
139     if (unlockpt(fd) == -1) return -1;
140     if (!(ptss = ptsname(fd))) return -1;
141     safeStrCpy(pty_name, ptss, sizeof(pty_name)/sizeof(pty_name[0]));
142     return fd;
143 }
144
145 #else /* not HAVE_GRANTPT */
146 #if HAVE__GETPTY
147 /* This code is for IRIX */
148
149 int PseudoTTY(pty_name)
150      char pty_name[];
151 {
152     int fd;
153     char *ptyn;
154
155     ptyn = _getpty(&fd, O_RDWR, 0600, 0);
156     if (ptyn == NULL) return -1;
157     safeStrCpy(pty_name, ptyn, sizeof(pty_name)/sizeof(pty_name[0]));
158     return fd;
159 }
160
161 #else /* not HAVE__GETPTY */
162 #if HAVE_LIBSEQ
163 /* This code is for Sequent DYNIX/ptx.  Untested. --tpm */
164
165 int PseudoTTY(pty_name)
166      char pty_name[];
167 {
168     int fd;
169     char *slave, *master;
170
171     fd = getpseudotty(&slave, &master);
172     if (fd < 0) return fd;
173     safeStrCpy(pty_name, slave, sizeof(pty_name)/sizeof(pty_name[0]));
174     return fd;
175 }
176
177 #else /* not HAVE_LIBSEQ */
178 /* This code is for all other systems */
179 /* The code is adapted from GNU Emacs 19.24 */
180
181 #ifndef FIRST_PTY_LETTER
182 #define FIRST_PTY_LETTER 'p'
183 #endif
184 #ifndef LAST_PTY_LETTER
185 #define LAST_PTY_LETTER 'z'
186 #endif
187
188 int PseudoTTY(pty_name)
189      char pty_name[];
190 {
191   struct stat stb;
192   register c, i;
193   int fd;
194
195   /* Some systems name their pseudoterminals so that there are gaps in
196      the usual sequence - for example, on HP9000/S700 systems, there
197      are no pseudoterminals with names ending in 'f'.  So we wait for
198      three failures in a row before deciding that we've reached the
199      end of the ptys.  */
200   int failed_count = 0;
201
202 #ifdef PTY_ITERATION
203   PTY_ITERATION
204 #else
205   for (c = FIRST_PTY_LETTER; c <= LAST_PTY_LETTER; c++)
206     for (i = 0; i < 16; i++)
207 #endif
208       {
209 #ifdef PTY_NAME_SPRINTF
210         PTY_NAME_SPRINTF
211 #else
212           sprintf (pty_name, "/dev/pty%c%x", c, i);
213 #endif /* no PTY_NAME_SPRINTF */
214
215 #ifdef PTY_OPEN
216         PTY_OPEN;
217 #else /* no PTY_OPEN */
218         if (stat (pty_name, &stb) < 0)
219           {
220             failed_count++;
221             if (failed_count >= 3)
222               return -1;
223           }
224         else
225           failed_count = 0;
226         fd = open (pty_name, O_RDWR, 0);
227 #endif /* no PTY_OPEN */
228
229         if (fd >= 0)
230           {
231             /* check to make certain that both sides are available
232                this avoids a nasty yet stupid bug in rlogins */
233 #ifdef PTY_TTY_NAME_SPRINTF
234             PTY_TTY_NAME_SPRINTF
235 #else
236               sprintf (pty_name,  "/dev/tty%c%x", c, i);
237 #endif /* no PTY_TTY_NAME_SPRINTF */
238 #ifndef UNIPLUS
239             if (access (pty_name, 6) != 0)
240               {
241                 close (fd);
242                 continue;
243               }
244 #endif /* not UNIPLUS */
245 #ifdef IBMRTAIX
246               /* On AIX, the parent gets SIGHUP when a pty attached
247                  child dies.  So, we ignore SIGHUP once we've started
248                  a child on a pty.  Note that this may cause xboard
249                  not to die when it should, i.e., when its own
250                  controlling tty goes away.
251               */
252               signal(SIGHUP, SIG_IGN);
253 #endif /* IBMRTAIX */
254             return fd;
255           }
256       }
257   return -1;
258 }
259
260 #endif /* not HAVE_LIBSEQ */
261 #endif /* not HAVE__GETPTY */
262 #endif /* not HAVE_GRANTPT */
263 #endif /* USE_PTYS */