OSDN Git Service

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