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