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.11 (Berkeley) 06/18/90"; 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 int 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 finish() 120 { 121 union wait status; 122 register int pid; 123 register int die = 0; 124 125 while ((pid = wait3(&status, WNOHANG, 0)) > 0) 126 if (pid == child) 127 die = 1; 128 129 if (die) 130 done(); 131 } 132 133 dooutput() 134 { 135 register int cc; 136 time_t tvec, time(); 137 char obuf[BUFSIZ], *ctime(); 138 139 (void) close(0); 140 tvec = time((time_t *)NULL); 141 fprintf(fscript, "Script started on %s", ctime(&tvec)); 142 for (;;) { 143 cc = read(master, obuf, sizeof (obuf)); 144 if (cc <= 0) 145 break; 146 (void) write(1, obuf, cc); 147 (void) fwrite(obuf, 1, cc, fscript); 148 } 149 done(); 150 } 151 152 doshell() 153 { 154 int t; 155 156 /*** 157 t = open(_PATH_TTY, O_RDWR); 158 if (t >= 0) { 159 (void) ioctl(t, TIOCNOTTY, (char *)0); 160 (void) close(t); 161 } 162 ***/ 163 getslave(); 164 (void) close(master); 165 (void) fclose(fscript); 166 (void) dup2(slave, 0); 167 (void) dup2(slave, 1); 168 (void) dup2(slave, 2); 169 (void) close(slave); 170 execl(shell, "sh", "-i", 0); 171 perror(shell); 172 fail(); 173 } 174 175 fixtty() 176 { 177 struct termios rtt; 178 179 rtt = tt; 180 cfmakeraw(&rtt); 181 rtt.c_lflag &= ~ECHO; 182 (void) tcsetattr(0, TCSAFLUSH, &rtt); 183 } 184 185 fail() 186 { 187 188 (void) kill(0, SIGTERM); 189 done(); 190 } 191 192 done() 193 { 194 time_t tvec, time(); 195 char *ctime(); 196 197 if (subchild) { 198 tvec = time((time_t *)NULL); 199 fprintf(fscript,"\nScript done on %s", ctime(&tvec)); 200 (void) fclose(fscript); 201 (void) close(master); 202 } else { 203 (void) tcsetattr(0, TCSAFLUSH, &tt); 204 printf("Script done, file is %s\n", fname); 205 } 206 exit(0); 207 } 208 209 getmaster() 210 { 211 char *pty, *bank, *cp; 212 struct stat stb; 213 214 pty = &line[strlen("/dev/ptyp")]; 215 for (bank = "pqrs"; *bank; bank++) { 216 line[strlen("/dev/pty")] = *bank; 217 *pty = '0'; 218 if (stat(line, &stb) < 0) 219 break; 220 for (cp = "0123456789abcdef"; *cp; cp++) { 221 *pty = *cp; 222 master = open(line, O_RDWR); 223 if (master >= 0) { 224 char *tp = &line[strlen("/dev/")]; 225 int ok; 226 227 /* verify slave side is usable */ 228 *tp = 't'; 229 ok = access(line, R_OK|W_OK) == 0; 230 *tp = 'p'; 231 if (ok) { 232 (void) tcgetattr(0, &tt); 233 (void) ioctl(0, TIOCGWINSZ, 234 (char *)&win); 235 return; 236 } 237 (void) close(master); 238 } 239 } 240 } 241 fprintf(stderr, "Out of pty's\n"); 242 fail(); 243 } 244 245 getslave() 246 { 247 248 line[strlen("/dev/")] = 't'; 249 slave = open(line, O_RDWR); 250 if (slave < 0) { 251 perror(line); 252 fail(); 253 } 254 (void) tcsetattr(slave, TCSAFLUSH, &tt); 255 (void) ioctl(slave, TIOCSWINSZ, (char *)&win); 256 (void) setsid(); 257 (void) ioctl(slave, TIOCSCTTY, 0); 258 } 259