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