xref: /csrg-svn/usr.bin/script/script.c (revision 38683)
121575Sdist /*
221575Sdist  * Copyright (c) 1980 Regents of the University of California.
334628Sbostic  * All rights reserved.
434628Sbostic  *
534628Sbostic  * Redistribution and use in source and binary forms are permitted
634911Sbostic  * provided that the above copyright notice and this paragraph are
734911Sbostic  * duplicated in all such forms and that any documentation,
834911Sbostic  * advertising materials, and other materials related to such
934911Sbostic  * distribution and use acknowledge that the software was developed
1034911Sbostic  * by the University of California, Berkeley.  The name of the
1134911Sbostic  * University may not be used to endorse or promote products derived
1234911Sbostic  * from this software without specific prior written permission.
1334911Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1434911Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1534911Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1621575Sdist  */
1721575Sdist 
186318Swnj #ifndef lint
1921575Sdist char copyright[] =
2021575Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\
2121575Sdist  All rights reserved.\n";
2234628Sbostic #endif /* not lint */
2312990Ssam 
2421575Sdist #ifndef lint
25*38683Sbostic static char sccsid[] = "@(#)script.c	5.9 (Berkeley) 08/21/89";
2634628Sbostic #endif /* not lint */
2721575Sdist 
281089Sbill /*
296318Swnj  * script
301089Sbill  */
316318Swnj #include <sys/types.h>
326318Swnj #include <sys/stat.h>
3337141Smarc #include <termios.h>
346318Swnj #include <sys/ioctl.h>
3513621Ssam #include <sys/time.h>
3617589Ssam #include <sys/file.h>
3737874Sbostic #include <sys/signal.h>
3834628Sbostic #include <stdio.h>
3937874Sbostic #include <paths.h>
401089Sbill 
416318Swnj char	*shell;
426318Swnj FILE	*fscript;
436318Swnj int	master;
446318Swnj int	slave;
456318Swnj int	child;
4624450Sbloom int	subchild;
4734628Sbostic char	*fname;
481089Sbill 
4937141Smarc struct	termios tt;
5018029Sbloom struct	winsize win;
516318Swnj int	lb;
526318Swnj int	l;
536318Swnj char	*line = "/dev/ptyXX";
546318Swnj int	aflg;
551089Sbill 
566318Swnj main(argc, argv)
576318Swnj 	int argc;
586318Swnj 	char *argv[];
596318Swnj {
6034628Sbostic 	extern char *optarg;
6134628Sbostic 	extern int optind;
6234628Sbostic 	int ch;
6334628Sbostic 	int finish();
6434628Sbostic 	char *getenv();
651089Sbill 
6634628Sbostic 	while ((ch = getopt(argc, argv, "a")) != EOF)
6734628Sbostic 		switch((char)ch) {
686318Swnj 		case 'a':
696318Swnj 			aflg++;
706318Swnj 			break;
7134628Sbostic 		case '?':
726318Swnj 		default:
7334628Sbostic 			fprintf(stderr, "usage: script [-a] [file]\n");
746318Swnj 			exit(1);
751089Sbill 		}
7634628Sbostic 	argc -= optind;
7734628Sbostic 	argv += optind;
7834628Sbostic 
796318Swnj 	if (argc > 0)
806318Swnj 		fname = argv[0];
8134628Sbostic 	else
8234628Sbostic 		fname = "typescript";
836318Swnj 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
846318Swnj 		perror(fname);
851089Sbill 		fail();
861089Sbill 	}
8734628Sbostic 
8834628Sbostic 	shell = getenv("SHELL");
8934628Sbostic 	if (shell == NULL)
9037874Sbostic 		shell = _PATH_BSHELL;
9134628Sbostic 
926318Swnj 	getmaster();
936318Swnj 	printf("Script started, file is %s\n", fname);
946318Swnj 	fixtty();
951089Sbill 
966318Swnj 	(void) signal(SIGCHLD, finish);
976318Swnj 	child = fork();
986318Swnj 	if (child < 0) {
996318Swnj 		perror("fork");
1006318Swnj 		fail();
1011089Sbill 	}
1026318Swnj 	if (child == 0) {
10324450Sbloom 		subchild = child = fork();
10424450Sbloom 		if (child < 0) {
1056318Swnj 			perror("fork");
1066318Swnj 			fail();
1076318Swnj 		}
10824450Sbloom 		if (child)
1091089Sbill 			dooutput();
1106318Swnj 		else
1116318Swnj 			doshell();
1121089Sbill 	}
1136318Swnj 	doinput();
1141089Sbill }
1151089Sbill 
1161089Sbill doinput()
1171089Sbill {
11834628Sbostic 	register int cc;
1196318Swnj 	char ibuf[BUFSIZ];
1201089Sbill 
1216318Swnj 	(void) fclose(fscript);
1226318Swnj 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
1236318Swnj 		(void) write(master, ibuf, cc);
1246318Swnj 	done();
1256318Swnj }
1261089Sbill 
12713621Ssam #include <sys/wait.h>
1281089Sbill 
1296318Swnj finish()
1306318Swnj {
1316318Swnj 	union wait status;
13224450Sbloom 	register int pid;
13324450Sbloom 	register int die = 0;
1341089Sbill 
13524450Sbloom 	while ((pid = wait3(&status, WNOHANG, 0)) > 0)
13624450Sbloom 		if (pid == child)
13724450Sbloom 			die = 1;
13824450Sbloom 
13924450Sbloom 	if (die)
14024450Sbloom 		done();
1411089Sbill }
1421089Sbill 
1431089Sbill dooutput()
1441089Sbill {
14534628Sbostic 	register int cc;
14634628Sbostic 	time_t tvec, time();
14734628Sbostic 	char obuf[BUFSIZ], *ctime();
1481089Sbill 
1496318Swnj 	(void) close(0);
15034628Sbostic 	tvec = time((time_t *)NULL);
1516318Swnj 	fprintf(fscript, "Script started on %s", ctime(&tvec));
1526318Swnj 	for (;;) {
1536318Swnj 		cc = read(master, obuf, sizeof (obuf));
1546318Swnj 		if (cc <= 0)
1556318Swnj 			break;
1566318Swnj 		(void) write(1, obuf, cc);
1576318Swnj 		(void) fwrite(obuf, 1, cc, fscript);
1581089Sbill 	}
15925473Sserge 	done();
1601089Sbill }
1611089Sbill 
1621089Sbill doshell()
1631089Sbill {
1646318Swnj 	int t;
1651089Sbill 
16637141Smarc 	/***
16737874Sbostic 	t = open(_PATH_TTY, O_RDWR);
1686318Swnj 	if (t >= 0) {
16924451Sbloom 		(void) ioctl(t, TIOCNOTTY, (char *)0);
1706318Swnj 		(void) close(t);
1716318Swnj 	}
17237141Smarc 	***/
1736318Swnj 	getslave();
1746318Swnj 	(void) close(master);
1756318Swnj 	(void) fclose(fscript);
17624451Sbloom 	(void) dup2(slave, 0);
17724451Sbloom 	(void) dup2(slave, 1);
17824451Sbloom 	(void) dup2(slave, 2);
1796318Swnj 	(void) close(slave);
1801089Sbill 	execl(shell, "sh", "-i", 0);
1816318Swnj 	perror(shell);
1821089Sbill 	fail();
1831089Sbill }
1841089Sbill 
1851089Sbill fixtty()
1861089Sbill {
18737141Smarc 	struct termios rtt;
1881089Sbill 
18937141Smarc 	rtt = tt;
19037141Smarc 	cfmakeraw(&rtt);
19137141Smarc 	rtt.c_lflag &= ~ECHO;
19237141Smarc 	(void) tcsetattr(0, TCSADFLUSH, &rtt);
1931089Sbill }
1941089Sbill 
1951089Sbill fail()
1961089Sbill {
1971089Sbill 
1986318Swnj 	(void) kill(0, SIGTERM);
1991089Sbill 	done();
2001089Sbill }
2011089Sbill 
2021089Sbill done()
2031089Sbill {
20434628Sbostic 	time_t tvec, time();
20534628Sbostic 	char *ctime();
2061089Sbill 
20725473Sserge 	if (subchild) {
20834628Sbostic 		tvec = time((time_t *)NULL);
209*38683Sbostic 		fprintf(fscript,"\nScript done on %s", ctime(&tvec));
21025473Sserge 		(void) fclose(fscript);
21125473Sserge 		(void) close(master);
21225473Sserge 	} else {
21337141Smarc 		(void) tcsetattr(0, TCSADFLUSH, &tt);
21424450Sbloom 		printf("Script done, file is %s\n", fname);
21524450Sbloom 	}
2166318Swnj 	exit(0);
2171089Sbill }
2181089Sbill 
2196318Swnj getmaster()
2206318Swnj {
22117589Ssam 	char *pty, *bank, *cp;
2226318Swnj 	struct stat stb;
2236318Swnj 
22417589Ssam 	pty = &line[strlen("/dev/ptyp")];
22517589Ssam 	for (bank = "pqrs"; *bank; bank++) {
22617589Ssam 		line[strlen("/dev/pty")] = *bank;
22717589Ssam 		*pty = '0';
2286318Swnj 		if (stat(line, &stb) < 0)
2296318Swnj 			break;
23017589Ssam 		for (cp = "0123456789abcdef"; *cp; cp++) {
23117589Ssam 			*pty = *cp;
23217589Ssam 			master = open(line, O_RDWR);
2336318Swnj 			if (master >= 0) {
23417589Ssam 				char *tp = &line[strlen("/dev/")];
23517589Ssam 				int ok;
23617589Ssam 
23717589Ssam 				/* verify slave side is usable */
23817589Ssam 				*tp = 't';
23917589Ssam 				ok = access(line, R_OK|W_OK) == 0;
24017589Ssam 				*tp = 'p';
24117589Ssam 				if (ok) {
24237141Smarc 					(void) tcgetattr(0, &tt);
24337141Smarc 				    	(void) ioctl(0, TIOCGWINSZ,
24437141Smarc 						(char *)&win);
24517589Ssam 					return;
24617589Ssam 				}
24724451Sbloom 				(void) close(master);
2486318Swnj 			}
2496318Swnj 		}
2506318Swnj 	}
2516318Swnj 	fprintf(stderr, "Out of pty's\n");
2526318Swnj 	fail();
2531089Sbill }
2541089Sbill 
2556318Swnj getslave()
2561089Sbill {
2576318Swnj 
2586318Swnj 	line[strlen("/dev/")] = 't';
25917589Ssam 	slave = open(line, O_RDWR);
2606318Swnj 	if (slave < 0) {
2616318Swnj 		perror(line);
2626318Swnj 		fail();
2631089Sbill 	}
26437141Smarc 	(void) tcsetattr(slave, TCSADFLUSH, &tt);
26524451Sbloom 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
26637141Smarc 	(void) setsid();
26737141Smarc 	(void) ioctl(slave, TIOCSCTTY, 0);
2681089Sbill }
269