1 /* 2 * Copyright (c) 1980, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char copyright[] = 10 "@(#) Copyright (c) 1980, 1992, 1993\n\ 11 The Regents of the University of California. All rights reserved.\n"; 12 #endif /* not lint */ 13 14 #ifndef lint 15 static char sccsid[] = "@(#)script.c 8.1 (Berkeley) 06/06/93"; 16 #endif /* not lint */ 17 18 #include <sys/types.h> 19 #include <sys/wait.h> 20 #include <sys/stat.h> 21 #include <sys/ioctl.h> 22 #include <sys/time.h> 23 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <paths.h> 27 #include <signal.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <termios.h> 32 #include <tzfile.h> 33 #include <unistd.h> 34 35 FILE *fscript; 36 int master, slave; 37 int child, subchild; 38 int outcc; 39 char *fname; 40 41 struct termios tt; 42 43 __dead void done __P((void)); 44 void dooutput __P((void)); 45 void doshell __P((void)); 46 void err __P((const char *, ...)); 47 void fail __P((void)); 48 void finish __P((int)); 49 void scriptflush __P((int)); 50 51 int 52 main(argc, argv) 53 int argc; 54 char *argv[]; 55 { 56 register int cc; 57 struct termios rtt; 58 struct winsize win; 59 int aflg, ch; 60 char ibuf[BUFSIZ]; 61 62 aflg = 0; 63 while ((ch = getopt(argc, argv, "a")) != EOF) 64 switch(ch) { 65 case 'a': 66 aflg = 1; 67 break; 68 case '?': 69 default: 70 (void)fprintf(stderr, "usage: script [-a] [file]\n"); 71 exit(1); 72 } 73 argc -= optind; 74 argv += optind; 75 76 if (argc > 0) 77 fname = argv[0]; 78 else 79 fname = "typescript"; 80 81 if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) 82 err("%s: %s", fname, strerror(errno)); 83 84 (void)tcgetattr(STDIN_FILENO, &tt); 85 (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win); 86 if (openpty(&master, &slave, NULL, &tt, &win) == -1) 87 err("openpty: %s", strerror(errno)); 88 89 (void)printf("Script started, output file is %s\n", fname); 90 rtt = tt; 91 cfmakeraw(&rtt); 92 rtt.c_lflag &= ~ECHO; 93 (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt); 94 95 (void)signal(SIGCHLD, finish); 96 child = fork(); 97 if (child < 0) { 98 perror("fork"); 99 fail(); 100 } 101 if (child == 0) { 102 subchild = child = fork(); 103 if (child < 0) { 104 perror("fork"); 105 fail(); 106 } 107 if (child) 108 dooutput(); 109 else 110 doshell(); 111 } 112 113 (void)fclose(fscript); 114 while ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0) 115 (void)write(master, ibuf, cc); 116 done(); 117 } 118 119 void 120 finish(signo) 121 int signo; 122 { 123 register int die, pid; 124 union wait status; 125 126 die = 0; 127 while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0) 128 if (pid == child) 129 die = 1; 130 131 if (die) 132 done(); 133 } 134 135 void 136 dooutput() 137 { 138 struct itimerval value; 139 register int cc; 140 time_t tvec; 141 char obuf[BUFSIZ]; 142 143 (void)close(STDIN_FILENO); 144 tvec = time(NULL); 145 (void)fprintf(fscript, "Script started on %s", ctime(&tvec)); 146 147 (void)signal(SIGALRM, scriptflush); 148 value.it_interval.tv_sec = SECSPERMIN / 2; 149 value.it_interval.tv_usec = 0; 150 value.it_value = value.it_interval; 151 (void)setitimer(ITIMER_REAL, &value, NULL); 152 for (;;) { 153 cc = read(master, obuf, sizeof (obuf)); 154 if (cc <= 0) 155 break; 156 (void)write(1, obuf, cc); 157 (void)fwrite(obuf, 1, cc, fscript); 158 outcc += cc; 159 } 160 done(); 161 } 162 163 void 164 scriptflush(signo) 165 int signo; 166 { 167 if (outcc) { 168 (void)fflush(fscript); 169 outcc = 0; 170 } 171 } 172 173 void 174 doshell() 175 { 176 char *shell; 177 178 shell = getenv("SHELL"); 179 if (shell == NULL) 180 shell = _PATH_BSHELL; 181 182 (void)close(master); 183 (void)fclose(fscript); 184 login_tty(slave); 185 execl(shell, "sh", "-i", NULL); 186 perror(shell); 187 fail(); 188 } 189 190 void 191 fail() 192 { 193 194 (void)kill(0, SIGTERM); 195 done(); 196 } 197 198 void 199 done() 200 { 201 time_t tvec; 202 203 if (subchild) { 204 tvec = time(NULL); 205 (void)fprintf(fscript,"\nScript done on %s", ctime(&tvec)); 206 (void)fclose(fscript); 207 (void)close(master); 208 } else { 209 (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt); 210 (void)printf("Script done, output file is %s\n", fname); 211 } 212 exit(0); 213 } 214 215 #if __STDC__ 216 #include <stdarg.h> 217 #else 218 #include <varargs.h> 219 #endif 220 221 void 222 #if __STDC__ 223 err(const char *fmt, ...) 224 #else 225 err(fmt, va_alist) 226 char *fmt; 227 va_dcl 228 #endif 229 { 230 va_list ap; 231 #if __STDC__ 232 va_start(ap, fmt); 233 #else 234 va_start(ap); 235 #endif 236 (void)fprintf(stderr, "script: "); 237 (void)vfprintf(stderr, fmt, ap); 238 va_end(ap); 239 (void)fprintf(stderr, "\n"); 240 exit(1); 241 /* NOTREACHED */ 242 } 243