xref: /csrg-svn/usr.bin/script/script.c (revision 62221)
121575Sdist /*
2*62221Sbostic  * Copyright (c) 1980, 1992, 1993
3*62221Sbostic  *	The Regents of the University of California.  All rights reserved.
434628Sbostic  *
542765Sbostic  * %sccs.include.redist.c%
621575Sdist  */
721575Sdist 
86318Swnj #ifndef lint
9*62221Sbostic static char copyright[] =
10*62221Sbostic "@(#) Copyright (c) 1980, 1992, 1993\n\
11*62221Sbostic 	The Regents of the University of California.  All rights reserved.\n";
1234628Sbostic #endif /* not lint */
1312990Ssam 
1421575Sdist #ifndef lint
15*62221Sbostic static char sccsid[] = "@(#)script.c	8.1 (Berkeley) 06/06/93";
1634628Sbostic #endif /* not lint */
1721575Sdist 
186318Swnj #include <sys/types.h>
1956926Sbostic #include <sys/wait.h>
206318Swnj #include <sys/stat.h>
216318Swnj #include <sys/ioctl.h>
2213621Ssam #include <sys/time.h>
2356926Sbostic 
2456926Sbostic #include <errno.h>
2556926Sbostic #include <fcntl.h>
2656926Sbostic #include <paths.h>
2756926Sbostic #include <signal.h>
2834628Sbostic #include <stdio.h>
2956926Sbostic #include <stdlib.h>
3056926Sbostic #include <string.h>
3156926Sbostic #include <termios.h>
3256926Sbostic #include <tzfile.h>
3356926Sbostic #include <unistd.h>
341089Sbill 
356318Swnj FILE	*fscript;
3656926Sbostic int	master, slave;
3756926Sbostic int	child, subchild;
3856926Sbostic int	outcc;
3934628Sbostic char	*fname;
401089Sbill 
4137141Smarc struct	termios tt;
421089Sbill 
4356926Sbostic __dead	void done __P((void));
4456926Sbostic 	void dooutput __P((void));
4556926Sbostic 	void doshell __P((void));
4656926Sbostic 	void err __P((const char *, ...));
4756926Sbostic 	void fail __P((void));
4856926Sbostic 	void finish __P((int));
4956926Sbostic 	void scriptflush __P((int));
5056926Sbostic 
5156926Sbostic int
main(argc,argv)526318Swnj main(argc, argv)
536318Swnj 	int argc;
546318Swnj 	char *argv[];
556318Swnj {
5656926Sbostic 	register int cc;
5756926Sbostic 	struct termios rtt;
5856926Sbostic 	struct winsize win;
5956926Sbostic 	int aflg, ch;
6056926Sbostic 	char ibuf[BUFSIZ];
611089Sbill 
6256926Sbostic 	aflg = 0;
6334628Sbostic 	while ((ch = getopt(argc, argv, "a")) != EOF)
6456926Sbostic 		switch(ch) {
656318Swnj 		case 'a':
6656926Sbostic 			aflg = 1;
676318Swnj 			break;
6834628Sbostic 		case '?':
696318Swnj 		default:
7056926Sbostic 			(void)fprintf(stderr, "usage: script [-a] [file]\n");
716318Swnj 			exit(1);
721089Sbill 		}
7334628Sbostic 	argc -= optind;
7434628Sbostic 	argv += optind;
7534628Sbostic 
766318Swnj 	if (argc > 0)
776318Swnj 		fname = argv[0];
7834628Sbostic 	else
7934628Sbostic 		fname = "typescript";
8034628Sbostic 
8156926Sbostic 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL)
8256926Sbostic 		err("%s: %s", fname, strerror(errno));
8334628Sbostic 
8456926Sbostic 	(void)tcgetattr(STDIN_FILENO, &tt);
8556926Sbostic 	(void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
8656926Sbostic 	if (openpty(&master, &slave, NULL, &tt, &win) == -1)
8756926Sbostic 		err("openpty: %s", strerror(errno));
8850403Smarc 
8956926Sbostic 	(void)printf("Script started, output file is %s\n", fname);
9056926Sbostic 	rtt = tt;
9156926Sbostic 	cfmakeraw(&rtt);
9256926Sbostic 	rtt.c_lflag &= ~ECHO;
9356926Sbostic 	(void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
941089Sbill 
9556926Sbostic 	(void)signal(SIGCHLD, finish);
966318Swnj 	child = fork();
976318Swnj 	if (child < 0) {
986318Swnj 		perror("fork");
996318Swnj 		fail();
1001089Sbill 	}
1016318Swnj 	if (child == 0) {
10224450Sbloom 		subchild = child = fork();
10324450Sbloom 		if (child < 0) {
1046318Swnj 			perror("fork");
1056318Swnj 			fail();
1066318Swnj 		}
10724450Sbloom 		if (child)
1081089Sbill 			dooutput();
1096318Swnj 		else
1106318Swnj 			doshell();
1111089Sbill 	}
1121089Sbill 
11356926Sbostic 	(void)fclose(fscript);
11456926Sbostic 	while ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0)
11556926Sbostic 		(void)write(master, ibuf, cc);
1166318Swnj 	done();
1176318Swnj }
1181089Sbill 
11946853Sbostic void
finish(signo)12056926Sbostic finish(signo)
12156926Sbostic 	int signo;
1226318Swnj {
12356926Sbostic 	register int die, pid;
1246318Swnj 	union wait status;
1251089Sbill 
12656926Sbostic 	die = 0;
12746853Sbostic 	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
12824450Sbloom 		if (pid == child)
12924450Sbloom 			die = 1;
13024450Sbloom 
13124450Sbloom 	if (die)
13224450Sbloom 		done();
1331089Sbill }
1341089Sbill 
13556926Sbostic void
dooutput()1361089Sbill dooutput()
1371089Sbill {
13856926Sbostic 	struct itimerval value;
13934628Sbostic 	register int cc;
14056926Sbostic 	time_t tvec;
14156926Sbostic 	char obuf[BUFSIZ];
1421089Sbill 
14356926Sbostic 	(void)close(STDIN_FILENO);
14456926Sbostic 	tvec = time(NULL);
14556926Sbostic 	(void)fprintf(fscript, "Script started on %s", ctime(&tvec));
14656926Sbostic 
14756926Sbostic 	(void)signal(SIGALRM, scriptflush);
14856926Sbostic 	value.it_interval.tv_sec = SECSPERMIN / 2;
14956926Sbostic 	value.it_interval.tv_usec = 0;
15056926Sbostic 	value.it_value = value.it_interval;
15156926Sbostic 	(void)setitimer(ITIMER_REAL, &value, NULL);
1526318Swnj 	for (;;) {
1536318Swnj 		cc = read(master, obuf, sizeof (obuf));
1546318Swnj 		if (cc <= 0)
1556318Swnj 			break;
15656926Sbostic 		(void)write(1, obuf, cc);
15756926Sbostic 		(void)fwrite(obuf, 1, cc, fscript);
15856926Sbostic 		outcc += cc;
1591089Sbill 	}
16025473Sserge 	done();
1611089Sbill }
1621089Sbill 
16356926Sbostic void
scriptflush(signo)16456926Sbostic scriptflush(signo)
16556926Sbostic 	int signo;
16656926Sbostic {
16756926Sbostic 	if (outcc) {
16856926Sbostic 		(void)fflush(fscript);
16956926Sbostic 		outcc = 0;
17056926Sbostic 	}
17156926Sbostic }
17256926Sbostic 
17356926Sbostic void
doshell()1741089Sbill doshell()
1751089Sbill {
17656926Sbostic 	char *shell;
1771089Sbill 
17856926Sbostic 	shell = getenv("SHELL");
17956926Sbostic 	if (shell == NULL)
18056926Sbostic 		shell = _PATH_BSHELL;
18156926Sbostic 
18256926Sbostic 	(void)close(master);
18356926Sbostic 	(void)fclose(fscript);
18450403Smarc 	login_tty(slave);
18556926Sbostic 	execl(shell, "sh", "-i", NULL);
1866318Swnj 	perror(shell);
1871089Sbill 	fail();
1881089Sbill }
1891089Sbill 
19056926Sbostic void
fail()1911089Sbill fail()
1921089Sbill {
1931089Sbill 
19456926Sbostic 	(void)kill(0, SIGTERM);
1951089Sbill 	done();
1961089Sbill }
1971089Sbill 
19856926Sbostic void
done()1991089Sbill done()
2001089Sbill {
20156926Sbostic 	time_t tvec;
2021089Sbill 
20325473Sserge 	if (subchild) {
20456926Sbostic 		tvec = time(NULL);
20556926Sbostic 		(void)fprintf(fscript,"\nScript done on %s", ctime(&tvec));
20656926Sbostic 		(void)fclose(fscript);
20756926Sbostic 		(void)close(master);
20825473Sserge 	} else {
20956926Sbostic 		(void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
21056926Sbostic 		(void)printf("Script done, output file is %s\n", fname);
21124450Sbloom 	}
2126318Swnj 	exit(0);
2131089Sbill }
21456926Sbostic 
21556926Sbostic #if __STDC__
21656926Sbostic #include <stdarg.h>
21756926Sbostic #else
21856926Sbostic #include <varargs.h>
21956926Sbostic #endif
22056926Sbostic 
22156926Sbostic void
22256926Sbostic #if __STDC__
err(const char * fmt,...)22356926Sbostic err(const char *fmt, ...)
22456926Sbostic #else
22556926Sbostic err(fmt, va_alist)
22656926Sbostic 	char *fmt;
22756926Sbostic 	va_dcl
22856926Sbostic #endif
22956926Sbostic {
23056926Sbostic 	va_list ap;
23156926Sbostic #if __STDC__
23256926Sbostic 	va_start(ap, fmt);
23356926Sbostic #else
23456926Sbostic 	va_start(ap);
23556926Sbostic #endif
23656926Sbostic 	(void)fprintf(stderr, "script: ");
23756926Sbostic 	(void)vfprintf(stderr, fmt, ap);
23856926Sbostic 	va_end(ap);
23956926Sbostic 	(void)fprintf(stderr, "\n");
24056926Sbostic 	exit(1);
24156926Sbostic 	/* NOTREACHED */
24256926Sbostic }
243