<pre style='margin:0'>
Christopher Nielsen (mascguy) pushed a commit to branch master
in repository macports-legacy-support.

</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/034c6c4599f660bd7d80b53fb0cc8efd4dbc602b">https://github.com/macports/macports-legacy-support/commit/034c6c4599f660bd7d80b53fb0cc8efd4dbc602b</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit 034c6c4599f660bd7d80b53fb0cc8efd4dbc602b
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Wed Jun 11 19:18:24 2025 -0700

<span style='display:block; white-space:pre;color:#404040;'>    Add tool for testing boottime sysctl().
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Given the issues with this sysctl, it's useful to have a standalone
</span><span style='display:block; white-space:pre;color:#404040;'>    tool to check and report its results.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    Also adds missing clean target for tools.
</span><span style='display:block; white-space:pre;color:#404040;'>    
</span><span style='display:block; white-space:pre;color:#404040;'>    TESTED:
</span><span style='display:block; white-space:pre;color:#404040;'>    Shows expected results, including failures.
</span>---
 Makefile         |   6 +-
 tools/boottime.c | 372 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 377 insertions(+), 1 deletion(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/Makefile b/Makefile
</span><span style='display:block; white-space:pre;color:#808080;'>index 439678f..24ec50f 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/Makefile
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/Makefile
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -537,7 +537,11 @@ test_clean: xtest_clean $(MANRUNPREFIX)clean
</span>   @$(RMDIR) $(XLIBDIR)
        $(RM) -r $(TEST_TEMP)
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-clean: $(MANRUNPREFIX)clean test_clean
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+tools_clean:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   $(RM) $(TOOLDIR)*.o $(TOOLDIR)/boottime $(TOOLDIR)/clock_info
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   $(RM) $(TOOLDIR)/mach_time $(TOOLDIR)/realpath_test
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+clean: $(MANRUNPREFIX)clean test_clean tools_clean
</span>   $(RM) $(foreach D,$(SRCDIR),$D/*.o $D/*.o.* $D/*.d)
        $(RM) $(BUILDDLIBPATH) $(BUILDSLIBPATH) $(BUILDSYSLIBPATH)
        @$(RMDIR) $(BUILDLIBDIR)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/boottime.c b/tools/boottime.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..ad76fb2
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/boottime.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,372 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2025 Frederick H. G. Wright II <fw@fwright.net>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Permission to use, copy, modify, and distribute this software for any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * purpose with or without fee is hereby granted, provided that the above
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyright notice and this permission notice appear in all copies.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This is a tool for obtaining the system boot time, for the purpose
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * of investigating bugs in that mechanism.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This tool is intended to be built without legacy-support, but can
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * optionally load the legacy-support library from either the "system"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * location or the relative build-tree location.  In the former case,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * the default "/opt/local" prefix is assumed, unless the MPPREFIX
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * definition is overridden.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <dlfcn.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <libgen.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stddef.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/sysctl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/types.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* RTLD_FIRST is unavailable on 10.4 - make it ignored. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifndef RTLD_FIRST
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define RTLD_FIRST 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if defined(__ppc__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "ppc"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#elif defined(__ppc64__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "ppc64"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#elif defined(__i386__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "i386"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#elif defined(__x86_64__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "x86_64"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#elif defined(__arm__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "arm"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#elif defined(__arm64__) || defined(__aarch64__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "arm64"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "unknown"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSCTL_OSVER_CLASS CTL_KERN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSCTL_OSVER_ITEM  KERN_OSRELEASE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* sysctl to check whether we're running natively (not Rosetta 1) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSCTL_NATIVE "sysctl.proc_native"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* sysctl to check whether we're running in Rosetta 2 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSCTL_TRANSLATED "sysctl.proc_translated"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef int (sysctl_fn_t)(int *name, u_int namelen,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             void *oldp, size_t *oldlenp, void *newp, size_t newlen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef int (sysctlbyname_fn_t)(const char *name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             void *oldp, size_t *oldlenp, void *newp, size_t newlen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef int (sysctlnametomib_fn_t)(const char *name, int *mibp, size_t *sizep);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#ifndef MPPREFIX
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MPPREFIX "/opt/local"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define LIBDIR "lib"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define LSLIB "libMacportsLegacySupport.dylib"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MPLSLIB MPPREFIX "/" LIBDIR "/" LSLIB
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define LOCALLSLIB "../" LIBDIR "/" LSLIB
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define UL (unsigned long)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static char osver[256];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_osver(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int mib[] = {SYSCTL_OSVER_CLASS, SYSCTL_OSVER_ITEM};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int miblen = sizeof(mib) / sizeof(mib[0]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t len = sizeof(osver);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (sysctl(mib, miblen, osver, &len, NULL, 0)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (len <= 0 || len >= (ssize_t) sizeof(osver)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  osver[len] = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (osver[len - 1] == '\n') osver[len - 1] = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Test whether running under Rosetta */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* -1 no, 1 Rosetta 1, 2 Rosetta 2 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+check_rosetta(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int native, translated;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t native_sz = sizeof(native);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t translated_sz = sizeof(translated);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Check for Rosetta 1 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (sysctlbyname(SYSCTL_NATIVE, &native, &native_sz, NULL, 0) < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* If sysctl failed, must be real ppc. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (!native) return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* If "native", check for Rosetta 2 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (sysctlbyname(SYSCTL_TRANSLATED, &translated, &translated_sz,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                   NULL, 0) < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    /* If sysctl failed, must be really native. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return translated ? 2 : -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+load_lib(int legacy, char *progname, int verbose)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  char *progdir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  char lslib[PATH_MAX], lsreal[PATH_MAX];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  const char *libpath;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  void *libhandle = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (legacy > 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    libpath = MPLSLIB;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    progdir = dirname(progname);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    (void) snprintf(lslib, sizeof(lslib), "%s/" LOCALLSLIB, progdir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (!(libpath = realpath(lslib, lsreal))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      printf("Unable to resolve library path '%s': %s\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             lslib, strerror(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (!(libhandle = dlopen(libpath, RTLD_FIRST))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("Unable to open library: %s\n", dlerror());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("    Loaded %s, handle = 0x%0*lX\n", libpath,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           (int) sizeof(void *) * 2, UL libhandle);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return libhandle;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+close_lib(void **libhandle)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (*libhandle && dlclose(*libhandle)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("Unable to close library: %s\n", dlerror());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  *libhandle = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+func_lookup(const char *name, void *libhandle, int verbose)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  void *handle = libhandle;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  void *adr = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Try extra library first, then general */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (libhandle) adr = dlsym(handle, name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (!adr) adr = dlsym((handle = RTLD_NEXT), name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (!adr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      printf("    %s not found\n", name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else if (handle == RTLD_NEXT) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      printf("    Located %s in library handle RTLD_NEXT\n", name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      printf("    Located %s in library handle 0x%0*lX\n", name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             (int) sizeof(void *) * 2, UL libhandle);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return adr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static size_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+init_bt(struct timeval *bt)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  uint32_t *ip = (uint32_t *) bt;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  /* Prefill result with garbage, to detect incomplete stores */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  while (ip < (uint32_t *)(bt + 1)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    *ip++ = 0xDEADBEEFU;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return sizeof(*bt);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+print_err(const char *name, int ret, int err)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  printf("***  kern.boottime %s returned %d, errno = %d (%s)\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         name, ret, err, strerror(err));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+check_bt(const char *name, int retlen, struct timeval *bt)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (retlen != sizeof(*bt)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("***  kern.boottime %s returned length %d, which should be %d\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+           name, retlen, (int) sizeof(*bt));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if ((unsigned int) bt->tv_usec >= 1000000U) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (sizeof(bt->tv_usec) > 4) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      printf("***  kern.boottime %s tv_usec = 0x%016llX\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             name, (unsigned long long) bt->tv_usec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      printf("***  kern.boottime %s tv_usec = 0x%08X\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             name, (unsigned int) bt->tv_usec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+print_bt(const char *name, struct timeval *bt)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  printf("  kern.bootime %s result = { sec = %lld, usec = %lld }\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         name, (long long) bt->tv_sec, (long long) bt->tv_usec);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+show_mib(const char *name, const int *mib, size_t miblen)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int val;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  const int *mibend = mib + miblen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  printf("  kern.boottime%s mib = [", name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  while (mib < mibend) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    val = *mib++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    printf("%d%s", val, mib < mibend ? ", " : "");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  printf("]\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+do_flush(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  (void) fflush(stdout);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+main(int argc, char *argv[])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int ret, err, verbose = 0, legacy = 0, argn = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  const char *cp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  char chr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  void *libhandle = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  const char *rosetta;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  struct timeval boottime;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t boottime_len;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  int mib[8];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  size_t miblen;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  sysctlbyname_fn_t *sysctlbyname_p;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  sysctlnametomib_fn_t *sysctlnametomib_p;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  sysctl_fn_t *sysctl_p;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  static const int bt_mib[] = {CTL_KERN, KERN_BOOTTIME};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  static const size_t bt_miblen = sizeof(bt_mib) / sizeof(bt_mib[0]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  while (argn < argc && argv[argn][0] == '-') {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    cp = argv[argn];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    while ((chr = *++cp)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      switch (chr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        case 'v': ++verbose; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        case 'y': legacy = 1; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        case 'Y': legacy = -1; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ++argn;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  err = get_osver();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  switch (check_rosetta()) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    case -1: rosetta = "native"; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    case 1: rosetta = "Rosetta 1"; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    case 2: rosetta = "Rosetta 2"; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    default: rosetta = "???"; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  printf("OS is Darwin %s, CPU is %s (%s)\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         err ? "???" : osver, ARCH, rosetta);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (legacy) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (!(libhandle = load_lib(legacy, argv[0], verbose))) return 10;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  do_flush();  /* In case we crash */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  boottime_len = init_bt(&boottime);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if ((sysctlbyname_p = func_lookup("sysctlbyname", libhandle, verbose))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ret = (*sysctlbyname_p)("kern.boottime", &boottime, &boottime_len, NULL, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ret) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      print_err("by name", ret, errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      ret = check_bt("by name", boottime_len, &boottime);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (!ret || verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      print_bt("by name", &boottime);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  do_flush();  /* In case we crash */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  miblen = sizeof(mib) / sizeof(mib[0]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if ((sysctlnametomib_p = 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+       func_lookup("sysctlnametomib", libhandle, verbose))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ret = (*sysctlnametomib_p)("kern.boottime", mib, &miblen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ret) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      print_err("to mib", ret, errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      miblen = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (!ret || verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      show_mib("", mib, miblen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  } else miblen = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  do_flush();  /* In case we crash */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  sysctl_p = func_lookup("sysctl", libhandle, verbose);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (miblen) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    boottime_len = init_bt(&boottime);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (sysctl_p) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      ret = (*sysctl_p)(mib, miblen, &boottime, &boottime_len, NULL, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      if (ret) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        print_err("by mib", ret, errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        ret = check_bt("by mib", boottime_len, &boottime);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      if (!ret || verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+        print_bt("by mib", &boottime);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  do_flush();  /* In case we crash */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  boottime_len = init_bt(&boottime);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  memcpy(mib, bt_mib, bt_miblen * sizeof(bt_mib[0]));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  show_mib(" by consts", mib, bt_miblen);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  do_flush();  /* In case we crash */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  if (sysctl_p) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    ret = (*sysctl_p)(mib, bt_miblen, &boottime, &boottime_len, NULL, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (ret) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      print_err("by consts", ret, errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      ret = check_bt("by consts", boottime_len, &boottime);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    if (!ret || verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      print_bt("by consts", &boottime);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  do_flush();  /* In case we crash */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  close_lib(&libhandle);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span></pre><pre style='margin:0'>

</pre>