├── Makefile ├── README ├── io.c ├── io.h ├── ttyplay.1 ├── ttyplay.c ├── ttyrec.1 ├── ttyrec.c ├── ttyrec.h ├── ttytime.1 └── ttytime.c /Makefile: -------------------------------------------------------------------------------- 1 | CC = gcc 2 | CFLAGS = -O2 3 | VERSION = 1.0.8 4 | 5 | TARGET = ttyrec ttyplay ttytime 6 | 7 | DIST = ttyrec.c ttyplay.c ttyrec.h io.c io.h ttytime.c\ 8 | README Makefile ttyrec.1 ttyplay.1 ttytime.1 9 | 10 | all: $(TARGET) 11 | 12 | ttyrec: ttyrec.o io.o 13 | $(CC) $(CFLAGS) -o ttyrec ttyrec.o io.o 14 | 15 | ttyplay: ttyplay.o io.o 16 | $(CC) $(CFLAGS) -o ttyplay ttyplay.o io.o 17 | 18 | ttytime: ttytime.o io.o 19 | $(CC) $(CFLAGS) -o ttytime ttytime.o io.o 20 | 21 | clean: 22 | rm -f *.o $(TARGET) ttyrecord *~ 23 | 24 | dist: 25 | rm -rf ttyrec-$(VERSION) 26 | rm -f ttyrec-$(VERSION).tar.gz 27 | 28 | mkdir ttyrec-$(VERSION) 29 | cp $(DIST) ttyrec-$(VERSION) 30 | tar zcf ttyrec-$(VERSION).tar.gz ttyrec-$(VERSION) 31 | rm -rf ttyrec-$(VERSION) 32 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | ttyrec is a tty recorder. ttyplay is a tty player. 2 | 3 | Installation: 4 | 5 | % make 6 | 7 | or if your system is SVR4 system (Solaris etc.), 8 | 9 | % make CFLAGS=-DSVR4 10 | 11 | or if your system supports getpt(3), 12 | 13 | % make CFLAGS=-DHAVE_getpt 14 | 15 | HAVE_getpt is required if your linux system uses devfs. 16 | 17 | 18 | Usage: 19 | 20 | % ttyrec 21 | (In the excuted shell, do whatever you want and exit) 22 | 23 | % ttyplay ttyrecord 24 | 25 | Have fun! 26 | 27 | -- Satoru Takabayashi 28 | -------------------------------------------------------------------------------- /io.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000 Satoru Takabayashi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by the University of 16 | * California, Berkeley and its contributors. 17 | * 4. Neither the name of the University nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 | * SUCH DAMAGE. 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #include "ttyrec.h" 42 | 43 | #define SWAP_ENDIAN(val) ((unsigned int) ( \ 44 | (((unsigned int) (val) & (unsigned int) 0x000000ffU) << 24) | \ 45 | (((unsigned int) (val) & (unsigned int) 0x0000ff00U) << 8) | \ 46 | (((unsigned int) (val) & (unsigned int) 0x00ff0000U) >> 8) | \ 47 | (((unsigned int) (val) & (unsigned int) 0xff000000U) >> 24))) 48 | 49 | static int 50 | is_little_endian () 51 | { 52 | static int retval = -1; 53 | 54 | if (retval == -1) { 55 | int n = 1; 56 | char *p = (char *)&n; 57 | char x[] = {1, 0, 0, 0}; 58 | 59 | assert(sizeof(int) == 4); 60 | 61 | if (memcmp(p, x, 4) == 0) { 62 | retval = 1; 63 | } else { 64 | retval = 0; 65 | } 66 | } 67 | 68 | return retval; 69 | } 70 | 71 | static int 72 | convert_to_little_endian (int x) 73 | { 74 | if (is_little_endian()) { 75 | return x; 76 | } else { 77 | return SWAP_ENDIAN(x); 78 | } 79 | } 80 | 81 | int 82 | read_header (FILE *fp, Header *h) 83 | { 84 | int buf[3]; 85 | 86 | if (fread(buf, sizeof(int), 3, fp) == 0) { 87 | return 0; 88 | } 89 | 90 | h->tv.tv_sec = convert_to_little_endian(buf[0]); 91 | h->tv.tv_usec = convert_to_little_endian(buf[1]); 92 | h->len = convert_to_little_endian(buf[2]); 93 | 94 | return 1; 95 | } 96 | 97 | int 98 | write_header (FILE *fp, Header *h) 99 | { 100 | int buf[3]; 101 | 102 | buf[0] = convert_to_little_endian(h->tv.tv_sec); 103 | buf[1] = convert_to_little_endian(h->tv.tv_usec); 104 | buf[2] = convert_to_little_endian(h->len); 105 | 106 | if (fwrite(buf, sizeof(int), 3, fp) == 0) { 107 | return 0; 108 | } 109 | 110 | return 1; 111 | } 112 | 113 | static char *progname = ""; 114 | void 115 | set_progname (const char *name) 116 | { 117 | progname = strdup(name); 118 | } 119 | 120 | FILE * 121 | efopen (const char *path, const char *mode) 122 | { 123 | FILE *fp = fopen(path, mode); 124 | if (fp == NULL) { 125 | fprintf(stderr, "%s: %s: %s\n", progname, path, strerror(errno)); 126 | exit(EXIT_FAILURE); 127 | } 128 | return fp; 129 | } 130 | 131 | int 132 | edup (int oldfd) 133 | { 134 | int fd = dup(oldfd); 135 | if (fd == -1) { 136 | fprintf(stderr, "%s: dup failed: %s\n", progname, strerror(errno)); 137 | exit(EXIT_FAILURE); 138 | } 139 | return fd; 140 | } 141 | 142 | int 143 | edup2 (int oldfd, int newfd) 144 | { 145 | int fd = dup2(oldfd, newfd); 146 | if (fd == -1) { 147 | fprintf(stderr, "%s: dup2 failed: %s\n", progname, strerror(errno)); 148 | exit(EXIT_FAILURE); 149 | } 150 | return fd; 151 | } 152 | 153 | FILE * 154 | efdopen (int fd, const char *mode) 155 | { 156 | FILE *fp = fdopen(fd, mode); 157 | if (fp == NULL) { 158 | fprintf(stderr, "%s: fdopen failed: %s\n", progname, strerror(errno)); 159 | exit(EXIT_FAILURE); 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /io.h: -------------------------------------------------------------------------------- 1 | #ifndef __TTYREC_IO_H__ 2 | #define __TTYREC_IO_H__ 3 | 4 | #include "ttyrec.h" 5 | 6 | int read_header (FILE *fp, Header *h); 7 | int write_header (FILE *fp, Header *h); 8 | FILE* efopen (const char *path, const char *mode); 9 | int edup (int oldfd); 10 | int edup2 (int oldfd, int newfd); 11 | FILE* efdopen (int fd, const char *mode); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /ttyplay.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" This manual page is written by NAKANO Takeo 3 | .\" 4 | .TH TTYPLAY 1 5 | .SH NAME 6 | ttyplay \- player of the tty session recorded by ttyrec 7 | .SH SYNOPSIS 8 | .br 9 | .B ttyplay 10 | .I [\-s SPEED] [\-n] [\-p] file 11 | .br 12 | .SH DESCRIPTION 13 | .B Ttyplay 14 | plays the tty session in 15 | .IR file , 16 | which was recorded previously by 17 | .BR ttyrec (1). 18 | .PP 19 | When 20 | .B \-p 21 | option is given, 22 | .B ttyplay 23 | output the 24 | .I file 25 | as it grows. 26 | It means that you can see the "live" shell session 27 | running by another user. 28 | .PP 29 | If you hit any key during playback, it will go right to the next 30 | character typed. This is handy when examining sessions where a user 31 | spends a lot of time at a prompt. 32 | .PP 33 | Additionally, there are some special keys defined: 34 | .TP 35 | .BI + " or " f 36 | double the speed of playback. 37 | .TP 38 | .BI \- " or " s 39 | halve the speed of playback. 40 | .TP 41 | .BI 1 42 | set playback to speed 1.0 again. 43 | 44 | .SH OPTIONS 45 | .TP 46 | .BI \-s " SPEED" 47 | multiple the playing speed by 48 | .I SPEED 49 | (default is 1). 50 | .TP 51 | .B \-n 52 | no wait mode. 53 | Ignore the timing information in 54 | .IR file . 55 | .TP 56 | .B \-p 57 | peek another person's tty session. 58 | .SH "SEE ALSO" 59 | .BR script (1), 60 | .BR ttyrec (1), 61 | .BR ttytime (1) 62 | 63 | -------------------------------------------------------------------------------- /ttyplay.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2000 Satoru Takabayashi 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by the University of 16 | * California, Berkeley and its contributors. 17 | * 4. Neither the name of the University nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 | * SUCH DAMAGE. 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #include "ttyrec.h" 43 | #include "io.h" 44 | 45 | typedef double (*WaitFunc) (struct timeval prev, 46 | struct timeval cur, 47 | double speed); 48 | typedef int (*ReadFunc) (FILE *fp, Header *h, char **buf); 49 | typedef void (*WriteFunc) (char *buf, int len); 50 | typedef void (*ProcessFunc) (FILE *fp, double speed, 51 | ReadFunc read_func, WaitFunc wait_func); 52 | 53 | struct timeval 54 | timeval_diff (struct timeval tv1, struct timeval tv2) 55 | { 56 | struct timeval diff; 57 | 58 | diff.tv_sec = tv2.tv_sec - tv1.tv_sec; 59 | diff.tv_usec = tv2.tv_usec - tv1.tv_usec; 60 | if (diff.tv_usec < 0) { 61 | diff.tv_sec--; 62 | diff.tv_usec += 1000000; 63 | } 64 | 65 | return diff; 66 | } 67 | 68 | struct timeval 69 | timeval_div (struct timeval tv1, double n) 70 | { 71 | double x = ((double)tv1.tv_sec + (double)tv1.tv_usec / 1000000.0) / n; 72 | struct timeval div; 73 | 74 | div.tv_sec = (int)x; 75 | div.tv_usec = (x - (int)x) * 1000000; 76 | 77 | return div; 78 | } 79 | 80 | double 81 | ttywait (struct timeval prev, struct timeval cur, double speed) 82 | { 83 | static struct timeval drift = {0, 0}; 84 | struct timeval start; 85 | struct timeval diff = timeval_diff(prev, cur); 86 | fd_set readfs; 87 | 88 | gettimeofday(&start, NULL); 89 | 90 | assert(speed != 0); 91 | diff = timeval_diff(drift, timeval_div(diff, speed)); 92 | if (diff.tv_sec < 0) { 93 | diff.tv_sec = diff.tv_usec = 0; 94 | } 95 | 96 | FD_SET(STDIN_FILENO, &readfs); 97 | /* 98 | * We use select() for sleeping with subsecond precision. 99 | * select() is also used to wait user's input from a keyboard. 100 | * 101 | * Save "diff" since select(2) may overwrite it to {0, 0}. 102 | */ 103 | struct timeval orig_diff = diff; 104 | select(1, &readfs, NULL, NULL, &diff); 105 | diff = orig_diff; /* Restore the original diff value. */ 106 | if (FD_ISSET(0, &readfs)) { /* a user hits a character? */ 107 | char c; 108 | read(STDIN_FILENO, &c, 1); /* drain the character */ 109 | switch (c) { 110 | case '+': 111 | case 'f': 112 | speed *= 2; 113 | break; 114 | case '-': 115 | case 's': 116 | speed /= 2; 117 | break; 118 | case '1': 119 | speed = 1.0; 120 | break; 121 | } 122 | drift.tv_sec = drift.tv_usec = 0; 123 | } else { 124 | struct timeval stop; 125 | gettimeofday(&stop, NULL); 126 | /* Hack to accumulate the drift */ 127 | if (diff.tv_sec == 0 && diff.tv_usec == 0) { 128 | diff = timeval_diff(drift, diff); // diff = 0 - drift. 129 | } 130 | drift = timeval_diff(diff, timeval_diff(start, stop)); 131 | } 132 | return speed; 133 | } 134 | 135 | double 136 | ttynowait (struct timeval prev, struct timeval cur, double speed) 137 | { 138 | /* do nothing */ 139 | return 0; /* Speed isn't important. */ 140 | } 141 | 142 | int 143 | ttyread (FILE *fp, Header *h, char **buf) 144 | { 145 | if (read_header(fp, h) == 0) { 146 | return 0; 147 | } 148 | 149 | *buf = malloc(h->len); 150 | if (*buf == NULL) { 151 | perror("malloc"); 152 | } 153 | 154 | if (fread(*buf, 1, h->len, fp) == 0) { 155 | perror("fread"); 156 | } 157 | return 1; 158 | } 159 | 160 | int 161 | ttypread (FILE *fp, Header *h, char **buf) 162 | { 163 | /* 164 | * Read persistently just like tail -f. 165 | */ 166 | while (ttyread(fp, h, buf) == 0) { 167 | struct timeval w = {0, 250000}; 168 | select(0, NULL, NULL, NULL, &w); 169 | clearerr(fp); 170 | } 171 | return 1; 172 | } 173 | 174 | void 175 | ttywrite (char *buf, int len) 176 | { 177 | fwrite(buf, 1, len, stdout); 178 | } 179 | 180 | void 181 | ttynowrite (char *buf, int len) 182 | { 183 | /* do nothing */ 184 | } 185 | 186 | void 187 | ttyplay (FILE *fp, double speed, ReadFunc read_func, 188 | WriteFunc write_func, WaitFunc wait_func) 189 | { 190 | int first_time = 1; 191 | struct timeval prev; 192 | 193 | setbuf(stdout, NULL); 194 | setbuf(fp, NULL); 195 | 196 | while (1) { 197 | char *buf; 198 | Header h; 199 | 200 | if (read_func(fp, &h, &buf) == 0) { 201 | break; 202 | } 203 | 204 | if (!first_time) { 205 | speed = wait_func(prev, h.tv, speed); 206 | } 207 | first_time = 0; 208 | 209 | write_func(buf, h.len); 210 | prev = h.tv; 211 | free(buf); 212 | } 213 | } 214 | 215 | void 216 | ttyskipall (FILE *fp) 217 | { 218 | /* 219 | * Skip all records. 220 | */ 221 | ttyplay(fp, 0, ttyread, ttynowrite, ttynowait); 222 | } 223 | 224 | void ttyplayback (FILE *fp, double speed, 225 | ReadFunc read_func, WaitFunc wait_func) 226 | { 227 | ttyplay(fp, speed, ttyread, ttywrite, wait_func); 228 | } 229 | 230 | void ttypeek (FILE *fp, double speed, 231 | ReadFunc read_func, WaitFunc wait_func) 232 | { 233 | ttyskipall(fp); 234 | ttyplay(fp, speed, ttypread, ttywrite, ttynowait); 235 | } 236 | 237 | 238 | void 239 | usage (void) 240 | { 241 | printf("Usage: ttyplay [OPTION] [FILE]\n"); 242 | printf(" -s SPEED Set speed to SPEED [1.0]\n"); 243 | printf(" -n No wait mode\n"); 244 | printf(" -p Peek another person's ttyrecord\n"); 245 | exit(EXIT_FAILURE); 246 | } 247 | 248 | /* 249 | * We do some tricks so that select(2) properly works on 250 | * STDIN_FILENO in ttywait(). 251 | */ 252 | FILE * 253 | input_from_stdin (void) 254 | { 255 | FILE *fp; 256 | int fd = edup(STDIN_FILENO); 257 | edup2(STDOUT_FILENO, STDIN_FILENO); 258 | return efdopen(fd, "r"); 259 | } 260 | 261 | int 262 | main (int argc, char **argv) 263 | { 264 | double speed = 1.0; 265 | ReadFunc read_func = ttyread; 266 | WaitFunc wait_func = ttywait; 267 | ProcessFunc process = ttyplayback; 268 | FILE *input = NULL; 269 | struct termios old, new; 270 | 271 | set_progname(argv[0]); 272 | while (1) { 273 | int ch = getopt(argc, argv, "s:np"); 274 | if (ch == EOF) { 275 | break; 276 | } 277 | switch (ch) { 278 | case 's': 279 | if (optarg == NULL) { 280 | perror("-s option requires an argument"); 281 | exit(EXIT_FAILURE); 282 | } 283 | sscanf(optarg, "%lf", &speed); 284 | break; 285 | case 'n': 286 | wait_func = ttynowait; 287 | break; 288 | case 'p': 289 | process = ttypeek; 290 | break; 291 | default: 292 | usage(); 293 | } 294 | } 295 | 296 | if (optind < argc) { 297 | input = efopen(argv[optind], "r"); 298 | } else { 299 | input = input_from_stdin(); 300 | } 301 | assert(input != NULL); 302 | 303 | tcgetattr(0, &old); /* Get current terminal state */ 304 | new = old; /* Make a copy */ 305 | new.c_lflag &= ~(ICANON | ECHO | ECHONL); /* unbuffered, no echo */ 306 | tcsetattr(0, TCSANOW, &new); /* Make it current */ 307 | 308 | process(input, speed, read_func, wait_func); 309 | tcsetattr(0, TCSANOW, &old); /* Return terminal state */ 310 | 311 | return 0; 312 | } 313 | -------------------------------------------------------------------------------- /ttyrec.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" This manual page is written by NAKANO Takeo 3 | .\" 4 | .TH TTYREC 1 5 | .SH NAME 6 | ttyrec \- a tty recorder 7 | .SH SYNOPSIS 8 | .br 9 | .B ttyrec 10 | .I "[\-a][\-u] [file]" 11 | .br 12 | .SH DESCRIPTION 13 | .B Ttyrec 14 | is a tty recorder. 15 | It is a derivative of 16 | .BR script (1) 17 | command for recording timing information with microsecond accuracy as well. 18 | It can record emacs -nw, vi, lynx, or any programs running on tty. 19 | .PP 20 | .B Ttyrec 21 | invokes a shell and records the session until the shell exits. 22 | Recorded data can be played back with 23 | .BR ttyplay (1). 24 | If the argument 25 | .I file 26 | is given, the session will be recorded in that file. 27 | Otherwise, 28 | .I ttyrecord 29 | is used as default. 30 | .SH OPTIONS 31 | .TP 32 | .B \-a 33 | Append the output to 34 | .I file 35 | or 36 | .IR ttyrecord , 37 | rather than overwriting it. 38 | .TP 39 | .B \-u 40 | With this option, 41 | .B ttyrec 42 | automatically calls 43 | .BR uudecode (1) 44 | and saves its output when uuencoded data appear on the session. 45 | It allow you to transfer files from remote host. 46 | You can call 47 | .B ttyrec 48 | with this option, login to the remote host 49 | and invoke 50 | .BR uuencode (1) 51 | on it for the file you want to transfer. 52 | .TP 53 | .BI \-e " command" 54 | Invoke 55 | .I command 56 | when ttyrec starts. 57 | 58 | 59 | .SH ENVIRONMENT 60 | .TP 61 | .I SHELL 62 | If the variable 63 | .I SHELL 64 | exists, the shell forked by 65 | .B ttyrec 66 | will be that shell. 67 | If it's not set, 68 | the Bourne shell is assumed. 69 | (Most shells set this variable automatically). 70 | .SH "SEE ALSO" 71 | .BR script (1), 72 | .BR ttyplay (1), 73 | .BR ttytime (1), 74 | .BR uuencode (1), 75 | .BR uudecode (1) 76 | 77 | -------------------------------------------------------------------------------- /ttyrec.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mjording/ttyrec/c4fd0f2bc69dba852526df3610f98d867ba5ab24/ttyrec.c -------------------------------------------------------------------------------- /ttyrec.h: -------------------------------------------------------------------------------- 1 | #ifndef __TTYREC_H__ 2 | #define __TTYREC_H__ 3 | 4 | #include "sys/time.h" 5 | 6 | typedef struct header { 7 | struct timeval tv; 8 | int len; 9 | } Header; 10 | 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /ttytime.1: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" This manual page is written by NAKANO Takeo 3 | .\" 4 | .TH TTYTIME 1 5 | .SH NAME 6 | ttytime \- print the time of the recorded session data by ttyrec(1) 7 | .SH SYNOPSIS 8 | .br 9 | .B ttytime 10 | .I file... 11 | .SH DESCRIPTION 12 | .B Ttytime 13 | tells you the time of recorded data in seconds. 14 | For example: 15 | .sp 16 | .RS 17 | .nf 18 | % ttytime *.tty 19 | 173 foo.tty 20 | 1832 bar.tty 21 | .fi 22 | .RE 23 | .SH "SEE ALSO" 24 | .BR script (1), 25 | .BR ttyrec (1), 26 | .BR ttyplay (1) 27 | 28 | -------------------------------------------------------------------------------- /ttytime.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1980 Regents of the University of California. 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. All advertising materials mentioning features or use of this software 14 | * must display the following acknowledgement: 15 | * This product includes software developed by the University of 16 | * California, Berkeley and its contributors. 17 | * 4. Neither the name of the University nor the names of its contributors 18 | * may be used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 | * SUCH DAMAGE. 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | 38 | #include "io.h" 39 | #include "ttyrec.h" 40 | 41 | int 42 | calc_time (const char *filename) 43 | { 44 | Header start, end; 45 | FILE *fp = efopen(filename, "r"); 46 | 47 | read_header(fp, &start); 48 | fseek(fp, start.len, SEEK_CUR); 49 | while (1) { 50 | Header h; 51 | if (read_header(fp, &h) == 0) { 52 | break; 53 | } 54 | end = h; 55 | fseek(fp, h.len, SEEK_CUR); 56 | } 57 | return end.tv.tv_sec - start.tv.tv_sec; 58 | } 59 | 60 | int 61 | main (int argc, char **argv) 62 | { 63 | int i; 64 | set_progname(argv[0]); 65 | for (i = 1; i < argc; i++) { 66 | char *filename = argv[i]; 67 | printf("%7d %s\n", calc_time(filename), filename); 68 | } 69 | return 0; 70 | } 71 | --------------------------------------------------------------------------------