xref: /vim-8.2.3635/src/pty.c (revision fb094e14)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved		by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 /*
10  * The stuff in this file mostly comes from the "screen" program.
11  * Included with permission from Juergen Weigert.
12  * Copied from "pty.c".  "putenv.c" was used for putenv() in misc2.c.
13  *
14  * It has been modified to work better with Vim.
15  * The parts that are not used in Vim have been deleted.
16  * See the "screen" sources for the complete stuff.
17  *
18  * This specific version is distibuted under the Vim license (attribution by
19  * Juergen Weigert), the GPL applies to the original version, see the
20  * copyright notice below.
21  */
22 
23 /* Copyright (c) 1993
24  *	Juergen Weigert ([email protected])
25  *	Michael Schroeder ([email protected])
26  * Copyright (c) 1987 Oliver Laumann
27  *
28  * This program is free software; you can redistribute it and/or modify
29  * it under the terms of the GNU General Public License as published by
30  * the Free Software Foundation; either version 2, or (at your option)
31  * any later version.
32  *
33  * This program is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
36  * GNU General Public License for more details.
37  *
38  * You should have received a copy of the GNU General Public License
39  * along with this program (see the file COPYING); if not, write to the
40  * Free Software Foundation, Inc.,
41  * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
42  */
43 
44 #include "vim.h"
45 
46 #if defined(FEAT_GUI) || defined(FEAT_JOB_CHANNEL)
47 
48 #include <signal.h>
49 
50 #ifdef __CYGWIN32__
51 # include <sys/termios.h>
52 #endif
53 
54 #ifdef HAVE_SYS_IOCTL_H
55 # include <sys/ioctl.h>
56 #endif
57 
58 #if HAVE_STROPTS_H
59 #include <sys/types.h>
60 #ifdef sinix
61 #define buf_T __system_buf_t__
62 #endif
63 #include <stropts.h>
64 #ifdef sinix
65 #undef buf_T
66 #endif
67 # ifdef SUN_SYSTEM
68 #  include <sys/conf.h>
69 # endif
70 #endif
71 
72 #ifdef HAVE_UNISTD_H
73 # include <unistd.h>
74 #endif
75 
76 #if HAVE_TERMIO_H
77 # include <termio.h>
78 #else
79 # ifdef HAVE_TERMIOS_H
80 #  include <termios.h>
81 # endif
82 #endif
83 
84 #if HAVE_SYS_STREAM_H
85 # include <sys/stream.h>
86 #endif
87 
88 #if HAVE_SYS_PTEM_H
89 # include <sys/ptem.h>
90 #endif
91 
92 #if !defined(SUN_SYSTEM) && !defined(VMS)
93 # include <sys/ioctl.h>
94 #endif
95 
96 #if defined(SUN_SYSTEM) && defined(LOCKPTY) && !defined(TIOCEXCL)
97 # include <sys/ttold.h>
98 #endif
99 
100 #ifdef ISC
101 # include <sys/tty.h>
102 # include <sys/sioctl.h>
103 # include <sys/pty.h>
104 #endif
105 
106 #ifdef sgi
107 # include <sys/sysmacros.h>
108 #endif
109 
110 #if defined(_INCLUDE_HPUX_SOURCE) && !defined(hpux)
111 # define hpux
112 #endif
113 
114 /*
115  * if no PTYRANGE[01] is in the config file, we pick a default
116  */
117 #ifndef PTYRANGE0
118 # define PTYRANGE0 "qprs"
119 #endif
120 #ifndef PTYRANGE1
121 # define PTYRANGE1 "0123456789abcdef"
122 #endif
123 
124 /* SVR4 pseudo ttys don't seem to work with SCO-5 */
125 #ifdef M_UNIX
126 # undef HAVE_SVR4_PTYS
127 #endif
128 
129 static void initmaster(int);
130 
131 /*
132  *  Open all ptys with O_NOCTTY, just to be on the safe side.
133  */
134 #ifndef O_NOCTTY
135 # define O_NOCTTY 0
136 #endif
137 
138     static void
139 initmaster(int f UNUSED)
140 {
141 #ifndef VMS
142 # ifdef POSIX
143     tcflush(f, TCIOFLUSH);
144 # else
145 #  ifdef TIOCFLUSH
146     (void)ioctl(f, TIOCFLUSH, (char *) 0);
147 #  endif
148 # endif
149 # ifdef LOCKPTY
150     (void)ioctl(f, TIOCEXCL, (char *) 0);
151 # endif
152 #endif
153 }
154 
155 /*
156  * This causes a hang on some systems, but is required for a properly working
157  * pty on others.  Needs to be tuned...
158  */
159     int
160 SetupSlavePTY(int fd)
161 {
162     if (fd < 0)
163 	return 0;
164 #if defined(I_PUSH) && defined(HAVE_SVR4_PTYS) && !defined(sgi) && !defined(linux) && !defined(__osf__) && !defined(M_UNIX)
165 # if defined(HAVE_SYS_PTEM_H) || defined(hpux)
166     if (ioctl(fd, I_PUSH, "ptem") != 0)
167 	return -1;
168 # endif
169     if (ioctl(fd, I_PUSH, "ldterm") != 0)
170 	return -1;
171 # ifdef SUN_SYSTEM
172     if (ioctl(fd, I_PUSH, "ttcompat") != 0)
173 	return -1;
174 # endif
175 #endif
176     return 0;
177 }
178 
179 
180 #if defined(OSX) && !defined(PTY_DONE)
181 #define PTY_DONE
182     int
183 OpenPTY(char **ttyn)
184 {
185     int		f;
186     static char TtyName[32];
187 
188     if ((f = open_controlling_pty(TtyName)) < 0)
189 	return -1;
190     initmaster(f);
191     *ttyn = TtyName;
192     return f;
193 }
194 #endif
195 
196 #if (defined(sequent) || defined(_SEQUENT_)) && defined(HAVE_GETPSEUDOTTY) \
197 	&& !defined(PTY_DONE)
198 #define PTY_DONE
199     int
200 OpenPTY(char **ttyn)
201 {
202     char	*m, *s;
203     int		f;
204     /* used for opening a new pty-pair: */
205     static char PtyName[32];
206     static char TtyName[32];
207 
208     if ((f = getpseudotty(&s, &m)) < 0)
209 	return -1;
210 #ifdef _SEQUENT_
211     fvhangup(s);
212 #endif
213     vim_strncpy((char_u *)PtyName, (char_u *)m, sizeof(PtyName) - 1);
214     vim_strncpy((char_u *)TtyName, (char_u *)s, sizeof(TtyName) - 1);
215     initmaster(f);
216     *ttyn = TtyName;
217     return f;
218 }
219 #endif
220 
221 #if defined(__sgi) && !defined(PTY_DONE)
222 #define PTY_DONE
223     int
224 OpenPTY(char **ttyn)
225 {
226     int f;
227     char *name;
228     RETSIGTYPE (*sigcld) SIGPROTOARG;
229 
230     /*
231      * SIGCHLD set to SIG_DFL for _getpty() because it may fork() and
232      * exec() /usr/adm/mkpts
233      */
234     sigcld = signal(SIGCHLD, SIG_DFL);
235     name = _getpty(&f, O_RDWR | O_NONBLOCK | O_EXTRA, 0600, 0);
236     signal(SIGCHLD, sigcld);
237 
238     if (name == 0)
239 	return -1;
240     initmaster(f);
241     *ttyn = name;
242     return f;
243 }
244 #endif
245 
246 #if defined(MIPS) && defined(HAVE_DEV_PTC) && !defined(PTY_DONE)
247 #define PTY_DONE
248     int
249 OpenPTY(char **ttyn)
250 {
251     int		f;
252     stat_T	buf;
253     /* used for opening a new pty-pair: */
254     static char TtyName[32];
255 
256     if ((f = open("/dev/ptc", O_RDWR | O_NOCTTY | O_NONBLOCK | O_EXTRA, 0)) < 0)
257 	return -1;
258     if (mch_fstat(f, &buf) < 0)
259     {
260 	close(f);
261 	return -1;
262     }
263     sprintf(TtyName, "/dev/ttyq%d", minor(buf.st_rdev));
264     initmaster(f);
265     *ttyn = TtyName;
266     return f;
267 }
268 #endif
269 
270 #if defined(HAVE_SVR4_PTYS) && !defined(PTY_DONE) && !defined(hpux) \
271                     && !(defined(MACOS_X) && !defined(MAC_OS_X_VERSION_10_6))
272 
273 /* NOTE: Even though HPUX can have /dev/ptmx, the code below doesn't work!
274  * Same for Mac OS X Leopard (10.5). */
275 #define PTY_DONE
276     int
277 OpenPTY(char **ttyn)
278 {
279     int		f;
280     char	*m;
281     char	*(ptsname(int));
282     int		unlockpt(int);
283     int		grantpt(int);
284     RETSIGTYPE (*sigcld) SIGPROTOARG;
285     /* used for opening a new pty-pair: */
286     static char TtyName[32];
287 
288     if ((f = open("/dev/ptmx", O_RDWR | O_NOCTTY | O_EXTRA, 0)) == -1)
289 	return -1;
290 
291     /*
292      * SIGCHLD set to SIG_DFL for grantpt() because it fork()s and
293      * exec()s pt_chmod
294      */
295     sigcld = signal(SIGCHLD, SIG_DFL);
296     if ((m = ptsname(f)) == NULL || grantpt(f) || unlockpt(f))
297     {
298 	signal(SIGCHLD, sigcld);
299 	close(f);
300 	return -1;
301     }
302     signal(SIGCHLD, sigcld);
303     vim_strncpy((char_u *)TtyName, (char_u *)m, sizeof(TtyName) - 1);
304     initmaster(f);
305     *ttyn = TtyName;
306     return f;
307 }
308 #endif
309 
310 #if defined(_AIX) && defined(HAVE_DEV_PTC) && !defined(PTY_DONE)
311 #define PTY_DONE
312 
313 #ifdef _IBMR2
314 int aixhack = -1;
315 #endif
316 
317     int
318 OpenPTY(char **ttyn)
319 {
320     int		f;
321     /* used for opening a new pty-pair: */
322     static char TtyName[32];
323 
324     /* a dumb looking loop replaced by mycrofts code: */
325     if ((f = open("/dev/ptc", O_RDWR | O_NOCTTY | O_EXTRA)) < 0)
326 	return -1;
327     vim_strncpy((char_u *)TtyName, (char_u *)ttyname(f), sizeof(TtyName) - 1);
328     if (geteuid() != ROOT_UID && mch_access(TtyName, R_OK | W_OK))
329     {
330 	close(f);
331 	return -1;
332     }
333     initmaster(f);
334 # ifdef _IBMR2
335     if (aixhack >= 0)
336 	close(aixhack);
337     if ((aixhack = open(TtyName, O_RDWR | O_NOCTTY | O_EXTRA, 0)) < 0)
338     {
339 	close(f);
340 	return -1;
341     }
342 # endif
343     *ttyn = TtyName;
344     return f;
345 }
346 #endif
347 
348 #ifndef PTY_DONE
349 
350 # ifdef hpux
351 static char PtyProto[] = "/dev/ptym/ptyXY";
352 static char TtyProto[] = "/dev/pty/ttyXY";
353 # else
354 #  ifdef __BEOS__
355 static char PtyProto[] = "/dev/pt/XY";
356 static char TtyProto[] = "/dev/tt/XY";
357 #  else
358 static char PtyProto[] = "/dev/ptyXY";
359 static char TtyProto[] = "/dev/ttyXY";
360 #  endif
361 # endif
362 
363     int
364 OpenPTY(char **ttyn)
365 {
366     char	*p, *q, *l, *d;
367     int		f;
368     /* used for opening a new pty-pair: */
369     static char PtyName[32];
370     static char TtyName[32];
371 
372     strcpy(PtyName, PtyProto);
373     strcpy(TtyName, TtyProto);
374     for (p = PtyName; *p != 'X'; p++)
375 	;
376     for (q = TtyName; *q != 'X'; q++)
377 	;
378     for (l = PTYRANGE0; (*p = *l) != '\0'; l++)
379     {
380 	for (d = PTYRANGE1; (p[1] = *d) != '\0'; d++)
381 	{
382 	    if ((f = open(PtyName, O_RDWR | O_NOCTTY | O_EXTRA, 0)) == -1)
383 		continue;
384 	    q[0] = *l;
385 	    q[1] = *d;
386 	    if (geteuid() != ROOT_UID && mch_access(TtyName, R_OK | W_OK))
387 	    {
388 		close(f);
389 		continue;
390 	    }
391 #if defined(SUN_SYSTEM) && defined(TIOCGPGRP) && !defined(SUNOS3)
392 	    /* Hack to ensure that the slave side of the pty is
393 	     * unused. May not work in anything other than SunOS4.1
394 	     */
395 	    {
396 		int pgrp;
397 
398 		/* tcgetpgrp does not work (uses TIOCGETPGRP)! */
399 		if (ioctl(f, TIOCGPGRP, (char *)&pgrp) != -1 || errno != EIO)
400 		{
401 		    close(f);
402 		    continue;
403 		}
404 	    }
405 #endif
406 	    initmaster(f);
407 	    *ttyn = TtyName;
408 	    return f;
409 	}
410     }
411     return -1;
412 }
413 #endif
414 
415 #endif /* FEAT_GUI || FEAT_TERMINAL */
416