Annotation of src/usr.bin/script/script.c, Revision 1.34
1.34 ! jasper 1: /* $OpenBSD: script.c,v 1.33 2017/04/12 14:49:05 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: #include <sys/types.h>
59: #include <sys/wait.h>
60: #include <sys/stat.h>
61: #include <sys/ioctl.h>
62: #include <sys/time.h>
63:
64: #include <errno.h>
65: #include <fcntl.h>
66: #include <paths.h>
67: #include <signal.h>
68: #include <stdio.h>
69: #include <stdlib.h>
70: #include <string.h>
71: #include <termios.h>
72: #include <unistd.h>
73:
1.5 deraadt 74: #include <util.h>
1.7 mickey 75: #include <err.h>
1.5 deraadt 76:
1.1 deraadt 77: FILE *fscript;
78: int master, slave;
1.20 deraadt 79: volatile sig_atomic_t child;
80: pid_t subchild;
1.1 deraadt 81: char *fname;
82:
1.16 deraadt 83: volatile sig_atomic_t dead;
84: volatile sig_atomic_t sigdeadstatus;
85: volatile sig_atomic_t flush;
86:
1.1 deraadt 87: struct termios tt;
1.33 deraadt 88: int istty;
1.1 deraadt 89:
1.17 millert 90: __dead void done(int);
91: void dooutput(void);
1.34 ! jasper 92: void doshell(char *);
1.17 millert 93: void fail(void);
94: void finish(int);
95: void scriptflush(int);
96: void handlesigwinch(int);
1.1 deraadt 97:
98: int
1.19 deraadt 99: main(int argc, char *argv[])
1.1 deraadt 100: {
1.21 mickey 101: extern char *__progname;
1.16 deraadt 102: struct sigaction sa;
1.1 deraadt 103: struct winsize win;
1.16 deraadt 104: char ibuf[BUFSIZ];
1.34 ! jasper 105: char *cmd;
1.16 deraadt 106: ssize_t cc, off;
1.1 deraadt 107: int aflg, ch;
108:
1.34 ! jasper 109: cmd = NULL;
1.1 deraadt 110: aflg = 0;
1.34 ! jasper 111: while ((ch = getopt(argc, argv, "ac:")) != -1)
1.1 deraadt 112: switch(ch) {
113: case 'a':
114: aflg = 1;
115: break;
1.34 ! jasper 116: case 'c':
! 117: cmd = optarg;
! 118: break;
1.1 deraadt 119: default:
1.34 ! jasper 120: fprintf(stderr, "usage: %s [-a] [-c command] [file]\n",
! 121: __progname);
1.1 deraadt 122: exit(1);
123: }
124: argc -= optind;
125: argv += optind;
126:
127: if (argc > 0)
128: fname = argv[0];
129: else
130: fname = "typescript";
131:
132: if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL)
1.13 millert 133: err(1, "%s", fname);
1.1 deraadt 134:
1.33 deraadt 135: if (isatty(0)) {
136: if (tcgetattr(STDIN_FILENO, &tt) == 0 &&
137: ioctl(STDIN_FILENO, TIOCGWINSZ, &win) == 0)
138: istty = 1;
139: }
1.1 deraadt 140: if (openpty(&master, &slave, NULL, &tt, &win) == -1)
1.7 mickey 141: err(1, "openpty");
1.1 deraadt 142:
143: (void)printf("Script started, output file is %s\n", fname);
1.33 deraadt 144: if (istty) {
145: struct termios rtt = tt;
146:
147: cfmakeraw(&rtt);
148: rtt.c_lflag &= ~ECHO;
149: (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
150: }
1.1 deraadt 151:
1.16 deraadt 152: bzero(&sa, sizeof sa);
153: sigemptyset(&sa.sa_mask);
154: sa.sa_handler = handlesigwinch;
155: sa.sa_flags = SA_RESTART;
156: (void)sigaction(SIGWINCH, &sa, NULL);
157:
1.1 deraadt 158: child = fork();
159: if (child < 0) {
1.21 mickey 160: warn("fork");
1.1 deraadt 161: fail();
162: }
163: if (child == 0) {
164: subchild = child = fork();
165: if (child < 0) {
1.21 mickey 166: warn("fork");
1.1 deraadt 167: fail();
168: }
169: if (child)
170: dooutput();
171: else
1.34 ! jasper 172: doshell(cmd);
1.1 deraadt 173: }
174:
1.27 deraadt 175: bzero(&sa, sizeof sa);
176: sigemptyset(&sa.sa_mask);
177: sa.sa_handler = finish;
178: (void)sigaction(SIGCHLD, &sa, NULL);
179:
1.32 semarie 180: if (pledge("stdio proc tty", NULL) == -1)
1.31 deraadt 181: err(1, "pledge");
1.28 deraadt 182:
1.1 deraadt 183: (void)fclose(fscript);
1.16 deraadt 184: while (1) {
185: if (dead)
186: break;
187: cc = read(STDIN_FILENO, ibuf, BUFSIZ);
188: if (cc == -1 && errno == EINTR)
189: continue;
190: if (cc <= 0)
191: break;
192: for (off = 0; off < cc; ) {
193: ssize_t n = write(master, ibuf + off, cc - off);
1.24 deraadt 194: if (n == -1 && errno != EAGAIN)
195: break;
1.16 deraadt 196: if (n == 0)
197: break; /* skip writing */
198: if (n > 0)
199: off += n;
200: }
201: }
202: done(sigdeadstatus);
1.1 deraadt 203: }
204:
205: void
1.19 deraadt 206: finish(int signo)
1.1 deraadt 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.20 deraadt 213: if (pid == (pid_t)child) {
1.11 ericj 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
1.19 deraadt 224: handlesigwinch(int signo)
1.12 espie 225: {
1.16 deraadt 226: int save_errno = errno;
1.12 espie 227: struct winsize win;
228: pid_t pgrp;
229:
230: if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win) != -1) {
1.16 deraadt 231: ioctl(slave, TIOCSWINSZ, &win);
232: if (ioctl(slave, TIOCGPGRP, &pgrp) != -1)
233: killpg(pgrp, SIGWINCH);
1.12 espie 234: }
1.8 deraadt 235: errno = save_errno;
1.1 deraadt 236: }
237:
238: void
1.19 deraadt 239: dooutput(void)
1.1 deraadt 240: {
1.16 deraadt 241: struct sigaction sa;
1.1 deraadt 242: struct itimerval value;
1.22 millert 243: sigset_t blkalrm;
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.22 millert 252: sigemptyset(&blkalrm);
253: sigaddset(&blkalrm, SIGALRM);
1.16 deraadt 254: bzero(&sa, sizeof sa);
255: sigemptyset(&sa.sa_mask);
256: sa.sa_handler = scriptflush;
257: (void)sigaction(SIGALRM, &sa, NULL);
1.27 deraadt 258:
259: bzero(&sa, sizeof sa);
260: sigemptyset(&sa.sa_mask);
261: sa.sa_handler = SIG_IGN;
262: (void)sigaction(SIGCHLD, &sa, NULL);
1.28 deraadt 263:
1.32 semarie 264: if (pledge("stdio proc", NULL) == -1)
1.31 deraadt 265: err(1, "pledge");
1.16 deraadt 266:
1.26 millert 267: value.it_interval.tv_sec = 30;
1.1 deraadt 268: value.it_interval.tv_usec = 0;
269: value.it_value = value.it_interval;
270: (void)setitimer(ITIMER_REAL, &value, NULL);
271: for (;;) {
1.16 deraadt 272: if (flush) {
273: if (outcc) {
274: (void)fflush(fscript);
275: outcc = 0;
276: }
277: flush = 0;
278: }
1.1 deraadt 279: cc = read(master, obuf, sizeof (obuf));
1.16 deraadt 280: if (cc == -1 && errno == EINTR)
281: continue;
1.1 deraadt 282: if (cc <= 0)
283: break;
1.22 millert 284: sigprocmask(SIG_BLOCK, &blkalrm, NULL);
1.16 deraadt 285: for (off = 0; off < cc; ) {
1.23 deraadt 286: ssize_t n = write(STDOUT_FILENO, obuf + off, cc - off);
1.24 deraadt 287: if (n == -1 && errno != EAGAIN)
288: break;
1.16 deraadt 289: if (n == 0)
290: break; /* skip writing */
291: if (n > 0)
292: off += n;
293: }
1.1 deraadt 294: (void)fwrite(obuf, 1, cc, fscript);
295: outcc += cc;
1.22 millert 296: sigprocmask(SIG_UNBLOCK, &blkalrm, NULL);
1.1 deraadt 297: }
1.11 ericj 298: done(0);
1.1 deraadt 299: }
300:
301: void
1.19 deraadt 302: scriptflush(int signo)
1.1 deraadt 303: {
1.16 deraadt 304: flush = 1;
1.1 deraadt 305: }
306:
307: void
1.34 ! jasper 308: doshell(char *cmd)
1.1 deraadt 309: {
310: char *shell;
1.34 ! jasper 311: char *argp[] = {"sh", "-c", NULL, NULL};
1.1 deraadt 312:
313: shell = getenv("SHELL");
314: if (shell == NULL)
315: shell = _PATH_BSHELL;
316:
317: (void)close(master);
318: (void)fclose(fscript);
319: login_tty(slave);
1.34 ! jasper 320:
! 321: if (cmd != NULL) {
! 322: argp[2] = cmd;
! 323: execv(_PATH_BSHELL, argp);
! 324: warn("unable to execute %s", _PATH_BSHELL);
! 325: } else {
! 326: execl(shell, shell, "-i", (char *)NULL);
! 327: warn("%s", shell);
! 328: }
1.1 deraadt 329: fail();
330: }
331:
332: void
1.19 deraadt 333: fail(void)
1.1 deraadt 334: {
335:
336: (void)kill(0, SIGTERM);
1.11 ericj 337: done(1);
1.1 deraadt 338: }
339:
340: void
1.19 deraadt 341: done(int eval)
1.1 deraadt 342: {
343: time_t tvec;
344:
345: if (subchild) {
346: tvec = time(NULL);
347: (void)fprintf(fscript,"\nScript done on %s", ctime(&tvec));
348: (void)fclose(fscript);
349: (void)close(master);
350: } else {
1.33 deraadt 351: if (istty)
352: (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
1.1 deraadt 353: (void)printf("Script done, output file is %s\n", fname);
354: }
1.11 ericj 355: exit(eval);
1.1 deraadt 356: }