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