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 are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #ifndef lint 19 char copyright[] = 20 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 21 All rights reserved.\n"; 22 #endif /* not lint */ 23 24 #ifndef lint 25 static char sccsid[] = "@(#)script.c 5.6 (Berkeley) 06/29/88"; 26 #endif /* not lint */ 27 28 /* 29 * script 30 */ 31 #include <sys/types.h> 32 #include <sys/stat.h> 33 #include <sys/ioctl.h> 34 #include <sys/time.h> 35 #include <sys/file.h> 36 #include <stdio.h> 37 #include <signal.h> 38 39 char *shell; 40 FILE *fscript; 41 int master; 42 int slave; 43 int child; 44 int subchild; 45 char *fname; 46 47 struct sgttyb b; 48 struct tchars tc; 49 struct ltchars lc; 50 struct winsize win; 51 int lb; 52 int l; 53 char *line = "/dev/ptyXX"; 54 int aflg; 55 56 main(argc, argv) 57 int argc; 58 char *argv[]; 59 { 60 extern char *optarg; 61 extern int optind; 62 int ch; 63 int finish(); 64 char *getenv(); 65 66 while ((ch = getopt(argc, argv, "a")) != EOF) 67 switch((char)ch) { 68 case 'a': 69 aflg++; 70 break; 71 case '?': 72 default: 73 fprintf(stderr, "usage: script [-a] [file]\n"); 74 exit(1); 75 } 76 argc -= optind; 77 argv += optind; 78 79 if (argc > 0) 80 fname = argv[0]; 81 else 82 fname = "typescript"; 83 if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) { 84 perror(fname); 85 fail(); 86 } 87 88 shell = getenv("SHELL"); 89 if (shell == NULL) 90 shell = "/bin/sh"; 91 92 getmaster(); 93 printf("Script started, file is %s\n", fname); 94 fixtty(); 95 96 (void) signal(SIGCHLD, finish); 97 child = fork(); 98 if (child < 0) { 99 perror("fork"); 100 fail(); 101 } 102 if (child == 0) { 103 subchild = child = fork(); 104 if (child < 0) { 105 perror("fork"); 106 fail(); 107 } 108 if (child) 109 dooutput(); 110 else 111 doshell(); 112 } 113 doinput(); 114 } 115 116 doinput() 117 { 118 register int cc; 119 char ibuf[BUFSIZ]; 120 121 (void) fclose(fscript); 122 while ((cc = read(0, ibuf, BUFSIZ)) > 0) 123 (void) write(master, ibuf, cc); 124 done(); 125 } 126 127 #include <sys/wait.h> 128 129 finish() 130 { 131 union wait status; 132 register int pid; 133 register int die = 0; 134 135 while ((pid = wait3(&status, WNOHANG, 0)) > 0) 136 if (pid == child) 137 die = 1; 138 139 if (die) 140 done(); 141 } 142 143 dooutput() 144 { 145 register int cc; 146 time_t tvec, time(); 147 char obuf[BUFSIZ], *ctime(); 148 149 (void) close(0); 150 tvec = time((time_t *)NULL); 151 fprintf(fscript, "Script started on %s", ctime(&tvec)); 152 for (;;) { 153 cc = read(master, obuf, sizeof (obuf)); 154 if (cc <= 0) 155 break; 156 (void) write(1, obuf, cc); 157 (void) fwrite(obuf, 1, cc, fscript); 158 } 159 done(); 160 } 161 162 doshell() 163 { 164 int t; 165 166 t = open("/dev/tty", O_RDWR); 167 if (t >= 0) { 168 (void) ioctl(t, TIOCNOTTY, (char *)0); 169 (void) close(t); 170 } 171 getslave(); 172 (void) close(master); 173 (void) fclose(fscript); 174 (void) dup2(slave, 0); 175 (void) dup2(slave, 1); 176 (void) dup2(slave, 2); 177 (void) close(slave); 178 execl(shell, "sh", "-i", 0); 179 perror(shell); 180 fail(); 181 } 182 183 fixtty() 184 { 185 struct sgttyb sbuf; 186 187 sbuf = b; 188 sbuf.sg_flags |= RAW; 189 sbuf.sg_flags &= ~ECHO; 190 (void) ioctl(0, TIOCSETP, (char *)&sbuf); 191 } 192 193 fail() 194 { 195 196 (void) kill(0, SIGTERM); 197 done(); 198 } 199 200 done() 201 { 202 time_t tvec, time(); 203 char *ctime(); 204 205 if (subchild) { 206 tvec = time((time_t *)NULL); 207 fprintf(fscript,"\nscript done on %s", ctime(&tvec)); 208 (void) fclose(fscript); 209 (void) close(master); 210 } else { 211 (void) ioctl(0, TIOCSETP, (char *)&b); 212 printf("Script done, file is %s\n", fname); 213 } 214 exit(0); 215 } 216 217 getmaster() 218 { 219 char *pty, *bank, *cp; 220 struct stat stb; 221 222 pty = &line[strlen("/dev/ptyp")]; 223 for (bank = "pqrs"; *bank; bank++) { 224 line[strlen("/dev/pty")] = *bank; 225 *pty = '0'; 226 if (stat(line, &stb) < 0) 227 break; 228 for (cp = "0123456789abcdef"; *cp; cp++) { 229 *pty = *cp; 230 master = open(line, O_RDWR); 231 if (master >= 0) { 232 char *tp = &line[strlen("/dev/")]; 233 int ok; 234 235 /* verify slave side is usable */ 236 *tp = 't'; 237 ok = access(line, R_OK|W_OK) == 0; 238 *tp = 'p'; 239 if (ok) { 240 (void) ioctl(0, TIOCGETP, (char *)&b); 241 (void) ioctl(0, TIOCGETC, (char *)&tc); 242 (void) ioctl(0, TIOCGETD, (char *)&l); 243 (void) ioctl(0, TIOCGLTC, (char *)&lc); 244 (void) ioctl(0, TIOCLGET, (char *)&lb); 245 (void) ioctl(0, TIOCGWINSZ, (char *)&win); 246 return; 247 } 248 (void) close(master); 249 } 250 } 251 } 252 fprintf(stderr, "Out of pty's\n"); 253 fail(); 254 } 255 256 getslave() 257 { 258 259 line[strlen("/dev/")] = 't'; 260 slave = open(line, O_RDWR); 261 if (slave < 0) { 262 perror(line); 263 fail(); 264 } 265 (void) ioctl(slave, TIOCSETP, (char *)&b); 266 (void) ioctl(slave, TIOCSETC, (char *)&tc); 267 (void) ioctl(slave, TIOCSLTC, (char *)&lc); 268 (void) ioctl(slave, TIOCLSET, (char *)&lb); 269 (void) ioctl(slave, TIOCSETD, (char *)&l); 270 (void) ioctl(slave, TIOCSWINSZ, (char *)&win); 271 } 272