xref: /csrg-svn/usr.bin/script/script.c (revision 18029)
16318Swnj #ifndef lint
2*18029Sbloom static char *sccsid = "@(#)script.c	4.7 (Berkeley) 85/02/21";
31089Sbill #endif
412990Ssam 
51089Sbill /*
66318Swnj  * script
71089Sbill  */
86318Swnj #include <stdio.h>
96318Swnj #include <signal.h>
106318Swnj #include <sys/types.h>
116318Swnj #include <sys/stat.h>
126318Swnj #include <sys/ioctl.h>
136318Swnj #include <sgtty.h>
1413621Ssam #include <sys/time.h>
1517589Ssam #include <sys/file.h>
161089Sbill 
176318Swnj char	*getenv();
186318Swnj char	*ctime();
196318Swnj char	*shell;
206318Swnj FILE	*fscript;
216318Swnj int	master;
226318Swnj int	slave;
236318Swnj int	child;
246318Swnj char	*fname = "typescript";
256318Swnj int	finish();
261089Sbill 
276318Swnj struct	sgttyb b;
286318Swnj struct	tchars tc;
296318Swnj struct	ltchars lc;
30*18029Sbloom struct	winsize win;
316318Swnj int	lb;
326318Swnj int	l;
336318Swnj char	*line = "/dev/ptyXX";
346318Swnj int	aflg;
351089Sbill 
366318Swnj main(argc, argv)
376318Swnj 	int argc;
386318Swnj 	char *argv[];
396318Swnj {
406318Swnj 	int f;
411089Sbill 
421089Sbill 	shell = getenv("SHELL");
436318Swnj 	if (shell == 0)
446318Swnj 		shell = "/bin/sh";
456318Swnj 	argc--, argv++;
466318Swnj 	while (argc > 0 && argv[0][0] == '-') {
476318Swnj 		switch (argv[0][1]) {
481089Sbill 
496318Swnj 		case 'a':
506318Swnj 			aflg++;
516318Swnj 			break;
521089Sbill 
536318Swnj 		default:
546318Swnj 			fprintf(stderr,
556318Swnj 			    "usage: script [ -a ] [ typescript ]\n");
566318Swnj 			exit(1);
571089Sbill 		}
586318Swnj 		argc--, argv++;
591089Sbill 	}
606318Swnj 	if (argc > 0)
616318Swnj 		fname = argv[0];
626318Swnj 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
636318Swnj 		perror(fname);
641089Sbill 		fail();
651089Sbill 	}
666318Swnj 	getmaster();
676318Swnj 	printf("Script started, file is %s\n", fname);
686318Swnj 	fixtty();
691089Sbill 
706318Swnj 	(void) signal(SIGCHLD, finish);
716318Swnj 	child = fork();
726318Swnj 	if (child < 0) {
736318Swnj 		perror("fork");
746318Swnj 		fail();
751089Sbill 	}
766318Swnj 	if (child == 0) {
776318Swnj 		f = fork();
786318Swnj 		if (f < 0) {
796318Swnj 			perror("fork");
806318Swnj 			fail();
816318Swnj 		}
826318Swnj 		if (f)
831089Sbill 			dooutput();
846318Swnj 		else
856318Swnj 			doshell();
861089Sbill 	}
876318Swnj 	doinput();
881089Sbill }
891089Sbill 
901089Sbill doinput()
911089Sbill {
926318Swnj 	char ibuf[BUFSIZ];
936318Swnj 	int cc;
941089Sbill 
956318Swnj 	(void) fclose(fscript);
966318Swnj 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
976318Swnj 		(void) write(master, ibuf, cc);
986318Swnj 	done();
996318Swnj }
1001089Sbill 
10113621Ssam #include <sys/wait.h>
1021089Sbill 
1036318Swnj finish()
1046318Swnj {
1056318Swnj 	union wait status;
1061089Sbill 
1076318Swnj 	if (wait3(&status, WNOHANG, 0) != child)
1086318Swnj 		return;
1091089Sbill 	done();
1101089Sbill }
1111089Sbill 
1121089Sbill dooutput()
1131089Sbill {
1146318Swnj 	time_t tvec;
1156318Swnj 	char obuf[BUFSIZ];
1166318Swnj 	int cc;
1171089Sbill 
1186318Swnj 	(void) close(0);
1196318Swnj 	tvec = time((time_t *)0);
1206318Swnj 	fprintf(fscript, "Script started on %s", ctime(&tvec));
1216318Swnj 	for (;;) {
1226318Swnj 		cc = read(master, obuf, sizeof (obuf));
1236318Swnj 		if (cc <= 0)
1246318Swnj 			break;
1256318Swnj 		(void) write(1, obuf, cc);
1266318Swnj 		(void) fwrite(obuf, 1, cc, fscript);
1271089Sbill 	}
1286318Swnj 	tvec = time((time_t *)0);
1296318Swnj 	fprintf(fscript,"\nscript done on %s", ctime(&tvec));
1306318Swnj 	(void) fclose(fscript);
1316318Swnj 	(void) close(master);
1321089Sbill 	exit(0);
1331089Sbill }
1341089Sbill 
1351089Sbill doshell()
1361089Sbill {
1376318Swnj 	int t;
1381089Sbill 
13917589Ssam 	t = open("/dev/tty", O_RDWR);
1406318Swnj 	if (t >= 0) {
1416318Swnj 		ioctl(t, TIOCNOTTY, (char *)0);
1426318Swnj 		(void) close(t);
1436318Swnj 	}
1446318Swnj 	getslave();
1456318Swnj 	(void) close(master);
1466318Swnj 	(void) fclose(fscript);
1476318Swnj 	dup2(slave, 0);
1486318Swnj 	dup2(slave, 1);
1496318Swnj 	dup2(slave, 2);
1506318Swnj 	(void) close(slave);
1511089Sbill 	execl(shell, "sh", "-i", 0);
1526318Swnj 	perror(shell);
1531089Sbill 	fail();
1541089Sbill }
1551089Sbill 
1561089Sbill fixtty()
1571089Sbill {
1586318Swnj 	struct sgttyb sbuf;
1591089Sbill 
1606318Swnj 	sbuf = b;
1616318Swnj 	sbuf.sg_flags |= RAW;
1626318Swnj 	sbuf.sg_flags &= ~ECHO;
1636318Swnj 	ioctl(0, TIOCSETP, (char *)&sbuf);
1641089Sbill }
1651089Sbill 
1661089Sbill fail()
1671089Sbill {
1681089Sbill 
1696318Swnj 	(void) kill(0, SIGTERM);
1701089Sbill 	done();
1711089Sbill }
1721089Sbill 
1731089Sbill done()
1741089Sbill {
1751089Sbill 
1766318Swnj 	ioctl(0, TIOCSETP, (char *)&b);
1776318Swnj 	printf("Script done, file is %s\n", fname);
1786318Swnj 	exit(0);
1791089Sbill }
1801089Sbill 
1816318Swnj getmaster()
1826318Swnj {
18317589Ssam 	char *pty, *bank, *cp;
1846318Swnj 	struct stat stb;
1856318Swnj 	int i;
1866318Swnj 
18717589Ssam 	pty = &line[strlen("/dev/ptyp")];
18817589Ssam 	for (bank = "pqrs"; *bank; bank++) {
18917589Ssam 		line[strlen("/dev/pty")] = *bank;
19017589Ssam 		*pty = '0';
1916318Swnj 		if (stat(line, &stb) < 0)
1926318Swnj 			break;
19317589Ssam 		for (cp = "0123456789abcdef"; *cp; cp++) {
19417589Ssam 			*pty = *cp;
19517589Ssam 			master = open(line, O_RDWR);
1966318Swnj 			if (master >= 0) {
19717589Ssam 				char *tp = &line[strlen("/dev/")];
19817589Ssam 				int ok;
19917589Ssam 
20017589Ssam 				/* verify slave side is usable */
20117589Ssam 				*tp = 't';
20217589Ssam 				ok = access(line, R_OK|W_OK) == 0;
20317589Ssam 				*tp = 'p';
20417589Ssam 				if (ok) {
20517589Ssam 					ioctl(0, TIOCGETP, (char *)&b);
20617589Ssam 					ioctl(0, TIOCGETC, (char *)&tc);
20717589Ssam 					ioctl(0, TIOCGETD, (char *)&l);
20817589Ssam 					ioctl(0, TIOCGLTC, (char *)&lc);
20917589Ssam 					ioctl(0, TIOCLGET, (char *)&lb);
210*18029Sbloom 					ioctl(0, TIOCGWINSZ, (char *)&win);
21117589Ssam 					return;
21217589Ssam 				}
21317589Ssam 				close(master);
2146318Swnj 			}
2156318Swnj 		}
2166318Swnj 	}
2176318Swnj 	fprintf(stderr, "Out of pty's\n");
2186318Swnj 	fail();
2191089Sbill }
2201089Sbill 
2216318Swnj getslave()
2221089Sbill {
2236318Swnj 
2246318Swnj 	line[strlen("/dev/")] = 't';
22517589Ssam 	slave = open(line, O_RDWR);
2266318Swnj 	if (slave < 0) {
2276318Swnj 		perror(line);
2286318Swnj 		fail();
2291089Sbill 	}
2306318Swnj 	ioctl(slave, TIOCSETP, (char *)&b);
2316318Swnj 	ioctl(slave, TIOCSETC, (char *)&tc);
2326318Swnj 	ioctl(slave, TIOCSLTC, (char *)&lc);
2336318Swnj 	ioctl(slave, TIOCLSET, (char *)&lb);
2346318Swnj 	ioctl(slave, TIOCSETD, (char *)&l);
235*18029Sbloom 	ioctl(slave, TIOCSWINSZ, (char *)&win);
2361089Sbill }
237