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