xref: /titanic_53/usr/src/cmd/script/script.c (revision 34e485807cef99a975f8962a04f4b7d1aa3529fe)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate 
107c478bd9Sstevel@tonic-gate /*
117c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
127c478bd9Sstevel@tonic-gate  * All rights reserved.  The Berkeley software License Agreement
137c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
147c478bd9Sstevel@tonic-gate  */
157c478bd9Sstevel@tonic-gate 
167c478bd9Sstevel@tonic-gate /*	Portions Copyright(c) 1988, Sun Microsystems, Inc.	*/
177c478bd9Sstevel@tonic-gate /*	All Rights Reserved.					*/
187c478bd9Sstevel@tonic-gate 
197c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
207c478bd9Sstevel@tonic-gate 
217c478bd9Sstevel@tonic-gate /*
22*34e48580Sdp  * script: Produce a record of a terminal session.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate #include <stdio.h>
25*34e48580Sdp #include <stdlib.h>
26*34e48580Sdp #include <unistd.h>
277c478bd9Sstevel@tonic-gate #include <signal.h>
287c478bd9Sstevel@tonic-gate #include <fcntl.h>
297c478bd9Sstevel@tonic-gate #include <locale.h>
307c478bd9Sstevel@tonic-gate #include <time.h>
317c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
327c478bd9Sstevel@tonic-gate #include <sys/types.h>
337c478bd9Sstevel@tonic-gate #include <sys/stat.h>
347c478bd9Sstevel@tonic-gate #include <sys/termios.h>
357c478bd9Sstevel@tonic-gate #include <sys/file.h>
367c478bd9Sstevel@tonic-gate #include <errno.h>
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate int 	grantpt();
397c478bd9Sstevel@tonic-gate int 	unlockpt();
407c478bd9Sstevel@tonic-gate char	*ptsname();
41*34e48580Sdp void	doinput() __NORETURN;
42*34e48580Sdp void	dooutput();
43*34e48580Sdp void	doshell();
44*34e48580Sdp void	fixtty();
45*34e48580Sdp void	fail();
46*34e48580Sdp void	done() __NORETURN;
47*34e48580Sdp void	getmaster();
48*34e48580Sdp void	getslave();
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate char	*shell;
517c478bd9Sstevel@tonic-gate FILE	*fscript;
527c478bd9Sstevel@tonic-gate int	master;			/* file descriptor for master pseudo-tty */
537c478bd9Sstevel@tonic-gate int	slave;			/* file descriptor for slave pseudo-tty */
547c478bd9Sstevel@tonic-gate int	child;
557c478bd9Sstevel@tonic-gate int	subchild;
567c478bd9Sstevel@tonic-gate char	*fname = "typescript";
577c478bd9Sstevel@tonic-gate void	sigwinch();
587c478bd9Sstevel@tonic-gate void	finish();
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate struct	termios b;
617c478bd9Sstevel@tonic-gate struct	winsize size;
627c478bd9Sstevel@tonic-gate int	lb;
637c478bd9Sstevel@tonic-gate int	l;
647c478bd9Sstevel@tonic-gate char	*mptname = "/dev/ptmx";	/* master pseudo-tty device */
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate int	aflg;
677c478bd9Sstevel@tonic-gate 
68*34e48580Sdp int
69*34e48580Sdp main(int argc, char *argv[])
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate 	uid_t ruidt;
727c478bd9Sstevel@tonic-gate 	gid_t gidt;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 	(void) setlocale(LC_ALL, "");
757c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN)
767c478bd9Sstevel@tonic-gate #define	TEXT_DOMAIN	"SYS_TEST"
777c478bd9Sstevel@tonic-gate #endif
787c478bd9Sstevel@tonic-gate 	(void) textdomain(TEXT_DOMAIN);
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	shell = getenv("SHELL");
81*34e48580Sdp 	if (shell == NULL)
827c478bd9Sstevel@tonic-gate 		shell = "/bin/sh";
837c478bd9Sstevel@tonic-gate 	argc--, argv++;
847c478bd9Sstevel@tonic-gate 	while (argc > 0 && argv[0][0] == '-') {
857c478bd9Sstevel@tonic-gate 		switch (argv[0][1]) {
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 		case 'a':
887c478bd9Sstevel@tonic-gate 			aflg++;
897c478bd9Sstevel@tonic-gate 			break;
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 		default:
927c478bd9Sstevel@tonic-gate 			fprintf(stderr,
937c478bd9Sstevel@tonic-gate 			    gettext("usage: script [ -a ] [ typescript ]\n"));
947c478bd9Sstevel@tonic-gate 			exit(1);
957c478bd9Sstevel@tonic-gate 		}
967c478bd9Sstevel@tonic-gate 		argc--, argv++;
977c478bd9Sstevel@tonic-gate 	}
987c478bd9Sstevel@tonic-gate 	if (argc > 0)
997c478bd9Sstevel@tonic-gate 		fname = argv[0];
1007c478bd9Sstevel@tonic-gate 	ruidt = getuid();
1017c478bd9Sstevel@tonic-gate 	gidt = getgid();
1027c478bd9Sstevel@tonic-gate 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
1037c478bd9Sstevel@tonic-gate 		perror(fname);
1047c478bd9Sstevel@tonic-gate 		fail();
1057c478bd9Sstevel@tonic-gate 	}
1067c478bd9Sstevel@tonic-gate 	chown(fname, ruidt, gidt);
1077c478bd9Sstevel@tonic-gate 	getmaster();
1087c478bd9Sstevel@tonic-gate 	printf(gettext("Script started, file is %s\n"), fname);
1097c478bd9Sstevel@tonic-gate 	fixtty();
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate 	(void) signal(SIGCHLD, finish);
1127c478bd9Sstevel@tonic-gate 	child = fork();
1137c478bd9Sstevel@tonic-gate 	if (child < 0) {
1147c478bd9Sstevel@tonic-gate 		perror("fork");
1157c478bd9Sstevel@tonic-gate 		fail();
1167c478bd9Sstevel@tonic-gate 	}
1177c478bd9Sstevel@tonic-gate 	if (child == 0) {
1187c478bd9Sstevel@tonic-gate 		subchild = child = fork();
1197c478bd9Sstevel@tonic-gate 		if (child < 0) {
1207c478bd9Sstevel@tonic-gate 			perror("fork");
1217c478bd9Sstevel@tonic-gate 			fail();
1227c478bd9Sstevel@tonic-gate 		}
1237c478bd9Sstevel@tonic-gate 		if (child)
1247c478bd9Sstevel@tonic-gate 			dooutput();
1257c478bd9Sstevel@tonic-gate 		else
1267c478bd9Sstevel@tonic-gate 			doshell();
1277c478bd9Sstevel@tonic-gate 	}
1287c478bd9Sstevel@tonic-gate 	doinput();
129*34e48580Sdp 	/* NOTREACHED */
130*34e48580Sdp 	return (0);
1317c478bd9Sstevel@tonic-gate }
1327c478bd9Sstevel@tonic-gate 
133*34e48580Sdp void
1347c478bd9Sstevel@tonic-gate doinput()
1357c478bd9Sstevel@tonic-gate {
1367c478bd9Sstevel@tonic-gate 	char ibuf[BUFSIZ];
1377c478bd9Sstevel@tonic-gate 	int cc;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate 	(void) fclose(fscript);
1407c478bd9Sstevel@tonic-gate 	sigset(SIGWINCH, sigwinch);
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate 	while ((cc = read(0, ibuf, BUFSIZ)) != 0) {
1437c478bd9Sstevel@tonic-gate 		if (cc == -1) {
1447c478bd9Sstevel@tonic-gate 			if (errno == EINTR) {   /* SIGWINCH probably */
1457c478bd9Sstevel@tonic-gate 				continue;
1467c478bd9Sstevel@tonic-gate 			} else {
1477c478bd9Sstevel@tonic-gate 				break;
1487c478bd9Sstevel@tonic-gate 			}
1497c478bd9Sstevel@tonic-gate 		}
1507c478bd9Sstevel@tonic-gate 		(void) write(master, ibuf, cc);
1517c478bd9Sstevel@tonic-gate 	}
1527c478bd9Sstevel@tonic-gate 	done();
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate void
1567c478bd9Sstevel@tonic-gate sigwinch()
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	struct winsize ws;
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	if (ioctl(0, TIOCGWINSZ, &ws) == 0)
1617c478bd9Sstevel@tonic-gate 		(void) ioctl(master, TIOCSWINSZ, &ws);
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate #include <sys/wait.h>
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate void
1677c478bd9Sstevel@tonic-gate finish()
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate 	int status;
1707c478bd9Sstevel@tonic-gate 	register int pid;
1717c478bd9Sstevel@tonic-gate 	register int die = 0;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate 	while ((pid = wait(&status)) > 0)
1747c478bd9Sstevel@tonic-gate 		if (pid == child)
1757c478bd9Sstevel@tonic-gate 			die = 1;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	if (die)
1787c478bd9Sstevel@tonic-gate 		done();
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate 
181*34e48580Sdp void
1827c478bd9Sstevel@tonic-gate dooutput()
1837c478bd9Sstevel@tonic-gate {
1847c478bd9Sstevel@tonic-gate 	time_t tvec;
1857c478bd9Sstevel@tonic-gate 	char obuf[BUFSIZ];
1867c478bd9Sstevel@tonic-gate 	char tbuf[BUFSIZ];
1877c478bd9Sstevel@tonic-gate 	int cc;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	(void) close(0);
1907c478bd9Sstevel@tonic-gate 	tvec = time((time_t *)0);
1917c478bd9Sstevel@tonic-gate 	strftime(tbuf, BUFSIZ, "%c", localtime(&tvec));
1927c478bd9Sstevel@tonic-gate 	fprintf(fscript, gettext("Script started on %s\n"), tbuf);
1937c478bd9Sstevel@tonic-gate 	for (;;) {
1947c478bd9Sstevel@tonic-gate 		cc = read(master, obuf, sizeof (obuf));
1957c478bd9Sstevel@tonic-gate 		if (cc <= 0)
1967c478bd9Sstevel@tonic-gate 			break;
1977c478bd9Sstevel@tonic-gate 		(void) write(1, obuf, cc);
1987c478bd9Sstevel@tonic-gate 		(void) fwrite(obuf, 1, cc, fscript);
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 	done();
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate 
203*34e48580Sdp void
2047c478bd9Sstevel@tonic-gate doshell()
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	setpgrp();	/* relinquish control terminal */
2087c478bd9Sstevel@tonic-gate 	getslave();
2097c478bd9Sstevel@tonic-gate 	(void) close(master);
2107c478bd9Sstevel@tonic-gate 	(void) fclose(fscript);
2117c478bd9Sstevel@tonic-gate 	(void) dup2(slave, 0);
2127c478bd9Sstevel@tonic-gate 	(void) dup2(slave, 1);
2137c478bd9Sstevel@tonic-gate 	(void) dup2(slave, 2);
2147c478bd9Sstevel@tonic-gate 	(void) close(slave);
2157c478bd9Sstevel@tonic-gate 	execl(shell, shell, "-i", (char *)0);
2167c478bd9Sstevel@tonic-gate 	perror(shell);
2177c478bd9Sstevel@tonic-gate 	fail();
2187c478bd9Sstevel@tonic-gate }
2197c478bd9Sstevel@tonic-gate 
220*34e48580Sdp void
2217c478bd9Sstevel@tonic-gate fixtty()
2227c478bd9Sstevel@tonic-gate {
2237c478bd9Sstevel@tonic-gate 	struct termios sbuf;
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	sbuf = b;
2267c478bd9Sstevel@tonic-gate 	sbuf.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|IXON);
2277c478bd9Sstevel@tonic-gate 	sbuf.c_oflag &= ~OPOST;
2287c478bd9Sstevel@tonic-gate 	sbuf.c_lflag &= ~(ICANON|ISIG|ECHO);
2297c478bd9Sstevel@tonic-gate 	sbuf.c_cc[VMIN] = 1;
2307c478bd9Sstevel@tonic-gate 	sbuf.c_cc[VTIME] = 0;
2317c478bd9Sstevel@tonic-gate 	(void) ioctl(0, TCSETSF, (char *)&sbuf);
2327c478bd9Sstevel@tonic-gate }
2337c478bd9Sstevel@tonic-gate 
234*34e48580Sdp void
2357c478bd9Sstevel@tonic-gate fail()
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	(void) kill(0, SIGTERM);
2397c478bd9Sstevel@tonic-gate 	done();
2407c478bd9Sstevel@tonic-gate }
2417c478bd9Sstevel@tonic-gate 
242*34e48580Sdp void
2437c478bd9Sstevel@tonic-gate done()
2447c478bd9Sstevel@tonic-gate {
2457c478bd9Sstevel@tonic-gate 	time_t tvec;
2467c478bd9Sstevel@tonic-gate 	char tbuf[BUFSIZ];
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	if (subchild) {
2497c478bd9Sstevel@tonic-gate 		tvec = time((time_t *)0);
2507c478bd9Sstevel@tonic-gate 		strftime(tbuf, BUFSIZ, "%c", localtime(&tvec));
2517c478bd9Sstevel@tonic-gate 		fprintf(fscript, gettext("\nscript done on %s\n"), tbuf);
2527c478bd9Sstevel@tonic-gate 		(void) fclose(fscript);
2537c478bd9Sstevel@tonic-gate 		(void) close(master);
2547c478bd9Sstevel@tonic-gate 	} else {
2557c478bd9Sstevel@tonic-gate 		(void) ioctl(0, TCSETSW, (char *)&b);
2567c478bd9Sstevel@tonic-gate 		printf(gettext("Script done, file is %s\n"), fname);
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 	exit(0);
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
261*34e48580Sdp void
2627c478bd9Sstevel@tonic-gate getmaster()
2637c478bd9Sstevel@tonic-gate {
2647c478bd9Sstevel@tonic-gate 	struct stat stb;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	if ((master = open(mptname, O_RDWR)) >= 0) { /* a pseudo-tty is free */
2677c478bd9Sstevel@tonic-gate 		(void) ioctl(0, TCGETS, (char *)&b);
2687c478bd9Sstevel@tonic-gate 		(void) ioctl(0, TIOCGWINSZ, (char *)&size);
2697c478bd9Sstevel@tonic-gate 		return;
2707c478bd9Sstevel@tonic-gate 	} else {				/* out of pseudo-tty's */
2717c478bd9Sstevel@tonic-gate 		perror(mptname);
2727c478bd9Sstevel@tonic-gate 		fprintf(stderr, gettext("Out of pseudo-tty's\n"));
2737c478bd9Sstevel@tonic-gate 		fail();
2747c478bd9Sstevel@tonic-gate 	}
2757c478bd9Sstevel@tonic-gate }
2767c478bd9Sstevel@tonic-gate 
277*34e48580Sdp void
2787c478bd9Sstevel@tonic-gate getslave()
2797c478bd9Sstevel@tonic-gate {
2807c478bd9Sstevel@tonic-gate 	char *slavename;	/* name of slave pseudo-tty */
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	grantpt(master);		/* change permissions of slave */
2837c478bd9Sstevel@tonic-gate 	unlockpt(master);			/* unlock slave */
2847c478bd9Sstevel@tonic-gate 	slavename = ptsname(master);		/* get name of slave */
2857c478bd9Sstevel@tonic-gate 	slave = open(slavename, O_RDWR);	/* open slave */
2867c478bd9Sstevel@tonic-gate 	if (slave < 0) {			/* error on opening slave */
2877c478bd9Sstevel@tonic-gate 		perror(slavename);
2887c478bd9Sstevel@tonic-gate 		fail();
2897c478bd9Sstevel@tonic-gate 	}
2907c478bd9Sstevel@tonic-gate 	ioctl(slave, I_PUSH, "ptem");	/* push pt hw emulation module */
2917c478bd9Sstevel@tonic-gate 	ioctl(slave, I_PUSH, "ldterm");		/* push line discipline */
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	(void) ioctl(slave, TCSETSF, (char *)&b);
2947c478bd9Sstevel@tonic-gate 	(void) ioctl(slave, TIOCSWINSZ, (char *)&size);
2957c478bd9Sstevel@tonic-gate }
296