]> granicus.if.org Git - sudo/commitdiff
Add sudo_gettime_uptime() to measure time while not sleeping.
authorTodd C. Miller <Todd.Miller@sudo.ws>
Sun, 19 Aug 2018 15:55:08 +0000 (09:55 -0600)
committerTodd C. Miller <Todd.Miller@sudo.ws>
Sun, 19 Aug 2018 15:55:08 +0000 (09:55 -0600)
aclocal.m4
config.h.in
configure
configure.ac
include/sudo_util.h
lib/util/gettime.c
lib/util/util.exp.in

index 07cfad57d4a434f39b91d30cd7f6fba6d4191396..4bc9f8ca54bd7cd8161d32a16c85cac687649302 100644 (file)
 # PARTICULAR PURPOSE.
 
 m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+# longlong.m4 serial 17
+dnl Copyright (C) 1999-2007, 2009-2016 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Paul Eggert.
+
+# Define HAVE_LONG_LONG_INT if 'long long int' works.
+# This fixes a bug in Autoconf 2.61, and can be faster
+# than what's in Autoconf 2.62 through 2.68.
+
+# Note: If the type 'long long int' exists but is only 32 bits large
+# (as on some very old compilers), HAVE_LONG_LONG_INT will not be
+# defined. In this case you can treat 'long long int' like 'long int'.
+
+AC_DEFUN([AC_TYPE_LONG_LONG_INT],
+[
+  AC_REQUIRE([AC_TYPE_UNSIGNED_LONG_LONG_INT])
+  AC_CACHE_CHECK([for long long int], [ac_cv_type_long_long_int],
+     [ac_cv_type_long_long_int=yes
+      if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+        ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
+        if test $ac_cv_type_long_long_int = yes; then
+          dnl Catch a bug in Tandem NonStop Kernel (OSS) cc -O circa 2004.
+          dnl If cross compiling, assume the bug is not important, since
+          dnl nobody cross compiles for this platform as far as we know.
+          AC_RUN_IFELSE(
+            [AC_LANG_PROGRAM(
+               [[@%:@include <limits.h>
+                 @%:@ifndef LLONG_MAX
+                 @%:@ define HALF \
+                          (1LL << (sizeof (long long int) * CHAR_BIT - 2))
+                 @%:@ define LLONG_MAX (HALF - 1 + HALF)
+                 @%:@endif]],
+               [[long long int n = 1;
+                 int i;
+                 for (i = 0; ; i++)
+                   {
+                     long long int m = n << i;
+                     if (m >> i != n)
+                       return 1;
+                     if (LLONG_MAX / 2 < m)
+                       break;
+                   }
+                 return 0;]])],
+            [],
+            [ac_cv_type_long_long_int=no],
+            [:])
+        fi
+      fi])
+  if test $ac_cv_type_long_long_int = yes; then
+    AC_DEFINE([HAVE_LONG_LONG_INT], [1],
+      [Define to 1 if the system has the type 'long long int'.])
+  fi
+])
+
+# Define HAVE_UNSIGNED_LONG_LONG_INT if 'unsigned long long int' works.
+# This fixes a bug in Autoconf 2.61, and can be faster
+# than what's in Autoconf 2.62 through 2.68.
+
+# Note: If the type 'unsigned long long int' exists but is only 32 bits
+# large (as on some very old compilers), AC_TYPE_UNSIGNED_LONG_LONG_INT
+# will not be defined. In this case you can treat 'unsigned long long int'
+# like 'unsigned long int'.
+
+AC_DEFUN([AC_TYPE_UNSIGNED_LONG_LONG_INT],
+[
+  AC_CACHE_CHECK([for unsigned long long int],
+    [ac_cv_type_unsigned_long_long_int],
+    [ac_cv_type_unsigned_long_long_int=yes
+     if test "x${ac_cv_prog_cc_c99-no}" = xno; then
+       AC_LINK_IFELSE(
+         [_AC_TYPE_LONG_LONG_SNIPPET],
+         [],
+         [ac_cv_type_unsigned_long_long_int=no])
+     fi])
+  if test $ac_cv_type_unsigned_long_long_int = yes; then
+    AC_DEFINE([HAVE_UNSIGNED_LONG_LONG_INT], [1],
+      [Define to 1 if the system has the type 'unsigned long long int'.])
+  fi
+])
+
+# Expands to a C program that can be used to test for simultaneous support
+# of 'long long' and 'unsigned long long'. We don't want to say that
+# 'long long' is available if 'unsigned long long' is not, or vice versa,
+# because too many programs rely on the symmetry between signed and unsigned
+# integer types (excluding 'bool').
+AC_DEFUN([_AC_TYPE_LONG_LONG_SNIPPET],
+[
+  AC_LANG_PROGRAM(
+    [[/* For now, do not test the preprocessor; as of 2007 there are too many
+         implementations with broken preprocessors.  Perhaps this can
+         be revisited in 2012.  In the meantime, code should not expect
+         #if to work with literals wider than 32 bits.  */
+      /* Test literals.  */
+      long long int ll = 9223372036854775807ll;
+      long long int nll = -9223372036854775807LL;
+      unsigned long long int ull = 18446744073709551615ULL;
+      /* Test constant expressions.   */
+      typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
+                     ? 1 : -1)];
+      typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
+                     ? 1 : -1)];
+      int i = 63;]],
+    [[/* Test availability of runtime routines for shift and division.  */
+      long long int llmax = 9223372036854775807ll;
+      unsigned long long int ullmax = 18446744073709551615ull;
+      return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
+              | (llmax / ll) | (llmax % ll)
+              | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+              | (ullmax / ull) | (ullmax % ull));]])
+])
+
 m4_include([m4/ax_append_flag.m4])
 m4_include([m4/ax_check_compile_flag.m4])
 m4_include([m4/ax_check_link_flag.m4])
