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