1 /*
2  * Copyright (c) 1994  Sony Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL SONY CORPORATION BE LIABLE FOR ANY CLAIM,
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *
23  * Except as contained in this notice, the name of Sony Corporation
24  * shall not be used in advertising or otherwise to promote the sale, use
25  * or other dealings in this Software without prior written authorization
26  * from Sony Corporation.
27  *
28  */
29 
30 /*
31  * $SonyRCSfile: ttytest.c,v $
32  * $SonyRevision: 1.1 $
33  * $SonyDate: 1994/06/03 08:03:31 $
34  */
35 
36 
37 #include <signal.h>
38 #include <termio.h>
39 #include <stdio.h>
40 #include <fcntl.h>
41 #include <stropts.h>
42 #include <sys/types.h>
43 
44 #define PTY_MASTER "/dev/ptmx"
45 #define BUFFSIZE 512
46 #define err_sys(x) fprintf(stderr, (x))
47 #define err_quit(x) { \
48 	             fprintf(stderr, (x)); \
49 	             exit(0); \
50                     }
51 
52 
53 static struct termio tty_termio;
54 static struct termio tty_mode;
55 static int sigcaught;
56 
exec_shell(fd,argv,envp)57 exec_shell(fd, argv, envp)
58 int fd;
59 char **argv;
60 char **envp;
61 {
62 	char *shell;
63 	char *getenv(), *rindex();
64 	struct termio b;
65 
66 	close(0); close(1); close(2);
67 	if (dup(fd) != 0 || dup(fd) != 1 || dup(fd) != 2)
68 	  err_sys("dup error");
69 	close(fd);
70 
71 	if ((shell = getenv("SHELL")) == NULL)
72 	  shell = "/bin/sh";
73 	if ((argv[0] = rindex(shell, '/')) != NULL)
74 	  argv[0]++;
75 	else
76 	  argv[0] = shell;
77 
78 	if (ioctl(0, TCGETA, (char *) &b) < 0)
79 	  return(-1);
80 fprintf(stderr, "erase=%x\n", b.c_cc[VERASE]);
81 	execve(shell, argv, envp);
82 	err_sys("execve error");
83 }
84 
pass_all(fd,childpid)85 pass_all(fd, childpid)
86 int fd;
87 int childpid;
88 {
89 	int newpid, nread;
90 	int sig_term();
91 	char buff[BUFFSIZE];
92 
93 	if ((newpid = fork()) < 0) {
94 		err_sys("parent1: can't fork");
95 	} else if (newpid == 0) {
96 		for ( ; ; ) {
97 			nread = read(0, buff, BUFFSIZE);
98 			if (nread < 0)
99 			  err_sys("read error fram stdin");
100 			else if (nread == 0)
101 			  break;
102 
103 			if (write(fd, buff, nread) != nread)
104 			  err_sys("writen error to stream pipe");
105 		}
106 		kill(getppid(), SIGTERM);
107 		exit(0);
108 	}
109 
110 
111 	sigcaught = 0;
112 
113 
114 	for ( ; ; ) {
115 		if ((nread = read(fd, buff, BUFFSIZE)) <= 0)
116 		  break;
117 
118 		if (write(1, buff, nread) != nread)
119 		  err_sys("write error to stdout");
120 	}
121 
122 	if (sigcaught == 0)
123 	  kill(newpid, SIGTERM);
124 
125 	return;
126 }
127 
128 int
pty_master()129 pty_master()
130 {
131 	int master_fd;
132 
133 	if ((master_fd = open(PTY_MASTER, O_RDWR)) < 0)
134 	  return(-1);
135 
136 	return(master_fd);
137 }
138 
139 int
pty_slave(master_fd)140 pty_slave(master_fd)
141 int master_fd;
142 {
143 	int slave_fd;
144 	char *slavename;
145 	int grantpt();
146 	int unlockpt();
147 	char *ptsname();
148 
149 	if (grantpt(master_fd) < 0) {
150 		close(master_fd);
151 		return(-1);
152 	}
153 
154 	if (unlockpt(master_fd) < 0) {
155 		close(master_fd);
156 		return(-1);
157 	}
158 
159 	slavename = ptsname(master_fd);
160 	if (slavename == NULL) {
161 		close(master_fd);
162 		return(-1);
163 	}
164 
165 	slave_fd = open(slavename, O_RDWR);
166 	if (slave_fd < 0) {
167 		close(master_fd);
168 		return(-1);
169 	}
170 
171 	if (ioctl(slave_fd, I_PUSH, "ptem") < 0 ) {
172 		close(master_fd);
173 		return(-1);
174 	}
175 
176 	if (ioctl(slave_fd, I_PUSH, "ldterm") < 0) {
177 		close(master_fd);
178 		return(-1);
179 	}
180 	return(slave_fd);
181 }
182 
183 int
tty_raw(fd)184 tty_raw(fd)
185 int fd;
186 {
187 	struct termio temp_mode;
188 
189 	if (ioctl(fd, TCGETA, (char *) &temp_mode) < 0)
190 	  return(-1);
191 
192 	tty_mode = temp_mode;
193 
194 	temp_mode.c_iflag = 0;
195 	temp_mode.c_oflag &= ~OPOST;
196 	temp_mode.c_lflag &= ~(ISIG | ICANON | ECHO | XCASE);
197 	temp_mode.c_cflag &= ~(CSIZE | PARENB);
198 	temp_mode.c_cflag |= CS8;
199 	temp_mode.c_cc[VMIN] = 1;
200 	temp_mode.c_cc[VTIME] = 1;
201 
202 	if (ioctl(fd, TCSETA, (char *) &temp_mode) <0)
203 	  return(-1);
204 
205 	return(0);
206 }
207 
208 int
tty_reset(fd)209 tty_reset(fd)
210 int fd;
211 {
212 	if (ioctl(fd, TCSETA, (char *) &tty_mode) < 0)
213 	  return(-1);
214 
215 	return(0);
216 }
217 
tty_getmode(oldfd)218 int tty_getmode(oldfd)
219 int oldfd;
220 {
221 	if (ioctl(oldfd, TCGETA, (char *) &tty_termio) < 0)
222 	  return(-1);
223 fprintf(stderr, "tty_getmode erase=%x\n", tty_termio.c_cc[VERASE]);
224 	return(0);
225 }
226 
227 int
tty_setmode(newfd)228 tty_setmode(newfd)
229 int newfd;
230 {
231 	if (ioctl(newfd, TCSETA, (char *) &tty_termio) < 0)
232 	  return(-1);
233 
234 fprintf(stderr, "tty_setmode erase=%x\n", tty_termio.c_cc[VERASE]);
235 	return(0);
236 }
237 
main(argc,argv,envp)238 main(argc, argv, envp)
239 int argc;
240 char **argv;
241 char **envp;
242 {
243 	int master_fd, slave_fd, childpid;
244 
245 	if (!isatty(0) || !isatty(1))
246 	  err_quit("stdin and stdout must be a terminal");
247 
248 	if ((master_fd = pty_master()) < 0)
249 	  err_sys("can't open master pty");
250 	if(tty_getmode(0) < 0)
251 	  err_sys("can't get tty mode of standard input");
252 
253 	if ((childpid = fork()) < 0)
254 	  err_sys("can't fork");
255 	else if (childpid == 0) {
256 		setpgrp();
257 		if ((slave_fd = pty_slave(master_fd)) < 0)
258 		  err_sys("can't open pty slave");
259 		close(master_fd);
260 		if (tty_setmode(slave_fd) < 0)
261 		  err_sys("can't set tty mode of pty slave");
262 
263 		exec_shell(slave_fd, argv, envp);
264 	}
265 
266 
267 	if (tty_raw(0) < 0)
268 	  err_sys("tty_raw error");
269 	pass_all(master_fd, childpid);
270 
271 	if (tty_reset(0) < 0)
272 	  err_sys("tty_reset error");
273 
274 	exit(0);
275