showterm 0.1.1 → 0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/showterm +1 -3
- data/ext/Makefile +34 -0
- data/ext/README +27 -0
- data/ext/extconf.rb +0 -0
- data/ext/io.c +161 -0
- data/ext/io.h +13 -0
- data/ext/ttyplay.1 +62 -0
- data/ext/ttyplay.c +312 -0
- data/ext/ttyrec.1 +76 -0
- data/ext/ttyrec.c +483 -0
- data/ext/ttyrec.h +12 -0
- data/ext/ttytime.1 +27 -0
- data/ext/ttytime.c +70 -0
- data/lib/showterm.rb +69 -23
- data/showterm.gemspec +2 -1
- metadata +17 -3
data/ext/ttyrec.c
ADDED
@@ -0,0 +1,483 @@
|
|
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
|
+
/* 1999-02-22 Arkadiusz Mi�kiewicz <misiek@misiek.eu.org>
|
35
|
+
* - added Native Language Support
|
36
|
+
*/
|
37
|
+
|
38
|
+
/* 2000-12-27 Satoru Takabayashi <satoru@namazu.org>
|
39
|
+
* - modify `script' to create `ttyrec'.
|
40
|
+
*/
|
41
|
+
|
42
|
+
/*
|
43
|
+
* script
|
44
|
+
*/
|
45
|
+
#include <sys/types.h>
|
46
|
+
#include <sys/stat.h>
|
47
|
+
#include <termios.h>
|
48
|
+
#include <sys/ioctl.h>
|
49
|
+
#include <sys/time.h>
|
50
|
+
#include <sys/file.h>
|
51
|
+
#include <sys/signal.h>
|
52
|
+
#include <stdio.h>
|
53
|
+
#include <time.h>
|
54
|
+
#include <unistd.h>
|
55
|
+
#include <string.h>
|
56
|
+
#include <stdlib.h>
|
57
|
+
|
58
|
+
#if defined(SVR4)
|
59
|
+
#include <fcntl.h>
|
60
|
+
#include <stropts.h>
|
61
|
+
#endif /* SVR4 */
|
62
|
+
|
63
|
+
#include <sys/time.h>
|
64
|
+
#include "ttyrec.h"
|
65
|
+
#include "io.h"
|
66
|
+
|
67
|
+
#define HAVE_inet_aton
|
68
|
+
#define HAVE_scsi_h
|
69
|
+
#define HAVE_kd_h
|
70
|
+
|
71
|
+
#define _(FOO) FOO
|
72
|
+
|
73
|
+
#ifdef HAVE_openpty
|
74
|
+
#include <libutil.h>
|
75
|
+
#endif
|
76
|
+
|
77
|
+
#if defined(SVR4) && !defined(CDEL)
|
78
|
+
#if defined(_POSIX_VDISABLE)
|
79
|
+
#define CDEL _POSIX_VDISABLE
|
80
|
+
#elif defined(CDISABLE)
|
81
|
+
#define CDEL CDISABLE
|
82
|
+
#else /* not _POSIX_VISIBLE && not CDISABLE */
|
83
|
+
#define CDEL 255
|
84
|
+
#endif /* not _POSIX_VISIBLE && not CDISABLE */
|
85
|
+
#endif /* SVR4 && ! CDEL */
|
86
|
+
|
87
|
+
void done(void);
|
88
|
+
void fail(void);
|
89
|
+
void fixtty(void);
|
90
|
+
void getmaster(void);
|
91
|
+
void getslave(void);
|
92
|
+
void doinput(void);
|
93
|
+
void dooutput(void);
|
94
|
+
void doshell(const char*);
|
95
|
+
|
96
|
+
char *shell;
|
97
|
+
FILE *fscript;
|
98
|
+
int master;
|
99
|
+
int slave;
|
100
|
+
int child;
|
101
|
+
int subchild;
|
102
|
+
char *fname;
|
103
|
+
|
104
|
+
struct termios tt;
|
105
|
+
struct winsize win;
|
106
|
+
int lb;
|
107
|
+
int l;
|
108
|
+
#if !defined(SVR4)
|
109
|
+
#ifndef HAVE_openpty
|
110
|
+
char line[] = "/dev/ptyXX";
|
111
|
+
#endif
|
112
|
+
#endif /* !SVR4 */
|
113
|
+
int aflg;
|
114
|
+
int uflg;
|
115
|
+
|
116
|
+
int
|
117
|
+
main(argc, argv)
|
118
|
+
int argc;
|
119
|
+
char *argv[];
|
120
|
+
{
|
121
|
+
extern int optind;
|
122
|
+
int ch;
|
123
|
+
void finish();
|
124
|
+
char *getenv();
|
125
|
+
char *command = NULL;
|
126
|
+
|
127
|
+
while ((ch = getopt(argc, argv, "aue:h?")) != EOF)
|
128
|
+
switch((char)ch) {
|
129
|
+
case 'a':
|
130
|
+
aflg++;
|
131
|
+
break;
|
132
|
+
case 'u':
|
133
|
+
uflg++;
|
134
|
+
break;
|
135
|
+
case 'e':
|
136
|
+
command = strdup(optarg);
|
137
|
+
break;
|
138
|
+
case 'h':
|
139
|
+
case '?':
|
140
|
+
default:
|
141
|
+
fprintf(stderr, _("usage: ttyrec [-u] [-e command] [-a] [file]\n"));
|
142
|
+
exit(1);
|
143
|
+
}
|
144
|
+
argc -= optind;
|
145
|
+
argv += optind;
|
146
|
+
|
147
|
+
if (argc > 0)
|
148
|
+
fname = argv[0];
|
149
|
+
else
|
150
|
+
fname = "ttyrecord";
|
151
|
+
if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL) {
|
152
|
+
perror(fname);
|
153
|
+
fail();
|
154
|
+
}
|
155
|
+
setbuf(fscript, NULL);
|
156
|
+
|
157
|
+
shell = getenv("SHELL");
|
158
|
+
if (shell == NULL)
|
159
|
+
shell = "/bin/sh";
|
160
|
+
|
161
|
+
getmaster();
|
162
|
+
fixtty();
|
163
|
+
|
164
|
+
(void) signal(SIGCHLD, finish);
|
165
|
+
child = fork();
|
166
|
+
if (child < 0) {
|
167
|
+
perror("fork");
|
168
|
+
fail();
|
169
|
+
}
|
170
|
+
if (child == 0) {
|
171
|
+
subchild = child = fork();
|
172
|
+
if (child < 0) {
|
173
|
+
perror("fork");
|
174
|
+
fail();
|
175
|
+
}
|
176
|
+
if (child)
|
177
|
+
dooutput();
|
178
|
+
else
|
179
|
+
doshell(command);
|
180
|
+
}
|
181
|
+
doinput();
|
182
|
+
|
183
|
+
return 0;
|
184
|
+
}
|
185
|
+
|
186
|
+
void
|
187
|
+
doinput()
|
188
|
+
{
|
189
|
+
register int cc;
|
190
|
+
char ibuf[BUFSIZ];
|
191
|
+
|
192
|
+
(void) fclose(fscript);
|
193
|
+
#ifdef HAVE_openpty
|
194
|
+
(void) close(slave);
|
195
|
+
#endif
|
196
|
+
while ((cc = read(0, ibuf, BUFSIZ)) > 0)
|
197
|
+
(void) write(master, ibuf, cc);
|
198
|
+
done();
|
199
|
+
}
|
200
|
+
|
201
|
+
#include <sys/wait.h>
|
202
|
+
|
203
|
+
void
|
204
|
+
finish()
|
205
|
+
{
|
206
|
+
#if defined(SVR4)
|
207
|
+
int status;
|
208
|
+
#else /* !SVR4 */
|
209
|
+
union wait status;
|
210
|
+
#endif /* !SVR4 */
|
211
|
+
register int pid;
|
212
|
+
register int die = 0;
|
213
|
+
|
214
|
+
while ((pid = wait3((int *)&status, WNOHANG, 0)) > 0)
|
215
|
+
if (pid == child)
|
216
|
+
die = 1;
|
217
|
+
|
218
|
+
if (die)
|
219
|
+
done();
|
220
|
+
}
|
221
|
+
|
222
|
+
struct linebuf {
|
223
|
+
char str[BUFSIZ + 1]; /* + 1 for an additional NULL character.*/
|
224
|
+
int len;
|
225
|
+
};
|
226
|
+
|
227
|
+
|
228
|
+
void
|
229
|
+
check_line (const char *line)
|
230
|
+
{
|
231
|
+
static int uuencode_mode = 0;
|
232
|
+
static FILE *uudecode;
|
233
|
+
|
234
|
+
if (uuencode_mode == 1) {
|
235
|
+
fprintf(uudecode, "%s", line);
|
236
|
+
if (strcmp(line, "end\n") == 0) {
|
237
|
+
pclose(uudecode);
|
238
|
+
uuencode_mode = 0;
|
239
|
+
}
|
240
|
+
} else {
|
241
|
+
int dummy; char dummy2[BUFSIZ];
|
242
|
+
if (sscanf(line, "begin %o %s", &dummy, dummy2) == 2) {
|
243
|
+
/*
|
244
|
+
* uuencode line found!
|
245
|
+
*/
|
246
|
+
uudecode = popen("uudecode", "w");
|
247
|
+
fprintf(uudecode, "%s", line);
|
248
|
+
uuencode_mode = 1;
|
249
|
+
}
|
250
|
+
}
|
251
|
+
}
|
252
|
+
|
253
|
+
void
|
254
|
+
check_output(const char *str, int len)
|
255
|
+
{
|
256
|
+
static struct linebuf lbuf = {"", 0};
|
257
|
+
int i;
|
258
|
+
|
259
|
+
for (i = 0; i < len; i++) {
|
260
|
+
if (lbuf.len < BUFSIZ) {
|
261
|
+
lbuf.str[lbuf.len] = str[i];
|
262
|
+
if (lbuf.str[lbuf.len] == '\r') {
|
263
|
+
lbuf.str[lbuf.len] = '\n';
|
264
|
+
}
|
265
|
+
lbuf.len++;
|
266
|
+
if (lbuf.str[lbuf.len - 1] == '\n') {
|
267
|
+
if (lbuf.len > 1) { /* skip a blank line. */
|
268
|
+
lbuf.str[lbuf.len] = '\0';
|
269
|
+
check_line(lbuf.str);
|
270
|
+
}
|
271
|
+
lbuf.len = 0;
|
272
|
+
}
|
273
|
+
} else {/* buffer overflow */
|
274
|
+
lbuf.len = 0;
|
275
|
+
}
|
276
|
+
}
|
277
|
+
}
|
278
|
+
|
279
|
+
void
|
280
|
+
dooutput()
|
281
|
+
{
|
282
|
+
int cc;
|
283
|
+
char obuf[BUFSIZ];
|
284
|
+
|
285
|
+
setbuf(stdout, NULL);
|
286
|
+
(void) close(0);
|
287
|
+
#ifdef HAVE_openpty
|
288
|
+
(void) close(slave);
|
289
|
+
#endif
|
290
|
+
for (;;) {
|
291
|
+
Header h;
|
292
|
+
|
293
|
+
cc = read(master, obuf, BUFSIZ);
|
294
|
+
if (cc <= 0)
|
295
|
+
break;
|
296
|
+
if (uflg)
|
297
|
+
check_output(obuf, cc);
|
298
|
+
h.len = cc;
|
299
|
+
gettimeofday(&h.tv, NULL);
|
300
|
+
(void) write(1, obuf, cc);
|
301
|
+
(void) write_header(fscript, &h);
|
302
|
+
(void) fwrite(obuf, 1, cc, fscript);
|
303
|
+
}
|
304
|
+
done();
|
305
|
+
}
|
306
|
+
|
307
|
+
void
|
308
|
+
doshell(const char* command)
|
309
|
+
{
|
310
|
+
/***
|
311
|
+
int t;
|
312
|
+
|
313
|
+
t = open(_PATH_TTY, O_RDWR);
|
314
|
+
if (t >= 0) {
|
315
|
+
(void) ioctl(t, TIOCNOTTY, (char *)0);
|
316
|
+
(void) close(t);
|
317
|
+
}
|
318
|
+
***/
|
319
|
+
getslave();
|
320
|
+
(void) close(master);
|
321
|
+
(void) fclose(fscript);
|
322
|
+
(void) dup2(slave, 0);
|
323
|
+
(void) dup2(slave, 1);
|
324
|
+
(void) dup2(slave, 2);
|
325
|
+
(void) close(slave);
|
326
|
+
|
327
|
+
if (!command) {
|
328
|
+
execl(shell, strrchr(shell, '/') + 1, "-i", 0);
|
329
|
+
} else {
|
330
|
+
execl(shell, strrchr(shell, '/') + 1, "-c", command, 0);
|
331
|
+
}
|
332
|
+
perror(shell);
|
333
|
+
fail();
|
334
|
+
}
|
335
|
+
|
336
|
+
void
|
337
|
+
fixtty()
|
338
|
+
{
|
339
|
+
struct termios rtt;
|
340
|
+
|
341
|
+
rtt = tt;
|
342
|
+
#if defined(SVR4)
|
343
|
+
rtt.c_iflag = 0;
|
344
|
+
rtt.c_lflag &= ~(ISIG|ICANON|XCASE|ECHO|ECHOE|ECHOK|ECHONL);
|
345
|
+
rtt.c_oflag = OPOST;
|
346
|
+
rtt.c_cc[VINTR] = CDEL;
|
347
|
+
rtt.c_cc[VQUIT] = CDEL;
|
348
|
+
rtt.c_cc[VERASE] = CDEL;
|
349
|
+
rtt.c_cc[VKILL] = CDEL;
|
350
|
+
rtt.c_cc[VEOF] = 1;
|
351
|
+
rtt.c_cc[VEOL] = 0;
|
352
|
+
#else /* !SVR4 */
|
353
|
+
cfmakeraw(&rtt);
|
354
|
+
rtt.c_lflag &= ~ECHO;
|
355
|
+
#endif /* !SVR4 */
|
356
|
+
(void) tcsetattr(0, TCSAFLUSH, &rtt);
|
357
|
+
}
|
358
|
+
|
359
|
+
void
|
360
|
+
fail()
|
361
|
+
{
|
362
|
+
|
363
|
+
(void) kill(0, SIGTERM);
|
364
|
+
done();
|
365
|
+
}
|
366
|
+
|
367
|
+
void
|
368
|
+
done()
|
369
|
+
{
|
370
|
+
if (subchild) {
|
371
|
+
(void) fclose(fscript);
|
372
|
+
(void) close(master);
|
373
|
+
} else {
|
374
|
+
(void) tcsetattr(0, TCSAFLUSH, &tt);
|
375
|
+
}
|
376
|
+
exit(0);
|
377
|
+
}
|
378
|
+
|
379
|
+
void
|
380
|
+
getmaster()
|
381
|
+
{
|
382
|
+
#if defined(SVR4)
|
383
|
+
(void) tcgetattr(0, &tt);
|
384
|
+
(void) ioctl(0, TIOCGWINSZ, (char *)&win);
|
385
|
+
if ((master = open("/dev/ptmx", O_RDWR)) < 0) {
|
386
|
+
perror("open(\"/dev/ptmx\", O_RDWR)");
|
387
|
+
fail();
|
388
|
+
}
|
389
|
+
#else /* !SVR4 */
|
390
|
+
#ifdef HAVE_openpty
|
391
|
+
(void) tcgetattr(0, &tt);
|
392
|
+
(void) ioctl(0, TIOCGWINSZ, (char *)&win);
|
393
|
+
if (openpty(&master, &slave, NULL, &tt, &win) < 0) {
|
394
|
+
fprintf(stderr, _("openpty failed\n"));
|
395
|
+
fail();
|
396
|
+
}
|
397
|
+
#else
|
398
|
+
#ifdef HAVE_getpt
|
399
|
+
if ((master = getpt()) < 0) {
|
400
|
+
perror("getpt()");
|
401
|
+
fail();
|
402
|
+
}
|
403
|
+
#else
|
404
|
+
char *pty, *bank, *cp;
|
405
|
+
struct stat stb;
|
406
|
+
|
407
|
+
pty = &line[strlen("/dev/ptyp")];
|
408
|
+
for (bank = "pqrs"; *bank; bank++) {
|
409
|
+
line[strlen("/dev/pty")] = *bank;
|
410
|
+
*pty = '0';
|
411
|
+
if (stat(line, &stb) < 0)
|
412
|
+
break;
|
413
|
+
for (cp = "0123456789abcdef"; *cp; cp++) {
|
414
|
+
*pty = *cp;
|
415
|
+
master = open(line, O_RDWR);
|
416
|
+
if (master >= 0) {
|
417
|
+
char *tp = &line[strlen("/dev/")];
|
418
|
+
int ok;
|
419
|
+
|
420
|
+
/* verify slave side is usable */
|
421
|
+
*tp = 't';
|
422
|
+
ok = access(line, R_OK|W_OK) == 0;
|
423
|
+
*tp = 'p';
|
424
|
+
if (ok) {
|
425
|
+
(void) tcgetattr(0, &tt);
|
426
|
+
(void) ioctl(0, TIOCGWINSZ,
|
427
|
+
(char *)&win);
|
428
|
+
return;
|
429
|
+
}
|
430
|
+
(void) close(master);
|
431
|
+
}
|
432
|
+
}
|
433
|
+
}
|
434
|
+
fprintf(stderr, _("Out of pty's\n"));
|
435
|
+
fail();
|
436
|
+
#endif /* not HAVE_getpt */
|
437
|
+
#endif /* not HAVE_openpty */
|
438
|
+
#endif /* !SVR4 */
|
439
|
+
}
|
440
|
+
|
441
|
+
void
|
442
|
+
getslave()
|
443
|
+
{
|
444
|
+
#if defined(SVR4)
|
445
|
+
(void) setsid();
|
446
|
+
grantpt( master);
|
447
|
+
unlockpt(master);
|
448
|
+
if ((slave = open((const char *)ptsname(master), O_RDWR)) < 0) {
|
449
|
+
perror("open(fd, O_RDWR)");
|
450
|
+
fail();
|
451
|
+
}
|
452
|
+
if (isastream(slave)) {
|
453
|
+
if (ioctl(slave, I_PUSH, "ptem") < 0) {
|
454
|
+
perror("ioctl(fd, I_PUSH, ptem)");
|
455
|
+
fail();
|
456
|
+
}
|
457
|
+
if (ioctl(slave, I_PUSH, "ldterm") < 0) {
|
458
|
+
perror("ioctl(fd, I_PUSH, ldterm)");
|
459
|
+
fail();
|
460
|
+
}
|
461
|
+
#ifndef _HPUX_SOURCE
|
462
|
+
if (ioctl(slave, I_PUSH, "ttcompat") < 0) {
|
463
|
+
perror("ioctl(fd, I_PUSH, ttcompat)");
|
464
|
+
fail();
|
465
|
+
}
|
466
|
+
#endif
|
467
|
+
(void) ioctl(0, TIOCGWINSZ, (char *)&win);
|
468
|
+
}
|
469
|
+
#else /* !SVR4 */
|
470
|
+
#ifndef HAVE_openpty
|
471
|
+
line[strlen("/dev/")] = 't';
|
472
|
+
slave = open(line, O_RDWR);
|
473
|
+
if (slave < 0) {
|
474
|
+
perror(line);
|
475
|
+
fail();
|
476
|
+
}
|
477
|
+
(void) tcsetattr(slave, TCSAFLUSH, &tt);
|
478
|
+
(void) ioctl(slave, TIOCSWINSZ, (char *)&win);
|
479
|
+
#endif
|
480
|
+
(void) setsid();
|
481
|
+
(void) ioctl(slave, TIOCSCTTY, 0);
|
482
|
+
#endif /* SVR4 */
|
483
|
+
}
|
data/ext/ttyrec.h
ADDED
data/ext/ttytime.1
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
.\"
|
2
|
+
.\" This manual page is written by NAKANO Takeo <nakano@webmasters.gr.jp>
|
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
|
+
|
data/ext/ttytime.c
ADDED
@@ -0,0 +1,70 @@
|
|
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 <stdio.h>
|
35
|
+
#include <stdlib.h>
|
36
|
+
#include <assert.h>
|
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
|
+
}
|
data/lib/showterm.rb
CHANGED
@@ -1,54 +1,100 @@
|
|
1
|
-
require 'json'
|
2
1
|
require 'tempfile'
|
3
2
|
require 'net/https'
|
4
3
|
|
5
4
|
module Showterm
|
6
5
|
extend self
|
7
6
|
|
7
|
+
# Record a terminal session.
|
8
|
+
#
|
9
|
+
# If a command is given, use that command; otherwise the current user's
|
10
|
+
# login shell will be used.
|
11
|
+
#
|
12
|
+
# @param [*String] cmd
|
13
|
+
# @return [scriptfile, timingfile] the two halves of a termshow
|
8
14
|
def record!(*cmd)
|
9
|
-
|
10
15
|
scriptfile = Tempfile.new('showterm.script')
|
11
|
-
|
12
|
-
|
13
|
-
sf, tf = [scriptfile, timingfile].map(&:path)
|
14
|
-
|
15
|
-
scriptfile.close(true)
|
16
|
-
timingfile.close(true)
|
16
|
+
scriptfile.close(false)
|
17
17
|
|
18
|
-
args = []
|
18
|
+
args = [File.join(File.dirname(__FILE__), '../ext/ttyrec')]
|
19
19
|
if cmd.size > 0
|
20
|
-
args << '-
|
20
|
+
args << '-e' + cmd.join(" ")
|
21
21
|
end
|
22
|
-
|
23
|
-
args << '-q'
|
24
|
-
args << '-t' + tf
|
25
|
-
args << sf
|
22
|
+
args << scriptfile.path
|
26
23
|
|
27
24
|
puts "showterm is recording, quit when you're done."
|
28
|
-
|
29
|
-
unless system('script', *args)
|
30
|
-
raise "Could not run 'script', please check that it's installed"
|
31
|
-
end
|
32
|
-
|
25
|
+
system(*args) or raise "showterm recording failed"
|
33
26
|
puts 'showterm recording finished'
|
34
27
|
|
35
|
-
|
28
|
+
ret = scriptfile.open.read
|
29
|
+
scriptfile.close(true)
|
30
|
+
convert(ret)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Get the current width of the terminal
|
34
|
+
#
|
35
|
+
# @return [Integer] number of columns
|
36
|
+
def terminal_width
|
37
|
+
guess = `tput cols`.to_i
|
38
|
+
guess == 0 ? 80 : guess
|
36
39
|
end
|
37
40
|
|
38
|
-
|
41
|
+
# Upload the termshow to showterm.io
|
42
|
+
#
|
43
|
+
# @param [String] scriptfile The ANSI dump of the terminal
|
44
|
+
# @param [String] timingfile The timings
|
45
|
+
# @param [Integer] cols The width of the terminal
|
46
|
+
def upload!(scriptfile, timingfile, cols=terminal_width)
|
39
47
|
puts 'uploading, please wait.'
|
40
48
|
request = Net::HTTP::Post.new("/scripts")
|
41
|
-
request.set_form_data(:scriptfile =>
|
42
|
-
:timingfile =>
|
49
|
+
request.set_form_data(:scriptfile => scriptfile,
|
50
|
+
:timingfile => timingfile,
|
43
51
|
:cols => cols)
|
44
52
|
|
45
53
|
response = http(request)
|
46
54
|
raise response.body unless Net::HTTPSuccess === response
|
47
55
|
puts response.body
|
56
|
+
rescue => e
|
57
|
+
raise if retried
|
58
|
+
retried = true
|
59
|
+
retry
|
48
60
|
end
|
49
61
|
|
50
62
|
private
|
51
63
|
|
64
|
+
# The original version of showterm used the 'script' binary.
|
65
|
+
#
|
66
|
+
# Unfortunately that varies wildly from platform to platform, so we now
|
67
|
+
# bundle 'ttyrec' instead. This converts between the output of ttyrec and
|
68
|
+
# the output of 'script' so that the server remains solely a 'script' server.
|
69
|
+
#
|
70
|
+
# @param [String] ttyrecord
|
71
|
+
# @return [scriptfile, timingfile]
|
72
|
+
def convert(ttyrecord)
|
73
|
+
ttyrecord.force_encoding('BINARY') if ttyrecord.respond_to?(:force_encoding)
|
74
|
+
raise "Invalid ttyrecord: #{ttyrecord.inspect}" if ttyrecord.size < 12
|
75
|
+
|
76
|
+
scriptfile = "Converted from ttyrecord\n"
|
77
|
+
timingfile = ""
|
78
|
+
|
79
|
+
prev_sec, prev_usec = ttyrecord.unpack('VV')
|
80
|
+
pos = 0
|
81
|
+
|
82
|
+
while pos < ttyrecord.size
|
83
|
+
sec, usec, bytes = ttyrecord[pos..(pos + 12)].unpack('VVV')
|
84
|
+
time = (sec - prev_sec) + (usec - prev_usec) * 0.000_001
|
85
|
+
|
86
|
+
prev_sec = sec
|
87
|
+
prev_usec = usec
|
88
|
+
|
89
|
+
timingfile << "#{time} #{bytes}\n"
|
90
|
+
scriptfile << ttyrecord[(pos + 12)...(pos + 12 + bytes)]
|
91
|
+
|
92
|
+
pos += 12 + bytes
|
93
|
+
end
|
94
|
+
|
95
|
+
[scriptfile, timingfile]
|
96
|
+
end
|
97
|
+
|
52
98
|
def http(request)
|
53
99
|
connection = Net::HTTP.new("showterm.herokuapp.com", 443)
|
54
100
|
connection.use_ssl = true
|