Merge commit 'b1e7e97d3b60469b243b3b2e22c7d8cbd11c7c90'
[unleashed.git] / usr / src / cmd / script / script.c
blob313a35df8aefb7f18775bd54646f4e993c162375
1 /*
2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
11 * Copyright (c) 1980 Regents of the University of California.
12 * All rights reserved. The Berkeley software License Agreement
13 * specifies the terms and conditions for redistribution.
16 /* Portions Copyright(c) 1988, Sun Microsystems, Inc. */
17 /* All Rights Reserved. */
20 * script: Produce a record of a terminal session.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <signal.h>
26 #include <fcntl.h>
27 #include <locale.h>
28 #include <time.h>
29 #include <sys/stropts.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/termios.h>
33 #include <sys/file.h>
34 #include <errno.h>
36 int grantpt();
37 int unlockpt();
38 char *ptsname();
39 void doinput() __NORETURN;
40 void dooutput();
41 void doshell();
42 void fixtty();
43 void fail();
44 void done() __NORETURN;
45 void getmaster();
46 void getslave();
48 char *shell;
49 FILE *fscript;
50 int master; /* file descriptor for master pseudo-tty */
51 int slave; /* file descriptor for slave pseudo-tty */
52 int child;
53 int subchild;
54 char *fname = "typescript";
55 void sigwinch();
56 void finish();
58 struct termios b;
59 struct winsize size;
60 int lb;
61 int l;
62 char *mptname = "/dev/ptmx"; /* master pseudo-tty device */
64 int aflg;
66 int
67 main(int argc, char *argv[])
69 uid_t ruidt;
70 gid_t gidt;
72 (void) setlocale(LC_ALL, "");
73 #if !defined(TEXT_DOMAIN)
74 #define TEXT_DOMAIN "SYS_TEST"
75 #endif
76 (void) textdomain(TEXT_DOMAIN);
78 shell = getenv("SHELL");
79 if (shell == NULL)
80 shell = "/bin/sh";
81 argc--, argv++;
82 while (argc > 0 && argv[0][0] == '-') {
83 switch (argv[0][1]) {
85 case 'a':
86 aflg++;
87 break;
89 default:
90 fprintf(stderr,
91 gettext("usage: script [ -a ] [ typescript ]\n"));
92 exit(1);
94 argc--, argv++;
96 if (argc > 0)
97 fname = argv[0];
98 ruidt = getuid();
99 gidt = getgid();
100 if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
101 perror(fname);
102 fail();
104 setbuf(fscript, NULL);
105 chown(fname, ruidt, gidt);
106 getmaster();
107 printf(gettext("Script started, file is %s\n"), fname);
108 fixtty();
110 (void) signal(SIGCHLD, finish);
111 child = fork();
112 if (child < 0) {
113 perror("fork");
114 fail();
116 if (child == 0) {
117 subchild = child = fork();
118 if (child < 0) {
119 perror("fork");
120 fail();
122 if (child)
123 dooutput();
124 else
125 doshell();
127 doinput();
128 /* NOTREACHED */
129 return (0);
132 void
133 doinput()
135 char ibuf[BUFSIZ];
136 int cc;
138 (void) fclose(fscript);
139 sigset(SIGWINCH, sigwinch);
141 while ((cc = read(0, ibuf, BUFSIZ)) != 0) {
142 if (cc == -1) {
143 if (errno == EINTR) { /* SIGWINCH probably */
144 continue;
145 } else {
146 break;
149 (void) write(master, ibuf, cc);
151 done();
154 void
155 sigwinch()
157 struct winsize ws;
159 if (ioctl(0, TIOCGWINSZ, &ws) == 0)
160 (void) ioctl(master, TIOCSWINSZ, &ws);
163 #include <sys/wait.h>
165 void
166 finish()
168 int status;
169 register int pid;
170 register int die = 0;
172 while ((pid = wait(&status)) > 0)
173 if (pid == child)
174 die = 1;
176 if (die)
177 done();
180 void
181 dooutput()
183 time_t tvec;
184 char obuf[BUFSIZ];
185 char tbuf[BUFSIZ];
186 int cc;
188 (void) close(0);
189 tvec = time((time_t *)0);
190 strftime(tbuf, BUFSIZ, "%c", localtime(&tvec));
191 fprintf(fscript, gettext("Script started on %s\n"), tbuf);
192 for (;;) {
193 cc = read(master, obuf, sizeof (obuf));
194 if (cc <= 0)
195 break;
196 (void) write(1, obuf, cc);
197 (void) fwrite(obuf, 1, cc, fscript);
199 done();
202 void
203 doshell()
206 setpgrp(); /* relinquish control terminal */
207 getslave();
208 (void) close(master);
209 (void) fclose(fscript);
210 (void) dup2(slave, 0);
211 (void) dup2(slave, 1);
212 (void) dup2(slave, 2);
213 (void) close(slave);
214 execl(shell, shell, "-i", (char *)0);
215 perror(shell);
216 fail();
219 void
220 fixtty()
222 struct termios sbuf;
224 sbuf = b;
225 sbuf.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|IXON);
226 sbuf.c_oflag &= ~OPOST;
227 sbuf.c_lflag &= ~(ICANON|ISIG|ECHO);
228 sbuf.c_cc[VMIN] = 1;
229 sbuf.c_cc[VTIME] = 0;
230 (void) ioctl(0, TCSETSF, (char *)&sbuf);
233 void
234 fail()
237 (void) kill(0, SIGTERM);
238 done();
241 void
242 done()
244 time_t tvec;
245 char tbuf[BUFSIZ];
247 if (subchild) {
248 tvec = time((time_t *)0);
249 strftime(tbuf, BUFSIZ, "%c", localtime(&tvec));
250 fprintf(fscript, gettext("\nscript done on %s\n"), tbuf);
251 (void) fclose(fscript);
252 (void) close(master);
253 } else {
254 (void) ioctl(0, TCSETSW, (char *)&b);
255 printf(gettext("Script done, file is %s\n"), fname);
257 exit(0);
260 void
261 getmaster()
263 struct stat stb;
265 if ((master = open(mptname, O_RDWR)) >= 0) { /* a pseudo-tty is free */
266 (void) ioctl(0, TCGETS, (char *)&b);
267 (void) ioctl(0, TIOCGWINSZ, (char *)&size);
268 return;
269 } else { /* out of pseudo-tty's */
270 perror(mptname);
271 fprintf(stderr, gettext("Out of pseudo-tty's\n"));
272 fail();
276 void
277 getslave()
279 char *slavename; /* name of slave pseudo-tty */
281 grantpt(master); /* change permissions of slave */
282 unlockpt(master); /* unlock slave */
283 slavename = ptsname(master); /* get name of slave */
284 slave = open(slavename, O_RDWR); /* open slave */
285 if (slave < 0) { /* error on opening slave */
286 perror(slavename);
287 fail();
289 ioctl(slave, I_PUSH, "ptem"); /* push pt hw emulation module */
290 ioctl(slave, I_PUSH, "ldterm"); /* push line discipline */
292 (void) ioctl(slave, TCSETSF, (char *)&b);
293 (void) ioctl(slave, TIOCSWINSZ, (char *)&size);