[BACK]Return to script.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / usr.bin / script

Annotation of src/usr.bin/script/script.c, Revision 1.10

1.10    ! wiz         1: /*     $NetBSD: script.c,v 1.9 2003/08/07 11:15:48 agc Exp $   */
1.3       jtc         2:
1.1       cgd         3: /*
1.3       jtc         4:  * Copyright (c) 1980, 1992, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
1.9       agc        15:  * 3. Neither the name of the University nor the names of its contributors
1.1       cgd        16:  *    may be used to endorse or promote products derived from this software
                     17:  *    without specific prior written permission.
                     18:  *
                     19:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     20:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     21:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     22:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     23:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     24:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     25:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     26:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     27:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     28:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     29:  * SUCH DAMAGE.
                     30:  */
                     31:
1.5       lukem      32: #include <sys/cdefs.h>
1.1       cgd        33: #ifndef lint
1.5       lukem      34: __COPYRIGHT("@(#) Copyright (c) 1980, 1992, 1993\n\
                     35:        The Regents of the University of California.  All rights reserved.\n");
1.1       cgd        36: #endif /* not lint */
                     37:
                     38: #ifndef lint
1.3       jtc        39: #if 0
                     40: static char sccsid[] = "@(#)script.c   8.1 (Berkeley) 6/6/93";
                     41: #endif
1.10    ! wiz        42: __RCSID("$NetBSD: script.c,v 1.9 2003/08/07 11:15:48 agc Exp $");
1.1       cgd        43: #endif /* not lint */
                     44:
                     45: #include <sys/types.h>
1.3       jtc        46: #include <sys/wait.h>
1.1       cgd        47: #include <sys/stat.h>
                     48: #include <sys/ioctl.h>
                     49: #include <sys/time.h>
1.8       atatat     50: #include <sys/uio.h>
1.3       jtc        51:
1.5       lukem      52: #include <err.h>
1.3       jtc        53: #include <errno.h>
                     54: #include <fcntl.h>
                     55: #include <paths.h>
                     56: #include <signal.h>
1.1       cgd        57: #include <stdio.h>
1.3       jtc        58: #include <stdlib.h>
                     59: #include <string.h>
                     60: #include <termios.h>
1.6       kleink     61: #include <time.h>
1.3       jtc        62: #include <tzfile.h>
                     63: #include <unistd.h>
1.5       lukem      64: #include <util.h>
1.1       cgd        65:
1.8       atatat     66: struct stamp {
                     67:        uint64_t scr_len;       /* amount of data */
                     68:        uint64_t scr_sec;       /* time it arrived in seconds... */
                     69:        uint32_t scr_usec;      /* ...and microseconds */
                     70:        uint32_t scr_direction; /* 'i', 'o', etc (also indicates endianness) */
                     71: };
                     72:
1.1       cgd        73: FILE   *fscript;
1.3       jtc        74: int    master, slave;
                     75: int    child, subchild;
                     76: int    outcc;
1.8       atatat     77: int    usesleep, rawout;
1.1       cgd        78: char   *fname;
                     79:
                     80: struct termios tt;
                     81:
1.5       lukem      82: void   done __P((void));
                     83: void   dooutput __P((void));
                     84: void   doshell __P((void));
                     85: void   fail __P((void));
                     86: void   finish __P((int));
                     87: int    main __P((int, char **));
                     88: void   scriptflush __P((int));
1.8       atatat     89: void   record __P((FILE *, char *, size_t, int));
                     90: void   playback __P((FILE *));
1.3       jtc        91:
                     92: int