index 69a2b647abb325039c86ea01ed87555f99622298..f8d09ceb0e81df3c8197fd1c3bd182ded6c3dec6 100644 (file)
 /* Define to 1 if you have the <login_cap.h> header file. */
 #undef HAVE_LOGIN_CAP_H
 
-/* Define to 1 if the system has the type `long long int'. */
+/* Define to 1 if the system has the type 'long long int'. */
 #undef HAVE_LONG_LONG_INT
 
 /* Define to 1 if you have the `lrand48' function. */
 /* Define to 1 if you have the <machine/endian.h> header file. */
 #undef HAVE_MACHINE_ENDIAN_H
 
+/* Define to 1 if you have the `mach_continuous_time' function. */
+#undef HAVE_MACH_CONTINUOUS_TIME
+
 /* Define to 1 if you have the <maillock.h> header file. */
 #undef HAVE_MAILLOCK_H
 
 /* Define to 1 if you have the `unsetenv' function. */
 #undef HAVE_UNSETENV
 
-/* Define to 1 if the system has the type `unsigned long long int'. */
+/* Define to 1 if the system has the type 'unsigned long long int'. */
 #undef HAVE_UNSIGNED_LONG_LONG_INT
 
 /* Define to 1 if you have the <util.h> header file. */
index 6e2a794311b2e9f0cc4580ad40647137b9dbe94e..2391c9b1786581e0ebf0fa6240f2438190c19d4d 100755 (executable)
--- a/configure
+++ b/configure
@@ -16279,6 +16279,19 @@ done
                fi
                RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES"
 
+               # Mach monotonic timer that runs while sleeping
+               for ac_func in mach_continuous_time
+do :
+  ac_fn_c_check_func "$LINENO" "mach_continuous_time" "ac_cv_func_mach_continuous_time"
+if test "x$ac_cv_func_mach_continuous_time" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_MACH_CONTINUOUS_TIME 1
+_ACEOF
+
+fi
+done
+
+
                # Undocumented API that dynamically allocates the groups.
                for ac_func in getgrouplist_2
 do :
