1: #ifndef lint 2: static char *sccsid = "@(#)script.c 4.1 (Berkeley) 10/1/80"; 3: #endif 4: /* 5: * script - makes copy of terminal conversation. usage: 6: * 7: * script [ -n ] [ -s ] [ -q ] [ -a ] [ -S shell ] [ file ] 8: * conversation saved in file. default is DFNAME 9: */ 10: 11: #define DFNAME "typescript" 12: 13: #ifdef HOUXP 14: #define STDSHELL "/bin/sh" 15: #define NEWSHELL "/p4/3723mrh/bin/csh" 16: char *shell = NEWSHELL; 17: #endif 18: 19: #ifdef HOUXT 20: #define STDSHELL "/bin/sh" 21: #define NEWSHELL "/t1/bruce/ucb/bin/csh" 22: char *shell = NEWSHELL; 23: #endif 24: 25: #ifdef CORY 26: #define STDSHELL "/bin/sh" 27: #define NEWSHELL "/bin/csh" 28: char *shell = NEWSHELL; 29: #endif 30: 31: #ifdef CC 32: #define STDSHELL "/bin/sh" 33: #define NEWSHELL "/bin/csh" 34: char *shell = NEWSHELL; 35: #endif 36: 37: #ifndef STDSHELL 38: # define V7ENV 39: #endif 40: 41: #ifdef V7ENV 42: #include <whoami.h> 43: #include <signal.h> 44: /* used for version 7 with environments - gets your environment shell */ 45: #define STDSHELL "/bin/sh" 46: #define NEWSHELL "/bin/csh" 47: char *shell; /* initialized in the code */ 48: # include <sys/types.h> 49: # include <sys/stat.h> 50: # define MODE st_mode 51: # define STAT stat 52: char *getenv(); 53: char *ctime(); 54: 55: #else 56: 57: /* 58: * The following is the structure of the block returned by 59: * the stat and fstat system calls. 60: */ 61: 62: struct inode { 63: char i_minor; /* +0: minor device of i-node */ 64: char i_major; /* +1: major device */ 65: int i_number; /* +2 */ 66: int i_flags; /* +4: see below */ 67: char i_nlinks; /* +6: number of links to file */ 68: char i_uid; /* +7: user ID of owner */ 69: char i_gid; /* +8: group ID of owner */ 70: char i_size0; /* +9: high byte of 24-bit size */ 71: int i_size1; /* +10: low word of 24-bit size */ 72: int i_addr[8]; /* +12: block numbers or device number */ 73: int i_actime[2]; /* +28: time of last access */ 74: int i_modtime[2]; /* +32: time of last modification */ 75: }; 76: 77: #define IALLOC 0100000 78: #define IFMT 060000 79: #define IFDIR 040000 80: #define IFCHR 020000 81: #define IFBLK 060000 82: #define MODE i_flags 83: #define STAT inode 84: #endif 85: 86: char *tty; /* name of users tty so can turn off writes */ 87: char *ttyname(); /* std subroutine */ 88: int mode = 0622; /* old permission bits for users tty */ 89: int outpipe[2]; /* pipe from shell to output */ 90: int fd; /* file descriptor of typescript file */ 91: int inpipe[2]; /* pipe from input to shell */ 92: long tvec; /* current time */ 93: char buffer[256]; /* for block I/O's */ 94: int n; /* number of chars read */ 95: int status; /* dummy for wait sys call */ 96: char *fname; /* name of typescript file */ 97: int forkval; /* temp for error checking */ 98: int qflg; /* true if -q (quiet) flag */ 99: int aflg; /* true if -q (append) flag */ 100: struct STAT sbuf; 101: int flsh(); 102: 103: main(argc,argv) int argc; char **argv; { 104: int done(); 105: 106: if ((tty = ttyname(2)) < 0) { 107: printf("Nested script not allowed.\n"); 108: fail(); 109: } 110: 111: #ifdef V7ENV 112: shell = getenv("SHELL"); 113: #endif 114: 115: while ( argc > 1 && argv[1][0] == '-') { 116: switch(argv[1][1]) { 117: case 'n': 118: shell = NEWSHELL; 119: break; 120: case 's': 121: shell = STDSHELL; 122: break; 123: case 'S': 124: shell = argv[2]; 125: argc--; argv++; 126: break; 127: case 'q': 128: qflg++; 129: break; 130: case 'a': 131: aflg++; 132: break; 133: default: 134: printf("Bad flag %s - ignored\n",argv[1]); 135: } 136: argc--; argv++; 137: } 138: 139: if (argc > 1) { 140: fname = argv[1]; 141: if (!aflg && stat(fname,&sbuf) >= 0) { 142: printf("File %s already exists.\n",fname); 143: done(); 144: } 145: } else fname = DFNAME; 146: if (!aflg) { 147: fd = creat(fname,0); /* so can't cat/lpr typescript from inside */ 148: } else { 149: /* try to append to existing file first */ 150: fd = open(fname,1); 151: if (fd >= 0) lseek(fd,0l,2); 152: else fd = creat(fname,0); 153: } 154: if (fd<0) { 155: printf("Can't create %s\n",fname); 156: if (unlink(fname)==0) { 157: printf("because of previous typescript bomb - try again\n"); 158: } 159: fail(); 160: } 161: 162: chmod(fname,0); /* in case it already exists */ 163: fixtty(); 164: if (!qflg) { 165: printf("Script started, file is %s\n",fname); 166: check(write(fd,"Script started on ",18)); 167: time(&tvec); 168: check(write(fd,ctime(&tvec),25)); 169: } 170: pipe(inpipe); 171: pipe(outpipe); 172: 173: forkval = fork(); 174: if (forkval < 0) 175: goto ffail; 176: if (forkval == 0) { 177: forkval = fork(); 178: if (forkval < 0) 179: goto ffail; 180: if (forkval == 0) 181: dooutput(); 182: forkval = fork(); 183: if (forkval < 0) 184: goto ffail; 185: if (forkval == 0) 186: doinput(); 187: doshell(); 188: } 189: close(inpipe[0]); close(inpipe[1]); 190: close(outpipe[0]); close(outpipe[1]); 191: signal(SIGINT, SIG_IGN); 192: signal(SIGQUIT, done); 193: wait(&status); 194: done(); 195: /*NOTREACHED*/ 196: 197: ffail: 198: printf("Fork failed. Try again.\n"); 199: fail(); 200: } 201: 202: /* input process - copy tty to pipe and file */ 203: doinput() 204: { 205: 206: signal(SIGINT, SIG_IGN); 207: signal(SIGQUIT, SIG_IGN); 208: #ifdef SIGTSTP 209: signal(SIGTSTP, SIG_IGN); 210: #endif 211: 212: close(inpipe[0]); 213: close(outpipe[0]); 214: close(outpipe[1]); 215: 216: /* main input loop - copy until end of file (ctrl D) */ 217: while ((n=read(0,buffer,256)) > 0) { 218: check(write(fd,buffer,n)); 219: write(inpipe[1],buffer,n); 220: } 221: 222: /* end of script - close files and exit */ 223: close(inpipe[1]); 224: close(fd); 225: done(); 226: } 227: 228: /* do output process - copy to tty & file */ 229: dooutput() 230: { 231: 232: signal(SIGINT, flsh); 233: signal(SIGQUIT, SIG_IGN); 234: #ifdef SIGTSTP 235: signal(SIGTSTP, SIG_IGN); 236: #endif 237: close(0); 238: close(inpipe[0]); 239: close(inpipe[1]); 240: close(outpipe[1]); 241: 242: /* main output proc loop */ 243: while (n=read(outpipe[0],buffer,256)) { 244: if (n > 0) { /* -1 means trap to flsh just happened */ 245: write(1,buffer,n); 246: check(write(fd,buffer,n)); 247: } 248: } 249: 250: /* output sees eof - close files and exit */ 251: if (!qflg) { 252: printf("Script done, file is %s\n",fname); 253: check(write(fd,"\nscript done on ",16)); 254: time(&tvec); 255: check(write(fd,ctime(&tvec),25)); 256: } 257: close(fd); 258: exit(0); 259: } 260: 261: /* exec shell, after diverting std input & output */ 262: doshell() 263: { 264: 265: close(0); 266: dup(inpipe[0]); 267: close(1); 268: dup(outpipe[1]); 269: close(2); 270: dup(outpipe[1]); 271: 272: /* close useless files */ 273: close(inpipe[0]); 274: close(inpipe[1]); 275: close(outpipe[0]); 276: close(outpipe[1]); 277: execl(shell, "sh", "-i", 0); 278: execl(STDSHELL, "sh", "-i", 0); 279: execl(NEWSHELL, "sh", "-i", 0); 280: printf("Can't execute shell\n"); 281: fail(); 282: } 283: 284: fixtty() 285: { 286: 287: fstat(2, &sbuf); 288: mode = sbuf.MODE&0777; 289: chmod(tty, 0600); 290: } 291: 292: /* come here on rubout to flush output - this doesn't work */ 293: flsh() 294: { 295: 296: signal(SIGINT, flsh); 297: /* lseek(outpipe[0],0l,2); /* seeks on pipes don't work !"$"$!! */ 298: } 299: 300: fail() 301: { 302: 303: unlink(fname); 304: kill(0, 15); /* shut off other script processes */ 305: done(); 306: } 307: 308: done() 309: { 310: 311: chmod(tty, mode); 312: chmod(fname, 0664); 313: exit(0); 314: } 315: 316: #ifndef V7ENV 317: #ifndef CC 318: char *ttyname(i) int i; { 319: char *string; 320: string = "/dev/ttyx"; 321: string[8] = ttyn(fd); 322: if (string[8] == 'x') return((char *) (-1)); 323: else return(string); 324: } 325: #endif 326: #endif 327: 328: check(nwritten) 329: int nwritten; 330: { 331: /* checks the result of a write call, if neg 332: assume ran out of disk space & die */ 333: if (nwritten < 0) { 334: write(1,"Disk quota exceeded - script quits\n",35); 335: kill(0,15); 336: done(); 337: } 338: }