Use ppoll() or pselect() if avaialble which use timespec.
/* Define to 1 if you have the `posix_spawnp' function. */
#undef HAVE_POSIX_SPAWNP
+/* Define to 1 if you have the `ppoll' function. */
+#undef HAVE_PPOLL
+
/* Define to 1 if you have the `pread' function. */
#undef HAVE_PREAD
/* Define to 1 if you have the <project.h> header file. */
#undef HAVE_PROJECT_H
+/* Define to 1 if you have the `pselect' function. */
+#undef HAVE_PSELECT
+
/* Define to 1 if you have the `pstat_getproc' function. */
#undef HAVE_PSTAT_GETPROC
fi
if test X"$enable_poll" = X""; then
- for ac_func in poll
+ for ac_func in ppoll poll
do :
- ac_fn_c_check_func "$LINENO" "poll" "ac_cv_func_poll"
-if test "x$ac_cv_func_poll" = xyes; then :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
cat >>confdefs.h <<_ACEOF
-#define HAVE_POLL 1
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
_ACEOF
- enable_poll=yes
+ enable_poll=yes; break
else
enable_poll=no
fi
done
elif test X"$enable_poll" = X"yes"; then
- $as_echo "#define HAVE_POLL 1" >>confdefs.h
+ for ac_func in ppoll
+do :
+ ac_fn_c_check_func "$LINENO" "ppoll" "ac_cv_func_ppoll"
+if test "x$ac_cv_func_ppoll" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_PPOLL 1
+_ACEOF
+
+else
+ $as_echo "#define HAVE_POLL 1" >>confdefs.h
+
+fi
+done
fi
if test "$enable_poll" = "yes"; then
COMMON_OBJS="${COMMON_OBJS} event_poll.lo"
else
+ for ac_func in pselect
+do :
+ ac_fn_c_check_func "$LINENO" "pselect" "ac_cv_func_pselect"
+if test "x$ac_cv_func_pselect" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_PSELECT 1
+_ACEOF
+
+fi
+done
+
COMMON_OBJS="${COMMON_OBJS} event_select.lo"
fi
dnl Choose event subsystem backend: poll or select
dnl
if test X"$enable_poll" = X""; then
- AC_CHECK_FUNCS([poll], [enable_poll=yes], [enable_poll=no])
+ AC_CHECK_FUNCS([ppoll poll], [enable_poll=yes; break], [enable_poll=no])
elif test X"$enable_poll" = X"yes"; then
- AC_DEFINE(HAVE_POLL)
+ AC_CHECK_FUNCS([ppoll], [], AC_DEFINE(HAVE_POLL))
fi
if test "$enable_poll" = "yes"; then
COMMON_OBJS="${COMMON_OBJS} event_poll.lo"
else
+ AC_CHECK_FUNCS([pselect])
COMMON_OBJS="${COMMON_OBJS} event_select.lo"
fi
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 */
+ struct timespec timeout; /* for SUDO_EV_TIMEOUT */
void *closure; /* user-provided data pointer */
};
TAILQ_HEAD(sudo_event_list, sudo_event);
sig_atomic_t signal_caught; /* at least one signal caught */
int num_handlers; /* number of installed handlers */
int signal_pipe[2]; /* so we can wake up on singal */
-#ifdef HAVE_POLL
+#if defined(HAVE_POLL) || defined(HAVE_PPOLL)
struct pollfd *pfds; /* array of struct pollfd */
int pfd_max; /* size of the pfds array */
int pfd_high; /* highest slot used */
#define sudo_ev_free(_a) sudo_ev_free_v1((_a))
/* Add an event, returns 0 on success, -1 on error */
-__dso_public int sudo_ev_add_v1(struct sudo_event_base *head, struct sudo_event *ev, struct timeval *timo, bool tohead);
+__dso_public int sudo_ev_add_v1(struct sudo_event_base *head, struct sudo_event *ev, struct timespec *timo, bool tohead);
#define sudo_ev_add(_a, _b, _c, _d) sudo_ev_add_v1((_a), (_b), (_c), (_d))
/* Delete an event, returns 0 on success, -1 on error */
#define sudo_ev_loop(_a, _b) sudo_ev_loop_v1((_a), (_b))
/* Return the remaining timeout associated with an event. */
-__dso_public int sudo_ev_get_timeleft_v1(struct sudo_event *ev, struct timeval *tv);
+__dso_public int sudo_ev_get_timeleft_v1(struct sudo_event *ev, struct timespec *tv);
#define sudo_ev_get_timeleft(_a, _b) sudo_ev_get_timeleft_v1((_a), (_b))
/* Cause the event loop to exit after one run through. */
#include <config.h>
#include <sys/types.h>
-#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STDBOOL_H
#endif /* HAVE_STRINGS_H */
#include <errno.h>
#include <fcntl.h>
+#include <time.h>
#include <unistd.h>
#include "sudo_compat.h"
/* Install signal handler as needed, saving the original value. */
if (TAILQ_EMPTY(&base->signals[signo])) {
struct sigaction sa;
- memset(&sa, 0, sizeof(sa));
- sigfillset(&sa.sa_mask);
- sa.sa_flags = SA_RESTART|SA_SIGINFO;
- sa.sa_sigaction = sudo_ev_handler;
- if (sigaction(signo, &sa, base->orig_handlers[signo]) != 0) {
+ memset(&sa, 0, sizeof(sa));
+ sigfillset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART|SA_SIGINFO;
+ sa.sa_sigaction = sudo_ev_handler;
+ if (sigaction(signo, &sa, base->orig_handlers[signo]) != 0) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"%s: unable to install handler for signo %d", __func__, signo);
debug_return_int(-1);
int
sudo_ev_add_v1(struct sudo_event_base *base, struct sudo_event *ev,
- struct timeval *timo, bool tohead)
+ struct timespec *timo, bool tohead)
{
debug_decl(sudo_ev_add, SUDO_DEBUG_EVENT)
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;
+ /* XXX - use monotime */
+ sudo_gettime_real(&ev->timeout);
+ sudo_timespecadd(&ev->timeout, timo, &ev->timeout);
TAILQ_FOREACH(evtmp, &base->timeouts, timeouts_entries) {
- if (sudo_timevalcmp(timo, &evtmp->timeout, <))
+ if (sudo_timespeccmp(timo, &evtmp->timeout, <))
break;
}
if (evtmp != NULL) {
int
sudo_ev_loop_v1(struct sudo_event_base *base, int flags)
{
- struct timeval now;
+ struct timespec now;
struct sudo_event *ev;
int nready, rc = 0;
debug_decl(sudo_ev_loop, SUDO_DEBUG_EVENT)
goto done;
case 0:
/* Timed out, activate timeout events. */
- gettimeofday(&now, NULL);
+ sudo_gettime_real(&now);
while ((ev = TAILQ_FIRST(&base->timeouts)) != NULL) {
- if (sudo_timevalcmp(&ev->timeout, &now, >))
+ if (sudo_timespeccmp(&ev->timeout, &now, >))
break;
/* Remove from timeouts list. */
CLR(ev->flags, SUDO_EVQ_TIMEOUTS);
}
int
-sudo_ev_get_timeleft_v1(struct sudo_event *ev, struct timeval *tv)
+sudo_ev_get_timeleft_v1(struct sudo_event *ev, struct timespec *ts)
{
- struct timeval now;
+ struct timespec now;
debug_decl(sudo_ev_get_timeleft, SUDO_DEBUG_EVENT)
if (!ISSET(ev->flags, SUDO_EVQ_TIMEOUTS)) {
- sudo_timevalclear(tv);
+ sudo_timespecclear(ts);
debug_return_int(-1);
}
- gettimeofday(&now, NULL);
- sudo_timevalsub(&ev->timeout, &now, tv);
- if (tv->tv_sec < 0 || (tv->tv_sec == 0 && tv->tv_usec < 0))
- sudo_timevalclear(tv);
+ sudo_gettime_real(&now);
+ sudo_timespecsub(&ev->timeout, &now, ts);
+ if (ts->tv_sec < 0 || (ts->tv_sec == 0 && ts->tv_nsec < 0))
+ sudo_timespecclear(ts);
debug_return_int(0);
}
#include <config.h>
#include <sys/types.h>
-#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STDBOOL_H
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
+#include <time.h>
#include <unistd.h>
#include <errno.h>
#include <poll.h>
#include "sudo_compat.h"
+#include "sudo_util.h"
#include "sudo_fatal.h"
#include "sudo_debug.h"
#include "sudo_event.h"
debug_return_int(0);
}
+#ifdef HAVE_PPOLL
+static int
+sudo_ev_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timo)
+{
+ return ppoll(fds, nfds, timo, NULL);
+}
+#else
+static int
+sudo_ev_poll(struct pollfd *fds, nfds_t nfds, const struct timespec *timo)
+{
+ const int timeout = (timo->tv_sec * 1000) + (timo->tv_nsec / 1000000);
+
+ return poll(fds, nfds, timeout);
+}
+#endif /* HAVE_PPOLL */
+
int
sudo_ev_scan_impl(struct sudo_event_base *base, int flags)
{
+ struct timespec now, ts, *timeout;
struct sudo_event *ev;
- int nready, timeout;
- struct timeval now;
+ int nready;
debug_decl(sudo_ev_scan_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)
- timeout = 0;
+ sudo_gettime_real(&now);
+ sudo_timespecsub(&ev->timeout, &now, &ts);
+ if (ts.tv_sec < 0 || (ts.tv_sec == 0 && ts.tv_nsec < 0))
+ sudo_timespecclear(&ts);
+ timeout = &ts;
} else {
- timeout = (flags & SUDO_EVLOOP_NONBLOCK) ? 0 : -1;
+ if (ISSET(flags, SUDO_EVLOOP_NONBLOCK)) {
+ sudo_timespecclear(&ts);
+ timeout = &ts;
+ } else {
+ timeout = NULL;
+ }
}
- nready = poll(base->pfds, base->pfd_high + 1, timeout);
+ nready = sudo_ev_poll(base->pfds, base->pfd_high + 1, timeout);
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: %d fds ready", __func__, nready);
switch (nready) {
case -1:
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif /* HAVE_STRINGS_H */
+#include <time.h>
#include <unistd.h>
#include <errno.h>
#include "sudo_compat.h"
+#include "sudo_util.h"
#include "sudo_fatal.h"
#include "sudo_debug.h"
#include "sudo_event.h"
-#include "sudo_util.h"
int
sudo_ev_base_alloc_impl(struct sudo_event_base *base)
debug_return_int(0);
}
+#ifdef HAVE_PSELECT
+static int
+sudo_ev_select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, const struct timespec *timeout)
+{
+ return pselect(nfds, readfds, writefds, exceptfds, timeout, NULL);
+}
+#else
+static int
+sudo_ev_select(int nfds, fd_set *readfds, fd_set *writefds,
+ fd_set *exceptfds, const struct timespec *timeout)
+{
+ struct timeval tvbuf, *tv = NULL;
+
+ if (timeout != NULL) {
+ TIMESPEC_TO_TIMEVAL(&tvbuf, timeout);
+ tv = &tvbuf;
+ }
+ return select(nfds, readfds, writefds, exceptfds, tv);
+}
+#endif /* HAVE_PSELECT */
+
int
sudo_ev_scan_impl(struct sudo_event_base *base, int flags)
{
- struct timeval now, tv, *timeout;
+ struct timespec now, ts, *timeout;
struct sudo_event *ev;
size_t setsize;
int nready;
debug_decl(sudo_ev_loop, SUDO_DEBUG_EVENT)
if ((ev = TAILQ_FIRST(&base->timeouts)) != NULL) {
- gettimeofday(&now, NULL);
- sudo_timevalsub(&ev->timeout, &now, &tv);
- if (tv.tv_sec < 0 || (tv.tv_sec == 0 && tv.tv_usec < 0))
- sudo_timevalclear(&tv);
- timeout = &tv;
+ sudo_gettime_real(&now);
+ sudo_timespecsub(&ev->timeout, &now, &ts);
+ if (ts.tv_sec < 0 || (ts.tv_sec == 0 && ts.tv_nsec < 0))
+ sudo_timespecclear(&ts);
+ timeout = &ts;
} else {
if (ISSET(flags, SUDO_EVLOOP_NONBLOCK)) {
- sudo_timevalclear(&tv);
- timeout = &tv;
+ sudo_timespecclear(&ts);
+ timeout = &ts;
} else {
timeout = NULL;
}
sudo_debug_printf(SUDO_DEBUG_DEBUG, "%s: select high fd %d",
__func__, base->highfd);
- nready = select(base->highfd + 1, base->readfds_out, base->writefds_out,
- NULL, timeout);
+ nready = sudo_ev_select(base->highfd + 1, base->readfds_out,
+ base->writefds_out, NULL, timeout);
sudo_debug_printf(SUDO_DEBUG_INFO, "%s: %d fds ready", __func__, nready);
switch (nready) {
case -1:
struct timing_closure {
const char *decimal;
- struct timeval *max_delay;
+ struct timespec *max_delay;
int idx;
union {
struct {
struct sudo_lbuf;
struct passwd;
struct stat;
-struct timeval;
+struct timespec;
/*
* Function prototypes
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/stat.h>
-#include <sys/time.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#include <stdio.h>
#endif /* HAVE_STDBOOL_H */
#include <regex.h>
#include <signal.h>
+#include <time.h>
#ifdef HAVE_ZLIB_H
# include <zlib.h>
#endif
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 timeval *max_wait, const char *decimal, bool interactive);
+static int replay_session(struct timespec *max_wait, const char *decimal, bool interactive);
static void sudoreplay_cleanup(void);
static void usage(int);
static void write_output(int fd, int what, void *v);
const char *decimal, *id, *user = NULL, *pattern = NULL, *tty = NULL;
char *cp, *ep, path[PATH_MAX];
struct log_info *li;
- struct timeval max_delay_storage, *max_delay = NULL;
+ struct timespec max_delay_storage, *max_delay = NULL;
double dval;
debug_decl(main, SUDO_DEBUG_MAIN)
if (*ep != '\0' || errno != 0)
sudo_fatalx(U_("invalid max wait: %s"), optarg);
if (dval <= 0.0) {
- sudo_timevalclear(&max_delay_storage);
+ sudo_timespecclear(&max_delay_storage);
} else {
max_delay_storage.tv_sec = dval;
- max_delay_storage.tv_usec =
- (dval - max_delay_storage.tv_sec) * 1000000.0;
+ max_delay_storage.tv_nsec =
+ (dval - max_delay_storage.tv_sec) * 1000000000.0;
}
max_delay = &max_delay_storage;
break;
int state;
const char *cp;
struct sudo_event *ev;
- struct timeval timeout;
+ struct timespec timeout;
};
/* getsize states */
gc.nums_maxdepth = 1;
gc.cp = getsize_response;
gc.timeout.tv_sec = 10;
- gc.timeout.tv_usec = 0;
+ gc.timeout.tv_nsec = 0;
/* Setup an event for reading the terminal size */
evbase = sudo_ev_base_alloc();
static int
read_timing_record(struct replay_closure *closure)
{
- struct timeval timeout;
+ struct timespec timeout;
char buf[LINE_MAX];
double delay;
debug_decl(read_timing_record, SUDO_DEBUG_UTIL)
/* Adjust delay using speed factor. */
delay /= speed_factor;
- /* Convert delay to a timeval. */
+ /* Convert delay to a timespec. */
timeout.tv_sec = delay;
- timeout.tv_usec = (delay - timeout.tv_sec) * 1000000.0;
+ timeout.tv_nsec = (delay - timeout.tv_sec) * 1000000000.0;
/* Clamp timeout to max delay. */
if (closure->timing.max_delay != NULL) {
- if (sudo_timevalcmp(&timeout, closure->timing.max_delay, >))
+ if (sudo_timespeccmp(&timeout, closure->timing.max_delay, >))
timeout = *closure->timing.max_delay;
}
}
static struct replay_closure *
-replay_closure_alloc(struct timeval *max_delay, const char *decimal, bool interactive)
+replay_closure_alloc(struct timespec *max_delay, const char *decimal, bool interactive)
{
struct replay_closure *closure;
debug_decl(replay_closure_alloc, SUDO_DEBUG_UTIL)
}
static int
-replay_session(struct timeval *max_delay, const char *decimal, bool interactive)
+replay_session(struct timespec *max_delay, const char *decimal, bool interactive)
{
struct replay_closure *closure;
int ret = 0;
{
struct replay_closure *closure = v;
static bool paused = false;
- struct timeval tv;
+ struct timespec ts;
ssize_t nread;
char ch;
debug_decl(read_keyboard, SUDO_DEBUG_UTIL)
break;
case '<':
speed_factor /= 2;
- sudo_ev_get_timeleft(closure->delay_ev, &tv);
- if (sudo_timevalisset(&tv)) {
+ sudo_ev_get_timeleft(closure->delay_ev, &ts);
+ if (sudo_timespecisset(&ts)) {
/* Double remaining timeout. */
- tv.tv_sec *= 2;
- tv.tv_usec *= 2;
- if (tv.tv_usec >= 1000000) {
- tv.tv_sec++;
- tv.tv_usec -= 1000000;
+ ts.tv_sec *= 2;
+ ts.tv_nsec *= 2;
+ if (ts.tv_nsec >= 1000000000) {
+ ts.tv_sec++;
+ ts.tv_nsec -= 1000000000;
}
- if (sudo_ev_add(NULL, closure->delay_ev, &tv, false) == -1) {
+ if (sudo_ev_add(NULL, closure->delay_ev, &ts, false) == -1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"failed to double remaining delay timeout");
}
break;
case '>':
speed_factor *= 2;
- sudo_ev_get_timeleft(closure->delay_ev, &tv);
- if (sudo_timevalisset(&tv)) {
+ sudo_ev_get_timeleft(closure->delay_ev, &ts);
+ if (sudo_timespecisset(&ts)) {
/* Halve remaining timeout. */
- if (tv.tv_sec & 1)
- tv.tv_usec += 500000;
- tv.tv_sec /= 2;
- tv.tv_usec /= 2;
- if (sudo_ev_add(NULL, closure->delay_ev, &tv, false) == -1) {
+ if (ts.tv_sec & 1)
+ ts.tv_nsec += 500000000;
+ ts.tv_sec /= 2;
+ ts.tv_nsec /= 2;
+ if (sudo_ev_add(NULL, closure->delay_ev, &ts, false) == -1) {
sudo_debug_printf(SUDO_DEBUG_ERROR|SUDO_DEBUG_LINENO,
"failed to halve remaining delay timeout");
}