xref: /csrg-svn/usr.bin/script/script.c (revision 46853)
121575Sdist /*
221575Sdist  * Copyright (c) 1980 Regents of the University of California.
334628Sbostic  * All rights reserved.
434628Sbostic  *
542765Sbostic  * %sccs.include.redist.c%
621575Sdist  */
721575Sdist 
86318Swnj #ifndef lint
921575Sdist char copyright[] =
1021575Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\
1121575Sdist  All rights reserved.\n";
1234628Sbostic #endif /* not lint */
1312990Ssam 
1421575Sdist #ifndef lint
15*46853Sbostic static char sccsid[] = "@(#)script.c	5.12 (Berkeley) 03/01/91";
1634628Sbostic #endif /* not lint */
1721575Sdist 
181089Sbill /*
196318Swnj  * script
201089Sbill  */
216318Swnj #include <sys/types.h>
226318Swnj #include <sys/stat.h>
2337141Smarc #include <termios.h>
246318Swnj #include <sys/ioctl.h>
2513621Ssam #include <sys/time.h>
2617589Ssam #include <sys/file.h>
2737874Sbostic #include <sys/signal.h>
2834628Sbostic #include <stdio.h>
2937874Sbostic #include <paths.h>
301089Sbill 
316318Swnj char	*shell;
326318Swnj FILE	*fscript;
336318Swnj int	master;
346318Swnj int	slave;
356318Swnj int	child;
3624450Sbloom int	subchild;
3734628Sbostic char	*fname;
381089Sbill 
3937141Smarc struct	termios tt;
4018029Sbloom struct	winsize win;
416318Swnj int	lb;
426318Swnj int	l;
436318Swnj char	*line = "/dev/ptyXX";
446318Swnj int	aflg;
451089Sbill 
466318Swnj main(argc, argv)
476318Swnj 	int argc;
486318Swnj 	char *argv[];
496318Swnj {
5034628Sbostic 	extern char *optarg;
5134628Sbostic 	extern int optind;
5234628Sbostic 	int ch;
53*46853Sbostic 	void finish();
5434628Sbostic 	char *getenv();
551089Sbill 
5634628Sbostic 	while ((ch = getopt(argc, argv, "a")) != EOF)
5734628Sbostic 		switch((char)ch) {
586318Swnj 		case 'a':
596318Swnj 			aflg++;
606318Swnj 			break;
6134628Sbostic 		case '?':
626318Swnj 		default:
6334628Sbostic 			fprintf(stderr, "usage: script [-a] [file]\n");
646318Swnj 			exit(1);
651089Sbill 		}
6634628Sbostic 	argc -= optind;
6734628Sbostic 	argv += optind;
6834628Sbostic 
696318Swnj 	if (argc > 0)
706318Swnj 		fname = argv[0];
7134628Sbostic 	else
7234628Sbostic 		fname = "typescript";
736318Swnj 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
746318Swnj 		perror(fname);
751089Sbill 		fail();
761089Sbill 	}
7734628Sbostic 
7834628Sbostic 	shell = getenv("SHELL");
7934628Sbostic 	if (shell == NULL)
8037874Sbostic 		shell = _PATH_BSHELL;
8134628Sbostic 
826318Swnj 	getmaster();
836318Swnj 	printf("Script started, file is %s\n", fname);
846318Swnj 	fixtty();
851089Sbill 
866318Swnj 	(void) signal(SIGCHLD, finish);
876318Swnj 	child = fork();
886318Swnj 	if (child < 0) {
896318Swnj 		perror("fork");
906318Swnj 		fail();
911089Sbill 	}
926318Swnj 	if (child == 0) {
9324450Sbloom 		subchild = child = fork();
9424450Sbloom 		if (child < 0) {
956318Swnj 			perror("fork");
966318Swnj 			fail();
976318Swnj 		}
9824450Sbloom 		if (child)
991089Sbill 			dooutput();
1006318Swnj 		else
1016318Swnj 			doshell();
1021089Sbill 	}
1036318Swnj 	doinput();
1041089Sbill }
1051089Sbill 
1061089Sbill doinput()
1071089Sbill {
10834628Sbostic 	register int cc;
1096318Swnj 	char ibuf[BUFSIZ];
1101089Sbill 
1116318Swnj 	(void) fclose(fscript);
1126318Swnj 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
1136318Swnj 		(void) write(master, ibuf, cc);
1146318Swnj 	done();
1156318Swnj }
1161089Sbill 
11713621Ssam #include <sys/wait.h>
1181089Sbill 
119*46853Sbostic void
1206318Swnj finish()
1216318Swnj {
1226318Swnj 	union wait status;
12324450Sbloom 	register int pid;
12424450Sbloom 	register int die = 0;
1251089Sbill 
126*46853Sbostic 	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
12724450Sbloom 		if (pid == child)
12824450Sbloom 			die = 1;
12924450Sbloom 
13024450Sbloom 	if (die)
13124450Sbloom 		done();
1321089Sbill }
1331089Sbill 
1341089Sbill dooutput()
1351089Sbill {
13634628Sbostic 	register int cc;
13734628Sbostic 	time_t tvec, time();
13834628Sbostic 	char obuf[BUFSIZ], *ctime();
1391089Sbill 
1406318Swnj 	(void) close(0);
14134628Sbostic 	tvec = time((time_t *)NULL);
1426318Swnj 	fprintf(fscript, "Script started on %s", ctime(&tvec));
1436318Swnj 	for (;;) {
1446318Swnj 		cc = read(master, obuf, sizeof (obuf));
1456318Swnj 		if (cc <= 0)
1466318Swnj 			break;
1476318Swnj 		(void) write(1, obuf, cc);
1486318Swnj 		(void) fwrite(obuf, 1, cc, fscript);
1491089Sbill 	}
15025473Sserge 	done();
1511089Sbill }
1521089Sbill 
1531089Sbill doshell()
1541089Sbill {
1556318Swnj 	int t;
1561089Sbill 
15737141Smarc 	/***
15837874Sbostic 	t = open(_PATH_TTY, O_RDWR);
1596318Swnj 	if (t >= 0) {
16024451Sbloom 		(void) ioctl(t, TIOCNOTTY, (char *)0);
1616318Swnj 		(void) close(t);
1626318Swnj 	}
16337141Smarc 	***/
1646318Swnj 	getslave();
1656318Swnj 	(void) close(master);
1666318Swnj 	(void) fclose(fscript);
16724451Sbloom 	(void) dup2(slave, 0);
16824451Sbloom 	(void) dup2(slave, 1);
16924451Sbloom 	(void) dup2(slave, 2);
1706318Swnj 	(void) close(slave);
1711089Sbill 	execl(shell, "sh", "-i", 0);
1726318Swnj 	perror(shell);
1731089Sbill 	fail();
1741089Sbill }
1751089Sbill 
1761089Sbill fixtty()
1771089Sbill {
17837141Smarc 	struct termios rtt;
1791089Sbill 
18037141Smarc 	rtt = tt;
18137141Smarc 	cfmakeraw(&rtt);
18237141Smarc 	rtt.c_lflag &= ~ECHO;
18343236Sbostic 	(void) tcsetattr(0, TCSAFLUSH, &rtt);
1841089Sbill }
1851089Sbill 
1861089Sbill fail()
1871089Sbill {
1881089Sbill 
1896318Swnj 	(void) kill(0, SIGTERM);
1901089Sbill 	done();
1911089Sbill }
1921089Sbill 
1931089Sbill done()
1941089Sbill {
19534628Sbostic 	time_t tvec, time();
19634628Sbostic 	char *ctime();
1971089Sbill 
19825473Sserge 	if (subchild) {
19934628Sbostic 		tvec = time((time_t *)NULL);
20038683Sbostic 		fprintf(fscript,"\nScript done on %s", ctime(&tvec));
20125473Sserge 		(void) fclose(fscript);
20225473Sserge 		(void) close(master);
20325473Sserge 	} else {
20443236Sbostic 		(void) tcsetattr(0, TCSAFLUSH, &tt);
20524450Sbloom 		printf("Script done, file is %s\n", fname);
20624450Sbloom 	}
2076318Swnj 	exit(0);
2081089Sbill }
2091089Sbill 
2106318Swnj getmaster()
2116318Swnj {
21217589Ssam 	char *pty, *bank, *cp;
2136318Swnj 	struct stat stb;
2146318Swnj 
21517589Ssam 	pty = &line[strlen("/dev/ptyp")];
21617589Ssam 	for (bank = "pqrs"; *bank; bank++) {
21717589Ssam 		line[strlen("/dev/pty")] = *bank;
21817589Ssam 		*pty = '0';
2196318Swnj 		if (stat(line, &stb) < 0)
2206318Swnj 			break;
22117589Ssam 		for (cp = "0123456789abcdef"; *cp; cp++) {
22217589Ssam 			*pty = *cp;
22317589Ssam 			master = open(line, O_RDWR);
2246318Swnj 			if (master >= 0) {
22517589Ssam 				char *tp = &line[strlen("/dev/")];
22617589Ssam 				int ok;
22717589Ssam 
22817589Ssam 				/* verify slave side is usable */
22917589Ssam 				*tp = 't';
23017589Ssam 				ok = access(line, R_OK|W_OK) == 0;
23117589Ssam 				*tp = 'p';
23217589Ssam 				if (ok) {
23337141Smarc 					(void) tcgetattr(0, &tt);
23437141Smarc 				    	(void) ioctl(0, TIOCGWINSZ,
23537141Smarc 						(char *)&win);
23617589Ssam 					return;
23717589Ssam 				}
23824451Sbloom 				(void) close(master);
2396318Swnj 			}
2406318Swnj 		}
2416318Swnj 	}
2426318Swnj 	fprintf(stderr, "Out of pty's\n");
2436318Swnj 	fail();
2441089Sbill }
2451089Sbill 
2466318Swnj getslave()
2471089Sbill {
2486318Swnj 
2496318Swnj 	line[strlen("/dev/")] = 't';
25017589Ssam 	slave = open(line, O_RDWR);
2516318Swnj 	if (slave < 0) {
2526318Swnj 		perror(line);
2536318Swnj 		fail();
2541089Sbill 	}
25543236Sbostic 	(void) tcsetattr(slave, TCSAFLUSH, &tt);
25624451Sbloom 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
25737141Smarc 	(void) setsid();
25837141Smarc 	(void) ioctl(slave, TIOCSCTTY, 0);
2591089Sbill }
260