Add support for libevent-style timed events. Adding a timed event
is currently O(n). The only consumer of timed events is sudoreplay which only used a singled one so O(n) == O(1) for now. This also allows us to remove the nanosleep compat function as we now use a timeout event instead.
This commit is contained in:
1
MANIFEST
1
MANIFEST
@@ -80,7 +80,6 @@ compat/mksiglist.h
|
||||
compat/mksigname.c
|
||||
compat/mksigname.h
|
||||
compat/mktemp.c
|
||||
compat/nanosleep.c
|
||||
compat/nss_dbdefs.h
|
||||
compat/pw_dup.c
|
||||
compat/regress/fnmatch/fnm_test.c
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
@@ -58,6 +59,7 @@ sudo_ev_base_alloc(void)
|
||||
|
||||
base = ecalloc(1, sizeof(*base));
|
||||
TAILQ_INIT(&base->events);
|
||||
TAILQ_INIT(&base->timeouts);
|
||||
if (sudo_ev_base_alloc_impl(base) != 0) {
|
||||
efree(base);
|
||||
base = NULL;
|
||||
@@ -88,6 +90,8 @@ sudo_ev_alloc(int fd, short events, sudo_ev_callback_t callback, void *closure)
|
||||
struct sudo_event *ev;
|
||||
debug_decl(sudo_ev_alloc, SUDO_DEBUG_EVENT)
|
||||
|
||||
/* XXX - sanity check events value */
|
||||
|
||||
ev = ecalloc(1, sizeof(*ev));
|
||||
ev->fd = fd;
|
||||
ev->events = events;
|
||||
@@ -111,11 +115,12 @@ sudo_ev_free(struct sudo_event *ev)
|
||||
}
|
||||
|
||||
int
|
||||
sudo_ev_add(struct sudo_event_base *base, struct sudo_event *ev, bool tohead)
|
||||
sudo_ev_add(struct sudo_event_base *base, struct sudo_event *ev,
|
||||
struct timeval *timo, bool tohead)
|
||||
{
|
||||
debug_decl(sudo_ev_add, SUDO_DEBUG_EVENT)
|
||||
|
||||
/* Don't add an event twice; revisit if we want to support timeouts. */
|
||||
/* Only add new events to the events list. */
|
||||
if (ev->base == NULL) {
|
||||
if (sudo_ev_add_impl(base, ev) != 0)
|
||||
debug_return_int(-1);
|
||||
@@ -125,6 +130,37 @@ sudo_ev_add(struct sudo_event_base *base, struct sudo_event *ev, bool tohead)
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&base->events, ev, entries);
|
||||
}
|
||||
} else {
|
||||
/* If no base specified, use existing one. */
|
||||
if (base == NULL)
|
||||
base = ev->base;
|
||||
|
||||
/* If event no longer has a timeout, remove from timeouts queue. */
|
||||
if (timo == NULL && timevalisset(&ev->timeout)) {
|
||||
timevalclear(&ev->timeout);
|
||||
TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
|
||||
}
|
||||
}
|
||||
/* Timeouts can be changed for existing events. */
|
||||
if (timo != NULL) {
|
||||
struct sudo_event *evtmp;
|
||||
if (timevalisset(&ev->timeout)) {
|
||||
/* Remove from timeouts list, then add back. */
|
||||
TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
|
||||
}
|
||||
/* Convert to absolute time and insert in sorted order; O(n). */
|
||||
gettimeofday(&ev->timeout, NULL);
|
||||
ev->timeout.tv_sec += timo->tv_sec;
|
||||
ev->timeout.tv_usec += timo->tv_usec;
|
||||
TAILQ_FOREACH(evtmp, &base->timeouts, timeouts_entries) {
|
||||
if (timevalcmp(timo, &evtmp->timeout, <))
|
||||
break;
|
||||
}
|
||||
if (evtmp != NULL) {
|
||||
TAILQ_INSERT_BEFORE(evtmp, ev, timeouts_entries);
|
||||
} else {
|
||||
TAILQ_INSERT_TAIL(&base->timeouts, ev, timeouts_entries);
|
||||
}
|
||||
}
|
||||
/* Clear pending delete so adding from callback works properly. */
|
||||
CLR(ev->flags, SUDO_EV_DELETE);
|
||||
@@ -162,6 +198,10 @@ sudo_ev_del(struct sudo_event_base *base, struct sudo_event *ev)
|
||||
/* Unlink from event list. */
|
||||
TAILQ_REMOVE(&base->events, ev, entries);
|
||||
|
||||
/* Unlink from timeouts list. */
|
||||
if (ISSET(ev->events, SUDO_EV_TIMEOUT) && timevalisset(&ev->timeout))
|
||||
TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
|
||||
|
||||
/* Unlink from active list and update base pointers as needed. */
|
||||
if (ISSET(ev->flags, SUDO_EV_ACTIVE)) {
|
||||
TAILQ_REMOVE(&base->active, ev, active_entries);
|
||||
@@ -186,7 +226,9 @@ sudo_ev_del(struct sudo_event_base *base, struct sudo_event *ev)
|
||||
int
|
||||
sudo_ev_loop(struct sudo_event_base *base, int flags)
|
||||
{
|
||||
int rc;
|
||||
struct timeval now;
|
||||
struct sudo_event *ev;
|
||||
int nready, rc = 0;
|
||||
debug_decl(sudo_ev_loop, SUDO_DEBUG_EVENT)
|
||||
|
||||
/*
|
||||
@@ -195,7 +237,7 @@ sudo_ev_loop(struct sudo_event_base *base, int flags)
|
||||
* All other base flags are ignored unless we are running events.
|
||||
*/
|
||||
if (ISSET(base->flags, SUDO_EVBASE_LOOPEXIT))
|
||||
flags |= SUDO_EVLOOP_ONCE;
|
||||
SET(flags, SUDO_EVLOOP_ONCE);
|
||||
base->flags = 0;
|
||||
|
||||
for (;;) {
|
||||
@@ -206,12 +248,32 @@ rescan:
|
||||
break;
|
||||
}
|
||||
|
||||
/* Call backend to setup the active queue. */
|
||||
/* Call backend to scan for I/O events. */
|
||||
TAILQ_INIT(&base->active);
|
||||
rc = sudo_ev_loop_impl(base, flags);
|
||||
if (rc == -1) {
|
||||
nready = sudo_ev_scan_impl(base, flags);
|
||||
switch (nready) {
|
||||
case -1:
|
||||
if (errno == EINTR || errno == ENOMEM)
|
||||
continue;
|
||||
rc = -1;
|
||||
goto done;
|
||||
case 0:
|
||||
/* Timed out, activate timeout events. */
|
||||
gettimeofday(&now, NULL);
|
||||
while ((ev = TAILQ_FIRST(&base->timeouts)) != NULL) {
|
||||
if (timevalcmp(&ev->timeout, &now, >))
|
||||
break;
|
||||
/* Remove from timeouts list. */
|
||||
timevalclear(&ev->timeout);
|
||||
TAILQ_REMOVE(&base->timeouts, ev, timeouts_entries);
|
||||
/* Make event active. */
|
||||
ev->revents = SUDO_EV_TIMEOUT;
|
||||
SET(ev->flags, SUDO_EV_ACTIVE);
|
||||
TAILQ_INSERT_TAIL(&base->active, ev, active_entries);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* I/O events active, sudo_ev_scan_impl() already added them. */
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -225,7 +287,7 @@ rescan:
|
||||
if (!ISSET(base->cur->events, SUDO_EV_PERSIST))
|
||||
SET(base->cur->flags, SUDO_EV_DELETE);
|
||||
base->cur->callback(base->cur->fd, base->cur->revents,
|
||||
base->cur->closure);
|
||||
base->cur->closure == sudo_ev_self_cbarg() ? base->cur : base->cur->closure);
|
||||
if (base->cur != NULL) {
|
||||
CLR(base->cur->flags, SUDO_EV_ACTIVE);
|
||||
if (ISSET(base->cur->flags, SUDO_EV_DELETE))
|
||||
@@ -233,21 +295,23 @@ rescan:
|
||||
}
|
||||
if (ISSET(base->flags, SUDO_EVBASE_LOOPBREAK)) {
|
||||
/* stop processing events immediately */
|
||||
base->flags |= SUDO_EVBASE_GOT_BREAK;
|
||||
SET(base->flags, SUDO_EVBASE_GOT_BREAK);
|
||||
base->pending = NULL;
|
||||
goto done;
|
||||
}
|
||||
if (ISSET(base->flags, SUDO_EVBASE_LOOPCONT)) {
|
||||
/* rescan events and start polling again */
|
||||
CLR(base->flags, SUDO_EVBASE_LOOPCONT);
|
||||
if (!ISSET(flags, SUDO_EVLOOP_ONCE)) {
|
||||
base->pending = NULL;
|
||||
goto rescan;
|
||||
}
|
||||
}
|
||||
}
|
||||
base->pending = NULL;
|
||||
if (ISSET(base->flags, SUDO_EVBASE_LOOPEXIT)) {
|
||||
/* exit loop after once through */
|
||||
base->flags |= SUDO_EVBASE_GOT_EXIT;
|
||||
SET(base->flags, SUDO_EVBASE_GOT_EXIT);
|
||||
goto done;
|
||||
}
|
||||
if (flags & (SUDO_EVLOOP_ONCE | SUDO_EVLOOP_NONBLOCK))
|
||||
@@ -262,7 +326,7 @@ void
|
||||
sudo_ev_loopexit(struct sudo_event_base *base)
|
||||
{
|
||||
debug_decl(sudo_ev_loopexit, SUDO_DEBUG_EVENT)
|
||||
base->flags |= SUDO_EVBASE_LOOPEXIT;
|
||||
SET(base->flags, SUDO_EVBASE_LOOPEXIT);
|
||||
debug_return;
|
||||
}
|
||||
|
||||
@@ -270,7 +334,7 @@ void
|
||||
sudo_ev_loopbreak(struct sudo_event_base *base)
|
||||
{
|
||||
debug_decl(sudo_ev_loopbreak, SUDO_DEBUG_EVENT)
|
||||
base->flags |= SUDO_EVBASE_LOOPBREAK;
|
||||
SET(base->flags, SUDO_EVBASE_LOOPBREAK);
|
||||
debug_return;
|
||||
}
|
||||
|
||||
@@ -278,7 +342,7 @@ void
|
||||
sudo_ev_loopcontinue(struct sudo_event_base *base)
|
||||
{
|
||||
debug_decl(sudo_ev_loopcontinue, SUDO_DEBUG_EVENT)
|
||||
base->flags |= SUDO_EVBASE_LOOPCONT;
|
||||
SET(base->flags, SUDO_EVBASE_LOOPCONT);
|
||||
debug_return;
|
||||
}
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
@@ -133,22 +134,33 @@ sudo_ev_del_impl(struct sudo_event_base *base, struct sudo_event *ev)
|
||||
int
|
||||
sudo_ev_loop_impl(struct sudo_event_base *base, int flags)
|
||||
{
|
||||
const int timeout = (flags & SUDO_EVLOOP_NONBLOCK) ? 0 : -1;
|
||||
struct sudo_event *ev;
|
||||
int nready;
|
||||
int nready, timeout;
|
||||
struct timeval now;
|
||||
debug_decl(sudo_ev_loop_impl, SUDO_DEBUG_EVENT)
|
||||
|
||||
if ((ev = TAILQ_FIRST(&base->timeouts)) != NULL) {
|
||||
struct timeval *timo = &ev->timeout;
|
||||
gettimeofday(&now, NULL);
|
||||
timeout = ((timo->tv_sec - now.tv_sec) * 1000) +
|
||||
((timo->tv_usec - now.tv_usec) / 1000);
|
||||
if (timeout <= 0)
|
||||
debug_return_int(0);
|
||||
} else {
|
||||
timeout = (flags & SUDO_EVLOOP_NONBLOCK) ? 0 : -1;
|
||||
}
|
||||
|
||||
nready = poll(base->pfds, base->pfd_high + 1, timeout);
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: %d fds ready", __func__, nready);
|
||||
switch (nready) {
|
||||
case -1:
|
||||
/* error or interrupted by signal */
|
||||
/* Error or interrupted by signal. */
|
||||
debug_return_int(-1);
|
||||
case 0:
|
||||
/* timeout or no events */
|
||||
/* Front end will activate timeout events. */
|
||||
break;
|
||||
default:
|
||||
/* Activate each event that fired. */
|
||||
/* Activate each I/O event that fired. */
|
||||
TAILQ_FOREACH(ev, &base->events, entries) {
|
||||
if (ev->pfd_idx != -1 && base->pfds[ev->pfd_idx].revents) {
|
||||
int what = 0;
|
||||
|
@@ -16,9 +16,10 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h> /* for howmany() on Linux */
|
||||
#include <sys/time.h>
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
# include <sys/sysmacros.h>
|
||||
# include <sys/sysmacros.h> /* for howmany() on Solaris */
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
# include <sys/select.h>
|
||||
@@ -108,20 +109,28 @@ sudo_ev_del_impl(struct sudo_event_base *base, struct sudo_event *ev)
|
||||
}
|
||||
|
||||
int
|
||||
sudo_ev_loop_impl(struct sudo_event_base *base, int flags)
|
||||
sudo_ev_scan_impl(struct sudo_event_base *base, int flags)
|
||||
{
|
||||
struct timeval tv, *timeout;
|
||||
struct timeval now, tv, *timeout;
|
||||
struct sudo_event *ev;
|
||||
int nready, highfd = 0;
|
||||
debug_decl(sudo_ev_loop, SUDO_DEBUG_EVENT)
|
||||
|
||||
if ((ev = TAILQ_FIRST(&base->timeouts)) != NULL) {
|
||||
gettimeofday(&now, NULL);
|
||||
tv = ev->timeout;
|
||||
timevalsub(&tv, &now);
|
||||
if (tv.tv_sec < 0 || tv.tv_usec < 0)
|
||||
debug_return_int(0);
|
||||
timeout = &tv;
|
||||
} else {
|
||||
if (ISSET(flags, SUDO_EVLOOP_NONBLOCK)) {
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
timevalclear(&tv);
|
||||
timeout = &tv;
|
||||
} else {
|
||||
timeout = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/* For select we need to redo readfds and writefds each time. */
|
||||
memset(base->readfds, 0, howmany(base->maxfd + 1, NFDBITS) * sizeof(fd_mask));
|
||||
@@ -148,13 +157,13 @@ sudo_ev_loop_impl(struct sudo_event_base *base, int flags)
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: %d fds ready", __func__, nready);
|
||||
switch (nready) {
|
||||
case -1:
|
||||
/* error or interrupted by signal */
|
||||
/* Error or interrupted by signal. */
|
||||
debug_return_int(-1);
|
||||
case 0:
|
||||
/* timeout or no events */
|
||||
/* Front end will activate timeout events. */
|
||||
break;
|
||||
default:
|
||||
/* Activate each event that fired. */
|
||||
/* Activate each I/O event that fired. */
|
||||
TAILQ_FOREACH(ev, &base->events, entries) {
|
||||
int what = 0;
|
||||
if (FD_ISSET(ev->fd, base->readfds))
|
||||
@@ -170,5 +179,5 @@ sudo_ev_loop_impl(struct sudo_event_base *base, int flags)
|
||||
}
|
||||
break;
|
||||
}
|
||||
debug_return_int(0);
|
||||
debug_return_int(nready);
|
||||
}
|
||||
|
@@ -209,9 +209,6 @@ mksigname.lo: $(srcdir)/mksigname.c $(top_builddir)/config.h \
|
||||
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/mksigname.c
|
||||
mktemp.lo: $(srcdir)/mktemp.c $(top_builddir)/config.h $(incdir)/missing.h
|
||||
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/mktemp.c
|
||||
nanosleep.lo: $(srcdir)/nanosleep.c $(top_builddir)/config.h \
|
||||
$(top_srcdir)/compat/timespec.h $(incdir)/missing.h
|
||||
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/nanosleep.c
|
||||
pw_dup.lo: $(srcdir)/pw_dup.c $(top_builddir)/config.h
|
||||
$(LIBTOOL) --mode=compile $(CC) -c -o $@ $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/pw_dup.c
|
||||
sig2str.lo: $(srcdir)/sig2str.c $(top_builddir)/config.h $(incdir)/missing.h
|
||||
|
@@ -1,57 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2011, 2013 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#ifndef HAVE_NANOSLEEP
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif /* HAVE_SYS_SELECT_H */
|
||||
#if TIME_WITH_SYS_TIME
|
||||
# include <time.h>
|
||||
#endif
|
||||
#ifndef HAVE_STRUCT_TIMESPEC
|
||||
# include "compat/timespec.h"
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include "missing.h"
|
||||
|
||||
int
|
||||
nanosleep(const struct timespec *ts, struct timespec *rts)
|
||||
{
|
||||
struct timeval timeout, endtime, now;
|
||||
int rval;
|
||||
|
||||
timeout.tv_sec = ts->tv_sec;
|
||||
timeout.tv_usec = ts->tv_nsec / 1000;
|
||||
if (rts != NULL) {
|
||||
gettimeofday(&endtime, NULL);
|
||||
timevaladd(&endtime, &timeout);
|
||||
}
|
||||
rval = select(0, NULL, NULL, NULL, &timeout);
|
||||
if (rts != NULL && rval == -1 && errno == EINTR) {
|
||||
gettimeofday(&now, NULL);
|
||||
timevalsub(&endtime, &now);
|
||||
rts->tv_sec = endtime.tv_sec;
|
||||
rts->tv_nsec = endtime.tv_usec * 1000;
|
||||
}
|
||||
return rval;
|
||||
}
|
||||
#endif /* HAVE_NANOSLEEP */
|
@@ -397,9 +397,6 @@
|
||||
/* Define to 1 if you have the <mps/ldap_ssl.h> header file. */
|
||||
#undef HAVE_MPS_LDAP_SSL_H
|
||||
|
||||
/* Define to 1 if you have the `nanosleep' function. */
|
||||
#undef HAVE_NANOSLEEP
|
||||
|
||||
/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
|
||||
#undef HAVE_NDIR_H
|
||||
|
||||
|
62
configure
vendored
62
configure
vendored
@@ -17653,68 +17653,6 @@ esac
|
||||
fi
|
||||
|
||||
|
||||
for ac_func in nanosleep
|
||||
do :
|
||||
ac_fn_c_check_func "$LINENO" "nanosleep" "ac_cv_func_nanosleep"
|
||||
if test "x$ac_cv_func_nanosleep" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_NANOSLEEP 1
|
||||
_ACEOF
|
||||
|
||||
else
|
||||
|
||||
# On Solaris, nanosleep is in librt
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for nanosleep in -lrt" >&5
|
||||
$as_echo_n "checking for nanosleep in -lrt... " >&6; }
|
||||
if ${ac_cv_lib_rt_nanosleep+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lrt $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char nanosleep ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return nanosleep ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_rt_nanosleep=yes
|
||||
else
|
||||
ac_cv_lib_rt_nanosleep=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_nanosleep" >&5
|
||||
$as_echo "$ac_cv_lib_rt_nanosleep" >&6; }
|
||||
if test "x$ac_cv_lib_rt_nanosleep" = xyes; then :
|
||||
REPLAY_LIBS="${REPLAY_LIBS} -lrt"
|
||||
else
|
||||
case " $LIBOBJS " in
|
||||
*" nanosleep.$ac_objext "* ) ;;
|
||||
*) LIBOBJS="$LIBOBJS nanosleep.$ac_objext"
|
||||
;;
|
||||
esac
|
||||
|
||||
fi
|
||||
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
for ac_func in getopt_long
|
||||
do :
|
||||
ac_fn_c_check_func "$LINENO" "getopt_long" "ac_cv_func_getopt_long"
|
||||
|
@@ -2370,10 +2370,6 @@ SUDO_FUNC_FNMATCH([AC_DEFINE(HAVE_FNMATCH)], [AC_LIBOBJ(fnmatch)
|
||||
])
|
||||
SUDO_FUNC_ISBLANK
|
||||
AC_REPLACE_FUNCS(memrchr memset_s pw_dup strlcpy strlcat)
|
||||
AC_CHECK_FUNCS(nanosleep, [], [
|
||||
# On Solaris, nanosleep is in librt
|
||||
AC_CHECK_LIB(rt, nanosleep, [REPLAY_LIBS="${REPLAY_LIBS} -lrt"], [AC_LIBOBJ(nanosleep)])
|
||||
])
|
||||
AC_CHECK_FUNCS(getopt_long, [], [AC_LIBOBJ(getopt_long)
|
||||
AC_MSG_CHECKING([for optreset])
|
||||
AC_CACHE_VAL(sudo_cv_optreset, [
|
||||
|
@@ -186,13 +186,6 @@
|
||||
#undef ISSET
|
||||
#define ISSET(t, f) ((t) & (f))
|
||||
|
||||
/*
|
||||
* Some systems define this in <sys/param.h> but we don't include that anymore.
|
||||
*/
|
||||
#ifndef howmany
|
||||
# define howmany(x, y) (((x) + ((y) - 1)) / (y))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Older systems may be missing stddef.h and/or offsetof macro
|
||||
*/
|
||||
@@ -413,9 +406,6 @@ char *mkdtemp(char *);
|
||||
#ifndef HAVE_MKSTEMPS
|
||||
int mkstemps(char *, int);
|
||||
#endif
|
||||
#ifndef HAVE_NANOSLEEP
|
||||
int nanosleep(const struct timespec *, struct timespec *);
|
||||
#endif
|
||||
#ifndef HAVE_PW_DUP
|
||||
struct passwd *pw_dup(const struct passwd *);
|
||||
#endif
|
||||
|
@@ -20,9 +20,10 @@
|
||||
#include "queue.h"
|
||||
|
||||
/* Event types */
|
||||
#define SUDO_EV_READ 0x01 /* fire when readable */
|
||||
#define SUDO_EV_WRITE 0x02 /* fire when writable */
|
||||
#define SUDO_EV_PERSIST 0x04 /* persist until deleted */
|
||||
#define SUDO_EV_TIMEOUT 0x01 /* fire after timeout */
|
||||
#define SUDO_EV_READ 0x02 /* fire when readable */
|
||||
#define SUDO_EV_WRITE 0x04 /* fire when writable */
|
||||
#define SUDO_EV_PERSIST 0x08 /* persist until deleted */
|
||||
|
||||
/* Event flags (internal) */
|
||||
#define SUDO_EV_ACTIVE 0x01 /* event is on the active queue */
|
||||
@@ -46,6 +47,7 @@ typedef void (*sudo_ev_callback_t)(int fd, int what, void *closure);
|
||||
struct sudo_event {
|
||||
TAILQ_ENTRY(sudo_event) entries;
|
||||
TAILQ_ENTRY(sudo_event) active_entries;
|
||||
TAILQ_ENTRY(sudo_event) timeouts_entries;
|
||||
struct sudo_event_base *base; /* base this event belongs to */
|
||||
int fd; /* fd we are interested in */
|
||||
short events; /* SUDO_EV_* flags (in) */
|
||||
@@ -53,6 +55,7 @@ struct sudo_event {
|
||||
short flags; /* internal event flags */
|
||||
short pfd_idx; /* index into pfds array (XXX) */
|
||||
sudo_ev_callback_t callback;/* user-provided callback */
|
||||
struct timeval timeout; /* for SUDO_EV_TIMEOUT */
|
||||
void *closure; /* user-provided data pointer */
|
||||
};
|
||||
|
||||
@@ -61,6 +64,7 @@ TAILQ_HEAD(sudo_event_list, sudo_event);
|
||||
struct sudo_event_base {
|
||||
struct sudo_event_list events; /* tail queue of all events */
|
||||
struct sudo_event_list active; /* tail queue of active events */
|
||||
struct sudo_event_list timeouts; /* tail queue of timeout events */
|
||||
struct sudo_event *cur; /* current active event being serviced */
|
||||
struct sudo_event *pending; /* next active event to be serviced */
|
||||
#ifdef HAVE_POLL
|
||||
@@ -89,7 +93,7 @@ struct sudo_event *sudo_ev_alloc(int fd, short events, sudo_ev_callback_t callba
|
||||
void sudo_ev_free(struct sudo_event *ev);
|
||||
|
||||
/* Add an event, returns 0 on success, -1 on error */
|
||||
int sudo_ev_add(struct sudo_event_base *head, struct sudo_event *ev, bool tohead);
|
||||
int sudo_ev_add(struct sudo_event_base *head, struct sudo_event *ev, struct timeval *timo, bool tohead);
|
||||
|
||||
/* Delete an event, returns 0 on success, -1 on error */
|
||||
int sudo_ev_del(struct sudo_event_base *head, struct sudo_event *ev);
|
||||
@@ -115,9 +119,16 @@ bool sudo_ev_got_break(struct sudo_event_base *base);
|
||||
/* Return the fd associated with an event. */
|
||||
#define sudo_ev_get_fd(_ev) ((_ev) ? (_ev)->fd : -1)
|
||||
|
||||
/* Return the (absolute) timeout associated with an event or NULL. */
|
||||
#define sudo_ev_get_timeout(_ev) \
|
||||
(((_ev) && timevalisset(&(_ev)->timeout)) ? &(_ev)->timeout : NULL)
|
||||
|
||||
/* Return the base an event is associated with or NULL. */
|
||||
#define sudo_ev_get_base(_ev) ((_ev) ? (_ev)->base : NULL)
|
||||
|
||||
/* Magic pointer value to use self pointer as callback arg. */
|
||||
#define sudo_ev_self_cbarg() ((void *)-1)
|
||||
|
||||
/*
|
||||
* Backend implementation.
|
||||
*/
|
||||
@@ -125,6 +136,6 @@ int sudo_ev_base_alloc_impl(struct sudo_event_base *base);
|
||||
void sudo_ev_base_free_impl(struct sudo_event_base *base);
|
||||
int sudo_ev_add_impl(struct sudo_event_base *base, struct sudo_event *ev);
|
||||
int sudo_ev_del_impl(struct sudo_event_base *base, struct sudo_event *ev);
|
||||
int sudo_ev_loop_impl(struct sudo_event_base *base, int flags);
|
||||
int sudo_ev_scan_impl(struct sudo_event_base *base, int flags);
|
||||
|
||||
#endif /* _SUDO_EVENT_H */
|
||||
|
2
mkdep.pl
2
mkdep.pl
@@ -70,7 +70,7 @@ sub mkdep {
|
||||
$makefile =~ s:\@SUDOERS_OBJS\@:bsm_audit.lo linux_audit.lo ldap.lo sssd.lo:;
|
||||
# XXX - fill in AUTH_OBJS from contents of the auth dir instead
|
||||
$makefile =~ s:\@AUTH_OBJS\@:afs.lo aix_auth.lo bsdauth.lo dce.lo fwtk.lo getspwuid.lo kerb5.lo pam.lo passwd.lo rfc1938.lo secureware.lo securid5.lo sia.lo:;
|
||||
$makefile =~ s:\@LTLIBOBJS\@:closefrom.lo dlopen.lo fnmatch.lo getcwd.lo getgrouplist.lo getline.lo getprogname.lo getopt_long.lo glob.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo nanosleep.lo pw_dup.lo sig2str.lo siglist.lo signame.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo utimes.lo globtest.o fnm_test.o:;
|
||||
$makefile =~ s:\@LTLIBOBJS\@:closefrom.lo dlopen.lo fnmatch.lo getcwd.lo getgrouplist.lo getline.lo getprogname.lo getopt_long.lo glob.lo isblank.lo memrchr.lo memset_s.lo mksiglist.lo mksigname.lo mktemp.lo pw_dup.lo sig2str.lo siglist.lo signame.lo snprintf.lo strlcat.lo strlcpy.lo strsignal.lo utimes.lo globtest.o fnm_test.o:;
|
||||
|
||||
# Parse OBJS lines
|
||||
my %objs;
|
||||
|
@@ -840,7 +840,8 @@ sudoreplay.o: $(srcdir)/sudoreplay.c $(top_builddir)/config.h \
|
||||
$(incdir)/missing.h $(incdir)/alloc.h $(incdir)/fatal.h \
|
||||
$(incdir)/gettext.h $(srcdir)/logging.h $(srcdir)/iolog.h \
|
||||
$(incdir)/queue.h $(incdir)/sudo_plugin.h $(incdir)/sudo_conf.h \
|
||||
$(incdir)/queue.h $(incdir)/sudo_debug.h
|
||||
$(incdir)/queue.h $(incdir)/sudo_debug.h $(incdir)/sudo_event.h \
|
||||
$(incdir)/queue.h
|
||||
$(CC) -c $(CPPFLAGS) $(CFLAGS) $(PIE_CFLAGS) $(SSP_CFLAGS) $(DEFS) $(srcdir)/sudoreplay.c
|
||||
testsudoers.o: $(srcdir)/testsudoers.c $(top_builddir)/config.h \
|
||||
$(top_srcdir)/compat/fnmatch.h $(srcdir)/tsgetgrpw.h \
|
||||
|
@@ -18,16 +18,10 @@
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
# include <sys/sysmacros.h>
|
||||
#endif
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/ioctl.h>
|
||||
#ifdef HAVE_SYS_SELECT_H
|
||||
#include <sys/select.h>
|
||||
#endif /* HAVE_SYS_SELECT_H */
|
||||
#include <stdio.h>
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
@@ -105,6 +99,7 @@
|
||||
#include "sudo_plugin.h"
|
||||
#include "sudo_conf.h"
|
||||
#include "sudo_debug.h"
|
||||
#include "sudo_event.h"
|
||||
|
||||
#ifndef LINE_MAX
|
||||
# define LINE_MAX 2048
|
||||
@@ -125,6 +120,14 @@ struct log_info {
|
||||
int cols;
|
||||
};
|
||||
|
||||
/* Closure for write_output */
|
||||
struct write_closure {
|
||||
struct sudo_event *wevent;
|
||||
struct iovec *iov;
|
||||
unsigned int iovcnt;
|
||||
size_t nbytes;
|
||||
};
|
||||
|
||||
/*
|
||||
* Handle expressions like:
|
||||
* ( user millert or user root ) and tty console and command /bin/sh
|
||||
@@ -162,7 +165,9 @@ struct search_node {
|
||||
|
||||
static struct search_node_list search_expr = STAILQ_HEAD_INITIALIZER(search_expr);
|
||||
|
||||
static int timing_idx_adj = 0;
|
||||
static int timing_idx_adj;
|
||||
|
||||
static double speed_factor = 1.0;
|
||||
|
||||
static const char *session_dir = _PATH_SUDO_IO_LOGDIR;
|
||||
|
||||
@@ -186,17 +191,16 @@ extern void get_ttysize(int *rowp, int *colp);
|
||||
|
||||
static int list_sessions(int, char **, const char *, const char *, const char *);
|
||||
static int parse_expr(struct search_node_list *, char **, bool);
|
||||
static void check_input(int, double *);
|
||||
static void delay(double);
|
||||
static void check_input(int fd, int what, void *v);
|
||||
static void help(void) __attribute__((__noreturn__));
|
||||
static void usage(int);
|
||||
static int open_io_fd(char *path, int len, struct io_log_file *iol);
|
||||
static int parse_timing(const char *buf, const char *decimal, int *idx, double *seconds, size_t *nbytes);
|
||||
static struct log_info *parse_logfile(char *logfile);
|
||||
static void free_log_info(struct log_info *li);
|
||||
static ssize_t atomic_writev(int fd, struct iovec *iov, int iovcnt);
|
||||
static void sudoreplay_handler(int);
|
||||
static void sudoreplay_cleanup(void);
|
||||
static void write_output(int fd, int what, void *v);
|
||||
|
||||
#ifdef HAVE_REGCOMP
|
||||
# define REGEX_T regex_t
|
||||
@@ -228,12 +232,16 @@ main(int argc, char *argv[])
|
||||
bool def_filter = true;
|
||||
const char *decimal, *id, *user = NULL, *pattern = NULL, *tty = NULL;
|
||||
char path[PATH_MAX], buf[LINE_MAX], *cp, *ep;
|
||||
double seconds, to_wait, speed = 1.0, max_wait = 0;
|
||||
double seconds, to_wait, max_wait = 0;
|
||||
struct sudo_event_base *evbase;
|
||||
struct sudo_event *input_ev, *output_ev;
|
||||
struct timeval timeout;
|
||||
sigaction_t sa;
|
||||
size_t len, nbytes, nread;
|
||||
struct log_info *li;
|
||||
struct iovec *iov = NULL;
|
||||
int iovcnt = 0, iovmax = 0;
|
||||
unsigned int i, iovcnt = 0, iovmax = 0;
|
||||
struct write_closure wc;
|
||||
debug_decl(main, SUDO_DEBUG_MAIN)
|
||||
|
||||
#if defined(SUDO_DEVEL) && defined(__OpenBSD__)
|
||||
@@ -291,7 +299,7 @@ main(int argc, char *argv[])
|
||||
break;
|
||||
case 's':
|
||||
errno = 0;
|
||||
speed = strtod(optarg, &ep);
|
||||
speed_factor = strtod(optarg, &ep);
|
||||
if (*ep != '\0' || errno != 0)
|
||||
fatalx(_("invalid speed factor: %s"), optarg);
|
||||
break;
|
||||
@@ -392,6 +400,18 @@ main(int argc, char *argv[])
|
||||
iov = ecalloc(iovmax, sizeof(*iov));
|
||||
}
|
||||
|
||||
/* Setup event base and input/output events. */
|
||||
evbase = sudo_ev_base_alloc();
|
||||
if (evbase == NULL)
|
||||
fatal(NULL);
|
||||
input_ev = sudo_ev_alloc(STDIN_FILENO, interactive ? SUDO_EV_READ :
|
||||
SUDO_EV_TIMEOUT, check_input, sudo_ev_self_cbarg());
|
||||
if (input_ev == NULL)
|
||||
fatal(NULL);
|
||||
output_ev = sudo_ev_alloc(STDIN_FILENO, SUDO_EV_WRITE, write_output, &wc);
|
||||
if (output_ev == NULL)
|
||||
fatal(NULL);
|
||||
|
||||
/*
|
||||
* Timing file consists of line of the format: "%f %d\n"
|
||||
*/
|
||||
@@ -405,14 +425,18 @@ main(int argc, char *argv[])
|
||||
if (!parse_timing(buf, decimal, &idx, &seconds, &nbytes))
|
||||
fatalx(_("invalid timing file line: %s"), buf);
|
||||
|
||||
if (interactive)
|
||||
check_input(STDIN_FILENO, &speed);
|
||||
|
||||
/* Adjust delay using speed factor and clamp to max_wait */
|
||||
to_wait = seconds / speed;
|
||||
to_wait = seconds / speed_factor;
|
||||
if (max_wait && to_wait > max_wait)
|
||||
to_wait = max_wait;
|
||||
delay(to_wait);
|
||||
|
||||
/* Convert delay to a timeval. */
|
||||
timeout.tv_sec = to_wait;
|
||||
timeout.tv_usec = (to_wait - timeout.tv_sec) * 1000000.0;
|
||||
|
||||
/* Run event event loop to delay and get keyboard input. */
|
||||
sudo_ev_add(evbase, input_ev, &timeout, false);
|
||||
sudo_ev_loop(evbase, 0);
|
||||
|
||||
/* Even if we are not replaying, we still have to delay. */
|
||||
if (io_log_files[idx].fd.v == NULL)
|
||||
@@ -423,6 +447,7 @@ main(int argc, char *argv[])
|
||||
need_nlcr = (idx == IOFD_STDOUT || idx == IOFD_STDERR);
|
||||
|
||||
/* All output is sent to stdout. */
|
||||
/* XXX - assumes no wall clock time spent writing output. */
|
||||
while (nbytes != 0) {
|
||||
if (nbytes > sizeof(buf))
|
||||
len = sizeof(buf);
|
||||
@@ -485,8 +510,19 @@ main(int argc, char *argv[])
|
||||
iov[0].iov_len = nread;
|
||||
iovcnt = 1;
|
||||
}
|
||||
if (atomic_writev(STDOUT_FILENO, iov, iovcnt) == -1)
|
||||
fatal(_("writing to standard output"));
|
||||
|
||||
/* Setup closure for write_output. */
|
||||
memset(&wc, 0, sizeof(wc));
|
||||
wc.wevent = output_ev;
|
||||
wc.iov = iov;
|
||||
wc.iovcnt = iovcnt;
|
||||
for (i = 0; i < iovcnt; i++)
|
||||
wc.nbytes += iov[i].iov_len;
|
||||
|
||||
/* Run event event loop to write output. */
|
||||
/* XXX - should use a single event loop with a circular buffer. */
|
||||
sudo_ev_add(evbase, output_ev, NULL, false);
|
||||
sudo_ev_loop(evbase, 0);
|
||||
}
|
||||
}
|
||||
term_restore(STDIN_FILENO, 1);
|
||||
@@ -495,31 +531,6 @@ done:
|
||||
exit(exitcode);
|
||||
}
|
||||
|
||||
static void
|
||||
delay(double secs)
|
||||
{
|
||||
struct timespec ts, rts;
|
||||
int rval;
|
||||
|
||||
/*
|
||||
* Typical max resolution is 1/HZ but we can't portably check that.
|
||||
* If the interval is small enough, just ignore it.
|
||||
*/
|
||||
if (secs < 0.0001)
|
||||
return;
|
||||
|
||||
rts.tv_sec = secs;
|
||||
rts.tv_nsec = (secs - (double) rts.tv_sec) * 1000000000.0;
|
||||
do {
|
||||
memcpy(&ts, &rts, sizeof(ts));
|
||||
rval = nanosleep(&ts, &rts);
|
||||
} while (rval == -1 && errno == EINTR);
|
||||
if (rval == -1) {
|
||||
fatal_nodebug("nanosleep: tv_sec %lld, tv_nsec %ld",
|
||||
(long long)ts.tv_sec, (long)ts.tv_nsec);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
open_io_fd(char *path, int len, struct io_log_file *iol)
|
||||
{
|
||||
@@ -538,67 +549,55 @@ open_io_fd(char *path, int len, struct io_log_file *iol)
|
||||
debug_return_int(iol->fd.v ? 0 : -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call writev(), restarting as needed and handling EAGAIN since
|
||||
* fd may be in non-blocking mode.
|
||||
*/
|
||||
static ssize_t
|
||||
atomic_writev(int fd, struct iovec *iov, int iovcnt)
|
||||
static void
|
||||
write_output(int fd, int what, void *v)
|
||||
{
|
||||
ssize_t n, nwritten = 0;
|
||||
size_t count, remainder, nbytes = 0;
|
||||
int i;
|
||||
debug_decl(atomic_writev, SUDO_DEBUG_UTIL)
|
||||
struct write_closure *wc = v;
|
||||
ssize_t nwritten;
|
||||
size_t count, remainder;
|
||||
unsigned int i;
|
||||
debug_decl(write_output, SUDO_DEBUG_UTIL)
|
||||
|
||||
for (i = 0; i < iovcnt; i++)
|
||||
nbytes += iov[i].iov_len;
|
||||
|
||||
for (;;) {
|
||||
n = writev(STDOUT_FILENO, iov, iovcnt);
|
||||
if (n > 0) {
|
||||
nwritten += n;
|
||||
remainder = nbytes - nwritten;
|
||||
if (remainder == 0)
|
||||
nwritten = writev(STDOUT_FILENO, wc->iov, wc->iovcnt);
|
||||
switch (nwritten) {
|
||||
case -1:
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
fatal(_("unable to write to %s"), "stdout");
|
||||
break;
|
||||
/* short writev, adjust iov and do the rest. */
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
remainder = wc->nbytes - nwritten;
|
||||
if (remainder == 0) {
|
||||
/* writev completed */
|
||||
debug_return;
|
||||
}
|
||||
|
||||
/* short writev, adjust iov so we can write the remainder. */
|
||||
count = 0;
|
||||
i = iovcnt;
|
||||
i = wc->iovcnt;
|
||||
while (i--) {
|
||||
count += iov[i].iov_len;
|
||||
count += wc->iov[i].iov_len;
|
||||
if (count == remainder) {
|
||||
iov += i;
|
||||
iovcnt -= i;
|
||||
wc->iov += i;
|
||||
wc->iovcnt -= i;
|
||||
break;
|
||||
}
|
||||
if (count > remainder) {
|
||||
size_t off = (count - remainder);
|
||||
/* XXX - side effect prevents iov from being const */
|
||||
iov[i].iov_base = (char *)iov[i].iov_base + off;
|
||||
iov[i].iov_len -= off;
|
||||
iov += i;
|
||||
iovcnt -= i;
|
||||
wc->iov[i].iov_base = (char *)wc->iov[i].iov_base + off;
|
||||
wc->iov[i].iov_len -= off;
|
||||
wc->iov += i;
|
||||
wc->iovcnt -= i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (n == 0 || errno == EAGAIN) {
|
||||
int nready;
|
||||
fd_set fdsw;
|
||||
FD_ZERO(&fdsw);
|
||||
FD_SET(STDOUT_FILENO, &fdsw);
|
||||
do {
|
||||
nready = select(STDOUT_FILENO + 1, NULL, &fdsw, NULL, NULL);
|
||||
} while (nready == -1 && errno == EINTR);
|
||||
if (nready == 1)
|
||||
continue;
|
||||
}
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
nwritten = -1;
|
||||
break;
|
||||
}
|
||||
debug_return_size_t(nwritten);
|
||||
|
||||
/* Reschedule event to write remainder. */
|
||||
sudo_ev_add(sudo_ev_get_base(wc->wevent), wc->wevent, NULL, false);
|
||||
debug_return;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1051,44 +1050,58 @@ list_sessions(int argc, char **argv, const char *pattern, const char *user,
|
||||
* pause, slow, fast
|
||||
*/
|
||||
static void
|
||||
check_input(int ttyfd, double *speed)
|
||||
check_input(int fd, int what, void *v)
|
||||
{
|
||||
fd_set *fdsr;
|
||||
int nready, paused = 0;
|
||||
struct timeval tv;
|
||||
struct sudo_event *ev = v;
|
||||
struct sudo_event_base *evbase = sudo_ev_get_base(ev);
|
||||
struct timeval tv, *timeout = NULL;
|
||||
static bool paused = 0;
|
||||
char ch;
|
||||
ssize_t n;
|
||||
debug_decl(check_input, SUDO_DEBUG_UTIL)
|
||||
|
||||
fdsr = ecalloc(howmany(ttyfd + 1, NFDBITS), sizeof(fd_mask));
|
||||
for (;;) {
|
||||
FD_SET(ttyfd, fdsr);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
nready = select(ttyfd + 1, fdsr, NULL, NULL, paused ? NULL : &tv);
|
||||
if (nready != 1)
|
||||
if (ISSET(what, SUDO_EV_READ)) {
|
||||
switch (read(fd, &ch, 1)) {
|
||||
case -1:
|
||||
if (errno != EINTR && errno != EAGAIN)
|
||||
fatal(_("unable to read %s"), "stdin");
|
||||
break;
|
||||
n = read(ttyfd, &ch, 1);
|
||||
if (n == 1) {
|
||||
case 0:
|
||||
/* Ignore EOF. */
|
||||
break;
|
||||
case 1:
|
||||
if (paused) {
|
||||
paused = 0;
|
||||
continue;
|
||||
/* Any key will unpause, event is finished. */
|
||||
/* XXX - pause time could be less than timeout */
|
||||
paused = false;
|
||||
debug_return;
|
||||
}
|
||||
switch (ch) {
|
||||
case ' ':
|
||||
paused = 1;
|
||||
paused = true;
|
||||
break;
|
||||
case '<':
|
||||
*speed /= 2;
|
||||
speed_factor /= 2;
|
||||
break;
|
||||
case '>':
|
||||
*speed *= 2;
|
||||
speed_factor *= 2;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (!paused) {
|
||||
/* Determine remaining timeout, if any. */
|
||||
timeout = sudo_ev_get_timeout(ev);
|
||||
if (timeout != NULL) {
|
||||
struct timeval now;
|
||||
gettimeofday(&now, NULL);
|
||||
tv = *timeout;
|
||||
timevalsub(&tv, &now);
|
||||
timeout = &tv;
|
||||
}
|
||||
}
|
||||
free(fdsr);
|
||||
/* Re-enable event. */
|
||||
sudo_ev_add(evbase, ev, timeout, false);
|
||||
}
|
||||
debug_return;
|
||||
}
|
||||
|
||||
|
@@ -305,7 +305,7 @@ exec_event_setup(int backchannel, struct exec_closure *ec)
|
||||
SUDO_EV_READ|SUDO_EV_PERSIST, signal_pipe_cb, ec);
|
||||
if (signal_event == NULL)
|
||||
fatal(NULL);
|
||||
if (sudo_ev_add(evbase, signal_event, false) == -1)
|
||||
if (sudo_ev_add(evbase, signal_event, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
|
||||
/* Event for command status via backchannel. */
|
||||
@@ -313,7 +313,7 @@ exec_event_setup(int backchannel, struct exec_closure *ec)
|
||||
SUDO_EV_READ|SUDO_EV_PERSIST, backchannel_cb, ec);
|
||||
if (backchannel_event == NULL)
|
||||
fatal(NULL);
|
||||
if (sudo_ev_add(evbase, backchannel_event, false) == -1)
|
||||
if (sudo_ev_add(evbase, backchannel_event, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
|
||||
/* The signal forwarding event gets added on demand. */
|
||||
@@ -837,7 +837,7 @@ schedule_signal(struct sudo_event_base *evbase, int signo)
|
||||
sigfwd->signo = signo;
|
||||
TAILQ_INSERT_TAIL(&sigfwd_list, sigfwd, entries);
|
||||
|
||||
if (sudo_ev_add(evbase, sigfwd_event, true) == -1)
|
||||
if (sudo_ev_add(evbase, sigfwd_event, NULL, true) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
|
||||
debug_return;
|
||||
|
@@ -503,12 +503,12 @@ io_callback(int fd, int what, void *v)
|
||||
/* Enable writer if not /dev/tty or we are foreground pgrp. */
|
||||
if (iob->wevent != NULL &&
|
||||
(foreground || !USERTTY_EVENT(iob->wevent))) {
|
||||
if (sudo_ev_add(evbase, iob->wevent, false) == -1)
|
||||
if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
}
|
||||
/* Re-enable reader if buffer is not full. */
|
||||
if (iob->len != sizeof(iob->buf)) {
|
||||
if (sudo_ev_add(evbase, iob->revent, false) == -1)
|
||||
if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
}
|
||||
break;
|
||||
@@ -566,14 +566,14 @@ io_callback(int fd, int what, void *v)
|
||||
}
|
||||
/* Re-enable writer if buffer is not empty. */
|
||||
if (iob->len > iob->off) {
|
||||
if (sudo_ev_add(evbase, iob->wevent, false) == -1)
|
||||
if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
}
|
||||
/* Enable reader if buffer is not full. */
|
||||
if (iob->revent != NULL &&
|
||||
(ttymode == TERM_RAW || !USERTTY_EVENT(iob->revent))) {
|
||||
if (iob->len != sizeof(iob->buf)) {
|
||||
if (sudo_ev_add(evbase, iob->revent, false) == -1)
|
||||
if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
}
|
||||
}
|
||||
@@ -866,7 +866,7 @@ add_io_events(struct sudo_event_base *evbase)
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||
"added I/O revent %p, fd %d, events %d",
|
||||
iob->revent, iob->revent->fd, iob->revent->events);
|
||||
if (sudo_ev_add(evbase, iob->revent, false) == -1)
|
||||
if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
}
|
||||
}
|
||||
@@ -876,7 +876,7 @@ add_io_events(struct sudo_event_base *evbase)
|
||||
sudo_debug_printf(SUDO_DEBUG_INFO,
|
||||
"added I/O wevent %p, fd %d, events %d",
|
||||
iob->wevent, iob->wevent->fd, iob->wevent->events);
|
||||
if (sudo_ev_add(evbase, iob->wevent, false) == -1)
|
||||
if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
}
|
||||
}
|
||||
@@ -921,14 +921,14 @@ del_io_events(void)
|
||||
/* Don't read from /dev/tty while flushing. */
|
||||
if (iob->revent != NULL && !USERTTY_EVENT(iob->revent)) {
|
||||
if (iob->len != sizeof(iob->buf)) {
|
||||
if (sudo_ev_add(evbase, iob->revent, false) == -1)
|
||||
if (sudo_ev_add(evbase, iob->revent, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
}
|
||||
}
|
||||
/* Flush any write buffers with data in them. */
|
||||
if (iob->wevent != NULL) {
|
||||
if (iob->len > iob->off) {
|
||||
if (sudo_ev_add(evbase, iob->wevent, false) == -1)
|
||||
if (sudo_ev_add(evbase, iob->wevent, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
}
|
||||
}
|
||||
@@ -1330,21 +1330,21 @@ exec_monitor(struct command_details *details, int backchannel)
|
||||
SUDO_EV_READ|SUDO_EV_PERSIST, mon_signal_pipe_cb, &mc);
|
||||
if (mc.signal_pipe_event == NULL)
|
||||
fatal(NULL);
|
||||
if (sudo_ev_add(evbase, mc.signal_pipe_event, false) == -1)
|
||||
if (sudo_ev_add(evbase, mc.signal_pipe_event, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
|
||||
mc.errpipe_event = sudo_ev_alloc(errpipe[0],
|
||||
SUDO_EV_READ|SUDO_EV_PERSIST, mon_errpipe_cb, &mc);
|
||||
if (mc.errpipe_event == NULL)
|
||||
fatal(NULL);
|
||||
if (sudo_ev_add(evbase, mc.errpipe_event, false) == -1)
|
||||
if (sudo_ev_add(evbase, mc.errpipe_event, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
|
||||
mc.backchannel_event = sudo_ev_alloc(backchannel,
|
||||
SUDO_EV_READ|SUDO_EV_PERSIST, mon_backchannel_cb, &mc);
|
||||
if (mc.backchannel_event == NULL)
|
||||
fatal(NULL);
|
||||
if (sudo_ev_add(evbase, mc.backchannel_event, false) == -1)
|
||||
if (sudo_ev_add(evbase, mc.backchannel_event, NULL, false) == -1)
|
||||
fatal(_("unable to add event to queue"));
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user