Changeset View
Changeset View
Standalone View
Standalone View
usr.bin/script/script.c
Show First 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | |||||
static const char *fname; | static const char *fname; | ||||
static char *fmfname; | static char *fmfname; | ||||
static int fflg, qflg, ttyflg; | static int fflg, qflg, ttyflg; | ||||
static int usesleep, rawout, showexit; | static int usesleep, rawout, showexit; | ||||
static TAILQ_HEAD(, buf_elm) obuf_list = TAILQ_HEAD_INITIALIZER(obuf_list); | static TAILQ_HEAD(, buf_elm) obuf_list = TAILQ_HEAD_INITIALIZER(obuf_list); | ||||
static struct termios tt; | static struct termios tt; | ||||
#ifndef TSTAMP_FMT | |||||
/* useful for tool and human reading */ | |||||
# define TSTAMP_FMT "%n@ %s [%Y-%m-%d %T] " | |||||
rpokala: That `%n` forces a newline, yes? To ensure that the timestamp line starts with e.g.
```… | |||||
Done Inline ActionsYes, the -r data may be single char at a time so you want a newline before each time-stamp for a readable result. Eg. $ script -T - /tmp/tboot.log | head @ 1646852915 [2022-03-09 11:08:35] Connected @ 1646852916 [2022-03-09 11:08:36] root@bhyve:2# @ 1646852917 [2022-03-09 11:08:37] r @ 1646852917 [2022-03-09 11:08:37] e @ 1646852917 [2022-03-09 11:08:37] b @ 1646852918 [2022-03-09 11:08:38] o @ 1646852918 [2022-03-09 11:08:38] o sjg: Yes, the `-r` data may be single char at a time so you want a newline before each time-stamp… | |||||
#endif | |||||
static const char *tstamp_fmt = TSTAMP_FMT; | |||||
static int tflg; | |||||
static void done(int) __dead2; | static void done(int) __dead2; | ||||
static void doshell(char **); | static void doshell(char **); | ||||
static void finish(void); | static void finish(void); | ||||
static void record(FILE *, char *, size_t, int); | static void record(FILE *, char *, size_t, int); | ||||
static void consume(FILE *, off_t, char *, int); | static void consume(FILE *, off_t, char *, int); | ||||
static void playback(FILE *) __dead2; | static void playback(FILE *) __dead2; | ||||
static void usage(void); | static void usage(void); | ||||
Show All 16 Lines | main(int argc, char *argv[]) | ||||
aflg = Fflg = kflg = pflg = 0; | aflg = Fflg = kflg = pflg = 0; | ||||
usesleep = 1; | usesleep = 1; | ||||
rawout = 0; | rawout = 0; | ||||
flushtime = 30; | flushtime = 30; | ||||
fm_fd = -1; /* Shut up stupid "may be used uninitialized" GCC | fm_fd = -1; /* Shut up stupid "may be used uninitialized" GCC | ||||
warning. (not needed w/clang) */ | warning. (not needed w/clang) */ | ||||
showexit = 0; | showexit = 0; | ||||
while ((ch = getopt(argc, argv, "adeFfkpqrt:")) != -1) | while ((ch = getopt(argc, argv, "adeFfkpqrT:t:")) != -1) | ||||
switch(ch) { | switch(ch) { | ||||
case 'a': | case 'a': | ||||
aflg = 1; | aflg = 1; | ||||
break; | break; | ||||
case 'd': | case 'd': | ||||
usesleep = 0; | usesleep = 0; | ||||
break; | break; | ||||
case 'e': /* Default behavior, accepted for linux compat */ | case 'e': /* Default behavior, accepted for linux compat */ | ||||
Show All 16 Lines | while ((ch = getopt(argc, argv, "adeFfkpqrT:t:")) != -1) | ||||
case 'r': | case 'r': | ||||
rawout = 1; | rawout = 1; | ||||
break; | break; | ||||
case 't': | case 't': | ||||
flushtime = atoi(optarg); | flushtime = atoi(optarg); | ||||
if (flushtime < 0) | if (flushtime < 0) | ||||
err(1, "invalid flush time %d", flushtime); | err(1, "invalid flush time %d", flushtime); | ||||
break; | break; | ||||
case 'T': | |||||
tflg = pflg = 1; | |||||
if (strchr(optarg, '%')) | |||||
tstamp_fmt = optarg; | |||||
break; | |||||
case '?': | case '?': | ||||
default: | default: | ||||
usage(); | usage(); | ||||
} | } | ||||
argc -= optind; | argc -= optind; | ||||
argv += optind; | argv += optind; | ||||
if (argc > 0) { | if (argc > 0) { | ||||
▲ Show 20 Lines • Show All 389 Lines • ▼ Show 20 Lines | case 'e': | ||||
ctime(&tclock)); | ctime(&tclock)); | ||||
(void)consume(fp, stamp.scr_len, buf, reg); | (void)consume(fp, stamp.scr_len, buf, reg); | ||||
break; | break; | ||||
case 'i': | case 'i': | ||||
/* throw input away */ | /* throw input away */ | ||||
(void)consume(fp, stamp.scr_len, buf, reg); | (void)consume(fp, stamp.scr_len, buf, reg); | ||||
break; | break; | ||||
case 'o': | case 'o': | ||||
if (tflg) { | |||||
if (stamp.scr_len == 0) | |||||
continue; | |||||
l = strftime(buf, sizeof buf, tstamp_fmt, | |||||
localtime(&tclock)); | |||||
(void)write(STDOUT_FILENO, buf, l); | |||||
} else { | |||||
tsi.tv_sec = tso.tv_sec - tsi.tv_sec; | tsi.tv_sec = tso.tv_sec - tsi.tv_sec; | ||||
tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec; | tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec; | ||||
if (tsi.tv_nsec < 0) { | if (tsi.tv_nsec < 0) { | ||||
tsi.tv_sec -= 1; | tsi.tv_sec -= 1; | ||||
tsi.tv_nsec += 1000000000; | tsi.tv_nsec += 1000000000; | ||||
} | } | ||||
if (usesleep) | if (usesleep) | ||||
(void)nanosleep(&tsi, NULL); | (void)nanosleep(&tsi, NULL); | ||||
tsi = tso; | tsi = tso; | ||||
} | |||||
while (stamp.scr_len > 0) { | while (stamp.scr_len > 0) { | ||||
l = MIN(DEF_BUF, stamp.scr_len); | l = MIN(DEF_BUF, stamp.scr_len); | ||||
if (fread(buf, sizeof(char), l, fp) != l) | if (fread(buf, sizeof(char), l, fp) != l) | ||||
err(1, "cannot read buffer"); | err(1, "cannot read buffer"); | ||||
(void)write(STDOUT_FILENO, buf, l); | (void)write(STDOUT_FILENO, buf, l); | ||||
stamp.scr_len -= l; | stamp.scr_len -= l; | ||||
} | } | ||||
break; | break; | ||||
default: | default: | ||||
errx(1, "invalid direction"); | errx(1, "invalid direction"); | ||||
} | } | ||||
} | } | ||||
(void)fclose(fp); | (void)fclose(fp); | ||||
exit(0); | exit(0); | ||||
} | } |
That %n forces a newline, yes? To ensure that the timestamp line starts with e.g.
even if the preceding line was incomplete and didn't include a newline?