xref: /csrg-svn/usr.bin/script/script.c (revision 34628)
121575Sdist /*
221575Sdist  * Copyright (c) 1980 Regents of the University of California.
3*34628Sbostic  * All rights reserved.
4*34628Sbostic  *
5*34628Sbostic  * Redistribution and use in source and binary forms are permitted
6*34628Sbostic  * provided that this notice is preserved and that due credit is given
7*34628Sbostic  * to the University of California at Berkeley. The name of the University
8*34628Sbostic  * may not be used to endorse or promote products derived from this
9*34628Sbostic  * software without specific prior written permission. This software
10*34628Sbostic  * is provided ``as is'' without express or implied warranty.
1121575Sdist  */
1221575Sdist 
136318Swnj #ifndef lint
1421575Sdist char copyright[] =
1521575Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\
1621575Sdist  All rights reserved.\n";
17*34628Sbostic #endif /* not lint */
1812990Ssam 
1921575Sdist #ifndef lint
20*34628Sbostic static char sccsid[] = "@(#)script.c	5.5 (Berkeley) 06/03/88";
21*34628Sbostic #endif /* not lint */
2221575Sdist 
231089Sbill /*
246318Swnj  * script
251089Sbill  */
266318Swnj #include <sys/types.h>
276318Swnj #include <sys/stat.h>
286318Swnj #include <sys/ioctl.h>
2913621Ssam #include <sys/time.h>
3017589Ssam #include <sys/file.h>
31*34628Sbostic #include <stdio.h>
32*34628Sbostic #include <signal.h>
331089Sbill 
346318Swnj char	*shell;
356318Swnj FILE	*fscript;
366318Swnj int	master;
376318Swnj int	slave;
386318Swnj int	child;
3924450Sbloom int	subchild;
40*34628Sbostic char	*fname;
411089Sbill 
426318Swnj struct	sgttyb b;
436318Swnj struct	tchars tc;
446318Swnj struct	ltchars lc;
4518029Sbloom struct	winsize win;
466318Swnj int	lb;
476318Swnj int	l;
486318Swnj char	*line = "/dev/ptyXX";
496318Swnj int	aflg;
501089Sbill 
516318Swnj main(argc, argv)
526318Swnj 	int argc;
536318Swnj 	char *argv[];
546318Swnj {
55*34628Sbostic 	extern char *optarg;
56*34628Sbostic 	extern int optind;
57*34628Sbostic 	int ch;
58*34628Sbostic 	int finish();
59*34628Sbostic 	char *getenv();
601089Sbill 
61*34628Sbostic 	while ((ch = getopt(argc, argv, "a")) != EOF)
62*34628Sbostic 		switch((char)ch) {
636318Swnj 		case 'a':
646318Swnj 			aflg++;
656318Swnj 			break;
66*34628Sbostic 		case '?':
676318Swnj 		default:
68*34628Sbostic 			fprintf(stderr, "usage: script [-a] [file]\n");
696318Swnj 			exit(1);
701089Sbill 		}
71*34628Sbostic 	argc -= optind;
72*34628Sbostic 	argv += optind;
73*34628Sbostic 
746318Swnj 	if (argc > 0)
756318Swnj 		fname = argv[0];
76*34628Sbostic 	else
77*34628Sbostic 		fname = "typescript";
786318Swnj 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
796318Swnj 		perror(fname);
801089Sbill 		fail();
811089Sbill 	}
82*34628Sbostic 
83*34628Sbostic 	shell = getenv("SHELL");
84*34628Sbostic 	if (shell == NULL)
85*34628Sbostic 		shell = "/bin/sh";
86*34628Sbostic 
876318Swnj 	getmaster();
886318Swnj 	printf("Script started, file is %s\n", fname);
896318Swnj 	fixtty();
901089Sbill 
916318Swnj 	(void) signal(SIGCHLD, finish);
926318Swnj 	child = fork();
936318Swnj 	if (child < 0) {
946318Swnj 		perror("fork");
956318Swnj 		fail();
961089Sbill 	}
976318Swnj 	if (child == 0) {
9824450Sbloom 		subchild = child = fork();
9924450Sbloom 		if (child < 0) {
1006318Swnj 			perror("fork");
1016318Swnj 			fail();
1026318Swnj 		}
10324450Sbloom 		if (child)
1041089Sbill 			dooutput();
1056318Swnj 		else
1066318Swnj 			doshell();
1071089Sbill 	}
1086318Swnj 	doinput();
1091089Sbill }
1101089Sbill 
1111089Sbill doinput()
1121089Sbill {
113*34628Sbostic 	register int cc;
1146318Swnj 	char ibuf[BUFSIZ];
1151089Sbill 
1166318Swnj 	(void) fclose(fscript);
1176318Swnj 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
1186318Swnj 		(void) write(master, ibuf, cc);
1196318Swnj 	done();
1206318Swnj }
1211089Sbill 
12213621Ssam #include <sys/wait.h>
1231089Sbill 
1246318Swnj finish()
1256318Swnj {
1266318Swnj 	union wait status;
12724450Sbloom 	register int pid;
12824450Sbloom 	register int die = 0;
1291089Sbill 
13024450Sbloom 	while ((pid = wait3(&status, WNOHANG, 0)) > 0)
13124450Sbloom 		if (pid == child)
13224450Sbloom 			die = 1;
13324450Sbloom 
13424450Sbloom 	if (die)
13524450Sbloom 		done();
1361089Sbill }
1371089Sbill 
1381089Sbill dooutput()
1391089Sbill {
140*34628Sbostic 	register int cc;
141*34628Sbostic 	time_t tvec, time();
142*34628Sbostic 	char obuf[BUFSIZ], *ctime();
1431089Sbill 
1446318Swnj 	(void) close(0);
145*34628Sbostic 	tvec = time((time_t *)NULL);
1466318Swnj 	fprintf(fscript, "Script started on %s", ctime(&tvec));
1476318Swnj 	for (;;) {
1486318Swnj 		cc = read(master, obuf, sizeof (obuf));
1496318Swnj 		if (cc <= 0)
1506318Swnj 			break;
1516318Swnj 		(void) write(1, obuf, cc);
1526318Swnj 		(void) fwrite(obuf, 1, cc, fscript);
1531089Sbill 	}
15425473Sserge 	done();
1551089Sbill }
1561089Sbill 
1571089Sbill doshell()
1581089Sbill {
1596318Swnj 	int t;
1601089Sbill 
16117589Ssam 	t = open("/dev/tty", O_RDWR);
1626318Swnj 	if (t >= 0) {
16324451Sbloom 		(void) ioctl(t, TIOCNOTTY, (char *)0);
1646318Swnj 		(void) close(t);
1656318Swnj 	}
1666318Swnj 	getslave();
1676318Swnj 	(void) close(master);
1686318Swnj 	(void) fclose(fscript);
16924451Sbloom 	(void) dup2(slave, 0);
17024451Sbloom 	(void) dup2(slave, 1);
17124451Sbloom 	(void) dup2(slave, 2);
1726318Swnj 	(void) close(slave);
1731089Sbill 	execl(shell, "sh", "-i", 0);
1746318Swnj 	perror(shell);
1751089Sbill 	fail();
1761089Sbill }
1771089Sbill 
1781089Sbill fixtty()
1791089Sbill {
1806318Swnj 	struct sgttyb sbuf;
1811089Sbill 
1826318Swnj 	sbuf = b;
1836318Swnj 	sbuf.sg_flags |= RAW;
1846318Swnj 	sbuf.sg_flags &= ~ECHO;
18524451Sbloom 	(void) ioctl(0, TIOCSETP, (char *)&sbuf);
1861089Sbill }
1871089Sbill 
1881089Sbill fail()
1891089Sbill {
1901089Sbill 
1916318Swnj 	(void) kill(0, SIGTERM);
1921089Sbill 	done();
1931089Sbill }
1941089Sbill 
1951089Sbill done()
1961089Sbill {
197*34628Sbostic 	time_t tvec, time();
198*34628Sbostic 	char *ctime();
1991089Sbill 
20025473Sserge 	if (subchild) {
201*34628Sbostic 		tvec = time((time_t *)NULL);
20225473Sserge 		fprintf(fscript,"\nscript done on %s", ctime(&tvec));
20325473Sserge 		(void) fclose(fscript);
20425473Sserge 		(void) close(master);
20525473Sserge 	} else {
20624451Sbloom 		(void) ioctl(0, TIOCSETP, (char *)&b);
20724450Sbloom 		printf("Script done, file is %s\n", fname);
20824450Sbloom 	}
2096318Swnj 	exit(0);
2101089Sbill }
2111089Sbill 
2126318Swnj getmaster()
2136318Swnj {
21417589Ssam 	char *pty, *bank, *cp;
2156318Swnj 	struct stat stb;
2166318Swnj 
21717589Ssam 	pty = &line[strlen("/dev/ptyp")];
21817589Ssam 	for (bank = "pqrs"; *bank; bank++) {
21917589Ssam 		line[strlen("/dev/pty")] = *bank;
22017589Ssam 		*pty = '0';
2216318Swnj 		if (stat(line, &stb) < 0)
2226318Swnj 			break;
22317589Ssam 		for (cp = "0123456789abcdef"; *cp; cp++) {
22417589Ssam 			*pty = *cp;
22517589Ssam 			master = open(line, O_RDWR);
2266318Swnj 			if (master >= 0) {
22717589Ssam 				char *tp = &line[strlen("/dev/")];
22817589Ssam 				int ok;
22917589Ssam 
23017589Ssam 				/* verify slave side is usable */
23117589Ssam 				*tp = 't';
23217589Ssam 				ok = access(line, R_OK|W_OK) == 0;
23317589Ssam 				*tp = 'p';
23417589Ssam 				if (ok) {
23524451Sbloom 				    (void) ioctl(0, TIOCGETP, (char *)&b);
23624451Sbloom 				    (void) ioctl(0, TIOCGETC, (char *)&tc);
23724451Sbloom 				    (void) ioctl(0, TIOCGETD, (char *)&l);
23824451Sbloom 				    (void) ioctl(0, TIOCGLTC, (char *)&lc);
23924451Sbloom 				    (void) ioctl(0, TIOCLGET, (char *)&lb);
24024451Sbloom 				    (void) ioctl(0, TIOCGWINSZ, (char *)&win);
24117589Ssam 					return;
24217589Ssam 				}
24324451Sbloom 				(void) close(master);
2446318Swnj 			}
2456318Swnj 		}
2466318Swnj 	}
2476318Swnj 	fprintf(stderr, "Out of pty's\n");
2486318Swnj 	fail();
2491089Sbill }
2501089Sbill 
2516318Swnj getslave()
2521089Sbill {
2536318Swnj 
2546318Swnj 	line[strlen("/dev/")] = 't';
25517589Ssam 	slave = open(line, O_RDWR);
2566318Swnj 	if (slave < 0) {
2576318Swnj 		perror(line);
2586318Swnj 		fail();
2591089Sbill 	}
26024451Sbloom 	(void) ioctl(slave, TIOCSETP, (char *)&b);
26124451Sbloom 	(void) ioctl(slave, TIOCSETC, (char *)&tc);
26224451Sbloom 	(void) ioctl(slave, TIOCSLTC, (char *)&lc);
26324451Sbloom 	(void) ioctl(slave, TIOCLSET, (char *)&lb);
26424451Sbloom 	(void) ioctl(slave, TIOCSETD, (char *)&l);
26524451Sbloom 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
2661089Sbill }
267