s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by - replay sudo session logs
S\bSY\bYN\bNO\bOP\bPS\bSI\bIS\bS
- s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by [-\b-h\bhn\bnR\bR] [-\b-d\bd _\bd_\bi_\br] [-\b-f\bf _\bf_\bi_\bl_\bt_\be_\br] [-\b-m\bm _\bn_\bu_\bm] [-\b-s\bs _\bn_\bu_\bm] ID
+ s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by [-\b-h\bhn\bnR\bRS\bS] [-\b-d\bd _\bd_\bi_\br] [-\b-f\bf _\bf_\bi_\bl_\bt_\be_\br] [-\b-m\bm _\bn_\bu_\bm] [-\b-s\bs _\bn_\bu_\bm] ID
s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by [-\b-h\bh] [-\b-d\bd _\bd_\bi_\br] -\b-l\bl [search expression]
Do not attempt to re-size the terminal to match the terminal
size of the session.
+ -\b-S\bS, -\b--\b-s\bsu\bus\bsp\bpe\ben\bnd\bd-\b-w\bwa\bai\bit\bt
+ Wait while the command was suspended. By default, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by
+ will ignore the time interval between when the command was
+ suspended and when it was resumed. If the -\b-S\bS option is
+ specified, s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by will wait instead.
+
-\b-s\bs, -\b--\b-s\bsp\bpe\bee\bed\bd _\bs_\bp_\be_\be_\bd_\b__\bf_\ba_\bc_\bt_\bo_\br
This option causes s\bsu\bud\bdo\bor\bre\bep\bpl\bla\bay\by to adjust the number of seconds
it will wait between key presses or program output. This can
file distributed with s\bsu\bud\bdo\bo or https://www.sudo.ws/license.html for
complete details.
-Sudo 1.8.25 March 8, 2018 Sudo 1.8.25
+Sudo 1.8.26 October 5, 2018 Sudo 1.8.26
struct sudo_event *sigtstp_ev;
struct timing_closure timing;
bool interactive;
+ bool suspend_wait;
struct io_buffer {
unsigned int len; /* buffer length (how much produced) */
unsigned int off; /* write position (how much already consumed) */
static int ttyfd = -1;
-static const char short_opts[] = "d:f:hlm:nRs:V";
+static const char short_opts[] = "d:f:hlm:nRSs:V";
static struct option long_opts[] = {
{ "directory", required_argument, NULL, 'd' },
{ "filter", required_argument, NULL, 'f' },
{ "max-wait", required_argument, NULL, 'm' },
{ "non-interactive", no_argument, NULL, 'n' },
{ "no-resize", no_argument, NULL, 'R' },
+ { "suspend-wait", no_argument, NULL, 'S' },
{ "speed", required_argument, NULL, 's' },
{ "version", no_argument, NULL, 'V' },
{ NULL, no_argument, NULL, '\0' },
static int parse_expr(struct search_node_list *, char **, bool);
static void read_keyboard(int fd, int what, void *v);
static void help(void) __attribute__((__noreturn__));
-static int replay_session(struct timespec *max_wait, const char *decimal, bool interactive);
+static int replay_session(struct timespec *max_wait, const char *decimal, bool interactive, bool suspend_wait);
static void sudoreplay_cleanup(void);
static void usage(int);
static void write_output(int fd, int what, void *v);
{
int ch, i, plen, exitcode = 0;
bool def_filter = true, listonly = false;
- bool interactive = true, resize = true;
+ bool interactive = true, suspend_wait = false, resize = true;
const char *decimal, *id, *user = NULL, *pattern = NULL, *tty = NULL;
char *cp, *ep, path[PATH_MAX];
struct log_info *li;
case 'R':
resize = false;
break;
+ case 'S':
+ suspend_wait = true;
+ break;
case 's':
errno = 0;
speed_factor = strtod(optarg, &ep);
li = NULL;
/* Replay session corresponding to io_log_files[]. */
- exitcode = replay_session(max_delay, decimal, interactive);
+ exitcode = replay_session(max_delay, decimal, interactive, suspend_wait);
restore_terminal_size();
sudo_term_restore(ttyfd, true);
{
debug_decl(next_timing_record, SUDO_DEBUG_UTIL)
+again:
switch (read_timing_record(closure)) {
case 0:
/* success */
+ if (closure->timing.event == IO_EVENT_SUSPEND &&
+ closure->timing.u.signo == SIGCONT && !closure->suspend_wait) {
+ /* Ignore time spent suspended. */
+ goto again;
+ }
break;
case 1:
/* EOF */
}
static struct replay_closure *
-replay_closure_alloc(struct timespec *max_delay, const char *decimal, bool interactive)
+replay_closure_alloc(struct timespec *max_delay, const char *decimal,
+ bool interactive, bool suspend_wait)
{
struct replay_closure *closure;
debug_decl(replay_closure_alloc, SUDO_DEBUG_UTIL)
debug_return_ptr(NULL);
closure->interactive = interactive;
+ closure->suspend_wait = suspend_wait;
closure->timing.max_delay = max_delay;
closure->timing.decimal = decimal;
}
static int
-replay_session(struct timespec *max_delay, const char *decimal, bool interactive)
+replay_session(struct timespec *max_delay, const char *decimal,
+ bool interactive, bool suspend_wait)
{
struct replay_closure *closure;
int ret = 0;
debug_decl(replay_session, SUDO_DEBUG_UTIL)
/* Allocate the delay closure and read the first timing record. */
- closure = replay_closure_alloc(max_delay, decimal, interactive);
+ closure = replay_closure_alloc(max_delay, decimal, interactive,
+ suspend_wait);
if (read_timing_record(closure) != 0) {
ret = 1;
goto done;
usage(int fatal)
{
fprintf(fatal ? stderr : stdout,
- _("usage: %s [-hnR] [-d dir] [-m num] [-s num] ID\n"),
+ _("usage: %s [-hnRS] [-d dir] [-m num] [-s num] ID\n"),
getprogname());
fprintf(fatal ? stderr : stdout,
_("usage: %s [-h] [-d dir] -l [search expression]\n"),
" -h, --help display help message and exit\n"
" -l, --list list available session IDs, with optional expression\n"
" -m, --max-wait=num max number of seconds to wait between events\n"
+ " -S, --suspend-wait wait while the command was suspended\n"
" -s, --speed=num speed up or slow down output\n"
" -V, --version display version information and exit"));
exit(0);