xref: /vim-8.2.3635/src/pty.c (revision e16b00a1)
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) && !defined(MACOS)
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) && !defined(MACOS_X)
271 
272 /* NOTE: Even though HPUX can have /dev/ptmx, the code below doesn't work!
273  * Same for Mac OS X Leopard. */
274 #define PTY_DONE
275     int
276 OpenPTY(char **ttyn)
277 {
278     int		f;
279     char	*m;
280     char	*(ptsname(int));
281     int		unlockpt(int);
282     int		grantpt(int);
283     RETSIGTYPE (*sigcld) SIGPROTOARG;
284     /* used for opening a new pty-pair: */
285     static char TtyName[32];
286 
287     if ((f = open("/dev/ptmx", O_RDWR | O_NOCTTY | O_EXTRA, 0)) == -1)
288 	return -1;
289 
290     /*
291      * SIGCHLD set to SIG_DFL for grantpt() because it fork()s and
292      * exec()s pt_chmod
293      */
294     sigcld = signal(SIGCHLD, SIG_DFL);
295     if ((m = ptsname(f)) == NULL || grantpt(f) || unlockpt(f))
296     {
297 	signal(SIGCHLD, sigcld);
298 	close(f);
299 	return -1;
300     }
301     signal(SIGCHLD, sigcld);
302     vim_strncpy((char_u *)TtyName, (char_u *)m, sizeof(TtyName) - 1);
303     initmaster(f);
304     *ttyn = TtyName;
305     return f;
306 }
307 #endif
308 
309 #if defined(_AIX) && defined(HAVE_DEV_PTC) && !defined(PTY_DONE)
310 #define PTY_DONE
311 
312 #ifdef _IBMR2
313 int aixhack = -1;
314 #endif
315 
316     int
317 OpenPTY(char **ttyn)
318 {
319     int		f;
320     /* used for opening a new pty-pair: */
321     static char TtyName[32];
322 
323     /* a dumb looking loop replaced by mycrofts code: */
324     if ((f = open("/dev/ptc", O_RDWR | O_NOCTTY | O_EXTRA)) < 0)
325 	return -1;
326     vim_strncpy((char_u *)TtyName, (char_u *)ttyname(f), sizeof(TtyName) - 1);
327     if (geteuid() != ROOT_UID && mch_access(TtyName, R_OK | W_OK))
328     {
329 	close(f);
330 	return -1;
331     }
332     initmaster(f);
333 # ifdef _IBMR2
334     if (aixhack >= 0)
335 	close(aixhack);
336     if ((aixhack = open(TtyName, O_RDWR | O_NOCTTY | O_EXTRA, 0)) < 0)
337     {
338 	close(f);
339 	return -1;
340     }
341 # endif
342     *ttyn = TtyName;
343     return f;
344 }
345 #endif
346 
347 #ifndef PTY_DONE
348 
349 # ifdef hpux
350 static char PtyProto[] = "/dev/ptym/ptyXY";
351 static char TtyProto[] = "/dev/pty/ttyXY";
352 # else
353 #  ifdef __BEOS__
354 static char PtyProto[] = "/dev/pt/XY";
355 static char TtyProto[] = "/dev/tt/XY";
356 #  else
357 static char PtyProto[] = "/dev/ptyXY";
358 static char TtyProto[] = "/dev/ttyXY";
359 #  endif
360 # endif
361 
362     int
363 OpenPTY(char **ttyn)
364 {
365     char	*p, *q, *l, *d;
366     int		f;
367     /* used for opening a new pty-pair: */
368     static char PtyName[32];
369     static char TtyName[32];
370 
371     strcpy(PtyName, PtyProto);
372     strcpy(TtyName, TtyProto);
373     for (p = PtyName; *p != 'X'; p++)
374 	;
375     for (q = TtyName; *q != 'X'; q++)
376 	;
377     for (l = PTYRANGE0; (*p = *l) != '\0'; l++)
378     {
379 	for (d = PTYRANGE1; (p[1] = *d) != '\0'; d++)
380 	{
381 #if !defined(MACOS) || defined(USE_CARBONIZED)
382 	    if ((f = open(PtyName, O_RDWR | O_NOCTTY | O_EXTRA, 0)) == -1)
383 #else
384 	    if ((f = open(PtyName, O_RDWR | O_NOCTTY | O_EXTRA)) == -1)
385 #endif
386 		continue;
387 	    q[0] = *l;
388 	    q[1] = *d;
389 #ifndef MACOS
390 	    if (geteuid() != ROOT_UID && mch_access(TtyName, R_OK | W_OK))
391 	    {
392 		close(f);
393 		continue;
394 	    }
395 #endif
396 #if defined(SUN_SYSTEM) && defined(TIOCGPGRP) && !defined(SUNOS3)
397 	    /* Hack to ensure that the slave side of the pty is
398 	     * unused. May not work in anything other than SunOS4.1
399 	     */
400 	    {
401 		int pgrp;
402 
403 		/* tcgetpgrp does not work (uses TIOCGETPGRP)! */
404 		if (ioctl(f, TIOCGPGRP, (char *)&pgrp) != -1 || errno != EIO)
405 		{
406 		    close(f);
407 		    continue;
408 		}
409 	    }
410 #endif
411 	    initmaster(f);
412 	    *ttyn = TtyName;
413 	    return f;
414 	}
415     }
416     return -1;
417 }
418 #endif
419 
420 #endif /* FEAT_GUI || FEAT_TERMINAL */
421