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