1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 10 /* 11 * Copyright (c) 1980 Regents of the University of California. 12 * All rights reserved. The Berkeley software License Agreement 13 * specifies the terms and conditions for redistribution. 14 */ 15 16 /* Portions Copyright(c) 1988, Sun Microsystems, Inc. */ 17 /* All Rights Reserved. */ 18 19 /* 20 * script: Produce a record of a terminal session. 21 */ 22 #include <stdio.h> 23 #include <stdlib.h> 24 #include <unistd.h> 25 #include <signal.h> 26 #include <fcntl.h> 27 #include <locale.h> 28 #include <time.h> 29 #include <sys/stropts.h> 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 #include <sys/termios.h> 33 #include <sys/file.h> 34 #include <errno.h> 35 36 int grantpt(); 37 int unlockpt(); 38 char *ptsname(); 39 void doinput() __NORETURN; 40 void dooutput(); 41 void doshell(); 42 void fixtty(); 43 void fail(); 44 void done() __NORETURN; 45 void getmaster(); 46 void getslave(); 47 48 char *shell; 49 FILE *fscript; 50 int master; /* file descriptor for master pseudo-tty */ 51 int slave; /* file descriptor for slave pseudo-tty */ 52 int child; 53 int subchild; 54 char *fname = "typescript"; 55 void sigwinch(); 56 void finish(); 57 58 struct termios b; 59 struct winsize size; 60 int lb; 61 int l; 62 char *mptname = "/dev/ptmx"; /* master pseudo-tty device */ 63 64 int aflg; 65 66 int 67 main(int argc, char *argv[]) 68 { 69 uid_t ruidt; 70 gid_t gidt; 71 72 (void) setlocale(LC_ALL, ""); 73 #if !defined(TEXT_DOMAIN) 74 #define TEXT_DOMAIN "SYS_TEST" 75 #endif 76 (void) textdomain(TEXT_DOMAIN); 77 78 shell = getenv("SHELL"); 79 if (shell == NULL) 80 shell = "/bin/sh"; 81 argc--, argv++; 82 while (argc > 0 && argv[0][0] == '-') { 83 switch (argv[0][1]) { 84 85 case 'a': 86 aflg++; 87 break; 88 89 default: 90 fprintf(stderr, 91 gettext("usage: script [ -a ] [ typescript ]\n")); 92 exit(1); 93 } 94 argc--, argv++; 95 } 96 if (argc > 0) 97 fname = argv[0]; 98 ruidt = getuid(); 99 gidt = getgid(); 100 if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) { 101 perror(fname); 102 fail(); 103 } 104 setbuf(fscript, NULL); 105 chown(fname, ruidt, gidt); 106 getmaster(); 107 printf(gettext("Script started, file is %s\n"), fname); 108 fixtty(); 109 110 (void) signal(SIGCHLD, finish); 111 child = fork(); 112 if (child < 0) { 113 perror("fork"); 114 fail(); 115 } 116 if (child == 0) { 117 subchild = child = fork(); 118 if (child < 0) { 119 perror("fork"); 120 fail(); 121 } 122 if (child) 123 dooutput(); 124 else 125 doshell(); 126 } 127 doinput(); 128 /* NOTREACHED */ 129 return (0); 130 } 131 132 void 133 doinput() 134 { 135 char ibuf[BUFSIZ]; 136 int cc; 137 138 (void) fclose(fscript); 139 sigset(SIGWINCH, sigwinch); 140 141 while ((cc = read(0, ibuf, BUFSIZ)) != 0) { 142 if (cc == -1) { 143 if (errno == EINTR) { /* SIGWINCH probably */ 144 continue; 145 } else { 146 break; 147 } 148 } 149 (void) write(master, ibuf, cc); 150 } 151 done(); 152 } 153 154 void 155 sigwinch() 156 { 157 struct winsize ws; 158 159 if (ioctl(0, TIOCGWINSZ, &ws) == 0) 160 (void) ioctl(master, TIOCSWINSZ, &ws); 161 } 162 163 #include <sys/wait.h> 164 165 void 166 finish() 167 { 168 int status; 169 register int pid; 170 register int die = 0; 171 172 while ((pid = wait(&status)) > 0) 173 if (pid == child) 174 die = 1; 175 176 if (die) 177 done(); 178 } 179 180 void 181 dooutput() 182 { 183 time_t tvec; 184 char obuf[BUFSIZ]; 185 char tbuf[BUFSIZ]; 186 int cc; 187 188 (void) close(0); 189 tvec = time((time_t *)0); 190 strftime(tbuf, BUFSIZ, "%c", localtime(&tvec)); 191 fprintf(fscript, gettext("Script started on %s\n"), tbuf); 192 for (;;) { 193 cc = read(master, obuf, sizeof (obuf)); 194 if (cc <= 0) 195 break; 196 (void) write(1, obuf, cc); 197 (void) fwrite(obuf, 1, cc, fscript); 198 } 199 done(); 200 } 201 202 void 203 doshell() 204 { 205 206 setpgrp(); /* relinquish control terminal */ 207 getslave(); 208 (void) close(master); 209 (void) fclose(fscript); 210 (void) dup2(slave, 0); 211 (void) dup2(slave, 1); 212 (void) dup2(slave, 2); 213 (void) close(slave); 214 execl(shell, shell, "-i", (char *)0); 215 perror(shell); 216 fail(); 217 } 218 219 void 220 fixtty() 221 { 222 struct termios sbuf; 223 224 sbuf = b; 225 sbuf.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|IXON); 226 sbuf.c_oflag &= ~OPOST; 227 sbuf.c_lflag &= ~(ICANON|ISIG|ECHO); 228 sbuf.c_cc[VMIN] = 1; 229 sbuf.c_cc[VTIME] = 0; 230 (void) ioctl(0, TCSETSF, (char *)&sbuf); 231 } 232 233 void 234 fail() 235 { 236 237 (void) kill(0, SIGTERM); 238 done(); 239 } 240 241 void 242 done() 243 { 244 time_t tvec; 245 char tbuf[BUFSIZ]; 246 247 if (subchild) { 248 tvec = time((time_t *)0); 249 strftime(tbuf, BUFSIZ, "%c", localtime(&tvec)); 250 fprintf(fscript, gettext("\nscript done on %s\n"), tbuf); 251 (void) fclose(fscript); 252 (void) close(master); 253 } else { 254 (void) ioctl(0, TCSETSW, (char *)&b); 255 printf(gettext("Script done, file is %s\n"), fname); 256 } 257 exit(0); 258 } 259 260 void 261 getmaster() 262 { 263 struct stat stb; 264 265 if ((master = open(mptname, O_RDWR)) >= 0) { /* a pseudo-tty is free */ 266 (void) ioctl(0, TCGETS, (char *)&b); 267 (void) ioctl(0, TIOCGWINSZ, (char *)&size); 268 return; 269 } else { /* out of pseudo-tty's */ 270 perror(mptname); 271 fprintf(stderr, gettext("Out of pseudo-tty's\n")); 272 fail(); 273 } 274 } 275 276 void 277 getslave() 278 { 279 char *slavename; /* name of slave pseudo-tty */ 280 281 grantpt(master); /* change permissions of slave */ 282 unlockpt(master); /* unlock slave */ 283 slavename = ptsname(master); /* get name of slave */ 284 slave = open(slavename, O_RDWR); /* open slave */ 285 if (slave < 0) { /* error on opening slave */ 286 perror(slavename); 287 fail(); 288 } 289 ioctl(slave, I_PUSH, "ptem"); /* push pt hw emulation module */ 290 ioctl(slave, I_PUSH, "ldterm"); /* push line discipline */ 291 292 (void) ioctl(slave, TCSETSF, (char *)&b); 293 (void) ioctl(slave, TIOCSWINSZ, (char *)&size); 294 } 295