Home | History | Annotate | Line # | Download | only in script
script.c revision 1.1.1.1
      1 /*
      2  * Copyright (c) 1980 Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 char copyright[] =
     36 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
     37  All rights reserved.\n";
     38 #endif /* not lint */
     39 
     40 #ifndef lint
     41 static char sccsid[] = "@(#)script.c	5.13 (Berkeley) 3/5/91";
     42 #endif /* not lint */
     43 
     44 /*
     45  * script
     46  */
     47 #include <sys/types.h>
     48 #include <sys/stat.h>
     49 #include <termios.h>
     50 #include <sys/ioctl.h>
     51 #include <sys/time.h>
     52 #include <sys/file.h>
     53 #include <sys/signal.h>
     54 #include <stdio.h>
     55 #include <paths.h>
     56 
     57 char	*shell;
     58 FILE	*fscript;
     59 int	master;
     60 int	slave;
     61 int	child;
     62 int	subchild;
     63 char	*fname;
     64 
     65 struct	termios tt;
     66 struct	winsize win;
     67 int	lb;
     68 int	l;
     69 char	line[] = "/dev/ptyXX";
     70 int	aflg;
     71 
     72 main(argc, argv)
     73 	int argc;
     74 	char *argv[];
     75 {
     76 	extern char *optarg;
     77 	extern int optind;
     78 	int ch;
     79 	void finish();
     80 	char *getenv();
     81 
     82 	while ((ch = getopt(argc, argv, "a")) != EOF)
     83 		switch((char)ch) {
     84 		case 'a':
     85 			aflg++;
     86 			break;
     87 		case '?':
     88 		default:
     89 			fprintf(stderr, "usage: script [-a] [file]\n");
     90 			exit(1);
     91 		}
     92 	argc -= optind;
     93 	argv += optind;
     94 
     95 	if (argc > 0)
     96 		fname = argv[0];
     97 	else
     98 		fname = "typescript";
     99 	if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
    100 		perror(fname);
    101 		fail();
    102 	}
    103 
    104 	shell = getenv("SHELL");
    105 	if (shell == NULL)
    106 		shell = _PATH_BSHELL;
    107 
    108 	getmaster();
    109 	printf("Script started, file is %s\n", fname);
    110 	fixtty();
    111 
    112 	(void) signal(SIGCHLD, finish);
    113 	child = fork();
    114 	if (child < 0) {
    115 		perror("fork");
    116 		fail();
    117 	}
    118 	if (child == 0) {
    119 		subchild = child = fork();
    120 		if (child < 0) {
    121 			perror("fork");
    122 			fail();
    123 		}
    124 		if (child)
    125 			dooutput();
    126 		else
    127 			doshell();
    128 	}
    129 	doinput();
    130 }
    131 
    132 doinput()
    133 {
    134 	register int cc;
    135 	char ibuf[BUFSIZ];
    136 
    137 	(void) fclose(fscript);
    138 	while ((cc = read(0, ibuf, BUFSIZ)) > 0)
    139 		(void) write(master, ibuf, cc);
    140 	done();
    141 }
    142 
    143 #include <sys/wait.h>
    144 
    145 void
    146 finish()
    147 {
    148 	union wait status;
    149 	register int pid;
    150 	register int die = 0;
    151 
    152 	while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
    153 		if (pid == child)
    154 			die = 1;
    155 
    156 	if (die)
    157 		done();
    158 }
    159 
    160 dooutput()
    161 {
    162 	register int cc;
    163 	time_t tvec, time();
    164 	char obuf[BUFSIZ], *ctime();
    165 
    166 	(void) close(0);
    167 	tvec = time((time_t *)NULL);
    168 	fprintf(fscript, "Script started on %s", ctime(&tvec));
    169 	for (;;) {
    170 		cc = read(master, obuf, sizeof (obuf));
    171 		if (cc <= 0)
    172 			break;
    173 		(void) write(1, obuf, cc);
    174 		(void) fwrite(obuf, 1, cc, fscript);
    175 	}
    176 	done();
    177 }
    178 
    179 doshell()
    180 {
    181 	int t;
    182 
    183 	/***
    184 	t = open(_PATH_TTY, O_RDWR);
    185 	if (t >= 0) {
    186 		(void) ioctl(t, TIOCNOTTY, (char *)0);
    187 		(void) close(t);
    188 	}
    189 	***/
    190 	getslave();
    191 	(void) close(master);
    192 	(void) fclose(fscript);
    193 	(void) dup2(slave, 0);
    194 	(void) dup2(slave, 1);
    195 	(void) dup2(slave, 2);
    196 	(void) close(slave);
    197 	execl(shell, "sh", "-i", 0);
    198 	perror(shell);
    199 	fail();
    200 }
    201 
    202 fixtty()
    203 {
    204 	struct termios rtt;
    205 
    206 	rtt = tt;
    207 	cfmakeraw(&rtt);
    208 	rtt.c_lflag &= ~ECHO;
    209 	(void) tcsetattr(0, TCSAFLUSH, &rtt);
    210 }
    211 
    212 fail()
    213 {
    214 
    215 	(void) kill(0, SIGTERM);
    216 	done();
    217 }
    218 
    219 done()
    220 {
    221 	time_t tvec, time();
    222 	char *ctime();
    223 
    224 	if (subchild) {
    225 		tvec = time((time_t *)NULL);
    226 		fprintf(fscript,"\nScript done on %s", ctime(&tvec));
    227 		(void) fclose(fscript);
    228 		(void) close(master);
    229 	} else {
    230 		(void) tcsetattr(0, TCSAFLUSH, &tt);
    231 		printf("Script done, file is %s\n", fname);
    232 	}
    233 	exit(0);
    234 }
    235 
    236 getmaster()
    237 {
    238 	char *pty, *bank, *cp;
    239 	struct stat stb;
    240 
    241 	pty = &line[strlen("/dev/ptyp")];
    242 	for (bank = "pqrs"; *bank; bank++) {
    243 		line[strlen("/dev/pty")] = *bank;
    244 		*pty = '0';
    245 		if (stat(line, &stb) < 0)
    246 			break;
    247 		for (cp = "0123456789abcdef"; *cp; cp++) {
    248 			*pty = *cp;
    249 			master = open(line, O_RDWR);
    250 			if (master >= 0) {
    251 				char *tp = &line[strlen("/dev/")];
    252 				int ok;
    253 
    254 				/* verify slave side is usable */
    255 				*tp = 't';
    256 				ok = access(line, R_OK|W_OK) == 0;
    257 				*tp = 'p';
    258 				if (ok) {
    259 					(void) tcgetattr(0, &tt);
    260 				    	(void) ioctl(0, TIOCGWINSZ,
    261 						(char *)&win);
    262 					return;
    263 				}
    264 				(void) close(master);
    265 			}
    266 		}
    267 	}
    268 	fprintf(stderr, "Out of pty's\n");
    269 	fail();
    270 }
    271 
    272 getslave()
    273 {
    274 
    275 	line[strlen("/dev/")] = 't';
    276 	slave = open(line, O_RDWR);
    277 	if (slave < 0) {
    278 		perror(line);
    279 		fail();
    280 	}
    281 	(void) tcsetattr(slave, TCSAFLUSH, &tt);
    282 	(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
    283 	(void) setsid();
    284 	(void) ioctl(slave, TIOCSCTTY, 0);
    285 }
    286