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