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 # if defined(HAVE_SYS_PTMS_H) && defined(HAVE_SVR4_PTYS) 70 # include <sys/ptms.h> 71 # endif 72 # endif 73 #endif 74 75 #ifdef HAVE_UNISTD_H 76 # include <unistd.h> 77 #endif 78 79 #if HAVE_TERMIO_H 80 # include <termio.h> 81 #else 82 # ifdef HAVE_TERMIOS_H 83 # include <termios.h> 84 # endif 85 #endif 86 87 #if HAVE_SYS_STREAM_H 88 # include <sys/stream.h> 89 #endif 90 91 #if HAVE_SYS_PTEM_H 92 # include <sys/ptem.h> 93 #endif 94 95 #if !defined(SUN_SYSTEM) && !defined(VMS) 96 # include <sys/ioctl.h> 97 #endif 98 99 #if defined(SUN_SYSTEM) && defined(LOCKPTY) && !defined(TIOCEXCL) 100 # include <sys/ttold.h> 101 #endif 102 103 #ifdef ISC 104 # include <sys/tty.h> 105 # include <sys/sioctl.h> 106 # include <sys/pty.h> 107 #endif 108 109 #ifdef sgi 110 # include <sys/sysmacros.h> 111 #endif 112 113 #if defined(_INCLUDE_HPUX_SOURCE) && !defined(hpux) 114 # define hpux 115 #endif 116 117 /* 118 * if no PTYRANGE[01] is in the config file, we pick a default 119 */ 120 #ifndef PTYRANGE0 121 # define PTYRANGE0 "qprs" 122 #endif 123 #ifndef PTYRANGE1 124 # define PTYRANGE1 "0123456789abcdef" 125 #endif 126 127 /* SVR4 pseudo ttys don't seem to work with SCO-5 */ 128 #ifdef M_UNIX 129 # undef HAVE_SVR4_PTYS 130 #endif 131 132 /* 133 * Open all ptys with O_NOCTTY, just to be on the safe side. 134 */ 135 #ifndef O_NOCTTY 136 # define O_NOCTTY 0 137 #endif 138 139 #if defined(HAVE_SVR4_PTYS) || defined(HAVE_POSIX_OPENPT) 140 // These should be in stdlib.h, but it depends on _XOPEN_SOURCE. 141 char *ptsname(int); 142 int unlockpt(int); 143 int grantpt(int); 144 int posix_openpt(int flags); 145 #endif 146 147 static void 148 initmaster(int f UNUSED) 149 { 150 #ifndef VMS 151 # ifdef POSIX 152 tcflush(f, TCIOFLUSH); 153 # else 154 # ifdef TIOCFLUSH 155 (void)ioctl(f, TIOCFLUSH, (char *) 0); 156 # endif 157 # endif 158 # ifdef LOCKPTY 159 (void)ioctl(f, TIOCEXCL, (char *) 0); 160 # endif 161 #endif 162 } 163 164 /* 165 * This causes a hang on some systems, but is required for a properly working 166 * pty on others. Needs to be tuned... 167 */ 168 int 169 setup_slavepty(int fd) 170 { 171 if (fd < 0) 172 return 0; 173 #if defined(I_PUSH) && defined(HAVE_SVR4_PTYS) && !defined(sgi) \ 174 && !defined(linux) && !defined(__osf__) && !defined(M_UNIX) 175 # if defined(HAVE_SYS_PTEM_H) || defined(hpux) 176 if (ioctl(fd, I_PUSH, "ptem") != 0) 177 return -1; 178 # endif 179 if (ioctl(fd, I_PUSH, "ldterm") != 0) 180 return -1; 181 # ifdef SUN_SYSTEM 182 if (ioctl(fd, I_PUSH, "ttcompat") != 0) 183 return -1; 184 # endif 185 #endif 186 return 0; 187 } 188 189 #if defined(HAVE_POSIX_OPENPT) && !defined(PTY_DONE) 190 #define PTY_DONE 191 int 192 mch_openpty(char **ttyn) 193 { 194 int f; 195 char *m; 196 RETSIGTYPE (*sigcld) SIGPROTOARG; 197 static char TtyName[32]; // used for opening a new pty-pair 198 199 if ((f = posix_openpt(O_RDWR | O_NOCTTY | O_EXTRA)) == -1) 200 return -1; 201 202 // SIGCHLD set to SIG_DFL for grantpt() because it fork()s and 203 // exec()s pt_chmod 204 sigcld = signal(SIGCHLD, SIG_DFL); 205 if ((m = ptsname(f)) == NULL || grantpt(f) || unlockpt(f)) 206 { 207 signal(SIGCHLD, sigcld); 208 close(f); 209 return -1; 210 } 211 signal(SIGCHLD, sigcld); 212 vim_strncpy((char_u *)TtyName, (char_u *)m, sizeof(TtyName) - 1); 213 initmaster(f); 214 *ttyn = TtyName; 215 return f; 216 } 217 #endif 218 219 #if defined(OSX) && !defined(PTY_DONE) 220 #define PTY_DONE 221 int 222 mch_openpty(char **ttyn) 223 { 224 int f; 225 static char TtyName[32]; 226 227 if ((f = open_controlling_pty(TtyName)) < 0) 228 return -1; 229 initmaster(f); 230 *ttyn = TtyName; 231 return f; 232 } 233 #endif 234 235 #if (defined(sequent) || defined(_SEQUENT_)) && defined(HAVE_GETPSEUDOTTY) \ 236 && !defined(PTY_DONE) 237 #define PTY_DONE 238 int 239 mch_openpty(char **ttyn) 240 { 241 char *m, *s; 242 int f; 243 /* used for opening a new pty-pair: */ 244 static char PtyName[32]; 245 static char TtyName[32]; 246 247 if ((f = getpseudotty(&s, &m)) < 0) 248 return -1; 249 #ifdef _SEQUENT_ 250 fvhangup(s); 251 #endif 252 vim_strncpy((char_u *)PtyName, (char_u *)m, sizeof(PtyName) - 1); 253 vim_strncpy((char_u *)TtyName, (char_u *)s, sizeof(TtyName) - 1); 254 initmaster(f); 255 *ttyn = TtyName; 256 return f; 257 } 258 #endif 259 260 #if defined(__sgi) && !defined(PTY_DONE) 261 #define PTY_DONE 262 int 263 mch_openpty(char **ttyn) 264 { 265 int f; 266 char *name; 267 RETSIGTYPE (*sigcld) SIGPROTOARG; 268 269 /* 270 * SIGCHLD set to SIG_DFL for _getpty() because it may fork() and 271 * exec() /usr/adm/mkpts 272 */ 273 sigcld = signal(SIGCHLD, SIG_DFL); 274 name = _getpty(&f, O_RDWR | O_NONBLOCK | O_EXTRA, 0600, 0); 275 signal(SIGCHLD, sigcld); 276 277 if (name == 0) 278 return -1; 279 initmaster(f); 280 *ttyn = name; 281 return f; 282 } 283 #endif 284 285 #if defined(MIPS) && defined(HAVE_DEV_PTC) && !defined(PTY_DONE) 286 #define PTY_DONE 287 int 288 mch_openpty(char **ttyn) 289 { 290 int f; 291 stat_T buf; 292 /* used for opening a new pty-pair: */ 293 static char TtyName[32]; 294 295 if ((f = open("/dev/ptc", O_RDWR | O_NOCTTY | O_NONBLOCK | O_EXTRA, 0)) < 0) 296 return -1; 297 if (mch_fstat(f, &buf) < 0) 298 { 299 close(f); 300 return -1; 301 } 302 sprintf(TtyName, "/dev/ttyq%d", minor(buf.st_rdev)); 303 initmaster(f); 304 *ttyn = TtyName; 305 return f; 306 } 307 #endif 308 309 #if defined(HAVE_SVR4_PTYS) && !defined(PTY_DONE) && !defined(hpux) \ 310 && !(defined(MACOS_X) && !defined(MAC_OS_X_VERSION_10_6)) 311 312 /* NOTE: Even though HPUX can have /dev/ptmx, the code below doesn't work! 313 * Same for Mac OS X Leopard (10.5). */ 314 #define PTY_DONE 315 int 316 mch_openpty(char **ttyn) 317 { 318 int f; 319 char *m; 320 RETSIGTYPE (*sigcld) SIGPROTOARG; 321 /* used for opening a new pty-pair: */ 322 static char TtyName[32]; 323 324 if ((f = open("/dev/ptmx", O_RDWR | O_NOCTTY | O_EXTRA, 0)) == -1) 325 return -1; 326 327 /* 328 * SIGCHLD set to SIG_DFL for grantpt() because it fork()s and 329 * exec()s pt_chmod 330 */ 331 sigcld = signal(SIGCHLD, SIG_DFL); 332 if ((m = ptsname(f)) == NULL || grantpt(f) || unlockpt(f)) 333 { 334 signal(SIGCHLD, sigcld); 335 close(f); 336 return -1; 337 } 338 signal(SIGCHLD, sigcld); 339 vim_strncpy((char_u *)TtyName, (char_u *)m, sizeof(TtyName) - 1); 340 initmaster(f); 341 *ttyn = TtyName; 342 return f; 343 } 344 #endif 345 346 #if defined(_AIX) && defined(HAVE_DEV_PTC) && !defined(PTY_DONE) 347 #define PTY_DONE 348 349 #ifdef _IBMR2 350 int aixhack = -1; 351 #endif 352 353 int 354 mch_openpty(char **ttyn) 355 { 356 int f; 357 /* used for opening a new pty-pair: */ 358 static char TtyName[32]; 359 360 /* a dumb looking loop replaced by mycrofts code: */ 361 if ((f = open("/dev/ptc", O_RDWR | O_NOCTTY | O_EXTRA)) < 0) 362 return -1; 363 vim_strncpy((char_u *)TtyName, (char_u *)ttyname(f), sizeof(TtyName) - 1); 364 if (geteuid() != ROOT_UID && mch_access(TtyName, R_OK | W_OK)) 365 { 366 close(f); 367 return -1; 368 } 369 initmaster(f); 370 # ifdef _IBMR2 371 if (aixhack >= 0) 372 close(aixhack); 373 if ((aixhack = open(TtyName, O_RDWR | O_NOCTTY | O_EXTRA, 0)) < 0) 374 { 375 close(f); 376 return -1; 377 } 378 # endif 379 *ttyn = TtyName; 380 return f; 381 } 382 #endif 383 384 #ifndef PTY_DONE 385 386 # ifdef hpux 387 static char PtyProto[] = "/dev/ptym/ptyXY"; 388 static char TtyProto[] = "/dev/pty/ttyXY"; 389 # else 390 # ifdef __BEOS__ 391 static char PtyProto[] = "/dev/pt/XY"; 392 static char TtyProto[] = "/dev/tt/XY"; 393 # else 394 static char PtyProto[] = "/dev/ptyXY"; 395 static char TtyProto[] = "/dev/ttyXY"; 396 # endif 397 # endif 398 399 int 400 mch_openpty(char **ttyn) 401 { 402 char *p, *q, *l, *d; 403 int f; 404 /* used for opening a new pty-pair: */ 405 static char PtyName[32]; 406 static char TtyName[32]; 407 408 strcpy(PtyName, PtyProto); 409 strcpy(TtyName, TtyProto); 410 for (p = PtyName; *p != 'X'; p++) 411 ; 412 for (q = TtyName; *q != 'X'; q++) 413 ; 414 for (l = PTYRANGE0; (*p = *l) != '\0'; l++) 415 { 416 for (d = PTYRANGE1; (p[1] = *d) != '\0'; d++) 417 { 418 if ((f = open(PtyName, O_RDWR | O_NOCTTY | O_EXTRA, 0)) == -1) 419 continue; 420 q[0] = *l; 421 q[1] = *d; 422 if (geteuid() != ROOT_UID && mch_access(TtyName, R_OK | W_OK)) 423 { 424 close(f); 425 continue; 426 } 427 #if defined(SUN_SYSTEM) && defined(TIOCGPGRP) && !defined(SUNOS3) 428 /* Hack to ensure that the slave side of the pty is 429 * unused. May not work in anything other than SunOS4.1 430 */ 431 { 432 int pgrp; 433 434 /* tcgetpgrp does not work (uses TIOCGETPGRP)! */ 435 if (ioctl(f, TIOCGPGRP, (char *)&pgrp) != -1 || errno != EIO) 436 { 437 close(f); 438 continue; 439 } 440 } 441 #endif 442 initmaster(f); 443 *ttyn = TtyName; 444 return f; 445 } 446 } 447 return -1; 448 } 449 #endif 450 451 /* 452 * Call isatty(fd), except for SunOS where it's done differently. 453 */ 454 int 455 mch_isatty(int fd) 456 { 457 # if defined(I_STR) && defined(HAVE_SYS_PTMS_H) && defined(HAVE_SVR4_PTYS) \ 458 && defined(SUN_SYSTEM) 459 // On SunOS, isatty() for /dev/ptmx returns false or sometimes can hang up 460 // in the inner ioctl(), and therefore first determine whether "fd" is a 461 // master device. 462 struct strioctl istr; 463 464 istr.ic_cmd = ISPTM; 465 istr.ic_timout = 0; 466 istr.ic_dp = NULL; 467 istr.ic_len = 0; 468 469 if (ioctl(fd, I_STR, &istr) == 0) 470 // Trick: return 2 in order to advice the caller that "fd" is a master 471 // device. cf. src/os_unix.c:get_tty_fd() 472 return 2; 473 # endif 474 return isatty(fd); 475 } 476 477 #endif /* FEAT_GUI || FEAT_JOB_CHANNEL */ 478