1.1       cgd        93: main(argc, argv)
                     94:        int argc;
                     95:        char *argv[];
                     96: {
1.5       lukem      97:        int cc;
1.3       jtc        98:        struct termios rtt;
                     99:        struct winsize win;
1.8       atatat    100:        int aflg, pflg, ch;
1.3       jtc       101:        char ibuf[BUFSIZ];
1.1       cgd       102:
1.3       jtc       103:        aflg = 0;
1.8       atatat    104:        pflg = 0;
                    105:        usesleep = 1;
                    106:        rawout = 0;
                    107:        while ((ch = getopt(argc, argv, "adpr")) != -1)
1.3       jtc       108:                switch(ch) {
1.1       cgd       109:                case 'a':
1.3       jtc       110:                        aflg = 1;
1.1       cgd       111:                        break;
1.8       atatat    112:                case 'd':
                    113:                        usesleep = 0;
                    114:                        break;
                    115:                case 'p':
                    116:                        pflg = 1;
                    117:                        break;
                    118:                case 'r':
                    119:                        rawout = 1;
                    120:                        break;
1.1       cgd       121:                case '?':
                    122:                default:
1.10    ! wiz       123:                        (void)fprintf(stderr, "usage: %s [-adpr] [file]\n",
        !           124:                            getprogname());
1.1       cgd       125:                        exit(1);
                    126:                }
                    127:        argc -= optind;
                    128:        argv += optind;
                    129:
                    130:        if (argc > 0)
                    131:                fname = argv[0];
                    132:        else
                    133:                fname = "typescript";
                    134:
1.8       atatat    135:        if ((fscript = fopen(fname, pflg ? "r" : aflg ? "a" : "w")) == NULL)
1.5       lukem     136:                err(1, "fopen %s", fname);
1.3       jtc       137:
1.8       atatat    138:        if (pflg)
                    139:                playback(fscript);
                    140:
1.3       jtc       141:        (void)tcgetattr(STDIN_FILENO, &tt);
                    142:        (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win);
                    143:        if (openpty(&master, &slave, NULL, &tt, &win) == -1)
1.5       lukem     144:                err(1, "openpty");
1.1       cgd       145:
1.3       jtc       146:        (void)printf("Script started, output file is %s\n", fname);
                    147:        rtt = tt;
                    148:        cfmakeraw(&rtt);
                    149:        rtt.c_lflag &= ~ECHO;
                    150:        (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &rtt);
1.1       cgd       151:
1.3       jtc       152:        (void)signal(SIGCHLD, finish);
1.1       cgd       153:        child = fork();
                    154:        if (child < 0) {
1.5       lukem     155:                warn("fork");
1.1       cgd       156:                fail();
                    157:        }
                    158:        if (child == 0) {
                    159:                subchild = child = fork();
                    160:                if (child < 0) {
1.5       lukem     161:                        warn("fork");
1.1       cgd       162:                        fail();
                    163:                }
                    164:                if (child)
                    165:                        dooutput();
                    166:                else
                    167:                        doshell();
                    168:        }
                    169:
1.8       atatat    170:        if (!rawout)
                    171:                (void)fclose(fscript);
                    172:        while ((cc = read(STDIN_FILENO, ibuf, BUFSIZ)) > 0) {
                    173:                if (rawout)
                    174:                        record(fscript, ibuf, cc, 'i');
1.3       jtc       175:                (void)write(master, ibuf, cc);
1.8       atatat    176:        }
1.1       cgd       177:        done();
1.5       lukem     178:        /* NOTREACHED */
                    179:        return (0);
1.1       cgd       180: }
                    181:
                    182: void
1.3       jtc       183: finish(signo)
                    184:        int signo;
1.1       cgd       185: {
1.7       christos  186:        int die, pid, status;
1.1       cgd       187:
1.3       jtc       188:        die = 0;
1.7       christos  189:        while ((pid = wait3(&status, WNOHANG, 0)) > 0)
1.1       cgd       190:                if (pid == child)
                    191:                        die = 1;
                    192:
                    193:        if (die)
                    194:                done();
                    195: }
                    196:
1.3       jtc       197: void
1.1       cgd       198: dooutput()
                    199: {
1.3       jtc       200:        struct itimerval value;
1.5       lukem     201:        int cc;
1.3       jtc       202:        time_t tvec;
                    203:        char obuf[BUFSIZ];
1.1       cgd       204:
1.3       jtc       205:        (void)close(STDIN_FILENO);
                    206:        tvec = time(NULL);
1.8       atatat    207:        if (rawout)
                    208:                record(fscript, NULL, 0, 's');
                    209:        else
                    210:                (void)fprintf(fscript, "Script started on %s", ctime(&tvec));
1.3       jtc       211:
                    212:        (void)signal(SIGALRM, scriptflush);
                    213:        value.it_interval.tv_sec = SECSPERMIN / 2;
                    214:        value.it_interval.tv_usec = 0;
                    215:        value.it_value = value.it_interval;
                    216:        (void)setitimer(ITIMER_REAL, &value, NULL);
1.1       cgd       217:        for (;;) {
                    218:                cc = read(master, obuf, sizeof (obuf));
                    219:                if (cc <= 0)
                    220:                        break;
1.3       jtc       221:                (void)write(1, obuf, cc);
1.8       atatat    222:                if (rawout)
                    223:                        record(fscript, obuf, cc, 'o');
                    224:                else
                    225:                        (void)fwrite(obuf, 1, cc, fscript);
1.3       jtc       226:                outcc += cc;
1.1       cgd       227:        }
                    228:        done();
                    229: }
                    230:
1.3       jtc       231: void
                    232: scriptflush(signo)
                    233:        int signo;
1.1       cgd       234: {
1.3       jtc       235:        if (outcc) {
                    236:                (void)fflush(fscript);
                    237:                outcc = 0;
1.1       cgd       238:        }
                    239: }
                    240:
1.3       jtc       241: void
                    242: doshell()
