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