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[] = "from: @(#)script.c 5.13 (Berkeley) 3/5/91";*/ 42 static char rcsid[] = "$Id: script.c,v 1.2 1993/08/01 18:08:35 mycroft Exp $"; 43 #endif /* not lint */ 44 45 /* 46 * script 47 */ 48 #include <sys/types.h> 49 #include <sys/stat.h> 50 #include <termios.h> 51 #include <sys/ioctl.h> 52 #include <sys/time.h> 53 #include <sys/file.h> 54 #include <sys/signal.h> 55 #include <stdio.h> 56 #include <paths.h> 57 58 char *shell; 59 FILE *fscript; 60 int master; 61 int slave; 62 int child; 63 int subchild; 64 char *fname; 65 66 struct termios tt; 67 struct winsize win; 68 int lb; 69 int l; 70 char line[] = "/dev/ptyXX"; 71 int aflg; 72 73 main(argc, argv) 74 int argc; 75 char *argv[]; 76 { 77 extern char *optarg; 78 extern int optind; 79 int ch; 80 void finish(); 81 char *getenv(); 82 83 while ((ch = getopt(argc, argv, "a")) != EOF) 84 switch((char)ch) { 85 case 'a': 86 aflg++; 87 break; 88 case '?': 89 default: 90 fprintf(stderr, "usage: script [-a] [file]\n"); 91 exit(1); 92 } 93 argc -= optind; 94 argv += optind; 95 96 if (argc > 0) 97 fname = argv[0]; 98 else 99 fname = "typescript"; 100 if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) { 101 perror(fname); 102 fail(); 103 } 104 105 shell = getenv("SHELL"); 106 if (shell == NULL) 107 shell = _PATH_BSHELL; 108 109 getmaster(); 110 printf("Script started, file is %s\n", fname); 111 fixtty(); 112 113 (void) signal(SIGCHLD, finish); 114 child = fork(); 115 if (child < 0) { 116 perror("fork"); 117 fail(); 118 } 119 if (child == 0) { 120 subchild = child = fork(); 121 if (child < 0) { 122 perror("fork"); 123 fail(); 124 } 125 if (child) 126 dooutput(); 127 else 128 doshell(); 129 } 130 doinput(); 131 } 132 133 doinput() 134 { 135 register int cc; 136 char ibuf[BUFSIZ]; 137 138 (void) fclose(fscript); 139 while ((cc = read(0, ibuf, BUFSIZ)) > 0) 140 (void) write(master, ibuf, cc); 141 done(); 142 } 143 144 #include <sys/wait.h> 145 146 void 147 finish() 148 { 149 union wait status; 150 register int pid; 151 register int die = 0; 152 153 while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0) 154 if (pid == child) 155 die = 1; 156 157 if (die) 158 done(); 159 } 160 161 dooutput() 162 { 163 register int cc; 164 time_t tvec, time(); 165 char obuf[BUFSIZ], *ctime(); 166 167 (void) close(0); 168 tvec = time((time_t *)NULL); 169 fprintf(fscript, "Script started on %s", ctime(&tvec)); 170 for (;;) { 171 cc = read(master, obuf, sizeof (obuf)); 172 if (cc <= 0) 173 break; 174 (void) write(1, obuf, cc); 175 (void) fwrite(obuf, 1, cc, fscript); 176 } 177 done(); 178 } 179 180 doshell() 181 { 182 int t; 183 184 /*** 185 t = open(_PATH_TTY, O_RDWR); 186 if (t >= 0) { 187 (void) ioctl(t, TIOCNOTTY, (char *)0); 188 (void) close(t); 189 } 190 ***/ 191 getslave(); 192 (void) close(master); 193 (void) fclose(fscript); 194 (void) dup2(slave, 0); 195 (void) dup2(slave, 1); 196 (void) dup2(slave, 2); 197 (void) close(slave); 198 execl(shell, "sh", "-i", 0); 199 perror(shell); 200 fail(); 201 } 202 203 fixtty() 204 { 205 struct termios rtt; 206 207 rtt = tt; 208 cfmakeraw(&rtt); 209 rtt.c_lflag &= ~ECHO; 210 (void) tcsetattr(0, TCSAFLUSH, &rtt); 211 } 212 213 fail() 214 { 215 216 (void) kill(0, SIGTERM); 217 done(); 218 } 219 220 done() 221 { 222 time_t tvec, time(); 223 char *ctime(); 224 225 if (subchild) { 226 tvec = time((time_t *)NULL); 227 fprintf(fscript,"\nScript done on %s", ctime(&tvec)); 228 (void) fclose(fscript); 229 (void) close(master); 230 } else { 231 (void) tcsetattr(0, TCSAFLUSH, &tt); 232 printf("Script done, file is %s\n", fname); 233 } 234 exit(0); 235 } 236 237 getmaster() 238 { 239 char *pty, *bank, *cp; 240 struct stat stb; 241 242 pty = &line[strlen("/dev/ptyp")]; 243 for (bank = "pqrs"; *bank; bank++) { 244 line[strlen("/dev/pty")] = *bank; 245 *pty = '0'; 246 if (stat(line, &stb) < 0) 247 break; 248 for (cp = "0123456789abcdef"; *cp; cp++) { 249 *pty = *cp; 250 master = open(line, O_RDWR); 251 if (master >= 0) { 252 char *tp = &line[strlen("/dev/")]; 253 int ok; 254 255 /* verify slave side is usable */ 256 *tp = 't'; 257 ok = access(line, R_OK|W_OK) == 0; 258 *tp = 'p'; 259 if (ok) { 260 (void) tcgetattr(0, &tt); 261 (void) ioctl(0, TIOCGWINSZ, 262 (char *)&win); 263 return; 264 } 265 (void) close(master); 266 } 267 } 268 } 269 fprintf(stderr, "Out of pty's\n"); 270 fail(); 271 } 272 273 getslave() 274 { 275 276 line[strlen("/dev/")] = 't'; 277 slave = open(line, O_RDWR); 278 if (slave < 0) { 279 perror(line); 280 fail(); 281 } 282 (void) tcsetattr(slave, TCSAFLUSH, &tt); 283 (void) ioctl(slave, TIOCSWINSZ, (char *)&win); 284 (void) setsid(); 285 (void) ioctl(slave, TIOCSCTTY, 0); 286 } 287