xref: /original-bsd/usr.bin/script/script.c (revision 403c148d)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)script.c	5.14 (Berkeley) 07/03/91";
16 #endif /* not lint */
17 
18 /*
19  * script
20  */
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <termios.h>
24 #include <sys/ioctl.h>
25 #include <sys/time.h>
26 #include <sys/file.h>
27 #include <sys/signal.h>
28 #include <stdio.h>
29 #include <paths.h>
30 
31 char	*shell;
32 FILE	*fscript;
33 int	master;
34 int	slave;
35 int	child;
36 int	subchild;
37 char	*fname;
38 
39 struct	termios tt;
40 struct	winsize win;
41 int	lb;
42 int	l;
43 char	line[] = "/dev/ptyXX";
44 int	aflg;
45 
46 main(argc, argv)
47 	int argc;
48 	char *argv[];
49 {
50 	extern char *optarg;
51 	extern int optind;
52 	int ch;
53 	void finish();
54 	char *getenv();
55 
56 	while ((ch = getopt(argc, argv, "a")) != EOF)
57 		switch((char)ch) {
58 		case 'a':
59 			aflg++;
60 			break;
61 		case '?':
62 		default:
63 			fprintf(stderr, "usage: script [-a] [file]\n");
64 			exit(1);
65 		}
66 	argc -= optind;
67 	argv += optind;
68 
69 	if (argc > 0)
70 		fname = argv[0];
71 	else
72 		fname = "typescript";
73 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
74 		perror(fname);
75 		fail();
76 	}
77 
78 	shell = getenv("SHELL");
79 	if (shell == NULL)
80 		shell = _PATH_BSHELL;
81 
82 	(void) tcgetattr(0, &tt);
83 	(void) ioctl(0, TIOCGWINSZ, (char *)&win);
84 	if (openpty(&master, &slave, NULL, &tt, &win) == -1) {
85 		perror("openpty");
86 		exit(1);
87 	}
88 
89 	printf("Script started, file is %s\n", fname);
90 	fixtty();	/* go raw */
91 
92 	(void) signal(SIGCHLD, finish);
93 	child = fork();
94 	if (child < 0) {
95 		perror("fork");
96 		fail();
97 	}
98 	if (child == 0) {
99 		subchild = child = fork();
100 		if (child < 0) {
101 			perror("fork");
102 			fail();
103 		}
104 		if (child)
105 			dooutput();
106 		else
107 			doshell();
108 	}
109 	doinput();
110 }
111 
112 doinput()
113 {
114 	register int cc;
115 	char ibuf[BUFSIZ];
116 
117 	(void) fclose(fscript);
118 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
119 		(void) write(master, ibuf, cc);
120 	done();
121 }
122 
123 #include <sys/wait.h>
124 
125 void
126 finish()
127 {
128 	union wait status;
129 	register int pid;
130 	register int die = 0;
131 
132 	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
133 		if (pid == child)
134 			die = 1;
135 
136 	if (die)
137 		done();
138 }
139 
140 dooutput()
141 {
142 	register int cc;
143 	time_t tvec, time();
144 	char obuf[BUFSIZ], *ctime();
145 
146 	(void) close(0);
147 	tvec = time((time_t *)NULL);
148 	fprintf(fscript, "Script started on %s", ctime(&tvec));
149 	for (;;) {
150 		cc = read(master, obuf, sizeof (obuf));
151 		if (cc <= 0)
152 			break;
153 		(void) write(1, obuf, cc);
154 		(void) fwrite(obuf, 1, cc, fscript);
155 	}
156 	done();
157 }
158 
159 doshell()
160 {
161 
162 	close(master);
163 	(void) fclose(fscript);
164 	login_tty(slave);
165 	execl(shell, "sh", "-i", 0);
166 	perror(shell);
167 	fail();
168 }
169 
170 fixtty()
171 {
172 	struct termios rtt;
173 
174 	rtt = tt;
175 	cfmakeraw(&rtt);
176 	rtt.c_lflag &= ~ECHO;
177 	(void) tcsetattr(0, TCSAFLUSH, &rtt);
178 }
179 
180 fail()
181 {
182 
183 	(void) kill(0, SIGTERM);
184 	done();
185 }
186 
187 done()
188 {
189 	time_t tvec, time();
190 	char *ctime();
191 
192 	if (subchild) {
193 		tvec = time((time_t *)NULL);
194 		fprintf(fscript,"\nScript done on %s", ctime(&tvec));
195 		(void) fclose(fscript);
196 		(void) close(master);
197 	} else {
198 		(void) tcsetattr(0, TCSAFLUSH, &tt);
199 		printf("Script done, file is %s\n", fname);
200 	}
201 	exit(0);
202 }
203