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