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
pty_stty(s,name)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
ttytype(request,fd,ttycopy,ttyinit,s)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
exp_init_pty()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
exp_getptymaster()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
exp_slave_control(master,control)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
exp_getptyslave(int ttycopy,int ttyinit,CONST char * stty_args)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
exp_wait_for_slave_open(fd)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
exp_pty_exit()778 exp_pty_exit()
779 {
780 /* a stub so we can do weird things on the cray */
781 }
782