1.1       cgd       243: {
1.3       jtc       244:        char *shell;
                    245:
                    246:        shell = getenv("SHELL");
                    247:        if (shell == NULL)
                    248:                shell = _PATH_BSHELL;
1.1       cgd       249:
1.3       jtc       250:        (void)close(master);
                    251:        (void)fclose(fscript);
                    252:        login_tty(slave);
1.4       mikel     253:        execl(shell, shell, "-i", NULL);
1.5       lukem     254:        warn("execl %s", shell);
1.3       jtc       255:        fail();
1.1       cgd       256: }
                    257:
1.3       jtc       258: void
1.1       cgd       259: fail()
                    260: {
                    261:
1.3       jtc       262:        (void)kill(0, SIGTERM);
1.1       cgd       263:        done();
                    264: }
                    265:
1.3       jtc       266: void
1.1       cgd       267: done()
                    268: {
1.3       jtc       269:        time_t tvec;
1.1       cgd       270:
                    271:        if (subchild) {
1.3       jtc       272:                tvec = time(NULL);
1.8       atatat    273:                if (rawout)
                    274:                        record(fscript, NULL, 0, 'e');
                    275:                else
                    276:                        (void)fprintf(fscript,"\nScript done on %s",
                    277:                            ctime(&tvec));
1.3       jtc       278:                (void)fclose(fscript);
                    279:                (void)close(master);
1.1       cgd       280:        } else {
1.3       jtc       281:                (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
                    282:                (void)printf("Script done, output file is %s\n", fname);
1.1       cgd       283:        }
1.8       atatat    284:        exit(0);
                    285: }
                    286:
                    287: void
                    288: record(fscript, buf, cc, direction)
                    289:        FILE *fscript;
                    290:        char *buf;
                    291:        size_t cc;
                    292:        int direction;
                    293: {
                    294:        struct iovec iov[2];
                    295:        struct stamp stamp;
                    296:        struct timeval tv;
                    297:
                    298:        (void)gettimeofday(&tv, NULL);
                    299:        stamp.scr_len = cc;
                    300:        stamp.scr_sec = tv.tv_sec;
                    301:        stamp.scr_usec = tv.tv_usec;
                    302:        stamp.scr_direction = direction;
                    303:        iov[0].iov_len = sizeof(stamp);
                    304:        iov[0].iov_base = &stamp;
                    305:        iov[1].iov_len = cc;
                    306:        iov[1].iov_base = buf;
                    307:        if (writev(fileno(fscript), &iov[0], 2) == -1)
                    308:                err(1, "writev");
                    309: }
                    310:
                    311: #define swapstamp(stamp) do { \
                    312:        if (stamp.scr_direction > 0xff) { \
                    313:                stamp.scr_len = bswap64(stamp.scr_len); \
                    314:                stamp.scr_sec = bswap64(stamp.scr_sec); \
                    315:                stamp.scr_usec = bswap32(stamp.scr_usec); \
                    316:                stamp.scr_direction = bswap32(stamp.scr_direction); \
                    317:        } \
                    318: } while (0/*CONSTCOND*/)
                    319:
                    320: void
                    321: playback(fscript)
                    322:        FILE *fscript;
                    323: {
                    324:        struct timespec tsi, tso;
                    325:        struct stamp stamp;
                    326:        char buf[BUFSIZ];
                    327:        size_t l;
                    328:        time_t clock;
                    329:
                    330:        do {
                    331:                if (fread(&stamp, sizeof(stamp), 1, fscript) != 1)
                    332:                        err(1, "reading playback header");
                    333:
                    334:                swapstamp(stamp);
                    335:                l = fread(buf, 1, stamp.scr_len, fscript);
                    336:                clock = stamp.scr_sec;
                    337:                tso.tv_sec = stamp.scr_sec;
                    338:                tso.tv_nsec = stamp.scr_usec * 1000;
                    339:
                    340:                switch (stamp.scr_direction) {
                    341:                case 's':
                    342:                        (void)printf("Script started on %s", ctime(&clock));
                    343:                        tsi = tso;
                    344:                        break;
                    345:                case 'e':
                    346:                        (void)printf("\nScript done on %s", ctime(&clock));
                    347:                        break;
                    348:                case 'i':
                    349:                        /* throw input away */
                    350:                        break;
                    351:                case 'o':
                    352:                        tsi.tv_sec = tso.tv_sec - tsi.tv_sec;
                    353:                        tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec;
                    354:                        if (tsi.tv_nsec < 0) {
                    355:                                tsi.tv_sec -= 1;
                    356:                                tsi.tv_nsec += 1000000000;
                    357:                        }
                    358:                        if (usesleep)
                    359:                                (void)nanosleep(&tsi, NULL);
                    360:                        tsi = tso;
                    361:                        (void)write(STDOUT_FILENO, buf, l);
                    362:                        break;
                    363:                }
                    364:        } while (stamp.scr_direction != 'e');
                    365:
                    366:        (void)fclose(fscript);
1.1       cgd       367:        exit(0);
                    368: }

CVSweb <webmaster@jp.NetBSD.org>