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