Add support for an optional offset when parsing the ID to replay.
The offset is a suffix in the form of @sec[.nanosec]
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
.\"
|
||||
.\" SPDX-License-Identifier: ISC
|
||||
.\"
|
||||
.\" Copyright (c) 2009-2020 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
.\" Copyright (c) 2009-2021 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -16,7 +16,7 @@
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.TH "SUDOREPLAY" "@mansectsu@" "May 26, 2021" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
|
||||
.TH "SUDOREPLAY" "@mansectsu@" "August 13, 2021" "Sudo @PACKAGE_VERSION@" "System Manager's Manual"
|
||||
.nh
|
||||
.if n .ad l
|
||||
.SH "NAME"
|
||||
@@ -30,7 +30,7 @@
|
||||
[\fB\-f\fR\ \fIfilter\fR]
|
||||
[\fB\-m\fR\ \fInum\fR]
|
||||
[\fB\-s\fR\ \fInum\fR]
|
||||
ID
|
||||
ID[\fI@offset\fR]
|
||||
.HP 11n
|
||||
\fBsudoreplay\fR
|
||||
[\fB\-h\fR]
|
||||
@@ -52,6 +52,16 @@ should either be a six character sequence of digits and
|
||||
upper case letters, e.g.,
|
||||
\fR0100A5\fR
|
||||
or a path name.
|
||||
The
|
||||
\fIID\fR
|
||||
may include an optional
|
||||
\fI@offset\fR
|
||||
suffix which may be used to start replaying at a specific time offset.
|
||||
The
|
||||
\fI@offset\fR
|
||||
is specified as a number in seconds since the start of the session
|
||||
with an optional decimal fraction.
|
||||
.PP
|
||||
Path names may be relative to the I/O log directory
|
||||
\fI@iolog_dir@\fR
|
||||
(unless overridden by the
|
||||
|
@@ -1,7 +1,7 @@
|
||||
.\"
|
||||
.\" SPDX-License-Identifier: ISC
|
||||
.\"
|
||||
.\" Copyright (c) 2009-2020 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
.\" Copyright (c) 2009-2021 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
.\" purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -15,7 +15,7 @@
|
||||
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
.\"
|
||||
.Dd May 26, 2021
|
||||
.Dd August 13, 2021
|
||||
.Dt SUDOREPLAY @mansectsu@
|
||||
.Os Sudo @PACKAGE_VERSION@
|
||||
.Sh NAME
|
||||
@@ -28,7 +28,7 @@
|
||||
.Op Fl f Ar filter
|
||||
.Op Fl m Ar num
|
||||
.Op Fl s Ar num
|
||||
ID
|
||||
.No ID Ns Op Ar @offset
|
||||
.Pp
|
||||
.Nm
|
||||
.Op Fl h
|
||||
@@ -50,6 +50,16 @@ should either be a six character sequence of digits and
|
||||
upper case letters, e.g.,
|
||||
.Li 0100A5
|
||||
or a path name.
|
||||
The
|
||||
.Em ID
|
||||
may include an optional
|
||||
.Ar @offset
|
||||
suffix which may be used to start replaying at a specific time offset.
|
||||
The
|
||||
.Ar @offset
|
||||
is specified as a number in seconds since the start of the session
|
||||
with an optional decimal fraction.
|
||||
.Pp
|
||||
Path names may be relative to the I/O log directory
|
||||
.Pa @iolog_dir@
|
||||
(unless overridden by the
|
||||
|
@@ -114,6 +114,11 @@ iolog_parse_delay(const char *cp, struct timespec *delay,
|
||||
|
||||
/* Radix may be in user's locale for sudo < 1.7.4 so accept that too. */
|
||||
if (*ep != '.' && *ep != *decimal_point) {
|
||||
if (*ep == '\0' || isspace((unsigned char)*ep)) {
|
||||
/* No fractional part. */
|
||||
delay->tv_nsec = 0;
|
||||
goto done;
|
||||
}
|
||||
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
|
||||
"invalid characters after seconds: %s", ep);
|
||||
debug_return_ptr(NULL);
|
||||
@@ -152,6 +157,7 @@ iolog_parse_delay(const char *cp, struct timespec *delay,
|
||||
}
|
||||
delay->tv_nsec = (long)llval;
|
||||
|
||||
done:
|
||||
/* Advance to the next field. */
|
||||
while (isspace((unsigned char)*ep))
|
||||
ep++;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* SPDX-License-Identifier: ISC
|
||||
*
|
||||
* Copyright (c) 2009-2020 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
* Copyright (c) 2009-2021 Todd C. Miller <Todd.Miller@sudo.ws>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
@@ -82,6 +82,7 @@ struct replay_closure {
|
||||
struct sudo_event *sigquit_ev;
|
||||
struct sudo_event *sigterm_ev;
|
||||
struct sudo_event *sigtstp_ev;
|
||||
struct timespec *offset;
|
||||
struct timespec *max_delay;
|
||||
struct timing_closure timing;
|
||||
int iolog_dir_fd;
|
||||
@@ -176,8 +177,8 @@ 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(int iolog_dir_fd, const char *iolog_dir,
|
||||
struct timespec *max_wait, const char *decimal, bool interactive,
|
||||
bool suspend_wait);
|
||||
struct timespec *offset, 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);
|
||||
@@ -195,7 +196,7 @@ static void setup_terminal(struct eventlog *evlog, bool interactive, bool resize
|
||||
isalnum((unsigned char)(s)[3]) && isalnum((unsigned char)(s)[4]) && \
|
||||
(s)[5] == '/' && \
|
||||
isalnum((unsigned char)(s)[6]) && isalnum((unsigned char)(s)[7]) && \
|
||||
(s)[8] == '\0')
|
||||
(s)[6] == '\0')
|
||||
|
||||
sudo_dso_public int main(int argc, char *argv[]);
|
||||
|
||||
@@ -207,6 +208,7 @@ main(int argc, char *argv[])
|
||||
bool interactive = true, suspend_wait = false, resize = true;
|
||||
const char *decimal, *id, *user = NULL, *pattern = NULL, *tty = NULL;
|
||||
char *cp, *ep, iolog_dir[PATH_MAX];
|
||||
struct timespec offset = { 0, 0};
|
||||
struct eventlog *evlog;
|
||||
struct timespec max_delay_storage, *max_delay = NULL;
|
||||
double dval;
|
||||
@@ -323,8 +325,16 @@ main(int argc, char *argv[])
|
||||
iolog_files[IOFD_TTYOUT].enabled = true;
|
||||
}
|
||||
|
||||
/* 6 digit ID in base 36, e.g. 01G712AB or free-form name */
|
||||
/* Check for offset in @sec.nsec form at the end of the id. */
|
||||
id = argv[0];
|
||||
if ((cp = strchr(id, '@')) != NULL) {
|
||||
ep = iolog_parse_delay(cp + 1, &offset, decimal);
|
||||
if (ep == NULL || *ep != '\0')
|
||||
sudo_fatalx(U_("invalid time offset %s"), cp + 1);
|
||||
*cp = '\0';
|
||||
}
|
||||
|
||||
/* 6 digit ID in base 36, e.g. 01G712AB or free-form name */
|
||||
if (VALID_ID(id)) {
|
||||
len = snprintf(iolog_dir, sizeof(iolog_dir), "%s/%.2s/%.2s/%.2s",
|
||||
session_dir, id, &id[2], &id[4]);
|
||||
@@ -376,8 +386,8 @@ main(int argc, char *argv[])
|
||||
evlog = NULL;
|
||||
|
||||
/* Replay session corresponding to iolog_files[]. */
|
||||
exitcode = replay_session(iolog_dir_fd, iolog_dir, max_delay, decimal,
|
||||
interactive, suspend_wait);
|
||||
exitcode = replay_session(iolog_dir_fd, iolog_dir, &offset, max_delay,
|
||||
decimal, interactive, suspend_wait);
|
||||
|
||||
restore_terminal_size();
|
||||
sudo_term_restore(ttyfd, true);
|
||||
@@ -774,6 +784,16 @@ get_timing_record(struct replay_closure *closure)
|
||||
closure->iobuf.toread = timing->u.nbytes;
|
||||
}
|
||||
|
||||
if (sudo_timespecisset(closure->offset)) {
|
||||
if (sudo_timespeccmp(&timing->delay, closure->offset, >)) {
|
||||
sudo_timespecsub(&timing->delay, closure->offset, &timing->delay);
|
||||
sudo_timespecclear(closure->offset);
|
||||
} else {
|
||||
sudo_timespecsub(closure->offset, &timing->delay, closure->offset);
|
||||
sudo_timespecclear(&timing->delay);
|
||||
}
|
||||
}
|
||||
|
||||
if (nodelay) {
|
||||
/* Already waited, fire immediately. */
|
||||
timing->delay.tv_sec = 0;
|
||||
@@ -957,8 +977,8 @@ signal_cb(int signo, int what, void *v)
|
||||
|
||||
static struct replay_closure *
|
||||
replay_closure_alloc(int iolog_dir_fd, const char *iolog_dir,
|
||||
struct timespec *max_delay, const char *decimal, bool interactive,
|
||||
bool suspend_wait)
|
||||
struct timespec *offset, struct timespec *max_delay, const char *decimal,
|
||||
bool interactive, bool suspend_wait)
|
||||
{
|
||||
struct replay_closure *closure;
|
||||
debug_decl(replay_closure_alloc, SUDO_DEBUG_UTIL);
|
||||
@@ -969,6 +989,7 @@ replay_closure_alloc(int iolog_dir_fd, const char *iolog_dir,
|
||||
closure->iolog_dir_fd = iolog_dir_fd;
|
||||
closure->iolog_dir = iolog_dir;
|
||||
closure->interactive = interactive;
|
||||
closure->offset = offset;
|
||||
closure->suspend_wait = suspend_wait;
|
||||
closure->max_delay = max_delay;
|
||||
closure->timing.decimal = decimal;
|
||||
@@ -1042,7 +1063,7 @@ bad:
|
||||
}
|
||||
|
||||
static int
|
||||
replay_session(int iolog_dir_fd, const char *iolog_dir,
|
||||
replay_session(int iolog_dir_fd, const char *iolog_dir, struct timespec *offset,
|
||||
struct timespec *max_delay, const char *decimal, bool interactive,
|
||||
bool suspend_wait)
|
||||
{
|
||||
@@ -1051,8 +1072,8 @@ replay_session(int iolog_dir_fd, const char *iolog_dir,
|
||||
debug_decl(replay_session, SUDO_DEBUG_UTIL);
|
||||
|
||||
/* Allocate the delay closure and read the first timing record. */
|
||||
closure = replay_closure_alloc(iolog_dir_fd, iolog_dir, max_delay, decimal,
|
||||
interactive, suspend_wait);
|
||||
closure = replay_closure_alloc(iolog_dir_fd, iolog_dir, offset, max_delay,
|
||||
decimal, interactive, suspend_wait);
|
||||
if (get_timing_record(closure) != 0) {
|
||||
ret = 1;
|
||||
goto done;
|
||||
|
Reference in New Issue
Block a user