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