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