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