@@ -18232,18 +18245,18 @@ else
 /* end confdefs.h.  */
 
   /* For now, do not test the preprocessor; as of 2007 there are too many
-        implementations with broken preprocessors.  Perhaps this can
-        be revisited in 2012.  In the meantime, code should not expect
-        #if to work with literals wider than 32 bits.  */
+         implementations with broken preprocessors.  Perhaps this can
+         be revisited in 2012.  In the meantime, code should not expect
+         #if to work with literals wider than 32 bits.  */
       /* Test literals.  */
       long long int ll = 9223372036854775807ll;
       long long int nll = -9223372036854775807LL;
       unsigned long long int ull = 18446744073709551615ULL;
       /* Test constant expressions.   */
       typedef int a[((-9223372036854775807LL < 0 && 0 < 9223372036854775807ll)
-                    ? 1 : -1)];
+                     ? 1 : -1)];
       typedef int b[(18446744073709551615ULL <= (unsigned long long int) -1
-                    ? 1 : -1)];
+                     ? 1 : -1)];
       int i = 63;
 int
 main ()
@@ -18252,9 +18265,9 @@ main ()
       long long int llmax = 9223372036854775807ll;
       unsigned long long int ullmax = 18446744073709551615ull;
       return ((ll << 63) | (ll >> 63) | (ll < i) | (ll > i)
-             | (llmax / ll) | (llmax % ll)
-             | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
-             | (ullmax / ull) | (ullmax % ull));
+              | (llmax / ll) | (llmax % ll)
+              | (ull << 63) | (ull >> 63) | (ull << i) | (ull >> i)
+              | (ullmax / ull) | (ullmax % ull));
   ;
   return 0;
 }
@@ -18286,33 +18299,33 @@ if ${ac_cv_type_long_long_int+:} false; then :
 else
   ac_cv_type_long_long_int=yes
       if test "x${ac_cv_prog_cc_c99-no}" = xno; then
-       ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
-       if test $ac_cv_type_long_long_int = yes; then
-                                 if test "$cross_compiling" = yes; then :
+        ac_cv_type_long_long_int=$ac_cv_type_unsigned_long_long_int
+        if test $ac_cv_type_long_long_int = yes; then
+                                        if test "$cross_compiling" = yes; then :
   :
 else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <limits.h>
-                #ifndef LLONG_MAX
-                # define HALF \
-                         (1LL << (sizeof (long long int) * CHAR_BIT - 2))
-                # define LLONG_MAX (HALF - 1 + HALF)
-                #endif
+                 #ifndef LLONG_MAX
+                 # define HALF \
+                          (1LL << (sizeof (long long int) * CHAR_BIT - 2))
+                 # define LLONG_MAX (HALF - 1 + HALF)
+                 #endif
 int
 main ()
 {
 long long int n = 1;
-                int i;
-                for (i = 0; ; i++)
-                  {
-                    long long int m = n << i;
-                    if (m >> i != n)
-                      return 1;
-                    if (LLONG_MAX / 2 < m)
-                      break;
-                  }
-                return 0;
+                 int i;
+                 for (i = 0; ; i++)
+                   {
+                     long long int m = n << i;
+                     if (m >> i != n)
+                       return 1;
+                     if (LLONG_MAX / 2 < m)
+                       break;
+                   }
+                 return 0;
   ;
   return 0;
 }
@@ -18326,7 +18339,7 @@ rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
   conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
 
-       fi
+        fi
       fi
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_long_int" >&5
index f95b7ba942786788dd6494f7b5eff991982f53d5..8ebff756e9b77aeebd679cfba92aaf925fec6346 100644 (file)
@@ -2215,6 +2215,9 @@ case "$host" in
                fi
                RTLD_PRELOAD_VAR="DYLD_INSERT_LIBRARIES"
 
