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: }

Defined functions

check defined in line 328; used 6 times
doinput defined in line 203; used 1 times
done defined in line 308; used 7 times
dooutput defined in line 229; used 1 times
doshell defined in line 262; used 1 times
fail defined in line 300; used 4 times
fixtty defined in line 284; used 1 times
flsh defined in line 293; used 3 times
main defined in line 103; never used
ttyname defined in line 318; used 4 times

Defined variables

aflg defined in line 99; used 3 times
buffer defined in line 93; used 6 times
fd defined in line 90; used 15 times
fname defined in line 96; used 14 times
forkval defined in line 97; used 9 times
inpipe defined in line 91; used 11 times
mode defined in line 88; used 2 times
n defined in line 94; used 7 times
outpipe defined in line 89; used 11 times
qflg defined in line 98; used 3 times
sbuf defined in line 100; used 3 times
sccsid defined in line 2; never used
shell defined in line 47; used 5 times
status defined in line 95; used 1 times
tty defined in line 86; used 3 times
tvec defined in line 92; used 4 times

Defined struct's

inode defined in line 62; never used

Defined macros

DFNAME defined in line 11; used 1 times
IALLOC defined in line 77; never used
IFBLK defined in line 81; never used
IFCHR defined in line 80; never used
IFDIR defined in line 79; never used
IFMT defined in line 78; never used
MODE defined in line 82; used 1 times
NEWSHELL defined in line 46; used 6 times
STAT defined in line 83; never used
STDSHELL defined in line 45; used 3 times
V7ENV defined in line 38; used 3 times
Last modified: 1982-10-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1218
Valid CSS Valid XHTML 1.0 Strict