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