The following reply was made to PR bin/114465; it has been noted by GNATS.

From: Anonymous <swel...@gmail.com>
To: bug-follo...@freebsd.org
Cc:  
Subject: Re: bin/114465: [patch] [request] script(1): add really cool -d, -p & 
-r options from NetBSD
Date: Mon, 20 Dec 2010 19:28:15 +0300

 Anonymous <swel...@gmail.com> writes:
 
 > +                    if (argv[0])
 > +                            fprintf(fscript, "command: ");
 > +                    for (k = 0 ; argv[k] ; ++k)
 > +                            fprintf(fscript, "%s%s", k ? " " : "", argv[k]);
 > +                    fprintf(fscript, "\n");
 
 I've sent wrong patch, the one without braces.
 
 --- script_replay.diff begins here ---
 Index: usr.bin/script/script.1
 ===================================================================
 --- usr.bin/script/script.1    (revision 216591)
 +++ usr.bin/script/script.1    (working copy)
 @@ -36,7 +36,7 @@
  .Nd make typescript of terminal session
  .Sh SYNOPSIS
  .Nm
 -.Op Fl akq
 +.Op Fl adkpqr
  .Op Fl t Ar time
  .Op Ar file Op Ar command ...
  .Sh DESCRIPTION
 @@ -72,10 +72,16 @@
  or
  .Pa typescript ,
  retaining the prior contents.
 +.It Fl d
 +Don't sleep between records when playing back a timestamped session.
  .It Fl k
  Log keys sent to program as well as output.
 +.It Fl p
 +Play back a recorded session in real time.
  .It Fl q
 -Run in quiet mode, omit the start and stop status messages.
 +Run in quiet mode, omit the start, stop and command status messages.
 +.It Fl r
 +Record a session with input, output, and timestamping.
  .It Fl t Ar time
  Specify time interval between flushing script output file.
  A value of 0
 @@ -148,6 +154,13 @@
  .Nm
  command appeared in
  .Bx 3.0 .
 +.Pp
 +The
 +.Fl d ,
 +.Fl p
 +and
 +.Fl r
 +options were imported from NetBSD.
  .Sh BUGS
  The
  .Nm
 Index: usr.bin/script/script.c
 ===================================================================
 --- usr.bin/script/script.c    (revision 216591)
 +++ usr.bin/script/script.c    (working copy)
 @@ -46,6 +46,9 @@
  #include <sys/stat.h>
  #include <sys/ioctl.h>
  #include <sys/time.h>
 +#include <sys/uio.h>
 +#include <sys/endian.h>
 +#include <sys/param.h>
  
  #include <err.h>
  #include <errno.h>
 @@ -59,11 +62,21 @@
  #include <termios.h>
  #include <unistd.h>
  
 +#define DEF_BUF 65536
 +
 +struct stamp {
 +      uint64_t scr_len;       /* amount of data */
 +      uint64_t scr_sec;       /* time it arrived in seconds... */
 +      uint32_t scr_usec;      /* ...and microseconds */
 +      uint32_t scr_direction; /* 'i', 'o', etc (also indicates endianness) */
 +};
 +
  static FILE *fscript;
  static int master, slave;
  static int child;
  static const char *fname;
  static int qflg, ttyflg;
 +static int usesleep, rawout;
  
  static struct termios tt;
  
 @@ -71,6 +84,9 @@
  static void doshell(char **);
  static void fail(void);
  static void finish(void);
 +static void record(FILE *, char *, size_t, int);
 +static void consume(FILE *, off_t, char *, int);
 +static void playback(FILE *);
  static void usage(void);
  
  int
 @@ -79,26 +95,39 @@
        int cc;
        struct termios rtt, stt;
        struct winsize win;
 -      int aflg, kflg, ch, n;
 +      int aflg, kflg, pflg, ch, n;
        struct timeval tv, *tvp;
        time_t tvec, start;
        char obuf[BUFSIZ];
        char ibuf[BUFSIZ];
        fd_set rfd;
        int flushtime = 30;
 +      int k;
  
 -      aflg = kflg = 0;
 -      while ((ch = getopt(argc, argv, "aqkt:")) != -1)
 +      aflg = kflg = pflg = 0;
 +      usesleep = 1;
 +      rawout = 0;
 + 
 +      while ((ch = getopt(argc, argv, "adkpqrt:")) != -1)
                switch(ch) {
                case 'a':
                        aflg = 1;
                        break;
 -              case 'q':
 -                      qflg = 1;
 +              case 'd':
 +                      usesleep = 0;
                        break;
                case 'k':
                        kflg = 1;
                        break;
 +              case 'p':
 +                      pflg = 1;
 +                      break;
 +              case 'q':
 +                      qflg = 1;
 +                      break;
 +              case 'r':
 +                      rawout = 1;
 +                      break;
                case 't':
                        flushtime = atoi(optarg);
                        if (flushtime < 0)
 @@ -118,9 +147,12 @@
        } else
                fname = "typescript";
  
 -      if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL)
 +      if ((fscript = fopen(fname, pflg ? "r" : aflg ? "a" : "w")) == NULL)
                err(1, "%s", fname);
  
 +      if (pflg)
 +              playback(fscript);
 +
        if ((ttyflg = isatty(STDIN_FILENO)) != 0) {
                if (tcgetattr(STDIN_FILENO, &tt) == -1)
                        err(1, "tcgetattr");
 @@ -133,10 +165,21 @@
                        err(1, "openpty");
        }
  
 +      if (rawout)
 +              record(fscript, NULL, 0, 's');
 +
        if (!qflg) {
                tvec = time(NULL);
                (void)printf("Script started, output file is %s\n", fname);
 -              (void)fprintf(fscript, "Script started on %s", ctime(&tvec));
 +              if (!rawout) {
 +                      (void)fprintf(fscript, "Script started on %s", 
ctime(&tvec));
 +                      if (argv[0]) {
 +                              fprintf(fscript, "command: ");
 +                              for (k = 0 ; argv[k] ; ++k)
 +                                      fprintf(fscript, "%s%s", k ? " " : "", 
argv[k]);
 +                              fprintf(fscript, "\n");
 +                      }
 +              }
                fflush(fscript);
        }
        if (ttyflg) {
 @@ -179,6 +222,8 @@
                        if (cc == 0)
                                (void)write(master, ibuf, 0);
                        if (cc > 0) {
 +                              if (rawout)
 +                                      record(fscript, ibuf, cc, 'i');
                                (void)write(master, ibuf, cc);
                                if (kflg && tcgetattr(master, &stt) >= 0 &&
                                    ((stt.c_lflag & ECHO) == 0)) {
 @@ -191,7 +236,10 @@
                        if (cc <= 0)
                                break;
                        (void)write(STDOUT_FILENO, obuf, cc);
 -                      (void)fwrite(obuf, 1, cc, fscript);
 +                      if (rawout)
 +                              record(fscript, obuf, cc, 'o');
 +                      else
 +                              (void)fwrite(obuf, 1, cc, fscript);
                }
                tvec = time(0);
                if (tvec - start >= flushtime) {
 @@ -231,17 +279,11 @@
  doshell(char **av)
  {
        const char *shell;
 -      int k;
  
        shell = getenv("SHELL");
        if (shell == NULL)
                shell = _PATH_BSHELL;
  
 -      if (av[0])
 -              for (k = 0 ; av[k] ; ++k)
 -                      fprintf(fscript, "%s%s", k ? " " : "", av[k]);
 -              fprintf(fscript, "\r\n");
 -
        (void)close(master);
        (void)fclose(fscript);
        login_tty(slave);
 @@ -271,11 +313,142 @@
        if (ttyflg)
                (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
        tvec = time(NULL);
 +      if (rawout)
 +              record(fscript, NULL, 0, 'e');
        if (!qflg) {
 -              (void)fprintf(fscript,"\nScript done on %s", ctime(&tvec));
 +              if (!rawout)
 +                      (void)fprintf(fscript,"\nScript done on %s", 
ctime(&tvec));
                (void)printf("\nScript done, output file is %s\n", fname);
        }
        (void)fclose(fscript);
        (void)close(master);
        exit(eno);
  }
 +
 +
 +static void
 +record(FILE *fp, char *buf, size_t cc, int direction)
 +{
 +      struct iovec iov[2];
 +      struct stamp stamp;
 +      struct timeval tv;
 +
 +      (void)gettimeofday(&tv, NULL);
 +      stamp.scr_len = cc;
 +      stamp.scr_sec = tv.tv_sec;
 +      stamp.scr_usec = tv.tv_usec;
 +      stamp.scr_direction = direction;
 +      iov[0].iov_len = sizeof(stamp);
 +      iov[0].iov_base = &stamp;
 +      iov[1].iov_len = cc;
 +      iov[1].iov_base = buf;
 +      if (writev(fileno(fp), &iov[0], 2) == -1)
 +              err(1, "writev");
 +}
 +
 +static void
 +consume(FILE *fp, off_t len, char *buf, int reg)
 +{
 +      size_t l;
 +
 +      if (reg) {
 +              if (fseeko(fp, len, SEEK_CUR) == -1)
 +                      err(1, NULL);
 +      }
 +      else {
 +              while (len > 0) {
 +                      l = MIN(DEF_BUF, len);
 +                      if (fread(buf, sizeof(char), l, fp) != l)
 +                              err(1, "cannot read buffer");
 +                      len -= l;
 +              }
 +      }
 +}
 +
 +#define swapstamp(stamp) do { \
 +      if (stamp.scr_direction > 0xff) { \
 +              stamp.scr_len = bswap64(stamp.scr_len); \
 +              stamp.scr_sec = bswap64(stamp.scr_sec); \
 +              stamp.scr_usec = bswap32(stamp.scr_usec); \
 +              stamp.scr_direction = bswap32(stamp.scr_direction); \
 +      } \
 +} while (0/*CONSTCOND*/)
 +
 +static void
 +playback(FILE *fp)
 +{
 +      struct timespec tsi, tso;
 +      struct stamp stamp;
 +      struct stat pst;
 +      char buf[DEF_BUF];
 +      off_t nread, save_len;
 +      size_t l;
 +      time_t tclock;
 +      int reg;
 +
 +      if (fstat(fileno(fp), &pst) == -1)
 +              err(1, "fstat failed"); 
 +
 +      reg = S_ISREG(pst.st_mode);
 +
 +      for (nread = 0; !reg || nread < pst.st_size; nread += save_len) {
 +              if (fread(&stamp, sizeof(stamp), 1, fp) != 1) {
 +                      if (reg)
 +                              err(1, "reading playback header");
 +                      else
 +                              break;
 +              }
 +              swapstamp(stamp);
 +              save_len = sizeof(stamp);
 +
 +              if (reg && stamp.scr_len >
 +                  (uint64_t)(pst.st_size - save_len) - nread)
 +                      err(1, "invalid stamp");
 +
 +              save_len += stamp.scr_len;
 +              tclock = stamp.scr_sec;
 +              tso.tv_sec = stamp.scr_sec;
 +              tso.tv_nsec = stamp.scr_usec * 1000;
 +
 +              switch (stamp.scr_direction) {
 +              case 's':
 +                      if (!qflg)
 +                              (void)printf("Script started on %s", 
ctime(&tclock));
 +                      tsi = tso;
 +                      (void)consume(fp, stamp.scr_len, buf, reg);
 +                      break;
 +              case 'e':
 +                      if (!qflg)
 +                              (void)printf("\nScript done on %s", 
ctime(&tclock));
 +                      (void)consume(fp, stamp.scr_len, buf, reg);
 +                      break;
 +              case 'i':
 +                      /* throw input away */
 +                      (void)consume(fp, stamp.scr_len, buf, reg);
 +                      break;
 +              case 'o':
 +                      tsi.tv_sec = tso.tv_sec - tsi.tv_sec;
 +                      tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec;
 +                      if (tsi.tv_nsec < 0) {
 +                              tsi.tv_sec -= 1;
 +                              tsi.tv_nsec += 1000000000;
 +                      }
 +                      if (usesleep)
 +                              (void)nanosleep(&tsi, NULL);
 +                      tsi = tso;
 +                      while (stamp.scr_len > 0) {
 +                              l = MIN(DEF_BUF, stamp.scr_len);
 +                              if (fread(buf, sizeof(char), l, fp) != l)
 +                                      err(1, "cannot read buffer");
 +
 +                              (void)write(STDOUT_FILENO, buf, l);
 +                              stamp.scr_len -= l;
 +                      }
 +                      break;
 +              default:
 +                      err(1, "invalid direction");
 +              }
 +      }
 +      (void)fclose(fp);
 +      exit(0);
 +}
 --- script_replay.diff ends here ---
_______________________________________________
freebsd-bugs@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"

Reply via email to