1/* pty_termios.c - routines to allocate ptys - termios version 2 3Written by: Don Libes, NIST, 2/6/90 4 5This file is in the public domain. However, the author and NIST 6would appreciate credit if you use this file or parts of it. 7 8*/ 9 10#include <stdio.h> 11#include <signal.h> 12 13#if defined(SIGCLD) && !defined(SIGCHLD) 14#define SIGCHLD SIGCLD 15#endif 16 17#include "expect_cf.h" 18 19/* 20 The following functions are linked from the Tcl library. They 21 don't cause anything else in the library to be dragged in, so it 22 shouldn't cause any problems (e.g., bloat). 23 24 The functions are relatively small but painful enough that I don't care 25 to recode them. You may, if you absolutely want to get rid of any 26 vestiges of Tcl. 27*/ 28extern char *TclGetRegError(); 29 30#if defined(HAVE_PTMX_BSD) && defined(HAVE_PTMX) 31/* 32 * Some systems have both PTMX and PTMX_BSD. 33 * In fact, alphaev56-dec-osf4.0e has /dev/pts, /dev/pty, /dev/ptym, 34 * /dev/ptm, /dev/ptmx, and /dev/ptmx_bsd 35 * Suggestion from Martin Buchholz <martin@xemacs.org> is that BSD 36 * is usually deprecated and so should be here. 37 */ 38#undef HAVE_PTMX_BSD 39#endif 40 41/* Linux and Digital systems can be configured to have both. 42According to Ashley Pittman <ashley@ilo.dec.com>, Digital works better 43with openpty which supports 4000 while ptmx supports 60. */ 44#if defined(HAVE_OPENPTY) && defined(HAVE_PTMX) 45#undef HAVE_PTMX 46#endif 47 48#if defined(HAVE_PTYM) && defined(HAVE_PTMX) 49/* 50 * HP-UX 10.0 with streams (optional) have both PTMX and PTYM. I don't 51 * know which is preferred but seeing as how the HP trap stuff is so 52 * unusual, it is probably safer to stick with the native HP pty support, 53 * too. 54 */ 55#undef HAVE_PTMX 56#endif 57 58#ifdef HAVE_UNISTD_H 59# include <unistd.h> 60#endif 61#ifdef HAVE_INTTYPES_H 62# include <inttypes.h> 63#endif 64#include <sys/types.h> 65#include <sys/stat.h> 66 67#ifdef NO_STDLIB_H 68#include "../compat/stdlib.h" 69#else 70#include <stdlib.h> 71#endif 72#ifdef HAVE_STRING_H 73#include <string.h> 74#endif 75 76#ifdef HAVE_SYSMACROS_H 77#include <sys/sysmacros.h> 78#endif 79 80#ifdef HAVE_PTYTRAP 81#include <sys/ptyio.h> 82#endif 83 84#include <sys/file.h> 85 86#ifdef HAVE_SYS_FCNTL_H 87# include <sys/fcntl.h> 88#else 89# include <fcntl.h> 90#endif 91 92#if defined(_SEQUENT_) 93# include <sys/strpty.h> 94#endif 95 96#if defined(HAVE_PTMX) && defined(HAVE_STROPTS_H) 97# include <sys/stropts.h> 98#endif 99 100#include "exp_win.h" 101 102#include "exp_tty_in.h" 103#include "exp_rename.h" 104#include "exp_pty.h" 105 106void expDiagLog(); 107void expDiagLogPtr(); 108 109#include <errno.h> 110/*extern char *sys_errlist[];*/ 111 112#ifndef TRUE 113#define TRUE 1 114#define FALSE 0 115#endif 116 117/* Convex getpty is different than older-style getpty */ 118/* Convex getpty is really just a cover function that does the traversal */ 119/* across the domain of pty names. It makes no attempt to verify that */ 120/* they can actually be used. Indded, the logic in the man page is */ 121/* wrong because it will allow you to allocate ptys that your own account */ 122/* already has in use. */ 123#if defined(HAVE_GETPTY) && defined(CONVEX) 124#undef HAVE_GETPTY 125#define HAVE_CONVEX_GETPTY 126extern char *getpty(); 127static char *master_name; 128static char slave_name[] = "/dev/ptyXX"; 129static char *tty_bank; /* ptr to char [p-z] denoting 130 which bank it is */ 131static char *tty_num; /* ptr to char [0-f] denoting 132 which number it is */ 133#endif 134 135#if defined(_SEQUENT_) && !defined(HAVE_PTMX) 136/* old-style SEQUENT, new-style uses ptmx */ 137static char *master_name, *slave_name; 138#endif /* _SEQUENT */ 139 140/* very old SGIs prefer _getpty over ptc */ 141#if defined(HAVE__GETPTY) && defined(HAVE_PTC) && !defined(HAVE_GETPTY) 142#undef HAVE_PTC 143#endif 144 145#if defined(HAVE_PTC) 146static char slave_name[] = "/dev/ttyqXXX"; 147/* some machines (e.g., SVR4.0 StarServer) have all of these and */ 148/* HAVE_PTC works best */ 149#undef HAVE_GETPTY 150#undef HAVE__GETPTY 151#endif 152 153#if defined(HAVE__GETPTY) || defined(HAVE_PTC_PTS) || defined(HAVE_PTMX) 154static char *slave_name; 155#endif 156 157#if defined(HAVE_GETPTY) 158#include <sys/vty.h> 159static char master_name[MAXPTYNAMELEN]; 160static char slave_name[MAXPTYNAMELEN]; 161#endif 162 163#if !defined(HAVE_GETPTY) && !defined(HAVE__GETPTY) && !defined(HAVE_PTC) && !defined(HAVE_PTC_PTS) && !defined(HAVE_PTMX) && !defined(HAVE_CONVEX_GETPTY) && !defined(_SEQUENT_) && !defined(HAVE_SCO_CLIST_PTYS) && !defined(HAVE_OPENPTY) 164#ifdef HAVE_PTYM 165 /* strange order and missing d is intentional */ 166static char banks[] = "pqrstuvwxyzabcefghijklo"; 167static char master_name[] = "/dev/ptym/ptyXXXX"; 168static char slave_name[] = "/dev/pty/ttyXXXX"; 169static char *slave_bank; 170static char *slave_num; 171#else 172static char banks[] = "pqrstuvwxyzPQRSTUVWXYZ"; 173static char master_name[] = "/dev/ptyXX"; 174static char slave_name [] = "/dev/ttyXX"; 175#endif /* HAVE_PTYM */ 176 177static char *tty_type; /* ptr to char [pt] denoting 178 whether it is a pty or tty */ 179static char *tty_bank; /* ptr to char [p-z] denoting 180 which bank it is */ 181static char *tty_num; /* ptr to char [0-f] denoting 182 which number it is */ 183#endif 184 185#if defined(HAVE_SCO_CLIST_PTYS) 186# define MAXPTYNAMELEN 64 187static char master_name[MAXPTYNAMELEN]; 188static char slave_name[MAXPTYNAMELEN]; 189#endif /* HAVE_SCO_CLIST_PTYS */ 190 191#ifdef HAVE_OPENPTY 192static char master_name[64]; 193static char slave_name[64]; 194#endif 195 196char *exp_pty_slave_name; 197char *exp_pty_error; 198 199#if 0 200static void 201pty_stty(s,name) 202char *s; /* args to stty */ 203char *name; /* name of pty */ 204{ 205#define MAX_ARGLIST 10240 206 char buf[MAX_ARGLIST]; /* overkill is easier */ 207 RETSIGTYPE (*old)(); /* save old sigalarm handler */ 208 int pid; 209 210 old = signal(SIGCHLD, SIG_DFL); 211 switch (pid = fork()) { 212 case 0: /* child */ 213 exec_stty(STTY_BIN,STTY_BIN,s); 214 break; 215 case -1: /* fail */ 216 default: /* parent */ 217 waitpid(pid); 218 break; 219 } 220 221 signal(SIGCHLD, old); /* restore signal handler */ 222} 223 224exec_stty(s) 225char *s; 226{ 227 char *args[50]; 228 char *cp; 229 int argi = 0; 230 int quoting = FALSE; 231 int in_token = FALSE; /* TRUE if we are reading a token */ 232 233 args[0] = cp = s; 234 while (*s) { 235 if (quoting) { 236 if (*s == '\\' && *(s+1) == '"') { /* quoted quote */ 237 s++; /* get past " */ 238 *cp++ = *s++; 239 } else if (*s == '\"') { /* close quote */ 240 end_token 241 quoting = FALSE; 242 } else *cp++ = *s++; /* suck up anything */ 243 } else if (*s == '\"') { /* open quote */ 244 in_token = TRUE; 245 quoting = TRUE; 246 s++; 247 } else if (isspace(*s)) { 248 end_token 249 } else { 250 *cp++ = *s++; 251 in_token = TRUE; 252 } 253 } 254 end_token 255 args[argi] = (char *) 0; /* terminate argv */ 256 execvp(args[0],args); 257} 258#endif /*0*/ 259 260static void 261pty_stty(s,name) 262char *s; /* args to stty */ 263char *name; /* name of pty */ 264{ 265#define MAX_ARGLIST 10240 266 char buf[MAX_ARGLIST]; /* overkill is easier */ 267 RETSIGTYPE (*old)(); /* save old sigalarm handler */ 268 269#ifdef STTY_READS_STDOUT 270 sprintf(buf,"%s %s > %s",STTY_BIN,s,name); 271#else 272 sprintf(buf,"%s %s < %s",STTY_BIN,s,name); 273#endif 274 old = signal(SIGCHLD, SIG_DFL); 275 system(buf); 276 signal(SIGCHLD, old); /* restore signal handler */ 277} 278 279int exp_dev_tty; /* file descriptor to /dev/tty or -1 if none */ 280static int knew_dev_tty;/* true if we had our hands on /dev/tty at any time */ 281 282exp_tty exp_tty_original; 283 284#define GET_TTYTYPE 0 285#define SET_TTYTYPE 1 286static void 287ttytype(request,fd,ttycopy,ttyinit,s) 288int request; 289int fd; 290 /* following are used only if request == SET_TTYTYPE */ 291int ttycopy; /* true/false, copy from /dev/tty */ 292int ttyinit; /* if true, initialize to sane state */ 293char *s; /* stty args */ 294{ 295 if (request == GET_TTYTYPE) { 296#ifdef HAVE_TCSETATTR 297 if (-1 == tcgetattr(fd, &exp_tty_original)) { 298#else 299 if (-1 == ioctl(fd, TCGETS, (char *)&exp_tty_original)) { 300#endif 301 knew_dev_tty = FALSE; 302 exp_dev_tty = -1; 303 } 304 exp_window_size_get(fd); 305 } else { /* type == SET_TTYTYPE */ 306 if (ttycopy && knew_dev_tty) { 307#ifdef HAVE_TCSETATTR 308 (void) tcsetattr(fd, TCSADRAIN, &exp_tty_current); 309#else 310 (void) ioctl(fd, TCSETS, (char *)&exp_tty_current); 311#endif 312 313 exp_window_size_set(fd); 314 } 315 316#ifdef __CENTERLINE__ 317#undef DFLT_STTY 318#define DFLT_STTY "sane" 319#endif 320 321/* Apollo Domain doesn't need this */ 322#ifdef DFLT_STTY 323 if (ttyinit) { 324 /* overlay parms originally supplied by Makefile */ 325/* As long as BSD stty insists on stdout == stderr, we can no longer write */ 326/* diagnostics to parent stderr, since stderr has is now child's */ 327/* Maybe someday they will fix stty? */ 328/* expDiagLogPtrStr("exp_getptyslave: (default) stty %s\n",DFLT_STTY);*/ 329 pty_stty(DFLT_STTY,slave_name); 330 } 331#endif 332 333 /* lastly, give user chance to override any terminal parms */ 334 if (s) { 335 /* give user a chance to override any terminal parms */ 336/* expDiagLogPtrStr("exp_getptyslave: (user-requested) stty %s\n",s);*/ 337 pty_stty(s,slave_name); 338 } 339 } 340} 341 342void 343exp_init_pty() 344{ 345#if !defined(HAVE_GETPTY) && !defined(HAVE__GETPTY) && !defined(HAVE_PTC) && !defined(HAVE_PTC_PTS) && !defined(HAVE_PTMX) && !defined(HAVE_CONVEX_GETPTY) && !defined(_SEQUENT_) && !defined(HAVE_SCO_CLIST_PTYS) && !defined(HAVE_OPENPTY) 346#ifdef HAVE_PTYM 347 static char dummy; 348 tty_bank = &master_name[strlen("/dev/ptym/pty")]; 349 tty_num = &master_name[strlen("/dev/ptym/ptyX")]; 350 slave_bank = &slave_name[strlen("/dev/pty/tty")]; 351 slave_num = &slave_name[strlen("/dev/pty/ttyX")]; 352#else 353 tty_bank = &master_name[strlen("/dev/pty")]; 354 tty_num = &master_name[strlen("/dev/ptyp")]; 355 tty_type = &slave_name[strlen("/dev/")]; 356#endif 357 358#endif /* HAVE_PTYM */ 359 360 361 exp_dev_tty = open("/dev/tty",O_RDWR); 362 knew_dev_tty = (exp_dev_tty != -1); 363 if (knew_dev_tty) ttytype(GET_TTYTYPE,exp_dev_tty,0,0,(char *)0); 364} 365 366#ifndef R_OK 367/* 3b2 doesn't define these according to jthomas@nmsu.edu. */ 368#define R_OK 04 369#define W_OK 02 370#endif 371 372int 373exp_getptymaster() 374{ 375 char *hex, *bank; 376 struct stat stat_buf; 377 int master = -1; 378 int slave = -1; 379 int num; 380 381 exp_pty_error = 0; 382 383#define TEST_PTY 1 384 385#if defined(HAVE_PTMX) || defined(HAVE_PTMX_BSD) 386#undef TEST_PTY 387#if defined(HAVE_PTMX_BSD) 388 if ((master = open("/dev/ptmx_bsd", O_RDWR)) == -1) return(-1); 389#else 390 if ((master = open("/dev/ptmx", O_RDWR)) == -1) return(-1); 391#endif 392 if ((slave_name = (char *)ptsname(master)) == NULL) { 393 close(master); 394 return(-1); 395 } 396 if (grantpt(master)) { 397 static char buf[500]; 398 exp_pty_error = buf; 399 sprintf(exp_pty_error,"grantpt(%s) failed - likely reason is that your system administrator (in a rage of blind passion to rid the system of security holes) removed setuid from the utility used internally by grantpt to change pty permissions. Tell your system admin to reestablish setuid on the utility. Get the utility name by running Expect under truss or trace.", expErrnoMsg(errno)); 400 close(master); 401 return(-1); 402 } 403 if (-1 == (int)unlockpt(master)) { 404 static char buf[500]; 405 exp_pty_error = buf; 406 sprintf(exp_pty_error,"unlockpt(%s) failed.", expErrnoMsg(errno)); 407 close(master); 408 return(-1); 409 } 410#ifdef TIOCFLUSH 411 (void) ioctl(master,TIOCFLUSH,(char *)0); 412#endif /* TIOCFLUSH */ 413 414 exp_pty_slave_name = slave_name; 415 return(master); 416#endif 417 418#if defined(HAVE__GETPTY) /* SGI needs it this way */ 419#undef TEST_PTY 420 slave_name = _getpty(&master, O_RDWR, 0600, 0); 421 if (slave_name == NULL) 422 return (-1); 423 exp_pty_slave_name = slave_name; 424 return(master); 425#endif 426 427#if defined(HAVE_PTC) && !defined(HAVE__GETPTY) /* old SGI, version 3 */ 428#undef TEST_PTY 429 master = open("/dev/ptc", O_RDWR); 430 if (master >= 0) { 431 int ptynum; 432 433 if (fstat(master, &stat_buf) < 0) { 434 close(master); 435 return(-1); 436 } 437 ptynum = minor(stat_buf.st_rdev); 438 sprintf(slave_name,"/dev/ttyq%d",ptynum); 439 } 440 exp_pty_slave_name = slave_name; 441 return(master); 442#endif 443 444#if defined(HAVE_GETPTY) && !defined(HAVE__GETPTY) 445#undef TEST_PTY 446 master = getpty(master_name, slave_name, O_RDWR); 447 /* is it really necessary to verify slave side is usable? */ 448 exp_pty_slave_name = slave_name; 449 return master; 450#endif 451 452#if defined(HAVE_PTC_PTS) 453#undef TEST_PTY 454 master = open("/dev/ptc",O_RDWR); 455 if (master >= 0) { 456 /* never fails */ 457 slave_name = ttyname(master); 458 } 459 exp_pty_slave_name = slave_name; 460 return(master); 461#endif 462 463#if defined(_SEQUENT_) && !defined(HAVE_PTMX) 464#undef TEST_PTY 465 /* old-style SEQUENT, new-style uses ptmx */ 466 master = getpseudotty(&slave_name, &master_name); 467 exp_pty_slave_name = slave_name; 468 return(master); 469#endif /* _SEQUENT_ */ 470 471#if defined(HAVE_OPENPTY) 472#undef TEST_PTY 473 if (openpty(&master, &slave, master_name, 0, 0) != 0) { 474 close(master); 475 close(slave); 476 return -1; 477 } 478 strcpy(slave_name, ttyname(slave)); 479 exp_pty_slave_name = slave_name; 480 close(slave); 481 return master; 482#endif /* HAVE_OPENPTY */ 483 484#if defined(TEST_PTY) 485 /* 486 * all pty allocation mechanisms after this require testing 487 */ 488 if (exp_pty_test_start() == -1) return -1; 489 490#if !defined(HAVE_CONVEX_GETPTY) && !defined(HAVE_PTYM) && !defined(HAVE_SCO_CLIST_PTYS) 491 for (bank = banks;*bank;bank++) { 492 *tty_bank = *bank; 493 *tty_num = '0'; 494 if (stat(master_name, &stat_buf) < 0) break; 495 for (hex = "0123456789abcdef";*hex;hex++) { 496 *tty_num = *hex; 497 strcpy(slave_name,master_name); 498 *tty_type = 't'; 499 master = exp_pty_test(master_name,slave_name,*tty_bank,tty_num); 500 if (master >= 0) goto done; 501 } 502 } 503#endif 504 505#ifdef HAVE_SCO_CLIST_PTYS 506 for (num = 0; ; num++) { 507 char num_str [16]; 508 509 sprintf (num_str, "%d", num); 510 sprintf (master_name, "%s%s", "/dev/ptyp", num_str); 511 if (stat (master_name, &stat_buf) < 0) 512 break; 513 sprintf (slave_name, "%s%s", "/dev/ttyp", num_str); 514 515 master = exp_pty_test(master_name,slave_name,'0',num_str); 516 if (master >= 0) 517 goto done; 518 } 519#endif 520 521#ifdef HAVE_PTYM 522 /* systems with PTYM follow this idea: 523 524 /dev/ptym/pty[a-ce-z][0-9a-f] master pseudo terminals 525 /dev/pty/tty[a-ce-z][0-9a-f] slave pseudo terminals 526 /dev/ptym/pty[a-ce-z][0-9][0-9] master pseudo terminals 527 /dev/pty/tty[a-ce-z][0-9][0-9] slave pseudo terminals 528 529 SPPUX (Convex's HPUX compatible) follows the PTYM convention but 530 extends it: 531 532 /dev/ptym/pty[a-ce-z][0-9][0-9][0-9] master pseudo terminals 533 /dev/pty/tty[a-ce-z][0-9][0-9][0-9] slave pseudo terminals 534 535 The code does not distinguish between HPUX and SPPUX because there 536 is no reason to. HPUX will merely fail the extended SPPUX tests. 537 In fact, most SPPUX systems will fail simply because few systems 538 will actually have the extended ptys. However, the tests are 539 fast so it is no big deal. 540 */ 541 542 /* 543 * pty[a-ce-z][0-9a-f] 544 */ 545 546 for (bank = banks;*bank;bank++) { 547 *tty_bank = *bank; 548 sprintf(tty_num,"0"); 549 if (stat(master_name, &stat_buf) < 0) break; 550 *(slave_num+1) = '\0'; 551 for (hex = "0123456789abcdef";*hex;hex++) { 552 *tty_num = *hex; 553 *slave_bank = *tty_bank; 554 *slave_num = *tty_num; 555 master = exp_pty_test(master_name,slave_name,*tty_bank,tty_num); 556 if (master >= 0) goto done; 557 } 558 } 559 560 /* 561 * tty[p-za-ce-o][0-9][0-9] 562 */ 563 564 for (bank = banks;*bank;bank++) { 565 *tty_bank = *bank; 566 sprintf(tty_num,"00"); 567 if (stat(master_name, &stat_buf) < 0) break; 568 for (num = 0; num<100; num++) { 569 *slave_bank = *tty_bank; 570 sprintf(tty_num,"%02d",num); 571 strcpy(slave_num,tty_num); 572 master = exp_pty_test(master_name,slave_name,*tty_bank,tty_num); 573 if (master >= 0) goto done; 574 } 575 } 576 577 /* 578 * tty[p-za-ce-o][0-9][0-9][0-9] 579 */ 580 for (bank = banks;*bank;bank++) { 581 *tty_bank = *bank; 582 sprintf(tty_num,"000"); 583 if (stat(master_name, &stat_buf) < 0) break; 584 for (num = 0; num<1000; num++) { 585 *slave_bank = *tty_bank; 586 sprintf(tty_num,"%03d",num); 587 strcpy(slave_num,tty_num); 588 master = exp_pty_test(master_name,slave_name,*tty_bank,tty_num); 589 if (master >= 0) goto done; 590 } 591 } 592 593#endif /* HAVE_PTYM */ 594 595#if defined(HAVE_CONVEX_GETPTY) 596 for (;;) { 597 if ((master_name = getpty()) == NULL) return -1; 598 599 strcpy(slave_name,master_name); 600 slave_name[5] = 't';/* /dev/ptyXY ==> /dev/ttyXY */ 601 602 tty_bank = &slave_name[8]; 603 tty_num = &slave_name[9]; 604 master = exp_pty_test(master_name,slave_name,*tty_bank,tty_num); 605 if (master >= 0) goto done; 606 } 607#endif 608 609 done: 610 exp_pty_test_end(); 611 exp_pty_slave_name = slave_name; 612 return(master); 613 614#endif /* defined(TEST_PTY) */ 615} 616 617/* if slave is opened in a child, slave_control(1) must be executed after */ 618/* master is opened (when child is opened is irrelevent) */ 619/* if slave is opened in same proc as master, slave_control(1) must executed */ 620/* after slave is opened */ 621/*ARGSUSED*/ 622void 623exp_slave_control(master,control) 624int master; 625int control; /* if 1, enable pty trapping of close/open/ioctl */ 626{ 627#ifdef HAVE_PTYTRAP 628 ioctl(master, TIOCTRAP, &control); 629#endif /* HAVE_PTYTRAP */ 630} 631 632int 633exp_getptyslave( 634 int ttycopy, 635 int ttyinit, 636 CONST char *stty_args) 637{ 638 int slave, slave2; 639 char buf[10240]; 640 641 if (0 > (slave = open(slave_name, O_RDWR))) { 642 static char buf[500]; 643 exp_pty_error = buf; 644 sprintf(exp_pty_error,"open(%s,rw) = %d (%s)",slave_name,slave,expErrnoMsg(errno)); 645 return(-1); 646 } 647 648#if defined(HAVE_PTMX_BSD) 649 if (ioctl (slave, I_LOOK, buf) != 0) 650 if (ioctl (slave, I_PUSH, "ldterm")) { 651 expDiagLogPtrStrStr("ioctl(%d,I_PUSH,\"ldterm\") = %s\n",slave,expErrnoMsg(errno)); 652 } 653#else 654#if defined(HAVE_PTMX) 655 if (ioctl(slave, I_PUSH, "ptem")) { 656 expDiagLogPtrStrStr("ioctl(%d,I_PUSH,\"ptem\") = %s\n",slave,expErrnoMsg(errno)); 657 } 658 if (ioctl(slave, I_PUSH, "ldterm")) { 659 expDiagLogPtrStrStr("ioctl(%d,I_PUSH,\"ldterm\") = %s\n",slave,expErrnoMsg(errno)); 660 } 661 if (ioctl(slave, I_PUSH, "ttcompat")) { 662 expDiagLogPtrStrStr("ioctl(%d,I_PUSH,\"ttcompat\") = %s\n",slave,expErrnoMsg(errno)); 663 } 664#endif 665#endif 666 667 if (0 == slave) { 668 /* if opened in a new process, slave will be 0 (and */ 669 /* ultimately, 1 and 2 as well) */ 670 671 /* duplicate 0 onto 1 and 2 to prepare for stty */ 672 fcntl(0,F_DUPFD,1); 673 fcntl(0,F_DUPFD,2); 674 } 675 676 ttytype(SET_TTYTYPE,slave,ttycopy,ttyinit,stty_args); 677 678#if 0 679#ifdef HAVE_PTYTRAP 680 /* do another open, to tell master that slave is done fiddling */ 681 /* with pty and master does not have to wait to do further acks */ 682 if (0 > (slave2 = open(slave_name, O_RDWR))) return(-1); 683 close(slave2); 684#endif /* HAVE_PTYTRAP */ 685#endif 686 687 (void) exp_pty_unlock(); 688 return(slave); 689} 690 691#ifdef HAVE_PTYTRAP 692#include <sys/ptyio.h> 693#include <sys/time.h> 694 695/* This function attempts to deal with HP's pty interface. This 696function simply returns an indication of what was trapped (or -1 for 697failure), the parent deals with the details. 698 699Originally, I tried to just trap open's but that is not enough. When 700the pty is initialized, ioctl's are generated and if not trapped will 701hang the child if no further trapping is done. (This could occur if 702parent spawns a process and then immediatley does a close.) So 703instead, the parent must trap the ioctl's. It probably suffices to 704trap the write ioctl's (and tiocsctty which some hp's need) - 705conceivably, stty could be smart enough not to do write's if the tty 706settings are already correct. In that case, we'll have to rethink 707this. 708 709Suggestions from HP engineers encouraged. I cannot imagine how this 710interface was intended to be used! 711 712*/ 713 714int 715exp_wait_for_slave_open(fd) 716int fd; 717{ 718 fd_set excep; 719 struct timeval t; 720 struct request_info ioctl_info; 721 int rc; 722 int found = 0; 723 724 int maxfds = sysconf(_SC_OPEN_MAX); 725 726 t.tv_sec = 30; /* 30 seconds */ 727 t.tv_usec = 0; 728 729 FD_ZERO(&excep); 730 FD_SET(fd,&excep); 731 732 rc = select(maxfds, 733 (SELECT_MASK_TYPE *)0, 734 (SELECT_MASK_TYPE *)0, 735 (SELECT_MASK_TYPE *)&excep, 736 &t); 737 if (rc != 1) { 738 expDiagLogPtrStr("spawned process never started: %s\r\n",expErrnoMsg(errno)); 739 return(-1); 740 } 741 if (ioctl(fd,TIOCREQCHECK,&ioctl_info) < 0) { 742 expDiagLogPtrStr("ioctl(TIOCREQCHECK) failed: %s\r\n",expErrnoMsg(errno)); 743 return(-1); 744 } 745 746 found = ioctl_info.request; 747 748 expDiagLogPtrX("trapped pty op = %x",found); 749 if (found == TIOCOPEN) { 750 expDiagLogPtr(" TIOCOPEN"); 751 } else if (found == TIOCCLOSE) { 752 expDiagLogPtr(" TIOCCLOSE"); 753 } 754 755#ifdef TIOCSCTTY 756 if (found == TIOCSCTTY) { 757 expDiagLogPtr(" TIOCSCTTY"); 758 } 759#endif 760 761 if (found & IOC_IN) { 762 expDiagLogPtr(" IOC_IN (set)"); 763 } else if (found & IOC_OUT) { 764 expDiagLogPtr(" IOC_OUT (get)"); 765 } 766 767 expDiagLogPtr("\n"); 768 769 if (ioctl(fd, TIOCREQSET, &ioctl_info) < 0) { 770 expDiagLogPtrStr("ioctl(TIOCREQSET) failed: %s\r\n",expErrnoMsg(errno)); 771 return(-1); 772 } 773 return(found); 774} 775#endif 776 777void 778exp_pty_exit() 779{ 780 /* a stub so we can do weird things on the cray */ 781} 782