#include #include #include #include #include #include #include #include #include "storage.h" #include "misc.h" #include "intf.h" #include "debug.h" static int killed; static char *filename; static struct tsnif_storage_handle storage_handle; static struct tsnif_storage_opts storage_opts = { .flags = TSNIF_STORAGE_OPT_READ, }; static void usage() { printf("tsnif-replay -f \n"); _exit(-1); } static void sig_handler(int sig) { printf("killed\n"); killed = 1; } static int get_args(int argc, char **argv) { int ret = 0; while (1) { int c; int option_index = 0; static struct option long_options[] = { {"file", required_argument, 0, 'f'}, {"version", no_argument, 0, 'V'}, {"verbose", required_argument, 0, 'v'}, {"debug", required_argument, 0, 'd'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "f:d:v:hV", long_options, &option_index); if (c == -1) break; switch (c) { case 'f': filename = optarg; break; case 'V': print_version(argv[0]); break; case 'v': ret = debug_parse_flags(0, optarg); break; case 'd': ret = debug_parse_flags(1, optarg); break; case 'h': usage(); break; default: printf("unknown option '%c'", c); } /* switch(c) */ } /* while(1) */ return ret; } static struct timeval get_timeout(struct timespec *ts_new, struct timespec *ts_old) { static struct timeval tv; tv.tv_sec = ts_new->tv_sec - ts_old->tv_sec; TSNIF_DEBUG(APP, "time new %ld:%ld\n", ts_new->tv_sec, ts_new->tv_nsec); TSNIF_DEBUG(APP, "time old %ld:%ld\n", ts_old->tv_sec, ts_old->tv_nsec); if (ts_new->tv_nsec >= ts_old->tv_nsec) tv.tv_usec = (ts_new->tv_nsec - ts_old->tv_nsec) / 1000; else { tv.tv_usec = (ts_new->tv_nsec + (1000000000 - ts_old->tv_nsec)) / 1000; if (tv.tv_sec) tv.tv_sec--; } TSNIF_DEBUG(APP, "time fin %ld %ld\n", tv.tv_sec, tv.tv_usec); return tv; } enum { ACTION_NEXT, ACTION_PREV, ACTION_PLAY, ACTION_FIRST, ACTION_TIMEOUT, ACTION_STOP, ACTION_RUN, ACTION_QUIT, ACTION_SLAVE, ACTION_MASTER, }; static int display_slave = 1; static int display_master= 0; static int play = 1; static int display_pty(int flags) { if ((flags == TSNIF_FLAGS_PTY_SLAVE) && !display_slave) return 0; if ((flags == TSNIF_FLAGS_PTY_MASTER) && !display_master) return 0; return 1; } static int output(struct tsnif_storage_rec *rec) { int type = tsnif_storage_term_type(&storage_handle); switch(type) { case TSNIF_TYPE_PTY: /* follow the user pty display settings */ if (!display_pty(rec->flags)) return 0; /* fallback intentionally */ case TSNIF_TYPE_TTY: case TSNIF_TYPE_TTYS: fwrite(rec->ptr, rec->len, 1, stdout); fflush(NULL); break; default: printf("failed: got unknown terminal type %d\n", type); } return 0; } static int get_action(struct timeval *tv) { int c, ret; jmp_buf env; fd_set rfds; setjmp(env); FD_ZERO(&rfds); FD_SET(0, &rfds); ret = select(1, &rfds, NULL, NULL, tv); /* select failed - finish replay */ if (-1 == ret) return ACTION_QUIT; /* timeout - continue with next record */ if (!ret) return ACTION_NEXT; /* WTF??? */ if (!FD_ISSET(0, &rfds)) return ACTION_QUIT; /* we got user input */ c = getchar(); if (c == '\033') { __fpurge(stdin); longjmp(env, 1); } switch(c) { case 'P' : return ACTION_PLAY; case 'p' : return ACTION_PREV; case 'n' : return ACTION_NEXT; case 'f' : return ACTION_FIRST; case 'q' : return ACTION_QUIT; case 't' : return ACTION_TIMEOUT; case 's' : return ACTION_SLAVE; case 'm' : return ACTION_MASTER; } longjmp(env, 1); return -1; } static int process(void) { struct tsnif_storage_rec rec; int err, action; err = tsnif_storage_read(&storage_handle, TSNIF_STORAGE_READ_NEXT, &rec); if (err < 0) return err; do { struct timespec ts_prev; struct timeval tv_def, *tv = NULL; if (err != TSNIF_STORAGE_READ_EOF) { output(&rec); if (play) { tv = &tv_def; memset(tv, 0x0, sizeof(*tv)); ts_prev = rec.time; err = tsnif_storage_read(&storage_handle, TSNIF_STORAGE_READ_NEXT, &rec); if (err < 0) break; *tv = get_timeout(&rec.time, &ts_prev); } } action = get_action(tv); switch(action) { case ACTION_PLAY: play = !play; break; case ACTION_PREV: err = tsnif_storage_read(&storage_handle, TSNIF_STORAGE_READ_PREV, &rec); if (err < 0) return err; /* we reached the first item, do not report * XXX different code for first item ??? */ if (err == TSNIF_STORAGE_READ_EOF) err = 0; /* stop play mode when going back */ play = 0; break; case ACTION_SLAVE: display_slave = !display_slave; break; case ACTION_MASTER: display_master = !display_master; break; } } while(action != ACTION_QUIT); return 0; } int main(int argc, char **argv) { int err, ret; jmp_buf env; if (get_args(argc, argv)) usage(); err = tsnif_storage_init(&storage_handle, &storage_opts, filename); if (err) return -1; if ((ret = setjmp(env))) { set_term(1); tsnif_storage_close(&storage_handle); printf("done err = %d\n", err); return err; } set_term(0); signal(SIGINT, sig_handler); err = process(); longjmp(env, 1); }