xref: /csrg-svn/usr.bin/script/script.c (revision 25473)
121575Sdist /*
221575Sdist  * Copyright (c) 1980 Regents of the University of California.
321575Sdist  * All rights reserved.  The Berkeley software License Agreement
421575Sdist  * specifies the terms and conditions for redistribution.
521575Sdist  */
621575Sdist 
76318Swnj #ifndef lint
821575Sdist char copyright[] =
921575Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\
1021575Sdist  All rights reserved.\n";
1121575Sdist #endif not lint
1212990Ssam 
1321575Sdist #ifndef lint
14*25473Sserge static char sccsid[] = "@(#)script.c	5.4 (Berkeley) 11/13/85";
1521575Sdist #endif not lint
1621575Sdist 
171089Sbill /*
186318Swnj  * script
191089Sbill  */
206318Swnj #include <stdio.h>
216318Swnj #include <signal.h>
226318Swnj #include <sys/types.h>
236318Swnj #include <sys/stat.h>
246318Swnj #include <sys/ioctl.h>
256318Swnj #include <sgtty.h>
2613621Ssam #include <sys/time.h>
2717589Ssam #include <sys/file.h>
281089Sbill 
296318Swnj char	*getenv();
306318Swnj char	*ctime();
316318Swnj char	*shell;
326318Swnj FILE	*fscript;
336318Swnj int	master;
346318Swnj int	slave;
356318Swnj int	child;
3624450Sbloom int	subchild;
376318Swnj char	*fname = "typescript";
386318Swnj int	finish();
391089Sbill 
406318Swnj struct	sgttyb b;
416318Swnj struct	tchars tc;
426318Swnj struct	ltchars lc;
4318029Sbloom struct	winsize win;
446318Swnj int	lb;
456318Swnj int	l;
466318Swnj char	*line = "/dev/ptyXX";
476318Swnj int	aflg;
481089Sbill 
496318Swnj main(argc, argv)
506318Swnj 	int argc;
516318Swnj 	char *argv[];
526318Swnj {
531089Sbill 
541089Sbill 	shell = getenv("SHELL");
556318Swnj 	if (shell == 0)
566318Swnj 		shell = "/bin/sh";
576318Swnj 	argc--, argv++;
586318Swnj 	while (argc > 0 && argv[0][0] == '-') {
596318Swnj 		switch (argv[0][1]) {
601089Sbill 
616318Swnj 		case 'a':
626318Swnj 			aflg++;
636318Swnj 			break;
641089Sbill 
656318Swnj 		default:
666318Swnj 			fprintf(stderr,
676318Swnj 			    "usage: script [ -a ] [ typescript ]\n");
686318Swnj 			exit(1);
691089Sbill 		}
706318Swnj 		argc--, argv++;
711089Sbill 	}
726318Swnj 	if (argc > 0)
736318Swnj 		fname = argv[0];
746318Swnj 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
756318Swnj 		perror(fname);
761089Sbill 		fail();
771089Sbill 	}
786318Swnj 	getmaster();
796318Swnj 	printf("Script started, file is %s\n", fname);
806318Swnj 	fixtty();
811089Sbill 
826318Swnj 	(void) signal(SIGCHLD, finish);
836318Swnj 	child = fork();
846318Swnj 	if (child < 0) {
856318Swnj 		perror("fork");
866318Swnj 		fail();
871089Sbill 	}
886318Swnj 	if (child == 0) {
8924450Sbloom 		subchild = child = fork();
9024450Sbloom 		if (child < 0) {
916318Swnj 			perror("fork");
926318Swnj 			fail();
936318Swnj 		}
9424450Sbloom 		if (child)
951089Sbill 			dooutput();
966318Swnj 		else
976318Swnj 			doshell();
981089Sbill 	}
996318Swnj 	doinput();
1001089Sbill }
1011089Sbill 
1021089Sbill doinput()
1031089Sbill {
1046318Swnj 	char ibuf[BUFSIZ];
1056318Swnj 	int cc;
1061089Sbill 
1076318Swnj 	(void) fclose(fscript);
1086318Swnj 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
1096318Swnj 		(void) write(master, ibuf, cc);
1106318Swnj 	done();
1116318Swnj }
1121089Sbill 
11313621Ssam #include <sys/wait.h>
1141089Sbill 
1156318Swnj finish()
1166318Swnj {
1176318Swnj 	union wait status;
11824450Sbloom 	register int pid;
11924450Sbloom 	register int die = 0;
1201089Sbill 
12124450Sbloom 	while ((pid = wait3(&status, WNOHANG, 0)) > 0)
12224450Sbloom 		if (pid == child)
12324450Sbloom 			die = 1;
12424450Sbloom 
12524450Sbloom 	if (die)
12624450Sbloom 		done();
1271089Sbill }
1281089Sbill 
1291089Sbill dooutput()
1301089Sbill {
1316318Swnj 	time_t tvec;
1326318Swnj 	char obuf[BUFSIZ];
1336318Swnj 	int cc;
1341089Sbill 
1356318Swnj 	(void) close(0);
1366318Swnj 	tvec = time((time_t *)0);
1376318Swnj 	fprintf(fscript, "Script started on %s", ctime(&tvec));
1386318Swnj 	for (;;) {
1396318Swnj 		cc = read(master, obuf, sizeof (obuf));
1406318Swnj 		if (cc <= 0)
1416318Swnj 			break;
1426318Swnj 		(void) write(1, obuf, cc);
1436318Swnj 		(void) fwrite(obuf, 1, cc, fscript);
1441089Sbill 	}
145*25473Sserge 	done();
1461089Sbill }
1471089Sbill 
1481089Sbill doshell()
1491089Sbill {
1506318Swnj 	int t;
1511089Sbill 
15217589Ssam 	t = open("/dev/tty", O_RDWR);
1536318Swnj 	if (t >= 0) {
15424451Sbloom 		(void) ioctl(t, TIOCNOTTY, (char *)0);
1556318Swnj 		(void) close(t);
1566318Swnj 	}
1576318Swnj 	getslave();
1586318Swnj 	(void) close(master);
1596318Swnj 	(void) fclose(fscript);
16024451Sbloom 	(void) dup2(slave, 0);
16124451Sbloom 	(void) dup2(slave, 1);
16224451Sbloom 	(void) dup2(slave, 2);
1636318Swnj 	(void) close(slave);
1641089Sbill 	execl(shell, "sh", "-i", 0);
1656318Swnj 	perror(shell);
1661089Sbill 	fail();
1671089Sbill }
1681089Sbill 
1691089Sbill fixtty()
1701089Sbill {
1716318Swnj 	struct sgttyb sbuf;
1721089Sbill 
1736318Swnj 	sbuf = b;
1746318Swnj 	sbuf.sg_flags |= RAW;
1756318Swnj 	sbuf.sg_flags &= ~ECHO;
17624451Sbloom 	(void) ioctl(0, TIOCSETP, (char *)&sbuf);
1771089Sbill }
1781089Sbill 
1791089Sbill fail()
1801089Sbill {
1811089Sbill 
1826318Swnj 	(void) kill(0, SIGTERM);
1831089Sbill 	done();
1841089Sbill }
1851089Sbill 
1861089Sbill done()
1871089Sbill {
188*25473Sserge 	time_t tvec;
1891089Sbill 
190*25473Sserge 	if (subchild) {
191*25473Sserge 		tvec = time((time_t *)0);
192*25473Sserge 		fprintf(fscript,"\nscript done on %s", ctime(&tvec));
193*25473Sserge 		(void) fclose(fscript);
194*25473Sserge 		(void) close(master);
195*25473Sserge 	} else {
19624451Sbloom 		(void) ioctl(0, TIOCSETP, (char *)&b);
19724450Sbloom 		printf("Script done, file is %s\n", fname);
19824450Sbloom 	}
1996318Swnj 	exit(0);
2001089Sbill }
2011089Sbill 
2026318Swnj getmaster()
2036318Swnj {
20417589Ssam 	char *pty, *bank, *cp;
2056318Swnj 	struct stat stb;
2066318Swnj 
20717589Ssam 	pty = &line[strlen("/dev/ptyp")];
20817589Ssam 	for (bank = "pqrs"; *bank; bank++) {
20917589Ssam 		line[strlen("/dev/pty")] = *bank;
21017589Ssam 		*pty = '0';
2116318Swnj 		if (stat(line, &stb) < 0)
2126318Swnj 			break;
21317589Ssam 		for (cp = "0123456789abcdef"; *cp; cp++) {
21417589Ssam 			*pty = *cp;
21517589Ssam 			master = open(line, O_RDWR);
2166318Swnj 			if (master >= 0) {
21717589Ssam 				char *tp = &line[strlen("/dev/")];
21817589Ssam 				int ok;
21917589Ssam 
22017589Ssam 				/* verify slave side is usable */
22117589Ssam 				*tp = 't';
22217589Ssam 				ok = access(line, R_OK|W_OK) == 0;
22317589Ssam 				*tp = 'p';
22417589Ssam 				if (ok) {
22524451Sbloom 				    (void) ioctl(0, TIOCGETP, (char *)&b);
22624451Sbloom 				    (void) ioctl(0, TIOCGETC, (char *)&tc);
22724451Sbloom 				    (void) ioctl(0, TIOCGETD, (char *)&l);
22824451Sbloom 				    (void) ioctl(0, TIOCGLTC, (char *)&lc);
22924451Sbloom 				    (void) ioctl(0, TIOCLGET, (char *)&lb);
23024451Sbloom 				    (void) ioctl(0, TIOCGWINSZ, (char *)&win);
23117589Ssam 					return;
23217589Ssam 				}
23324451Sbloom 				(void) close(master);
2346318Swnj 			}
2356318Swnj 		}
2366318Swnj 	}
2376318Swnj 	fprintf(stderr, "Out of pty's\n");
2386318Swnj 	fail();
2391089Sbill }
2401089Sbill 
2416318Swnj getslave()
2421089Sbill {
2436318Swnj 
2446318Swnj 	line[strlen("/dev/")] = 't';
24517589Ssam 	slave = open(line, O_RDWR);
2466318Swnj 	if (slave < 0) {
2476318Swnj 		perror(line);
2486318Swnj 		fail();
2491089Sbill 	}
25024451Sbloom 	(void) ioctl(slave, TIOCSETP, (char *)&b);
25124451Sbloom 	(void) ioctl(slave, TIOCSETC, (char *)&tc);
25224451Sbloom 	(void) ioctl(slave, TIOCSLTC, (char *)&lc);
25324451Sbloom 	(void) ioctl(slave, TIOCLSET, (char *)&lb);
25424451Sbloom 	(void) ioctl(slave, TIOCSETD, (char *)&l);
25524451Sbloom 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
2561089Sbill }
257