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