1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 4*7c478bd9Sstevel@tonic-gate */ 5*7c478bd9Sstevel@tonic-gate 6*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 7*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 8*7c478bd9Sstevel@tonic-gate 9*7c478bd9Sstevel@tonic-gate 10*7c478bd9Sstevel@tonic-gate /* 11*7c478bd9Sstevel@tonic-gate * Copyright (c) 1980 Regents of the University of California. 12*7c478bd9Sstevel@tonic-gate * All rights reserved. The Berkeley software License Agreement 13*7c478bd9Sstevel@tonic-gate * specifies the terms and conditions for redistribution. 14*7c478bd9Sstevel@tonic-gate */ 15*7c478bd9Sstevel@tonic-gate 16*7c478bd9Sstevel@tonic-gate /* Portions Copyright(c) 1988, Sun Microsystems, Inc. */ 17*7c478bd9Sstevel@tonic-gate /* All Rights Reserved. */ 18*7c478bd9Sstevel@tonic-gate 19*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 20*7c478bd9Sstevel@tonic-gate 21*7c478bd9Sstevel@tonic-gate /* 22*7c478bd9Sstevel@tonic-gate * script 23*7c478bd9Sstevel@tonic-gate */ 24*7c478bd9Sstevel@tonic-gate #include <stdio.h> 25*7c478bd9Sstevel@tonic-gate #include <signal.h> 26*7c478bd9Sstevel@tonic-gate #include <fcntl.h> 27*7c478bd9Sstevel@tonic-gate #include <locale.h> 28*7c478bd9Sstevel@tonic-gate #include <time.h> 29*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 30*7c478bd9Sstevel@tonic-gate #include <sys/types.h> 31*7c478bd9Sstevel@tonic-gate #include <sys/stat.h> 32*7c478bd9Sstevel@tonic-gate #include <sys/termios.h> 33*7c478bd9Sstevel@tonic-gate #include <sys/file.h> 34*7c478bd9Sstevel@tonic-gate #include <errno.h> 35*7c478bd9Sstevel@tonic-gate 36*7c478bd9Sstevel@tonic-gate int grantpt(); 37*7c478bd9Sstevel@tonic-gate int unlockpt(); 38*7c478bd9Sstevel@tonic-gate char *ptsname(); 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate char *getenv(); 41*7c478bd9Sstevel@tonic-gate struct tm *localtime(); 42*7c478bd9Sstevel@tonic-gate char *shell; 43*7c478bd9Sstevel@tonic-gate FILE *fscript; 44*7c478bd9Sstevel@tonic-gate int master; /* file descriptor for master pseudo-tty */ 45*7c478bd9Sstevel@tonic-gate int slave; /* file descriptor for slave pseudo-tty */ 46*7c478bd9Sstevel@tonic-gate int child; 47*7c478bd9Sstevel@tonic-gate int subchild; 48*7c478bd9Sstevel@tonic-gate char *fname = "typescript"; 49*7c478bd9Sstevel@tonic-gate void sigwinch(); 50*7c478bd9Sstevel@tonic-gate void finish(); 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate struct termios b; 53*7c478bd9Sstevel@tonic-gate struct winsize size; 54*7c478bd9Sstevel@tonic-gate int lb; 55*7c478bd9Sstevel@tonic-gate int l; 56*7c478bd9Sstevel@tonic-gate char *mptname = "/dev/ptmx"; /* master pseudo-tty device */ 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate int aflg; 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate main(argc, argv) 61*7c478bd9Sstevel@tonic-gate int argc; 62*7c478bd9Sstevel@tonic-gate char *argv[]; 63*7c478bd9Sstevel@tonic-gate { 64*7c478bd9Sstevel@tonic-gate uid_t ruidt; 65*7c478bd9Sstevel@tonic-gate gid_t gidt; 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate (void) setlocale(LC_ALL, ""); 68*7c478bd9Sstevel@tonic-gate #if !defined(TEXT_DOMAIN) 69*7c478bd9Sstevel@tonic-gate #define TEXT_DOMAIN "SYS_TEST" 70*7c478bd9Sstevel@tonic-gate #endif 71*7c478bd9Sstevel@tonic-gate (void) textdomain(TEXT_DOMAIN); 72*7c478bd9Sstevel@tonic-gate 73*7c478bd9Sstevel@tonic-gate shell = getenv("SHELL"); 74*7c478bd9Sstevel@tonic-gate if (shell == 0) 75*7c478bd9Sstevel@tonic-gate shell = "/bin/sh"; 76*7c478bd9Sstevel@tonic-gate argc--, argv++; 77*7c478bd9Sstevel@tonic-gate while (argc > 0 && argv[0][0] == '-') { 78*7c478bd9Sstevel@tonic-gate switch (argv[0][1]) { 79*7c478bd9Sstevel@tonic-gate 80*7c478bd9Sstevel@tonic-gate case 'a': 81*7c478bd9Sstevel@tonic-gate aflg++; 82*7c478bd9Sstevel@tonic-gate break; 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate default: 85*7c478bd9Sstevel@tonic-gate fprintf(stderr, 86*7c478bd9Sstevel@tonic-gate gettext("usage: script [ -a ] [ typescript ]\n")); 87*7c478bd9Sstevel@tonic-gate exit(1); 88*7c478bd9Sstevel@tonic-gate } 89*7c478bd9Sstevel@tonic-gate argc--, argv++; 90*7c478bd9Sstevel@tonic-gate } 91*7c478bd9Sstevel@tonic-gate if (argc > 0) 92*7c478bd9Sstevel@tonic-gate fname = argv[0]; 93*7c478bd9Sstevel@tonic-gate ruidt = getuid(); 94*7c478bd9Sstevel@tonic-gate gidt = getgid(); 95*7c478bd9Sstevel@tonic-gate if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) { 96*7c478bd9Sstevel@tonic-gate perror(fname); 97*7c478bd9Sstevel@tonic-gate fail(); 98*7c478bd9Sstevel@tonic-gate } 99*7c478bd9Sstevel@tonic-gate chown(fname, ruidt, gidt); 100*7c478bd9Sstevel@tonic-gate getmaster(); 101*7c478bd9Sstevel@tonic-gate printf(gettext("Script started, file is %s\n"), fname); 102*7c478bd9Sstevel@tonic-gate fixtty(); 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate (void) signal(SIGCHLD, finish); 105*7c478bd9Sstevel@tonic-gate child = fork(); 106*7c478bd9Sstevel@tonic-gate if (child < 0) { 107*7c478bd9Sstevel@tonic-gate perror("fork"); 108*7c478bd9Sstevel@tonic-gate fail(); 109*7c478bd9Sstevel@tonic-gate } 110*7c478bd9Sstevel@tonic-gate if (child == 0) { 111*7c478bd9Sstevel@tonic-gate subchild = child = fork(); 112*7c478bd9Sstevel@tonic-gate if (child < 0) { 113*7c478bd9Sstevel@tonic-gate perror("fork"); 114*7c478bd9Sstevel@tonic-gate fail(); 115*7c478bd9Sstevel@tonic-gate } 116*7c478bd9Sstevel@tonic-gate if (child) 117*7c478bd9Sstevel@tonic-gate dooutput(); 118*7c478bd9Sstevel@tonic-gate else 119*7c478bd9Sstevel@tonic-gate doshell(); 120*7c478bd9Sstevel@tonic-gate } 121*7c478bd9Sstevel@tonic-gate doinput(); 122*7c478bd9Sstevel@tonic-gate } 123*7c478bd9Sstevel@tonic-gate 124*7c478bd9Sstevel@tonic-gate doinput() 125*7c478bd9Sstevel@tonic-gate { 126*7c478bd9Sstevel@tonic-gate char ibuf[BUFSIZ]; 127*7c478bd9Sstevel@tonic-gate int cc; 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate (void) fclose(fscript); 130*7c478bd9Sstevel@tonic-gate sigset(SIGWINCH, sigwinch); 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate while ((cc = read(0, ibuf, BUFSIZ)) != 0) { 133*7c478bd9Sstevel@tonic-gate if (cc == -1) { 134*7c478bd9Sstevel@tonic-gate if (errno == EINTR) { /* SIGWINCH probably */ 135*7c478bd9Sstevel@tonic-gate continue; 136*7c478bd9Sstevel@tonic-gate } else { 137*7c478bd9Sstevel@tonic-gate break; 138*7c478bd9Sstevel@tonic-gate } 139*7c478bd9Sstevel@tonic-gate } 140*7c478bd9Sstevel@tonic-gate (void) write(master, ibuf, cc); 141*7c478bd9Sstevel@tonic-gate } 142*7c478bd9Sstevel@tonic-gate done(); 143*7c478bd9Sstevel@tonic-gate } 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate void 146*7c478bd9Sstevel@tonic-gate sigwinch() 147*7c478bd9Sstevel@tonic-gate { 148*7c478bd9Sstevel@tonic-gate struct winsize ws; 149*7c478bd9Sstevel@tonic-gate 150*7c478bd9Sstevel@tonic-gate if (ioctl(0, TIOCGWINSZ, &ws) == 0) 151*7c478bd9Sstevel@tonic-gate (void) ioctl(master, TIOCSWINSZ, &ws); 152*7c478bd9Sstevel@tonic-gate } 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate #include <sys/wait.h> 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate void 157*7c478bd9Sstevel@tonic-gate finish() 158*7c478bd9Sstevel@tonic-gate { 159*7c478bd9Sstevel@tonic-gate int status; 160*7c478bd9Sstevel@tonic-gate register int pid; 161*7c478bd9Sstevel@tonic-gate register int die = 0; 162*7c478bd9Sstevel@tonic-gate 163*7c478bd9Sstevel@tonic-gate while ((pid = wait(&status)) > 0) 164*7c478bd9Sstevel@tonic-gate if (pid == child) 165*7c478bd9Sstevel@tonic-gate die = 1; 166*7c478bd9Sstevel@tonic-gate 167*7c478bd9Sstevel@tonic-gate if (die) 168*7c478bd9Sstevel@tonic-gate done(); 169*7c478bd9Sstevel@tonic-gate } 170*7c478bd9Sstevel@tonic-gate 171*7c478bd9Sstevel@tonic-gate dooutput() 172*7c478bd9Sstevel@tonic-gate { 173*7c478bd9Sstevel@tonic-gate time_t tvec; 174*7c478bd9Sstevel@tonic-gate char obuf[BUFSIZ]; 175*7c478bd9Sstevel@tonic-gate char tbuf[BUFSIZ]; 176*7c478bd9Sstevel@tonic-gate int cc; 177*7c478bd9Sstevel@tonic-gate 178*7c478bd9Sstevel@tonic-gate (void) close(0); 179*7c478bd9Sstevel@tonic-gate tvec = time((time_t *)0); 180*7c478bd9Sstevel@tonic-gate strftime(tbuf, BUFSIZ, "%c", localtime(&tvec)); 181*7c478bd9Sstevel@tonic-gate fprintf(fscript, gettext("Script started on %s\n"), tbuf); 182*7c478bd9Sstevel@tonic-gate for (;;) { 183*7c478bd9Sstevel@tonic-gate cc = read(master, obuf, sizeof (obuf)); 184*7c478bd9Sstevel@tonic-gate if (cc <= 0) 185*7c478bd9Sstevel@tonic-gate break; 186*7c478bd9Sstevel@tonic-gate (void) write(1, obuf, cc); 187*7c478bd9Sstevel@tonic-gate (void) fwrite(obuf, 1, cc, fscript); 188*7c478bd9Sstevel@tonic-gate } 189*7c478bd9Sstevel@tonic-gate done(); 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate 192*7c478bd9Sstevel@tonic-gate doshell() 193*7c478bd9Sstevel@tonic-gate { 194*7c478bd9Sstevel@tonic-gate 195*7c478bd9Sstevel@tonic-gate setpgrp(); /* relinquish control terminal */ 196*7c478bd9Sstevel@tonic-gate getslave(); 197*7c478bd9Sstevel@tonic-gate (void) close(master); 198*7c478bd9Sstevel@tonic-gate (void) fclose(fscript); 199*7c478bd9Sstevel@tonic-gate (void) dup2(slave, 0); 200*7c478bd9Sstevel@tonic-gate (void) dup2(slave, 1); 201*7c478bd9Sstevel@tonic-gate (void) dup2(slave, 2); 202*7c478bd9Sstevel@tonic-gate (void) close(slave); 203*7c478bd9Sstevel@tonic-gate execl(shell, shell, "-i", (char *)0); 204*7c478bd9Sstevel@tonic-gate perror(shell); 205*7c478bd9Sstevel@tonic-gate fail(); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate fixtty() 209*7c478bd9Sstevel@tonic-gate { 210*7c478bd9Sstevel@tonic-gate struct termios sbuf; 211*7c478bd9Sstevel@tonic-gate 212*7c478bd9Sstevel@tonic-gate sbuf = b; 213*7c478bd9Sstevel@tonic-gate sbuf.c_iflag &= ~(INLCR|IGNCR|ICRNL|IUCLC|IXON); 214*7c478bd9Sstevel@tonic-gate sbuf.c_oflag &= ~OPOST; 215*7c478bd9Sstevel@tonic-gate sbuf.c_lflag &= ~(ICANON|ISIG|ECHO); 216*7c478bd9Sstevel@tonic-gate sbuf.c_cc[VMIN] = 1; 217*7c478bd9Sstevel@tonic-gate sbuf.c_cc[VTIME] = 0; 218*7c478bd9Sstevel@tonic-gate (void) ioctl(0, TCSETSF, (char *)&sbuf); 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate fail() 222*7c478bd9Sstevel@tonic-gate { 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate (void) kill(0, SIGTERM); 225*7c478bd9Sstevel@tonic-gate done(); 226*7c478bd9Sstevel@tonic-gate } 227*7c478bd9Sstevel@tonic-gate 228*7c478bd9Sstevel@tonic-gate done() 229*7c478bd9Sstevel@tonic-gate { 230*7c478bd9Sstevel@tonic-gate time_t tvec; 231*7c478bd9Sstevel@tonic-gate char tbuf[BUFSIZ]; 232*7c478bd9Sstevel@tonic-gate 233*7c478bd9Sstevel@tonic-gate if (subchild) { 234*7c478bd9Sstevel@tonic-gate tvec = time((time_t *)0); 235*7c478bd9Sstevel@tonic-gate strftime(tbuf, BUFSIZ, "%c", localtime(&tvec)); 236*7c478bd9Sstevel@tonic-gate fprintf(fscript, gettext("\nscript done on %s\n"), tbuf); 237*7c478bd9Sstevel@tonic-gate (void) fclose(fscript); 238*7c478bd9Sstevel@tonic-gate (void) close(master); 239*7c478bd9Sstevel@tonic-gate } else { 240*7c478bd9Sstevel@tonic-gate (void) ioctl(0, TCSETSW, (char *)&b); 241*7c478bd9Sstevel@tonic-gate printf(gettext("Script done, file is %s\n"), fname); 242*7c478bd9Sstevel@tonic-gate } 243*7c478bd9Sstevel@tonic-gate exit(0); 244*7c478bd9Sstevel@tonic-gate } 245*7c478bd9Sstevel@tonic-gate 246*7c478bd9Sstevel@tonic-gate getmaster() 247*7c478bd9Sstevel@tonic-gate { 248*7c478bd9Sstevel@tonic-gate struct stat stb; 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate if ((master = open(mptname, O_RDWR)) >= 0) { /* a pseudo-tty is free */ 251*7c478bd9Sstevel@tonic-gate (void) ioctl(0, TCGETS, (char *)&b); 252*7c478bd9Sstevel@tonic-gate (void) ioctl(0, TIOCGWINSZ, (char *)&size); 253*7c478bd9Sstevel@tonic-gate return; 254*7c478bd9Sstevel@tonic-gate } else { /* out of pseudo-tty's */ 255*7c478bd9Sstevel@tonic-gate perror(mptname); 256*7c478bd9Sstevel@tonic-gate fprintf(stderr, gettext("Out of pseudo-tty's\n")); 257*7c478bd9Sstevel@tonic-gate fail(); 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate } 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate getslave() 262*7c478bd9Sstevel@tonic-gate { 263*7c478bd9Sstevel@tonic-gate char *slavename; /* name of slave pseudo-tty */ 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate grantpt(master); /* change permissions of slave */ 266*7c478bd9Sstevel@tonic-gate unlockpt(master); /* unlock slave */ 267*7c478bd9Sstevel@tonic-gate slavename = ptsname(master); /* get name of slave */ 268*7c478bd9Sstevel@tonic-gate slave = open(slavename, O_RDWR); /* open slave */ 269*7c478bd9Sstevel@tonic-gate if (slave < 0) { /* error on opening slave */ 270*7c478bd9Sstevel@tonic-gate perror(slavename); 271*7c478bd9Sstevel@tonic-gate fail(); 272*7c478bd9Sstevel@tonic-gate } 273*7c478bd9Sstevel@tonic-gate ioctl(slave, I_PUSH, "ptem"); /* push pt hw emulation module */ 274*7c478bd9Sstevel@tonic-gate ioctl(slave, I_PUSH, "ldterm"); /* push line discipline */ 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate (void) ioctl(slave, TCSETSF, (char *)&b); 277*7c478bd9Sstevel@tonic-gate (void) ioctl(slave, TIOCSWINSZ, (char *)&size); 278*7c478bd9Sstevel@tonic-gate } 279