Annotation of src/usr.bin/script/script.c, Revision 1.16
1.16 ! deraadt 1: /* $OpenBSD: script.c,v 1.15 2001/07/09 07:04:52 deraadt Exp $ */
1.1 deraadt 2: /* $NetBSD: script.c,v 1.3 1994/12/21 08:55:43 jtc Exp $ */
3:
4: /*
1.16 ! deraadt 5: * Copyright (c) 2001 Theo de Raadt
! 6: * All rights reserved.
! 7: *
! 8: * Redistribution and use in source and binary forms, with or without
! 9: * modification, are permitted provided that the following conditions
! 10: * are met:
! 11: * 1. Redistributions of source code must retain the above copyright
! 12: * notice, this list of conditions and the following disclaimer.
! 13: * 2. Redistributions in binary form must reproduce the above copyright
! 14: * notice, this list of conditions and the following disclaimer in the
! 15: * documentation and/or other materials provided with the distribution.
! 16: *
! 17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 19: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 20: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 21: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 22: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 23: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 24: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 25: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 26: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 27: */
! 28:
! 29: /*
1.1 deraadt 30: * Copyright (c) 1980, 1992, 1993
31: * The Regents of the University of California. All rights reserved.
32: *
33: * Redistribution and use in source and binary forms, with or without
34: * modification, are permitted provided that the following conditions
35: * are met:
36: * 1. Redistributions of source code must retain the above copyright
37: * notice, this list of conditions and the following disclaimer.
38: * 2. Redistributions in binary form must reproduce the above copyright
39: * notice, this list of conditions and the following disclaimer in the
40: * documentation and/or other materials provided with the distribution.
41: * 3. All advertising materials mentioning features or use of this software
42: * must display the following acknowledgement:
43: * This product includes software developed by the University of
44: * California, Berkeley and its contributors.
45: * 4. Neither the name of the University nor the names of its contributors
46: * may be used to endorse or promote products derived from this software
47: * without specific prior written permission.
48: *
49: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59: * SUCH DAMAGE.
60: */
61:
62: #ifndef lint
63: static char copyright[] =
64: "@(#) Copyright (c) 1980, 1992, 1993\n\
65: The Regents of the University of California. All rights reserved.\n";
66: #endif /* not lint */
67:
68: #ifndef lint
69: #if 0
70: static char sccsid[] = "@(#)script.c 8.1 (Berkeley) 6/6/93";
71: #endif
1.16 ! deraadt 72: static char rcsid[] = "$OpenBSD: script.c,v 1.15 2001/07/09 07:04:52 deraadt Exp $";
1.1 deraadt 73: #endif /* not lint */
74:
75: #include <sys/types.h>
76: #include <sys/wait.h>
77: #include <sys/stat.h>
78: #include <sys/ioctl.h>
79: #include <sys/time.h>
80:
81: #include <errno.h>
82: #include <fcntl.h>
83: #include <paths.h>
84: #include <signal.h>
85: #include <stdio.h>
86: #include <stdlib.h>
87: #include <string.h>
88: #include <termios.h>
89: #include <tzfile.h>
90: #include <unistd.h>
91:
1.5 deraadt 92: #include <util.h>
1.7 mickey 93: #include <err.h>
1.5 deraadt 94:
1.1 deraadt 95: FILE *fscript;
96: int master, slave;
1.16 ! deraadt 97: pid_t child, subchild;
1.1 deraadt 98: char *fname;
99:
1.16 ! deraadt 100: volatile sig_atomic_t dead;
! 101: volatile sig_atomic_t sigdeadstatus;
! 102: volatile sig_atomic_t flush;
! 103:
1.1 deraadt 104: struct termios tt;
105:
1.16 ! deraadt 106: __dead void done __P((int));
! 107: void dooutput __P((void));
! 108: void doshell __P((void));
! 109: void fail __P((void));
! 110: void finish __P((int));
! 111: void scriptflush __P((int));
! 112: void handlesigwinch __P((int));
1.1 deraadt 113:
114: int
115: main(argc, argv)
116: int argc;
117: char *argv[];
118: {
1.16 ! deraadt 119: struct sigaction sa;
1.1 deraadt 120: struct termios rtt;
121: struct winsize win;
1.16 ! deraadt 122: char ibuf[BUFSIZ];
! 123: ssize_t cc, off;
1.1 deraadt 124: int aflg, ch;
125:
126: aflg = 0;
1.3 millert 127: while ((ch = getopt(argc, argv, "a")) != -1)
1.1 deraadt 128: switch(ch) {
129: case 'a':
130: aflg = 1;
131: break;
132: default:
133: (void)fprintf(stderr, "usage: script [-a] [file]\n");
134: exit(1);
135: }
136: argc -= optind;
137: argv += optind;
138:
139: if (argc > 0)
140: fname = argv[0];
141: else
142: fname = "typescript";
143:
144: if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL)
1.13 millert 145: err(1, "%s", fname);
1.1 deraadt 146:
147: (void)tcgetattr(STDIN_FILENO, &tt);
148: (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
149: if (openpty(&master, &slave, NULL, &tt, &win) == -1)
1.7 mickey 150: err(1, "openpty");
1.1 deraadt 151:
152: (void)printf("Script started, output file is %s\n", fname);
153: rtt = tt;
154: cfmakeraw(&rtt);
155: rtt.c_lflag &= ~ECHO;
156: (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
157:
1.16 ! deraadt 158: bzero(&sa, sizeof sa);
! 159: sigemptyset(&sa.sa_mask);
! 160: sa.sa_handler = finish;
! 161: (void)sigaction(SIGCHLD, &sa, NULL);
! 162:
! 163: sa.sa_handler = handlesigwinch;
! 164: sa.sa_flags = SA_RESTART;
! 165: (void)sigaction(SIGWINCH, &sa, NULL);
! 166:
1.1 deraadt 167: child = fork();
168: if (child < 0) {
169: perror("fork");
170: fail();
171: }
172: if (child == 0) {
173: subchild = child = fork();
174: if (child < 0) {
175: perror("fork");
176: fail();
177: }
178: if (child)
179: dooutput();
180: else
181: doshell();
182: }
183:
184: (void)fclose(fscript);
1.16 ! deraadt 185: while (1) {
! 186: if (dead)
! 187: break;
! 188: cc = read(STDIN_FILENO, ibuf, BUFSIZ);
! 189: if (cc == -1 && errno == EINTR)
! 190: continue;
! 191: if (cc <= 0)
! 192: break;
! 193: for (off = 0; off < cc; ) {
! 194: ssize_t n = write(master, ibuf + off, cc - off);
! 195: if (n == 0)
! 196: break; /* skip writing */
! 197: if (n > 0)
! 198: off += n;
! 199: }
! 200: }
! 201: done(sigdeadstatus);
1.1 deraadt 202: }
203:
204: void
205: finish(signo)
206: int signo;
207: {
1.8 deraadt 208: int save_errno = errno;
1.16 ! deraadt 209: int status, e = 1;
! 210: pid_t pid;
1.1 deraadt 211:
1.16 ! deraadt 212: while ((pid = wait3(&status, WNOHANG, 0)) > 0) {
1.11 ericj 213: if (pid == child) {
214: if (WIFEXITED(status))
1.16 ! deraadt 215: e = WEXITSTATUS(status);
1.11 ericj 216: }
1.16 ! deraadt 217: }
! 218: dead = 1;
! 219: sigdeadstatus = e;
1.12 espie 220: errno = save_errno;
221: }
222:
223: void
224: handlesigwinch(signo)
225: int signo;
226: {
1.16 ! deraadt 227: int save_errno = errno;
1.12 espie 228: struct winsize win;
229: pid_t pgrp;
230:
231: if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win) != -1) {
1.16 ! deraadt 232: ioctl(slave, TIOCSWINSZ, &win);
! 233: if (ioctl(slave, TIOCGPGRP, &pgrp) != -1)
! 234: killpg(pgrp, SIGWINCH);
1.12 espie 235: }
1.8 deraadt 236: errno = save_errno;
1.1 deraadt 237: }
238:
239: void
240: dooutput()
241: {
1.16 ! deraadt 242: struct sigaction sa;
1.1 deraadt 243: struct itimerval value;
1.16 ! deraadt 244: char obuf[BUFSIZ];
1.1 deraadt 245: time_t tvec;
1.16 ! deraadt 246: ssize_t outcc = 0, cc, off;
1.1 deraadt 247:
248: (void)close(STDIN_FILENO);
249: tvec = time(NULL);
250: (void)fprintf(fscript, "Script started on %s", ctime(&tvec));
251:
1.16 ! deraadt 252: bzero(&sa, sizeof sa);
! 253: sigemptyset(&sa.sa_mask);
! 254: sa.sa_handler = scriptflush;
! 255: (void)sigaction(SIGALRM, &sa, NULL);
! 256:
1.1 deraadt 257: value.it_interval.tv_sec = SECSPERMIN / 2;
258: value.it_interval.tv_usec = 0;
259: value.it_value = value.it_interval;
260: (void)setitimer(ITIMER_REAL, &value, NULL);
261: for (;;) {
1.16 ! deraadt 262: if (flush) {
! 263: if (outcc) {
! 264: (void)fflush(fscript);
! 265: outcc = 0;
! 266: }
! 267: flush = 0;
! 268: }
1.1 deraadt 269: cc = read(master, obuf, sizeof (obuf));
1.16 ! deraadt 270: if (cc == -1 && errno == EINTR)
! 271: continue;
1.1 deraadt 272: if (cc <= 0)
273: break;
1.16 ! deraadt 274: for (off = 0; off < cc; ) {
! 275: ssize_t n = write(1, obuf + off, cc - off);
! 276: if (n == 0)
! 277: break; /* skip writing */
! 278: if (n > 0)
! 279: off += n;
! 280: }
1.1 deraadt 281: (void)fwrite(obuf, 1, cc, fscript);
282: outcc += cc;
283: }
1.11 ericj 284: done(0);
1.1 deraadt 285: }
286:
287: void
288: scriptflush(signo)
289: int signo;
290: {
1.16 ! deraadt 291: flush = 1;
1.1 deraadt 292: }
293:
294: void
295: doshell()
296: {
297: char *shell;
298:
299: shell = getenv("SHELL");
300: if (shell == NULL)
301: shell = _PATH_BSHELL;
302:
303: (void)close(master);
304: (void)fclose(fscript);
305: login_tty(slave);
1.15 deraadt 306: execl(shell, shell, "-i", (char *)NULL);
1.1 deraadt 307: perror(shell);
308: fail();
309: }
310:
311: void
312: fail()
313: {
314:
315: (void)kill(0, SIGTERM);
1.11 ericj 316: done(1);
1.1 deraadt 317: }
318:
319: void
1.11 ericj 320: done(eval)
321: int eval;
1.1 deraadt 322: {
323: time_t tvec;
324:
325: if (subchild) {
326: tvec = time(NULL);
327: (void)fprintf(fscript,"\nScript done on %s", ctime(&tvec));
328: (void)fclose(fscript);
329: (void)close(master);
330: } else {
331: (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
332: (void)printf("Script done, output file is %s\n", fname);
333: }
1.11 ericj 334: exit(eval);
1.1 deraadt 335: }