xref: /original-bsd/usr.bin/script/script.c (revision e74403ba)
1 #ifndef lint
2 static char *sccsid = "@(#)script.c	4.5 (Berkeley) 83/07/02";
3 #endif
4 
5 /*
6  * script
7  */
8 #include <stdio.h>
9 #include <signal.h>
10 #include <sys/types.h>
11 #include <sys/stat.h>
12 #include <sys/ioctl.h>
13 #include <sgtty.h>
14 #include <sys/time.h>
15 
16 char	*getenv();
17 char	*ctime();
18 char	*shell;
19 FILE	*fscript;
20 int	master;
21 int	slave;
22 int	child;
23 char	*fname = "typescript";
24 int	finish();
25 
26 struct	sgttyb b;
27 struct	tchars tc;
28 struct	ltchars lc;
29 int	lb;
30 int	l;
31 char	*line = "/dev/ptyXX";
32 int	aflg;
33 
34 main(argc, argv)
35 	int argc;
36 	char *argv[];
37 {
38 	int f;
39 
40 	shell = getenv("SHELL");
41 	if (shell == 0)
42 		shell = "/bin/sh";
43 	argc--, argv++;
44 	while (argc > 0 && argv[0][0] == '-') {
45 		switch (argv[0][1]) {
46 
47 		case 'a':
48 			aflg++;
49 			break;
50 
51 		default:
52 			fprintf(stderr,
53 			    "usage: script [ -a ] [ typescript ]\n");
54 			exit(1);
55 		}
56 		argc--, argv++;
57 	}
58 	if (argc > 0)
59 		fname = argv[0];
60 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
61 		perror(fname);
62 		fail();
63 	}
64 	getmaster();
65 	printf("Script started, file is %s\n", fname);
66 	fixtty();
67 
68 	(void) signal(SIGCHLD, finish);
69 	child = fork();
70 	if (child < 0) {
71 		perror("fork");
72 		fail();
73 	}
74 	if (child == 0) {
75 		f = fork();
76 		if (f < 0) {
77 			perror("fork");
78 			fail();
79 		}
80 		if (f)
81 			dooutput();
82 		else
83 			doshell();
84 	}
85 	doinput();
86 }
87 
88 doinput()
89 {
90 	char ibuf[BUFSIZ];
91 	int cc;
92 
93 	(void) fclose(fscript);
94 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
95 		(void) write(master, ibuf, cc);
96 	done();
97 }
98 
99 #include <sys/wait.h>
100 
101 finish()
102 {
103 	union wait status;
104 
105 	if (wait3(&status, WNOHANG, 0) != child)
106 		return;
107 	done();
108 }
109 
110 dooutput()
111 {
112 	time_t tvec;
113 	char obuf[BUFSIZ];
114 	int cc;
115 
116 	(void) close(0);
117 	tvec = time((time_t *)0);
118 	fprintf(fscript, "Script started on %s", ctime(&tvec));
119 	for (;;) {
120 		cc = read(master, obuf, sizeof (obuf));
121 		if (cc <= 0)
122 			break;
123 		(void) write(1, obuf, cc);
124 		(void) fwrite(obuf, 1, cc, fscript);
125 	}
126 	tvec = time((time_t *)0);
127 	fprintf(fscript,"\nscript done on %s", ctime(&tvec));
128 	(void) fclose(fscript);
129 	(void) close(master);
130 	exit(0);
131 }
132 
133 doshell()
134 {
135 	int t;
136 
137 	t = open("/dev/tty", 2);
138 	if (t >= 0) {
139 		ioctl(t, TIOCNOTTY, (char *)0);
140 		(void) close(t);
141 	}
142 	getslave();
143 	(void) close(master);
144 	(void) fclose(fscript);
145 	dup2(slave, 0);
146 	dup2(slave, 1);
147 	dup2(slave, 2);
148 	(void) close(slave);
149 	execl(shell, "sh", "-i", 0);
150 	perror(shell);
151 	fail();
152 }
153 
154 fixtty()
155 {
156 	struct sgttyb sbuf;
157 
158 	sbuf = b;
159 	sbuf.sg_flags |= RAW;
160 	sbuf.sg_flags &= ~ECHO;
161 	ioctl(0, TIOCSETP, (char *)&sbuf);
162 }
163 
164 fail()
165 {
166 
167 	(void) kill(0, SIGTERM);
168 	done();
169 }
170 
171 done()
172 {
173 
174 	ioctl(0, TIOCSETP, (char *)&b);
175 	printf("Script done, file is %s\n", fname);
176 	exit(0);
177 }
178 
179 getmaster()
180 {
181 	char c;
182 	struct stat stb;
183 	int i;
184 
185 	for (c = 'p'; c <= 's'; c++) {
186 		line[strlen("/dev/pty")] = c;
187 		line[strlen("/dev/ptyp")] = '0';
188 		if (stat(line, &stb) < 0)
189 			break;
190 		for (i = 0; i < 16; i++) {
191 			line[strlen("/dev/ptyp")] = "0123456789abcdef"[i];
192 			master = open(line, 2);
193 			if (master >= 0) {
194 				ioctl(0, TIOCGETP, (char *)&b);
195 				ioctl(0, TIOCGETC, (char *)&tc);
196 				ioctl(0, TIOCGETD, (char *)&l);
197 				ioctl(0, TIOCGLTC, (char *)&lc);
198 				ioctl(0, TIOCLGET, (char *)&lb);
199 				return;
200 			}
201 		}
202 	}
203 	fprintf(stderr, "Out of pty's\n");
204 	fail();
205 }
206 
207 getslave()
208 {
209 
210 	line[strlen("/dev/")] = 't';
211 	slave = open(line, 2);
212 	if (slave < 0) {
213 		perror(line);
214 		fail();
215 	}
216 	ioctl(slave, TIOCSETP, (char *)&b);
217 	ioctl(slave, TIOCSETC, (char *)&tc);
218 	ioctl(slave, TIOCSLTC, (char *)&lc);
219 	ioctl(slave, TIOCLSET, (char *)&lb);
220 	ioctl(slave, TIOCSETD, (char *)&l);
221 }
222