123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330 |
- static char *sccsid = "@(#)script.c 4.1 (Berkeley) 10/1/80";
- /*
- * script - makes copy of terminal conversation. usage:
- *
- * script [ -n ] [ -s ] [ -q ] [ -a ] [ -S shell ] [ file ]
- * conversation saved in file. default is DFNAME
- */
- #define DFNAME "typescript"
- #define V7ENV
- #ifdef HOUXP
- #define STDSHELL "/bin/sh"
- #define NEWSHELL "/p4/3723mrh/bin/csh"
- char *shell = NEWSHELL;
- #endif
- #ifdef HOUXT
- #define STDSHELL "/bin/sh"
- #define NEWSHELL "/t1/bruce/ucb/bin/csh"
- char *shell = NEWSHELL;
- #endif
- #ifdef CORY
- #define STDSHELL "/bin/sh"
- #define NEWSHELL "/bin/csh"
- char *shell = NEWSHELL;
- #endif
- #ifdef CC
- #define STDSHELL "/bin/sh"
- #define NEWSHELL "/bin/csh"
- char *shell = NEWSHELL;
- #endif
- #ifndef STDSHELL
- # define V7ENV
- #endif
- #ifdef V7ENV
- #include <signal.h>
- /* used for version 7 with environments - gets your environment shell */
- #define STDSHELL "/bin/sh"
- #define NEWSHELL "/bin/csh"
- char *shell; /* initialized in the code */
- # include <sys/types.h>
- # include <sys/stat.h>
- # define MODE st_mode
- # define STAT stat
- char *getenv();
- #else
- /*
- * The following is the structure of the block returned by
- * the stat and fstat system calls.
- */
- struct inode {
- char i_minor; /* +0: minor device of i-node */
- char i_major; /* +1: major device */
- int i_number; /* +2 */
- int i_flags; /* +4: see below */
- char i_nlinks; /* +6: number of links to file */
- char i_uid; /* +7: user ID of owner */
- char i_gid; /* +8: group ID of owner */
- char i_size0; /* +9: high byte of 24-bit size */
- int i_size1; /* +10: low word of 24-bit size */
- int i_addr[8]; /* +12: block numbers or device number */
- int i_actime[2]; /* +28: time of last access */
- int i_modtime[2]; /* +32: time of last modification */
- };
- #define IALLOC 0100000
- #define IFMT 060000
- #define IFDIR 040000
- #define IFCHR 020000
- #define IFBLK 060000
- #define MODE i_flags
- #define STAT inode
- #endif
- char *tty; /* name of users tty so can turn off writes */
- char *ttyname(); /* std subroutine */
- int mode = 0622; /* old permission bits for users tty */
- int outpipe[2]; /* pipe from shell to output */
- int fd; /* file descriptor of typescript file */
- int inpipe[2]; /* pipe from input to shell */
- long tvec; /* current time */
- char buffer[256]; /* for block I/O's */
- int n; /* number of chars read */
- int status; /* dummy for wait sys call */
- char *fname; /* name of typescript file */
- int forkval, ttn; /* temps for error checking */
- int qflg; /* true if -q (quiet) flag */
- int aflg; /* true if -q (append) flag */
- struct STAT sbuf;
- int flsh();
- main(argc,argv) int argc; char **argv; {
- if ((tty = ttyname(2)) < 0) {
- printf("Nested script not allowed.\n");
- fail();
- }
- #ifdef V7ENV
- shell = getenv("SHELL");
- #endif
- while ( argc > 1 && argv[1][0] == '-') {
- switch(argv[1][1]) {
- case 'n':
- shell = NEWSHELL;
- break;
- case 's':
- shell = STDSHELL;
- break;
- case 'S':
- shell = argv[2];
- argc--; argv++;
- break;
- case 'q':
- qflg++;
- break;
- case 'a':
- aflg++;
- break;
- default:
- printf("Bad flag %s - ignored\n",argv[1]);
- }
- argc--; argv++;
- }
- if (argc > 1) {
- fname = argv[1];
- if (!aflg && stat(fname,&sbuf) >= 0) {
- printf("File %s already exists.\n",fname);
- done();
- }
- } else fname = DFNAME;
- if (!aflg) {
- fd = creat(fname,0); /* so can't cat/lpr typescript from inside */
- } else {
- /* try to append to existing file first */
- fd = open(fname,1);
- if (fd >= 0) lseek(fd,0l,2);
- else fd = creat(fname,0);
- }
- if (fd<0) {
- printf("Can't create %s\n",fname);
- if (unlink(fname)==0) {
- printf("because of previous typescript bomb - try again\n");
- }
- fail();
- }
- chmod(fname,0); /* in case it already exists */
- fixtty();
- if (!qflg) {
- printf("Script started, file is %s\n",fname);
- check(write(fd,"Script started on ",18));
- time(&tvec);
- check(write(fd,ctime(&tvec),25));
- }
- pipe(inpipe);
- pipe(outpipe);
- forkval = fork();
- if (forkval < 0)
- goto ffail;
- if (forkval == 0) {
- forkval = fork();
- if (forkval < 0)
- goto ffail;
- if (forkval == 0)
- dooutput();
- forkval = fork();
- if (forkval < 0)
- goto ffail;
- if (forkval == 0)
- doinput();
- doshell();
- }
- close(inpipe[0]); close(inpipe[1]);
- close(outpipe[0]); close(outpipe[1]);
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, done);
- wait(&status);
- done();
- /*NOTREACHED*/
- ffail:
- printf("Fork failed. Try again.\n");
- fail();
- }
- /* input process - copy tty to pipe and file */
- doinput()
- {
- signal(SIGINT, SIG_IGN);
- signal(SIGQUIT, SIG_IGN);
- close(inpipe[0]);
- close(outpipe[0]);
- close(outpipe[1]);
- /* main input loop - copy until end of file (ctrl D) */
- while ((n=read(0,buffer,256)) > 0) {
- check(write(fd,buffer,n));
- write(inpipe[1],buffer,n);
- }
- /* end of script - close files and exit */
- close(inpipe[1]);
- close(fd);
- done();
- }
- /* do output process - copy to tty & file */
- dooutput()
- {
- signal(SIGINT, flsh);
- signal(SIGQUIT, SIG_IGN);
- signal(SIGTSTP, SIG_IGN);
- close(0);
- close(inpipe[0]);
- close(inpipe[1]);
- close(outpipe[1]);
- /* main output proc loop */
- while (n=read(outpipe[0],buffer,256)) {
- if (n > 0) { /* -1 means trap to flsh just happened */
- write(1,buffer,n);
- check(write(fd,buffer,n));
- }
- }
- /* output sees eof - close files and exit */
- if (!qflg) {
- printf("Script done, file is %s\n",fname);
- check(write(fd,"\nscript done on ",16));
- time(&tvec);
- check(write(fd,ctime(&tvec),25));
- }
- close(fd);
- exit(0);
- }
- /* exec shell, after diverting std input & output */
- doshell()
- {
- close(0);
- dup(inpipe[0]);
- close(1);
- dup(outpipe[1]);
- close(2);
- dup(outpipe[1]);
- /* close useless files */
- close(inpipe[0]);
- close(inpipe[1]);
- close(outpipe[0]);
- close(outpipe[1]);
- execl(shell, "sh", "-i", 0);
- execl(STDSHELL, "sh", "-i", 0);
- execl(NEWSHELL, "sh", "-i", 0);
- printf("Can't execute shell\n");
- fail();
- }
- fixtty()
- {
- fstat(2, &sbuf);
- mode = sbuf.MODE&0777;
- chmod(tty, 0600);
- }
- /* come here on rubout to flush output - this doesn't work */
- flsh()
- {
- signal(SIGINT, flsh);
- /* lseek(outpipe[0],0l,2); /* seeks on pipes don't work !"$"$!! */
- }
- fail()
- {
- unlink(fname);
- kill(0, 15); /* shut off other script processes */
- done();
- }
- done()
- {
- chmod(tty, mode);
- chmod(fname, 0664);
- exit();
- }
- #ifndef V7ENV
- #ifndef CC
- char *ttyname(i) int i; {
- char *string;
- string = "/dev/ttyx";
- string[8] = ttyn(fd);
- if (string[8] == 'x') return((char *) (-1));
- else return(string);
- }
- #endif
- #endif
- check(n)
- int n;
- {
- /* checks the result of a write call, if neg
- assume ran out of disk space & die */
- if (n < 0) {
- write(1,"Disk quota exceeded - script quits\n",35);
- kill(0,15);
- done();
- }
- }
|