1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 char copyright[] = 36 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 37 All rights reserved.\n"; 38 #endif /* not lint */ 39 40 #ifndef lint 41 static char sccsid[] = "@(#)script.c 5.13 (Berkeley) 3/5/91"; 42 #endif /* not lint */ 43 44 /* 45 * script 46 */ 47 #include <sys/types.h> 48 #include <sys/stat.h> 49 #include <termios.h> 50 #include <sys/ioctl.h> 51 #include <sys/time.h> 52 #include <sys/file.h> 53 #include <sys/signal.h> 54 #include <stdio.h> 55 #include <paths.h> 56 57 char *shell; 58 FILE *fscript; 59 int master; 60 int slave; 61 int child; 62 int subchild; 63 char *fname; 64 65 struct termios tt; 66 struct winsize win; 67 int lb; 68 int l; 69 char line[] = "/dev/ptyXX"; 70 int aflg; 71 72 main(argc, argv) 73 int argc; 74 char *argv[]; 75 { 76 extern char *optarg; 77 extern int optind; 78 int ch; 79 void finish(); 80 char *getenv(); 81 82 while ((ch = getopt(argc, argv, "a")) != EOF) 83 switch((char)ch) { 84 case 'a': 85 aflg++; 86 break; 87 case '?': 88 default: 89 fprintf(stderr, "usage: script [-a] [file]\n"); 90 exit(1); 91 } 92 argc -= optind; 93 argv += optind; 94 95 if (argc > 0) 96 fname = argv[0]; 97 else 98 fname = "typescript"; 99 if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) { 100 perror(fname); 101 fail(); 102 } 103 104 shell = getenv("SHELL"); 105 if (shell == NULL) 106 shell = _PATH_BSHELL; 107 108 getmaster(); 109 printf("Script started, file is %s\n", fname); 110 fixtty(); 111 112 (void) signal(SIGCHLD, finish); 113 child = fork(); 114 if (child < 0) { 115 perror("fork"); 116 fail(); 117 } 118 if (child == 0) { 119 subchild = child = fork(); 120 if (child < 0) { 121 perror("fork"); 122 fail(); 123 } 124 if (child) 125 dooutput(); 126 else 127 doshell(); 128 } 129 doinput(); 130 } 131 132 doinput() 133 { 134 register int cc; 135 char ibuf[BUFSIZ]; 136 137 (void) fclose(fscript); 138 while ((cc = read(0, ibuf, BUFSIZ)) > 0) 139 (void) write(master, ibuf, cc); 140 done(); 141 } 142 143 #include <sys/wait.h> 144 145 void 146 finish() 147 { 148 union wait status; 149 register int pid; 150 register int die = 0; 151 152 while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0) 153 if (pid == child) 154 die = 1; 155 156 if (die) 157 done(); 158 } 159 160 dooutput() 161 { 162 register int cc; 163 time_t tvec, time(); 164 char obuf[BUFSIZ], *ctime(); 165 166 (void) close(0); 167 tvec = time((time_t *)NULL); 168 fprintf(fscript, "Script started on %s", ctime(&tvec)); 169 for (;;) { 170 cc = read(master, obuf, sizeof (obuf)); 171 if (cc <= 0) 172 break; 173 (void) write(1, obuf, cc); 174 (void) fwrite(obuf, 1, cc, fscript); 175 } 176 done(); 177 } 178 179 doshell() 180 { 181 int t; 182 183 /*** 184 t = open(_PATH_TTY, O_RDWR); 185 if (t >= 0) { 186 (void) ioctl(t, TIOCNOTTY, (char *)0); 187 (void) close(t); 188 } 189 ***/ 190 getslave(); 191 (void) close(master); 192 (void) fclose(fscript); 193 (void) dup2(slave, 0); 194 (void) dup2(slave, 1); 195 (void) dup2(slave, 2); 196 (void) close(slave); 197 execl(shell, "sh", "-i", 0); 198 perror(shell); 199 fail(); 200 } 201 202 fixtty() 203 { 204 struct termios rtt; 205 206 rtt = tt; 207 cfmakeraw(&rtt); 208 rtt.c_lflag &= ~ECHO; 209 (void) tcsetattr(0, TCSAFLUSH, &rtt); 210 } 211 212 fail() 213 { 214 215 (void) kill(0, SIGTERM); 216 done(); 217 } 218 219 done() 220 { 221 time_t tvec, time(); 222 char *ctime(); 223 224 if (subchild) { 225 tvec = time((time_t *)NULL); 226 fprintf(fscript,"\nScript done on %s", ctime(&tvec)); 227 (void) fclose(fscript); 228 (void) close(master); 229 } else { 230 (void) tcsetattr(0, TCSAFLUSH, &tt); 231 printf("Script done, file is %s\n", fname); 232 } 233 exit(0); 234 } 235 236 getmaster() 237 { 238 char *pty, *bank, *cp; 239 struct stat stb; 240 241 pty = &line[strlen("/dev/ptyp")]; 242 for (bank = "pqrs"; *bank; bank++) { 243 line[strlen("/dev/pty")] = *bank; 244 *pty = '0'; 245 if (stat(line, &stb) < 0) 246 break; 247 for (cp = "0123456789abcdef"; *cp; cp++) { 248 *pty = *cp; 249 master = open(line, O_RDWR); 250 if (master >= 0) { 251 char *tp = &line[strlen("/dev/")]; 252 int ok; 253 254 /* verify slave side is usable */ 255 *tp = 't'; 256 ok = access(line, R_OK|W_OK) == 0; 257 *tp = 'p'; 258 if (ok) { 259 (void) tcgetattr(0, &tt); 260 (void) ioctl(0, TIOCGWINSZ, 261 (char *)&win); 262 return; 263 } 264 (void) close(master); 265 } 266 } 267 } 268 fprintf(stderr, "Out of pty's\n"); 269 fail(); 270 } 271 272 getslave() 273 { 274 275 line[strlen("/dev/")] = 't'; 276 slave = open(line, O_RDWR); 277 if (slave < 0) { 278 perror(line); 279 fail(); 280 } 281 (void) tcsetattr(slave, TCSAFLUSH, &tt); 282 (void) ioctl(slave, TIOCSWINSZ, (char *)&win); 283 (void) setsid(); 284 (void) ioctl(slave, TIOCSCTTY, 0); 285 } 286