17c478bdstevel@tonic-gate/*
2179c3daRitwik Ghoshal * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37c478bdstevel@tonic-gate * Use is subject to license terms.
47c478bdstevel@tonic-gate */
57c478bdstevel@tonic-gate
67c478bdstevel@tonic-gate/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
77c478bdstevel@tonic-gate/*	  All Rights Reserved  	*/
87c478bdstevel@tonic-gate
97c478bdstevel@tonic-gate
107c478bdstevel@tonic-gate/*
117c478bdstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California.
127c478bdstevel@tonic-gate * All rights reserved.  The Berkeley software License Agreement
137c478bdstevel@tonic-gate * specifies the terms and conditions for redistribution.
147c478bdstevel@tonic-gate */
157c478bdstevel@tonic-gate
167c478bdstevel@tonic-gate/*	Portions Copyright(c) 1988, Sun Microsystems, Inc.	*/
177c478bdstevel@tonic-gate/*	All Rights Reserved.					*/
187c478bdstevel@tonic-gate
197c478bdstevel@tonic-gate/*
2034e4858dp * script: Produce a record of a terminal session.
217c478bdstevel@tonic-gate */
227c478bdstevel@tonic-gate#include <stdio.h>
2334e4858dp#include <stdlib.h>
2434e4858dp#include <unistd.h>
257c478bdstevel@tonic-gate#include <signal.h>
267c478bdstevel@tonic-gate#include <fcntl.h>
277c478bdstevel@tonic-gate#include <locale.h>
287c478bdstevel@tonic-gate#include <time.h>
297c478bdstevel@tonic-gate#include <sys/stropts.h>
307c478bdstevel@tonic-gate#include <sys/types.h>
317c478bdstevel@tonic-gate#include <sys/stat.h>
327c478bdstevel@tonic-gate#include <sys/termios.h>
337c478bdstevel@tonic-gate#include <sys/file.h>
347c478bdstevel@tonic-gate#include <errno.h>
357c478bdstevel@tonic-gate
367c478bdstevel@tonic-gateint 	grantpt();
377c478bdstevel@tonic-gateint 	unlockpt();
387c478bdstevel@tonic-gatechar	*ptsname();
3934e4858dpvoid	doinput() __NORETURN;
4034e4858dpvoid	dooutput();
4134e4858dpvoid	doshell();
4234e4858dpvoid	fixtty();
4334e4858dpvoid	fail();
4434e4858dpvoid	done() __NORETURN;
4534e4858dpvoid	getmaster();
4634e4858dpvoid	getslave();
477c478bdstevel@tonic-gate
487c478bdstevel@tonic-gatechar	*shell;
497c478bdstevel@tonic-gateFILE	*fscript;
507c478bdstevel@tonic-gateint	master;			/* file descriptor for master pseudo-tty */
517c478bdstevel@tonic-gateint	slave;			/* file descriptor for slave pseudo-tty */
527c478bdstevel@tonic-gateint	child;
537c478bdstevel@tonic-gateint	subchild;
547c478bdstevel@tonic-gatechar	*fname = "typescript";
557c478bdstevel@tonic-gatevoid	sigwinch();
567c478bdstevel@tonic-gatevoid	finish();
577c478bdstevel@tonic-gate
587c478bdstevel@tonic-gatestruct	termios b;
597c478bdstevel@tonic-gatestruct	winsize size;
607c478bdstevel@tonic-gateint	lb;
617c478bdstevel@tonic-gateint	l;
627c478bdstevel@tonic-gatechar	*mptname = "/dev/ptmx";	/* master pseudo-tty device */
637c478bdstevel@tonic-gate
647c478bdstevel@tonic-gateint	aflg;
657c478bdstevel@tonic-gate
6634e4858dpint
6734e4858dpmain(int argc, char *argv[])
687c478bdstevel@tonic-gate{
697c478bdstevel@tonic-gate	uid_t ruidt;
707c478bdstevel@tonic-gate	gid_t gidt;
717c478bdstevel@tonic-gate
727c478bdstevel@tonic-gate	(void) setlocale(LC_ALL, "");
737c478bdstevel@tonic-gate#if !defined(TEXT_DOMAIN)
747c478bdstevel@tonic-gate#define	TEXT_DOMAIN	"SYS_TEST"
757c478bdstevel@tonic-gate#endif
767c478bdstevel@tonic-gate	(void) textdomain(TEXT_DOMAIN);
777c478bdstevel@tonic-gate
787c478bdstevel@tonic-gate	shell = getenv("SHELL");
7934e4858dp	if (shell == NULL)
807c478bdstevel@tonic-gate		shell = "/bin/sh";
817c478bdstevel@tonic-gate	argc--, argv++;
827c478bdstevel@tonic-gate	while (argc > 0 && argv[0][0] == '-') {
837c478bdstevel@tonic-gate		switch (argv[0][1]) {
847c478bdstevel@tonic-gate
857c478bdstevel@tonic-gate		case 'a':
867c478bdstevel@tonic-gate			aflg++;
877c478bdstevel@tonic-gate			break;
887c478bdstevel@tonic-gate
897c478bdstevel@tonic-gate		default:
907c478bdstevel@tonic-gate			fprintf(stderr,
917c478bdstevel@tonic-gate			    gettext("usage: script [ -a ] [ typescript ]\n"));
927c478bdstevel@tonic-gate			exit(1);
937c478bdstevel@tonic-gate		}
947c478bdstevel@tonic-gate		argc--, argv++;
957c478bdstevel@tonic-gate	}
967c478bdstevel@tonic-gate	if (argc > 0)
977c478bdstevel@tonic-gate		fname = argv[0];
987c478bdstevel@tonic-gate	ruidt = getuid();
997c478bdstevel@tonic-gate	gidt = getgid();
1007c478bdstevel@tonic-gate	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
1017c478bdstevel@tonic-gate		perror(fname);
1027c478bdstevel@tonic-gate		fail();
1037c478bdstevel@tonic-gate	}
104179c3daRitwik Ghoshal	setbuf(fscript, NULL);
1057c478bdstevel@tonic-gate	chown(fname, ruidt, gidt);
1067c478bdstevel@tonic-gate	getmaster();
1077c478bdstevel@tonic-gate	printf(gettext("Script started, file is %s\n"), fname);
1087c478bdstevel@tonic-gate	fixtty();
1097c478bdstevel@tonic-gate
1107c478bdstevel@tonic-gate	(void) signal(SIGCHLD, finish);
1117c478bdstevel@tonic-gate	child = fork();
1127c478bdstevel@tonic-gate	if (child < 0) {
1137c478bdstevel@tonic-gate		perror("fork");
1147c478bdstevel@tonic-gate		fail();
1157c478bdstevel@tonic-gate	}
1167c478bdstevel@tonic-gate	if (child == 0) {
1177c478bdstevel@tonic-gate		subchild = child = fork();
1187c478bdstevel@tonic-gate		if (child < 0) {
1197c478bdstevel@tonic-gate			perror("fork");
1207c478bdstevel@tonic-gate			fail();
1217c478bdstevel@tonic-gate		}
1227c478bdstevel@tonic-gate		if (child)
1237c478bdstevel@tonic-gate			dooutput();
1247c478bdstevel@tonic-gate		else
1257c478bdstevel@tonic-gate			doshell();
1267c478bdstevel@tonic-gate	}
1277c478bdstevel@tonic-gate	doinput();
12834e4858dp	/* NOTREACHED */
12934e4858dp	return (0);
1307c478bdstevel@tonic-gate}
1317c478bdstevel@tonic-gate
13234e4858dpvoid
1337c478bdstevel@tonic-gatedoinput()
1347c478bdstevel@tonic-gate{
1357c478bdstevel@tonic-gate	char ibuf[BUFSIZ];
1367c478bdstevel@tonic-gate	int cc;
1377c478bdstevel@tonic-gate
1387c478bdstevel@tonic-gate	(void) fclose(fscript);
1397c478bdstevel@tonic-gate	sigset(SIGWINCH, sigwinch);
1407c478bdstevel@tonic-gate
1417c478bdstevel@tonic-gate	while ((cc = read(0, ibuf, BUFSIZ)) != 0) {
1427c478bdstevel@tonic-gate		if (cc == -1) {
1437c478bdstevel@tonic-gate			if (errno == EINTR) {   /* SIGWINCH probably */
1447c478bdstevel@tonic-gate				continue;
1457c478bdstevel@tonic-gate			} else {
1467c478bdstevel@tonic-gate				break;
1477c478bdstevel@tonic-gate			}
1487c478bdstevel@tonic-gate		}
1497c478bdstevel@tonic-gate		(void) write(master, ibuf, cc);
1507c478bdstevel@tonic-gate	}
1517c478bdstevel@tonic-gate	done();
1527c478bdstevel@tonic-gate}
1537c478bdstevel@tonic-gate
1547c478bdstevel@tonic-gatevoid
1557c478bdstevel@tonic-gatesigwinch()
1567c478bdstevel@tonic-gate{
1577c478bdstevel@tonic-gate	struct winsize ws;
1587c478bdstevel@tonic-gate
1597c478bdstevel@tonic-gate	if (ioctl(0, TIOCGWINSZ, &ws) == 0)
1607c478bdstevel@tonic-gate		(void) ioctl(master, TIOCSWINSZ, &ws);
1617c478bdstevel@tonic-gate}
1627c478bdstevel@tonic-gate
1637c478bdstevel@tonic-gate#include <sys/wait.h>
1647c478bdstevel@tonic-gate
1657c478bdstevel@tonic-gatevoid
1667c478bdstevel@tonic-gatefinish()
1677c478bdstevel@tonic-gate{
1687c478bdstevel@tonic-gate	int status;
1697c478bdstevel@tonic-gate	register int pid;
1707c478bdstevel@tonic-gate	register int die = 0;
1717c478bdstevel@tonic-gate
1727c478bdstevel@tonic-gate	while ((pid = wait(&status)) > 0)
1737c478bdstevel@tonic-gate		if (pid == child)
1747c478bdstevel@tonic-gate			die = 1;
1757c478bdstevel@tonic-gate
1767c478bdstevel@tonic-gate	if (die)
1777c478bdstevel@tonic-gate		done();
1787c478bdstevel@tonic-gate}
1797c478bdstevel@tonic-gate
18034e4858dpvoid
1817c478bdstevel@tonic-gatedooutput()
1827c478bdstevel@tonic-gate{
1837c478bdstevel@tonic-gate	time_t tvec;
1847c478bdstevel@tonic-gate	char obuf[BUFSIZ];
1857c478bdstevel@tonic-gate	char tbuf[BUFSIZ];
1867c478bdstevel@tonic-gate	int cc;
1877c478bdstevel@tonic-gate
1887c478bdstevel@tonic-gate	(void) close(0);
1897c478bdstevel@tonic-gate	tvec = time((time_t *)0);
1907c478bdstevel@tonic-gate	strftime(tbuf, BUFSIZ, "%c", localtime(&tvec));
1917c478bdstevel@tonic-gate	fprintf(fscript, gettext("Script started on %s\n"), tbuf);
1927c478bdstevel@tonic-gate	for (;;) {
1937c478bdstevel@tonic-gate		cc = read(master, obuf, sizeof (obuf));
1947c478bdstevel@tonic-gate		if (cc <= 0)
1957c478bdstevel@tonic-gate			break;
1967c478bdstevel@tonic-gate		(void) write(1, obuf, cc);
1977c478bdstevel@tonic-gate		(void) fwrite(obuf, 1, cc, fscript);
1987c478bdstevel@tonic-gate	}
1997c478bdstevel@tonic-gate	done();
2007c478bdstevel@tonic-gate}
2017c478bdstevel@tonic-gate
20234e4858dpvoid
2037c478bdstevel@tonic-gatedoshell()
2047c478bdstevel@tonic-gate{
2057c478bdstevel@tonic-gate
2067c478bdstevel@tonic-gate	setpgrp();	/* relinquish control terminal */
2077c478bdstevel@tonic-gate	getslave();
2087c478bdstevel@tonic-gate	(void) close(master);
2097c478bdstevel@tonic-gate	(void) fclose(fscript);
2107c478bdstevel@tonic-gate	(void) dup2(slave, 0);
2117c478bdstevel@tonic-gate	(void) dup2(slave, 1);
2127c478bdstevel@tonic-gate	(void) dup2(slave, 2);
2137c478bdstevel@tonic-gate	(void) close(slave);
2147c478bdstevel@tonic-gate	execl(shell, shell, "-i", (char *)0);
2157c478bdstevel@tonic-gate	perror(shell);
2167c478bdstevel@tonic-gate	fail();
2177c478bdstevel@tonic-gate}
2187c478bdstevel@tonic-gate
21934e4858dpvoid
2207c478bdstevel@tonic-gatefixtty()
2217c478bdstevel@tonic-gate{
2227c478bdstevel@tonic-gate	struct termios sbuf;
2237c478bdstevel@tonic-gate
2247c478bdstevel@tonic-gate	sbuf = b;
2257c478bdstevel@tonic-gate	sbuf.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|IXON);
2267c478bdstevel@tonic-gate	sbuf.c_oflag &= ~OPOST;
2277c478bdstevel@tonic-gate	sbuf.c_lflag &= ~(ICANON|ISIG|ECHO);
2287c478bdstevel@tonic-gate	sbuf.c_cc[VMIN] = 1;
2297c478bdstevel@tonic-gate	sbuf.c_cc[VTIME] = 0;
2307c478bdstevel@tonic-gate	(void) ioctl(0, TCSETSF, (char *)&sbuf);
2317c478bdstevel@tonic-gate}
2327c478bdstevel@tonic-gate
23334e4858dpvoid
2347c478bdstevel@tonic-gatefail()
2357c478bdstevel@tonic-gate{
2367c478bdstevel@tonic-gate
2377c478bdstevel@tonic-gate	(void) kill(0, SIGTERM);
2387c478bdstevel@tonic-gate	done();
2397c478bdstevel@tonic-gate}
2407c478bdstevel@tonic-gate
24134e4858dpvoid
2427c478bdstevel@tonic-gatedone()
2437c478bdstevel@tonic-gate{
2447c478bdstevel@tonic-gate	time_t tvec;
2457c478bdstevel@tonic-gate	char tbuf[BUFSIZ];
2467c478bdstevel@tonic-gate
2477c478bdstevel@tonic-gate	if (subchild) {
2487c478bdstevel@tonic-gate		tvec = time((time_t *)0);
2497c478bdstevel@tonic-gate		strftime(tbuf, BUFSIZ, "%c", localtime(&tvec));
2507c478bdstevel@tonic-gate		fprintf(fscript, gettext("\nscript done on %s\n"), tbuf);
2517c478bdstevel@tonic-gate		(void) fclose(fscript);
2527c478bdstevel@tonic-gate		(void) close(master);
2537c478bdstevel@tonic-gate	} else {
2547c478bdstevel@tonic-gate		(void) ioctl(0, TCSETSW, (char *)&b);
2557c478bdstevel@tonic-gate		printf(gettext("Script done, file is %s\n"), fname);
2567c478bdstevel@tonic-gate	}
2577c478bdstevel@tonic-gate	exit(0);
2587c478bdstevel@tonic-gate}
2597c478bdstevel@tonic-gate
26034e4858dpvoid
2617c478bdstevel@tonic-gategetmaster()
2627c478bdstevel@tonic-gate{
2637c478bdstevel@tonic-gate	struct stat stb;
2647c478bdstevel@tonic-gate
2657c478bdstevel@tonic-gate	if ((master = open(mptname, O_RDWR)) >= 0) { /* a pseudo-tty is free */
2667c478bdstevel@tonic-gate		(void) ioctl(0, TCGETS, (char *)&b);
2677c478bdstevel@tonic-gate		(void) ioctl(0, TIOCGWINSZ, (char *)&size);
2687c478bdstevel@tonic-gate		return;
2697c478bdstevel@tonic-gate	} else {				/* out of pseudo-tty's */
2707c478bdstevel@tonic-gate		perror(mptname);
2717c478bdstevel@tonic-gate		fprintf(stderr, gettext("Out of pseudo-tty's\n"));
2727c478bdstevel@tonic-gate		fail();
2737c478bdstevel@tonic-gate	}
2747c478bdstevel@tonic-gate}
2757c478bdstevel@tonic-gate
27634e4858dpvoid
2777c478bdstevel@tonic-gategetslave()
2787c478bdstevel@tonic-gate{
2797c478bdstevel@tonic-gate	char *slavename;	/* name of slave pseudo-tty */
2807c478bdstevel@tonic-gate
2817c478bdstevel@tonic-gate	grantpt(master);		/* change permissions of slave */
2827c478bdstevel@tonic-gate	unlockpt(master);			/* unlock slave */
2837c478bdstevel@tonic-gate	slavename = ptsname(master);		/* get name of slave */
2847c478bdstevel@tonic-gate	slave = open(slavename, O_RDWR);	/* open slave */
2857c478bdstevel@tonic-gate	if (slave < 0) {			/* error on opening slave */
2867c478bdstevel@tonic-gate		perror(slavename);
2877c478bdstevel@tonic-gate		fail();
2887c478bdstevel@tonic-gate	}
2897c478bdstevel@tonic-gate	ioctl(slave, I_PUSH, "ptem");	/* push pt hw emulation module */
2907c478bdstevel@tonic-gate	ioctl(slave, I_PUSH, "ldterm");		/* push line discipline */
2917c478bdstevel@tonic-gate
2927c478bdstevel@tonic-gate	(void) ioctl(slave, TCSETSF, (char *)&b);
2937c478bdstevel@tonic-gate	(void) ioctl(slave, TIOCSWINSZ, (char *)&size);
2947c478bdstevel@tonic-gate}
295