1/* pty_bsd.c - routines to allocate ptys - BSD version
2
3Written by: Don Libes, NIST, 2/6/90
4
5Design and implementation of this program was paid for by U.S. tax
6dollars.  Therefore it is public domain.  However, the author and NIST
7would appreciate credit if this program or parts of it are used.
8
9*/
10
11#include <stdio.h>		/* tmp for debugging */
12#include <signal.h>
13
14#if defined(SIGCLD) && !defined(SIGCHLD)
15#define SIGCHLD SIGCLD
16#endif
17
18#include <sys/types.h>
19#include <sys/stat.h>
20/*** #include <sys/ioctl.h> ***/
21#include <sys/file.h>
22#include <signal.h>
23#include <setjmp.h>
24#include "expect_cf.h"
25#include "exp_rename.h"
26#include "exp_tty_in.h"
27#include "exp_pty.h"
28
29void expDiagLog();
30void expDiagLogU();
31
32#ifndef TRUE
33#define TRUE 1
34#define FALSE 0
35#endif
36
37static char	master_name[] = "/dev/ptyXX";	/* master */
38static char	 slave_name[] = "/dev/ttyXX";	/* slave */
39static char	*tty_type;		/* ptr to char [pt] denoting
40					   whether it is a pty or tty */
41static char	*tty_bank;		/* ptr to char [p-z] denoting
42					   which bank it is */
43static char	*tty_num;		/* ptr to char [0-f] denoting
44					   which number it is */
45char *exp_pty_slave_name;
46char *exp_pty_error;
47
48static void
49pty_stty(s,name)
50char *s;		/* args to stty */
51char *name;		/* name of pty */
52{
53#define MAX_ARGLIST 10240
54	char buf[MAX_ARGLIST];	/* overkill is easier */
55	RETSIGTYPE (*old)();	/* save old sigalarm handler */
56
57#ifdef STTY_READS_STDOUT
58	sprintf(buf,"%s %s > %s",STTY_BIN,s,name);
59#else
60	sprintf(buf,"%s %s < %s",STTY_BIN,s,name);
61#endif
62	old = signal(SIGCHLD, SIG_DFL);
63	system(buf);
64	signal(SIGCHLD, old);	/* restore signal handler */
65}
66
67int exp_dev_tty;	/* file descriptor to /dev/tty or -1 if none */
68static int knew_dev_tty;/* true if we had our hands on /dev/tty at any time */
69
70#ifdef TIOCGWINSZ
71static struct winsize winsize = {0, 0};
72#endif
73#if defined(TIOCGSIZE) && !defined(TIOCGWINSZ)
74static struct ttysize winsize = {0, 0};
75#endif
76
77exp_tty exp_tty_original;
78
79#define GET_TTYTYPE	0
80#define SET_TTYTYPE	1
81static void
82ttytype(request,fd,ttycopy,ttyinit,s)
83int request;
84int fd;
85		/* following are used only if request == SET_TTYTYPE */
86int ttycopy;	/* if true, copy from /dev/tty */
87int ttyinit;	/* if true, initialize to sane state */
88char *s;	/* stty args */
89{
90	static struct	tchars tc;		/* special characters */
91	static struct	ltchars lc;		/* local special characters */
92	static struct	winsize win;		/* window size */
93	static int	lb;			/* local modes */
94	static int	l;			/* line discipline */
95
96	if (request == GET_TTYTYPE) {
97		if (-1 == ioctl(fd, TIOCGETP, (char *)&exp_tty_original)
98		 || -1 == ioctl(fd, TIOCGETC, (char *)&tc)
99		 || -1 == ioctl(fd, TIOCGETD, (char *)&l)
100		 || -1 == ioctl(fd, TIOCGLTC, (char *)&lc)
101		 || -1 == ioctl(fd, TIOCLGET, (char *)&lb)
102		 || -1 == ioctl(fd, TIOCGWINSZ, (char *)&win)) {
103			knew_dev_tty = FALSE;
104			exp_dev_tty = -1;
105		}
106#ifdef TIOCGWINSZ
107		ioctl(fd,TIOCGWINSZ,&winsize);
108#endif
109#if defined(TIOCGSIZE) && !defined(TIOCGWINSZ)
110		ioctl(fd,TIOCGSIZE,&winsize);
111#endif
112	} else {	/* type == SET_TTYTYPE */
113		if (ttycopy && knew_dev_tty) {
114			(void) ioctl(fd, TIOCSETP, (char *)&exp_tty_current);
115			(void) ioctl(fd, TIOCSETC, (char *)&tc);
116			(void) ioctl(fd, TIOCSLTC, (char *)&lc);
117			(void) ioctl(fd, TIOCLSET, (char *)&lb);
118			(void) ioctl(fd, TIOCSETD, (char *)&l);
119			(void) ioctl(fd, TIOCSWINSZ, (char *)&win);
120#ifdef TIOCSWINSZ
121			ioctl(fd,TIOCSWINSZ,&winsize);
122#endif
123#if defined(TIOCSSIZE) && !defined(TIOCSWINSZ)
124			ioctl(fd,TIOCGSIZE,&winsize);
125#endif
126		}
127
128#ifdef __CENTERLINE__
129#undef DFLT_STTY
130#define DFLT_STTY "sane"
131#endif
132
133/* Apollo Domain doesn't need this */
134#ifdef DFLT_STTY
135		if (ttyinit) {
136			/* overlay parms originally supplied by Makefile */
137			pty_stty(DFLT_STTY,slave_name);
138		}
139#endif
140
141		/* lastly, give user chance to override any terminal parms */
142		if (s) {
143			pty_stty(s,slave_name);
144		}
145	}
146}
147
148void
149exp_init_pty()
150{
151	tty_type = & slave_name[strlen("/dev/")];
152	tty_bank = &master_name[strlen("/dev/pty")];
153	tty_num  = &master_name[strlen("/dev/ptyp")];
154
155	exp_dev_tty = open("/dev/tty",O_RDWR);
156
157#if experimental
158	/* code to allocate force expect to get a controlling tty */
159	/* even if it doesn't start with one (i.e., under cron). */
160	/* This code is not necessary, but helpful for testing odd things. */
161	if (exp_dev_tty == -1) {
162		/* give ourselves a controlling tty */
163		int master = exp_getptymaster();
164		fcntl(master,F_SETFD,1);	/* close-on-exec */
165		setpgrp(0,0);
166		close(0);
167		close(1);
168		exp_getptyslave(exp_get_var(exp_interp,"stty_init"));
169		close(2);
170		fcntl(0,F_DUPFD,2);		/* dup 0 onto 2 */
171	}
172#endif
173
174	knew_dev_tty = (exp_dev_tty != -1);
175	if (knew_dev_tty) ttytype(GET_TTYTYPE,exp_dev_tty,0,0,(char *)0);
176}
177
178/* returns fd of master end of pseudotty */
179int
180exp_getptymaster()
181{
182	int master = -1;
183	char *hex, *bank;
184	struct stat statbuf;
185
186	exp_pty_error = 0;
187
188	if (exp_pty_test_start() == -1) return -1;
189
190	for (bank = "pqrstuvwxyzPQRSTUVWXYZ";*bank;bank++) {
191		*tty_bank = *bank;
192		*tty_num = '0';
193		if (stat(master_name, &statbuf) < 0) break;
194		for (hex = "0123456789abcdef";*hex;hex++) {
195			*tty_num = *hex;
196
197			/* generate slave name from master */
198			strcpy(slave_name,master_name);
199			*tty_type = 't';
200
201			master = exp_pty_test(master_name,slave_name,
202						*tty_bank,tty_num);
203			if (master >= 0) goto done;
204		}
205	}
206 done:
207	exp_pty_test_end();
208	exp_pty_slave_name = slave_name;
209	return(master);
210}
211
212/* see comment in pty_termios.c */
213/*ARGSUSED*/
214void
215exp_slave_control(master,control)
216int master;
217int control;
218{
219}
220
221int
222exp_getptyslave(ttycopy,ttyinit,stty_args)
223int ttycopy;
224int ttyinit;
225char *stty_args;
226{
227	int slave;
228
229	if (0 > (slave = open(slave_name, O_RDWR))) return(-1);
230
231	if (0 == slave) {
232		/* if opened in a new process, slave will be 0 (and */
233		/* ultimately, 1 and 2 as well) */
234
235		/* duplicate 0 onto 1 and 2 to prepare for stty */
236		fcntl(0,F_DUPFD,1);
237		fcntl(0,F_DUPFD,2);
238	}
239
240	ttytype(SET_TTYTYPE,slave,ttycopy,ttyinit,stty_args);
241	(void) exp_pty_unlock();
242	return(slave);
243}
244
245void
246exp_pty_exit()
247{
248	/* a stub so we can do weird things on the cray */
249}
250