+               # Mach monotonic timer that runs while sleeping
+               AC_CHECK_FUNCS([mach_continuous_time])
+
                # Undocumented API that dynamically allocates the groups.
                AC_CHECK_FUNCS([getgrouplist_2], [AC_CHECK_DECLS([getgrouplist_2])])
 
index 2d73107aab9dc81fe52ea784bf11f0fd0241567f..41d859900272e7ae3179cd305f4027020a805249 100644 (file)
@@ -170,6 +170,8 @@ __dso_public char *sudo_gethostname_v1(void);
 #define sudo_gethostname() sudo_gethostname_v1()
 
 /* gettime.c */
+__dso_public int sudo_gettime_awake_v1(struct timespec *ts);
+#define sudo_gettime_awake(_a) sudo_gettime_awake_v1((_a))
 __dso_public int sudo_gettime_mono_v1(struct timespec *ts);
 #define sudo_gettime_mono(_a) sudo_gettime_mono_v1((_a))
 __dso_public int sudo_gettime_real_v1(struct timespec *ts);
index 054c7b6957316baf846b1d51fc10f393c40ecbbb..63c9ea11da6f1c35f23ec0243accd9e7e652e592 100644 (file)
 #include "sudo_debug.h"
 #include "sudo_util.h"
 
-/* On Linux, CLOCK_MONOTONIC does not run while suspended. */
+/*
+ * On Linux and FreeBSD, CLOCK_MONOTONIC does not run while sleeping.
+ * Linux provides CLOCK_BOOTTIME which runs while sleeping (FreeBSD does not).
+ * Some systems provide CLOCK_UPTIME which only runs while awake.
+ */
 #if defined(CLOCK_BOOTTIME)
-# define SUDO_CLOCK_MONOTONIC  CLOCK_BOOTTIME
+# define SUDO_CLOCK_BOOTTIME   CLOCK_BOOTTIME
+#elif defined(CLOCK_MONOTONIC)
+# define SUDO_CLOCK_BOOTTIME   CLOCK_MONOTONIC
+#endif
+#if defined(CLOCK_UPTIME)
+# define SUDO_CLOCK_AWAKE      CLOCK_UPTIME
 #elif defined(CLOCK_MONOTONIC)
-# define SUDO_CLOCK_MONOTONIC  CLOCK_MONOTONIC
+# define SUDO_CLOCK_AWAKE      CLOCK_MONOTONIC
 #endif
 
+/*
+ * Wall clock time, may run backward.
+ */
 #if defined(HAVE_CLOCK_GETTIME)
 int
 sudo_gettime_real_v1(struct timespec *ts)
@@ -72,24 +84,28 @@ sudo_gettime_real_v1(struct timespec *ts)
 }
 #endif
 
-#if defined(HAVE_CLOCK_GETTIME) && defined(SUDO_CLOCK_MONOTONIC)
+/*
+ * Monotonic time, only runs forward.
+ * We use a timer that only increments while sleeping, if possible.
+ */
+#if defined(HAVE_CLOCK_GETTIME) && defined(SUDO_CLOCK_BOOTTIME)
 int
 sudo_gettime_mono_v1(struct timespec *ts)
 {
     static int has_monoclock = -1;
     debug_decl(sudo_gettime_mono, SUDO_DEBUG_UTIL)
 
-    /* Check whether the kernel/libc actually supports CLOCK_MONOTONIC. */
+    /* Check whether the kernel/libc actually supports a monotonic clock. */
 # ifdef _SC_MONOTONIC_CLOCK
     if (has_monoclock == -1)
        has_monoclock = sysconf(_SC_MONOTONIC_CLOCK) != -1;
 # endif
     if (!has_monoclock)
        debug_return_int(sudo_gettime_real(ts));
-    if (clock_gettime(SUDO_CLOCK_MONOTONIC, ts) == -1) {
+    if (clock_gettime(SUDO_CLOCK_BOOTTIME, ts) == -1) {
        sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
            "clock_gettime(%d) failed, using wall clock",
-           (int)SUDO_CLOCK_MONOTONIC);
+           (int)SUDO_CLOCK_BOOTTIME);
        has_monoclock = 0;
        debug_return_int(sudo_gettime_real(ts));
     }
