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