Imported Upstream version 5.45
[platform/upstream/expect.git] / pty_termios.c
1 /* pty_termios.c - routines to allocate ptys - termios version
2
3 Written by: Don Libes, NIST, 2/6/90
4
5 This file is in the public domain.  However, the author and NIST
6 would 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 */
28 extern 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.
42 According to Ashley Pittman <ashley@ilo.dec.com>, Digital works better
43 with 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
106 void expDiagLog();
107 void 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
126 extern char *getpty();
127 static char *master_name;
128 static char slave_name[] = "/dev/ptyXX";
129 static char     *tty_bank;              /* ptr to char [p-z] denoting
130                                            which bank it is */
131 static 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 */
137 static 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)
146 static 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)
154 static char *slave_name;
155 #endif
156
157 #if defined(HAVE_GETPTY)
158 #include <sys/vty.h>
159 static char master_name[MAXPTYNAMELEN];
160 static 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 */
166 static char     banks[] = "pqrstuvwxyzabcefghijklo";
167 static char     master_name[] = "/dev/ptym/ptyXXXX";
168 static char     slave_name[] = "/dev/pty/ttyXXXX";
169 static char     *slave_bank;
170 static char     *slave_num;
171 #else
172 static char     banks[] = "pqrstuvwxyzPQRSTUVWXYZ";
173 static char     master_name[] = "/dev/ptyXX";
174 static char     slave_name [] = "/dev/ttyXX";
175 #endif /* HAVE_PTYM */
176
177 static char     *tty_type;              /* ptr to char [pt] denoting
178                                            whether it is a pty or tty */
179 static char     *tty_bank;              /* ptr to char [p-z] denoting
180                                            which bank it is */
181 static 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
187 static char master_name[MAXPTYNAMELEN];
188 static char slave_name[MAXPTYNAMELEN];
189 #endif /* HAVE_SCO_CLIST_PTYS */
190
191 #ifdef HAVE_OPENPTY
192 static char master_name[64];
193 static char slave_name[64];
194 #endif
195
196 char *exp_pty_slave_name;
197 char *exp_pty_error;
198
199 #if 0
200 static void
201 pty_stty(s,name)
202 char *s;                /* args to stty */
203 char *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
224 exec_stty(s)
225 char *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
260 static void
261 pty_stty(s,name)
262 char *s;                /* args to stty */
263 char *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
279 int exp_dev_tty;        /* file descriptor to /dev/tty or -1 if none */
280 static int knew_dev_tty;/* true if we had our hands on /dev/tty at any time */
281
282 exp_tty exp_tty_original;
283
284 #define GET_TTYTYPE     0
285 #define SET_TTYTYPE     1
286 static void
287 ttytype(request,fd,ttycopy,ttyinit,s)
288 int request;
289 int fd;
290                 /* following are used only if request == SET_TTYTYPE */
291 int ttycopy;    /* true/false, copy from /dev/tty */
292 int ttyinit;    /* if true, initialize to sane state */
293 char *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
342 void
343 exp_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
372 int
373 exp_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*/
622 void
623 exp_slave_control(master,control)
624 int master;
625 int 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
632 int
633 exp_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
696 function simply returns an indication of what was trapped (or -1 for
697 failure), the parent deals with the details.
698
699 Originally, I tried to just trap open's but that is not enough.  When
700 the pty is initialized, ioctl's are generated and if not trapped will
701 hang the child if no further trapping is done.  (This could occur if
702 parent spawns a process and then immediatley does a close.)  So
703 instead, the parent must trap the ioctl's.  It probably suffices to
704 trap the write ioctl's (and tiocsctty which some hp's need) -
705 conceivably, stty could be smart enough not to do write's if the tty
706 settings are already correct.  In that case, we'll have to rethink
707 this.
708
709 Suggestions from HP engineers encouraged.  I cannot imagine how this
710 interface was intended to be used!
711
712 */
713    
714 int
715 exp_wait_for_slave_open(fd)
716 int 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
777 void
778 exp_pty_exit()
779 {
780         /* a stub so we can do weird things on the cray */
781 }