@@ -105,7 +121,11 @@ sudo_gettime_mono_v1(struct timespec *ts)
 
     if (timebase_info.denom == 0)
        (void) mach_timebase_info(&timebase_info);
-    abstime = mach_absolute_time();
+#ifdef HAVE_MACH_CONTINUOUS_TIME
+    abstime = mach_continuous_time();          /* runs while asleep */
+#else
+    abstime = mach_absolute_time();            /* doesn't run while asleep */
+#endif
     nsec = abstime * timebase_info.numer / timebase_info.denom;
     ts->tv_sec = nsec / 1000000000;
     ts->tv_nsec = nsec % 1000000000;
@@ -119,3 +139,55 @@ sudo_gettime_mono_v1(struct timespec *ts)
     return sudo_gettime_real(ts);
 }
 #endif
+
+/*
+ * Monotonic time, only runs forward.
+ * We use a timer that only increments while awake, if possible.
+ */
+#if defined(HAVE_CLOCK_GETTIME) && defined(SUDO_CLOCK_AWAKE)
+int
+sudo_gettime_awake_v1(struct timespec *ts)
+{
+    static int has_monoclock = -1;
+    debug_decl(sudo_gettime_awake, SUDO_DEBUG_UTIL)
+
+    /* Check whether the kernel/libc actually supports a monotonic clock. */
+# ifdef _SC_MONOTONIC_CLOCK
+    if (has_monoclock == -1)
+       has_monoclock = sysconf(_SC_MONOTONIC_CLOCK) != -1;
+# endif
+    if (!has_monoclock)
+       debug_return_int(sudo_gettime_real(ts));
+    if (clock_gettime(SUDO_CLOCK_AWAKE, ts) == -1) {
+       sudo_debug_printf(SUDO_DEBUG_WARN|SUDO_DEBUG_ERRNO|SUDO_DEBUG_LINENO,
+           "clock_gettime(%d) failed, using wall clock",
+           (int)SUDO_CLOCK_AWAKE);
+       has_monoclock = 0;
+       debug_return_int(sudo_gettime_real(ts));
+    }
+    debug_return_int(0);
+}
+#elif defined(__MACH__)
+int
+sudo_gettime_awake_v1(struct timespec *ts)
+{
+    uint64_t abstime, nsec;
+    static mach_timebase_info_data_t timebase_info;
+    debug_decl(sudo_gettime_awake, SUDO_DEBUG_UTIL)
+
+    if (timebase_info.denom == 0)
+       (void) mach_timebase_info(&timebase_info);
+    abstime = mach_absolute_time();
+    nsec = abstime * timebase_info.numer / timebase_info.denom;
+    ts->tv_sec = nsec / 1000000000;
+    ts->tv_nsec = nsec % 1000000000;
+    debug_return_int(0);
+}
+#else
+int
+sudo_gettime_awake_v1(struct timespec *ts)
+{
+    /* No monotonic uptime clock available, use wall clock. */
+    return sudo_gettime_real(ts);
+}
+#endif
index 4ae914348efe48001f587f95eb44b964f393753b..7cf84467d0931fbe6393ec9252c44c94d47ce7b9 100644 (file)
@@ -71,6 +71,7 @@ sudo_fatalx_nodebug_v1
 sudo_get_ttysize_v1
 sudo_getgrouplist2_v1
 sudo_gethostname_v1
+sudo_gettime_awake_v1
 sudo_gettime_mono_v1
 sudo_gettime_real_v1
 sudo_lbuf_append_quoted_v1