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 static void 140 initmaster(int f UNUSED) 141 { 142 #ifndef VMS 143 # ifdef POSIX 144 tcflush(f, TCIOFLUSH); 145 # else 146 # ifdef TIOCFLUSH 147 (void)ioctl(f, TIOCFLUSH, (char *) 0); 148 # endif 149 # endif 150 # ifdef LOCKPTY 151 (void)ioctl(f, TIOCEXCL, (char *) 0); 152 # endif 153 #endif 154 } 155 156 /* 157 * This causes a hang on some systems, but is required for a properly working 158 * pty on others. Needs to be tuned... 159 */ 160 int 161 setup_slavepty(int fd) 162 { 163 if (fd < 0) 164 return 0; 165 #if defined(I_PUSH) && defined(HAVE_SVR4_PTYS) && !defined(sgi) \ 166 && !defined(linux) && !defined(__osf__) && !defined(M_UNIX) 167 # if defined(HAVE_SYS_PTEM_H) || defined(hpux) 168 if (ioctl(fd, I_PUSH, "ptem") != 0) 169 return -1; 170 # endif 171 if (ioctl(fd, I_PUSH, "ldterm") != 0) 172 return -1; 173 # ifdef SUN_SYSTEM 174 if (ioctl(fd, I_PUSH, "ttcompat") != 0) 175 return -1; 176 # endif 177 #endif 178 return 0; 179 } 180 181 182 #if defined(OSX) && !defined(PTY_DONE) 183 #define PTY_DONE 184 int 185 mch_openpty(char **ttyn) 186 { 187 int f; 188 static char TtyName[32]; 189 190 if ((f = open_controlling_pty(TtyName)) < 0) 191 return -1; 192 initmaster(f); 193 *ttyn = TtyName; 194 return f; 195 } 196 #endif 197 198 #if (defined(sequent) || defined(_SEQUENT_)) && defined(HAVE_GETPSEUDOTTY) \ 199 && !defined(PTY_DONE) 200 #define PTY_DONE 201 int 202 mch_openpty(char **ttyn) 203 { 204 char *m, *s; 205 int f; 206 /* used for opening a new pty-pair: */ 207 static char PtyName[32]; 208 static char TtyName[32]; 209 210 if ((f = getpseudotty(&s, &m)) < 0) 211 return -1; 212 #ifdef _SEQUENT_ 213 fvhangup(s); 214 #endif 215 vim_strncpy((char_u *)PtyName, (char_u *)m, sizeof(PtyName) - 1); 216 vim_strncpy((char_u *)TtyName, (char_u *)s, sizeof(TtyName) - 1); 217 initmaster(f); 218 *ttyn = TtyName; 219 return f; 220 } 221 #endif 222 223 #if defined(__sgi) && !defined(PTY_DONE) 224 #define PTY_DONE 225 int 226 mch_openpty(char **ttyn) 227 { 228 int f; 229 char *name; 230 RETSIGTYPE (*sigcld) 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 mch_openpty(char **ttyn) 252 { 253 int f; 254 stat_T buf; 255 /* used for opening a new pty-pair: */ 256 static char TtyName[32]; 257 258 if ((f = open("/dev/ptc", O_RDWR | O_NOCTTY | O_NONBLOCK | O_EXTRA, 0)) < 0) 259 return -1; 260 if (mch_fstat(f, &buf) < 0) 261 { 262 close(f); 263 return -1; 264 } 265 sprintf(TtyName, "/dev/ttyq%d", minor(buf.st_rdev)); 266 initmaster(f); 267 *ttyn = TtyName; 268 return f; 269 } 270 #endif 271 272 #if defined(HAVE_SVR4_PTYS) && !defined(PTY_DONE) && !defined(hpux) \ 273 && !(defined(MACOS_X) && !defined(MAC_OS_X_VERSION_10_6)) 274 275 /* NOTE: Even though HPUX can have /dev/ptmx, the code below doesn't work! 276 * Same for Mac OS X Leopard (10.5). */ 277 #define PTY_DONE 278 int 279 mch_openpty(char **ttyn) 280 { 281 int f; 282 char *m; 283 char *(ptsname(int)); 284 int unlockpt(int); 285 int grantpt(int); 286 RETSIGTYPE (*sigcld) SIGPROTOARG; 287 /* used for opening a new pty-pair: */ 288 static char TtyName[32]; 289 290 if ((f = open("/dev/ptmx", O_RDWR | O_NOCTTY | O_EXTRA, 0)) == -1) 291 return -1; 292 293 /* 294 * SIGCHLD set to SIG_DFL for grantpt() because it fork()s and 295 * exec()s pt_chmod 296 */ 297 sigcld = signal(SIGCHLD, SIG_DFL); 298 if ((m = ptsname(f)) == NULL || grantpt(f) || unlockpt(f)) 299 { 300 signal(SIGCHLD, sigcld); 301 close(f); 302 return -1; 303 } 304 signal(SIGCHLD, sigcld); 305 vim_strncpy((char_u *)TtyName, (char_u *)m, sizeof(TtyName) - 1); 306 initmaster(f); 307 *ttyn = TtyName; 308 return f; 309 } 310 #endif 311 312 #if defined(_AIX) && defined(HAVE_DEV_PTC) && !defined(PTY_DONE) 313 #define PTY_DONE 314 315 #ifdef _IBMR2 316 int aixhack = -1; 317 #endif 318 319 int 320 mch_openpty(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 vim_strncpy((char_u *)TtyName, (char_u *)ttyname(f), sizeof(TtyName) - 1); 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 mch_openpty(char **ttyn) 367 { 368 char *p, *q, *l, *d; 369 int f; 370 /* used for opening a new pty-pair: */ 371 static char PtyName[32]; 372 static char TtyName[32]; 373 374 strcpy(PtyName, PtyProto); 375 strcpy(TtyName, TtyProto); 376 for (p = PtyName; *p != 'X'; p++) 377 ; 378 for (q = TtyName; *q != 'X'; q++) 379 ; 380 for (l = PTYRANGE0; (*p = *l) != '\0'; l++) 381 { 382 for (d = PTYRANGE1; (p[1] = *d) != '\0'; d++) 383 { 384 if ((f = open(PtyName, O_RDWR | O_NOCTTY | O_EXTRA, 0)) == -1) 385 continue; 386 q[0] = *l; 387 q[1] = *d; 388 if (geteuid() != ROOT_UID && mch_access(TtyName, R_OK | W_OK)) 389 { 390 close(f); 391 continue; 392 } 393 #if defined(SUN_SYSTEM) && defined(TIOCGPGRP) && !defined(SUNOS3) 394 /* Hack to ensure that the slave side of the pty is 395 * unused. May not work in anything other than SunOS4.1 396 */ 397 { 398 int pgrp; 399 400 /* tcgetpgrp does not work (uses TIOCGETPGRP)! */ 401 if (ioctl(f, TIOCGPGRP, (char *)&pgrp) != -1 || errno != EIO) 402 { 403 close(f); 404 continue; 405 } 406 } 407 #endif 408 initmaster(f); 409 *ttyn = TtyName; 410 return f; 411 } 412 } 413 return -1; 414 } 415 #endif 416 417 /* 418 * Call isatty(fd), except for SunOS where it's done differently. 419 */ 420 int 421 mch_isatty(int fd) 422 { 423 # if defined(I_STR) && defined(HAVE_SYS_PTMS_H) && defined(HAVE_SVR4_PTYS) \ 424 && defined(SUN_SYSTEM) 425 // On SunOS, isatty() for /dev/ptmx returns false or sometimes can hang up 426 // in the inner ioctl(), and therefore first determine whether "fd" is a 427 // master device. 428 struct strioctl istr; 429 430 istr.ic_cmd = ISPTM; 431 istr.ic_timout = 0; 432 istr.ic_dp = NULL; 433 istr.ic_len = 0; 434 435 if (ioctl(fd, I_STR, &istr) == 0) 436 // Trick: return 2 in order to advice the caller that "fd" is a master 437 // device. cf. src/os_unix.c:get_tty_fd() 438 return 2; 439 # endif 440 return isatty(fd); 441 } 442 443 #endif /* FEAT_GUI || FEAT_JOB_CHANNEL */ 444