<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>