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