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