Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Merge remote-tracking branch 'upstream/main'
Shawn Webb committed 1 year ago
commit c3b674e72b482acfac78f0cae6f4e9f4bdf8f39c
parent 84c2214
33 files changed +651 -237
modified .github/workflows/build.yaml
@@ -33,8 +33,7 @@ jobs:
                - ubsan
                - tsan
                exclude:
-
                - build-os: macos-latest
-
                  sanitize: ubsan # No space left on device
+
                # don't run the sanitizers on Ubuntu 22.04
                - build-os: ubuntu-latest
                  sanitize: [ "asan", "lsan" ]
                - build-os: ubuntu-latest
@@ -137,6 +136,7 @@ jobs:
            echo "CPP=${{ matrix.llvm-bindir }}/clang-cpp" >> "${GITHUB_ENV}"
            # this is miraculously not picked up by automake as the default
            echo "CC_FOR_BUILD=${{ matrix.llvm-bindir }}/clang" >> "${GITHUB_ENV}"
+
            echo "SRC_PKG=${GITHUB_WORKSPACE}/src.pkg" >> "${GITHUB_ENV}"
            echo "BUILD_PKG=${GITHUB_WORKSPACE}/build.pkg" >> "${GITHUB_ENV}"
            echo "INST_PKG=${GITHUB_WORKSPACE}/inst.pkg" >> "${GITHUB_ENV}"
            echo "NPROC=`getconf _NPROCESSORS_ONLN 2>/dev/null || getconf NPROCESSORS_ONLN 2>/dev/null || echo 1`" >> "${GITHUB_ENV}"
@@ -155,11 +155,13 @@ jobs:
            echo CC="${CC}"
            echo CPP="${CPP}"
            echo PKG_CONFIG_PATH="${PKG_CONFIG_PATH}"
+
            echo SRC_PKG="${SRC_PKG}"
            echo BUILD_PKG="${BUILD_PKG}"
            echo INST_PKG="${INST_PKG}"
+

            mkdir -p "${BUILD_PKG}"
            cd "${BUILD_PKG}"
-
            ${GITHUB_WORKSPACE}/src.pkg/configure --prefix=${INST_PKG} --with-libarchive.pc --with-libcurl --with-openssl.pc ${CFG_OPTS}
+
            ${SRC_PKG}/configure --prefix=${INST_PKG} --with-libarchive.pc --with-libcurl --with-openssl.pc ${CFG_OPTS}
            make -j${NPROC}

        - name: test&install pkg
modified .gitignore
@@ -91,15 +91,19 @@ scripts/sbin/pkg2ng
!/tests/frontend/*.in
!/tests/frontend/*.binin
!/tests/frontend/*.so.*
+
/tests/frontend/libfoo.so.1
+
/tests/frontend/libtest2fbsd.so.1
+
/tests/frontend/libtestfbsd.so.1
/tests/frontend/test_environment.sh
/tests/lua
/tests/metalog
/tests/merge
/tests/packing
/tests/pkg_add_dir_to_del
+
/tests/pkg_elf
/tests/pkg_printf
/tests/pkg_validation
/tests/plist
/tests/ssh
/tests/utils
-

+
/tests/vec
modified Makefile.autosetup
@@ -21,8 +21,9 @@ check: all
@if TESTS
all: Kyuafile

-
check:
-
	export UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1; \
+
check: UndefinedBehaviour.suppress
+
	export UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1:suppressions=$(top_builddir)/UndefinedBehaviour.suppress; \
+
	export ASAN_OPTIONS=detect_leaks=1; \
	export LLVM_PROFILE_FILE=/tmp/pkg.%p.profraw; \
	if [ "$(HTML)" != "" ]; then \
		args="-r $(top_builddir)/res.db" ; \
added UndefinedBehaviour.suppress.in
@@ -0,0 +1,9 @@
+
#
+
# These are errors that need to be taken care of, but in the sprit of
+
# "Put Your Own Oxygen Mask on First", we provide here a suppression list for
+
# _external_ sources.
+
#
+

+
# external/picosat/picosat.c:3432:33: runtime error: applying non-zero offset 8 to null pointer
+
# +SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior external/picosat/picosat.c:3432:33 
+
pointer-overflow:picosat.c

\ No newline at end of file
modified libpkg/Makefile.autosetup
@@ -125,9 +125,9 @@ LOCAL_LDFLAGS+= -ldl

@if pkgos_darwin
LOCAL_LDFLAGS+=	-lresolv
-
@else 
+
@else
@if pkgos_freebsd
-
LOCAL_LDFLAGS+=	-Wl,--version-script=$(top_srcdir)/libpkg/libpkg.ver,--undefined-version 
+
LOCAL_LDFLAGS+=	-Wl,--version-script=$(top_srcdir)/libpkg/libpkg.ver,--undefined-version
@else
### --undefined-version is a FreeBSD ld option
LOCAL_LDFLAGS+=	-Wl,--version-script=$(top_srcdir)/libpkg/libpkg.ver
@@ -173,6 +173,7 @@ STATIC_LIBS+= $(top_builddir)/external/libcurl/libcurl.a
@endif

VPATH=	$(top_srcdir)/libpkg
+
.PATH:	$(top_srcdir)/libpkg

include $(MK)/lib.mk

modified libpkg/pkg_abi.c
@@ -33,10 +33,9 @@
#include <unistd.h>

#include "pkg.h"
-

-
#include "private/pkg.h"
-
#include "private/event.h"
#include "private/binfmt.h"
+
#include "private/event.h"
+
#include "private/pkg.h"

#define _PATH_UNAME "/usr/bin/uname"

@@ -46,33 +45,22 @@ struct arch_trans {
	const char *archid;
};

-
static struct arch_trans machine_arch_translation[] = {
-
	{ "x86:32", "i386" },
-
	{ "x86:64", "amd64" },
-
	{ "powerpc:32:eb", "powerpc" },
-
	{ "powerpc:64:eb", "powerpc64" },
-
	{ "powerpc:64:el", "powerpc64le" },
-
	{ "sparc64:64", "sparc64" },
-
	{ "ia64:64", "ia64" },
+
static struct arch_trans machine_arch_translation[] = { { "x86:32", "i386" },
+
	{ "x86:64", "amd64" }, { "powerpc:32:eb", "powerpc" },
+
	{ "powerpc:64:eb", "powerpc64" }, { "powerpc:64:el", "powerpc64le" },
+
	{ "sparc64:64", "sparc64" }, { "ia64:64", "ia64" },
	/* All the ARM stuff */
	{ "armv6:32:el:eabi:hardfp", "armv6" },
-
	{ "armv7:32:el:eabi:hardfp", "armv7" },
-
	{ "aarch64:64", "aarch64" },
+
	{ "armv7:32:el:eabi:hardfp", "armv7" }, { "aarch64:64", "aarch64" },
	/* And now MIPS */
-
	{ "mips:32:el:o32", "mipsel" },
-
	{ "mips:32:el:n32", "mipsn32el" },
-
	{ "mips:32:eb:o32", "mips" },
-
	{ "mips:32:eb:n32", "mipsn32" },
-
	{ "mips:64:el:n64", "mips64el" },
-
	{ "mips:64:eb:n64", "mips64" },
+
	{ "mips:32:el:o32", "mipsel" }, { "mips:32:el:n32", "mipsn32el" },
+
	{ "mips:32:eb:o32", "mips" }, { "mips:32:eb:n32", "mipsn32" },
+
	{ "mips:64:el:n64", "mips64el" }, { "mips:64:eb:n64", "mips64" },
	/* And RISC-V */
-
	{ "riscv:32:hf", "riscv32" },
-
	{ "riscv:32:sf", "riscv32sf" },
-
	{ "riscv:64:hf", "riscv64" },
-
	{ "riscv:64:sf", "riscv64sf" },
+
	{ "riscv:32:hf", "riscv32" }, { "riscv:32:sf", "riscv32sf" },
+
	{ "riscv:64:hf", "riscv64" }, { "riscv:64:sf", "riscv64sf" },

-
	{ NULL, NULL }
-
};
+
	{ NULL, NULL } };

static int
pkg_get_myarch_fromfile(struct os_info *oi)
@@ -83,6 +71,9 @@ pkg_get_myarch_fromfile(struct os_info *oi)
		_PATH_UNAME,
		_PATH_BSHELL,
	};
+
	char work_abi_file[PATH_MAX];
+
	char work_arch_hint[PATH_MAX];
+

	int i, fd;

	/*
@@ -94,34 +85,70 @@ pkg_get_myarch_fromfile(struct os_info *oi)
	for (fd = -1, i = 0; i < NELEM(abi_files); i++) {
		if (abi_files[i] == NULL)
			continue;
+

+
		const char *sep = strrchr(abi_files[i], '#');
+
		if (sep) {
+
			strlcpy(work_abi_file, abi_files[i],
+
			    MIN(sep - abi_files[i] + 1, sizeof(work_abi_file)));
+
			strlcpy(work_arch_hint, sep + 1,
+
			    sizeof(work_arch_hint));
+
		} else {
+
			strlcpy(work_abi_file, abi_files[i],
+
			    sizeof(work_abi_file));
+
			work_arch_hint[0] = '\0';
+
		}
+

		/*
		 * Try prepending rootdir and using that if it exists.  If
		 * ABI_FILE is specified, assume that the consumer didn't want
		 * it mangled by rootdir.
		 */
-
		if (i > 0 && checkroot && snprintf(rooted_abi_file, PATH_MAX,
-
		    "%s/%s", ctx.pkg_rootdir, abi_files[i]) < PATH_MAX) {
-
			if ((fd = open(rooted_abi_file, O_RDONLY)) >= 0)
+
		if (i > 0 && checkroot &&
+
		    snprintf(rooted_abi_file, PATH_MAX, "%s/%s",
+
			ctx.pkg_rootdir, work_abi_file) < PATH_MAX) {
+
			if ((fd = open(rooted_abi_file, O_RDONLY)) >= 0) {
+
				strlcpy(work_abi_file, rooted_abi_file,
+
				    sizeof(work_abi_file));
				break;
+
			}
		}
-
		if ((fd = open(abi_files[i], O_RDONLY)) >= 0)
+
		if ((fd = open(work_abi_file, O_RDONLY)) >= 0) {
			break;
+
		}
		/* if the ABI_FILE was provided we only care about it */
		if (i == 0)
			break;
	}
	if (fd == -1) {
-
		pkg_emit_error("Unable to determine the ABI\n");
-
		return (EPKG_FATAL);
+
		pkg_emit_error(
+
		    "Unable to determine the ABI, none of the ABI_FILEs can be read.");
+
		return EPKG_FATAL;
+
	}
+

+
	if (work_arch_hint[0]) {
+
		snprintf(oi->abi, sizeof(oi->abi), "::%s",
+
		    work_arch_hint);
	}

	int ret = pkg_get_myarch_elfparse(fd, oi);
	if (EPKG_OK != ret) {
-
		lseek(fd, 0, SEEK_SET);
+
		if (-1 == lseek(fd, 0, SEEK_SET)) {
+
			pkg_emit_errno("Error seeking file", work_abi_file);
+
			ret = EPKG_FATAL;
+
		}
		ret = pkg_get_myarch_macho(fd, oi);
+
		if (EPKG_OK != ret) {
+
			pkg_emit_error(
+
			    "Unable to determine the ABI, %s cannot be parsed.",
+
			    work_abi_file);
+
			ret = EPKG_FATAL;
+
		}
	}

-
	close(fd);
+
	if (close(fd)) {
+
		pkg_emit_errno("Error closing file", work_abi_file);
+
		ret = EPKG_FATAL;
+
	}
	return ret;
}

@@ -132,6 +159,7 @@ pkg_get_myarch_with_legacy(struct os_info *oi)
		return (EPKG_FATAL);
	int err = pkg_get_myarch_fromfile(oi);
	if (err) {
+
		pkg_debug(1, "Error %d when trying to determine myarch.", err);
		free(oi->name);
		return (err);
	}
@@ -185,7 +213,7 @@ pkg_arch_to_legacy(const char *arch, char *dest, size_t sz)
			return (0);
		}
	}
-
	strlcpy(dest + i, arch + i, sz - (arch + i  - dest));
+
	strlcpy(dest + i, arch + i, sz - (arch + i - dest));

	return (0);
}
@@ -195,13 +223,14 @@ pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage)
{
	struct pkg_file *file = NULL;
	int ret = EPKG_OK;
-
	char fpath[MAXPATHLEN +1];
+
	char fpath[MAXPATHLEN + 1];
	const char *lib;
	bool failures = false;

-
	int (*pkg_analyse_init)(const char* stage)  = pkg_analyse_init_elf;
-
	int (*pkg_analyse)(const bool developer_mode, struct pkg *pkg, const char *fpath) = pkg_analyse_elf;
-
	int (*pkg_analyse_close)()  = pkg_analyse_close_elf;
+
	int (*pkg_analyse_init)(const char *stage) = pkg_analyse_init_elf;
+
	int (*pkg_analyse)(const bool developer_mode, struct pkg *pkg,
+
	    const char *fpath) = pkg_analyse_elf;
+
	int (*pkg_analyse_close)() = pkg_analyse_close_elf;

	if (tll_length(pkg->shlibs_required) != 0) {
		tll_free_and_free(pkg->shlibs_required, free);
@@ -219,12 +248,12 @@ pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage)
	/* Assume no architecture dependence, for contradiction */
	if (ctx.developer_mode)
		pkg->flags &= ~(PKG_CONTAINS_ELF_OBJECTS |
-
				PKG_CONTAINS_STATIC_LIBS |
-
				PKG_CONTAINS_LA);
+
		    PKG_CONTAINS_STATIC_LIBS | PKG_CONTAINS_LA);

	while (pkg_files(pkg, &file) == EPKG_OK) {
		if (stage != NULL)
-
			snprintf(fpath, sizeof(fpath), "%s/%s", stage, file->path);
+
			snprintf(fpath, sizeof(fpath), "%s/%s", stage,
+
			    file->path);
		else
			strlcpy(fpath, file->path, sizeof(fpath));

@@ -237,9 +266,11 @@ pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage)
	/*
	 * Do not depend on libraries that a package provides itself
	 */
-
	tll_foreach(pkg->shlibs_required, s) {
+
	tll_foreach(pkg->shlibs_required, s)
+
	{
		if (stringlist_contains(&pkg->shlibs_provided, s->item)) {
-
			pkg_debug(2, "remove %s from required shlibs as the "
+
			pkg_debug(2,
+
			    "remove %s from required shlibs as the "
			    "package %s provides this library itself",
			    s->item, pkg->name);
			tll_remove_and_free(pkg->shlibs_required, s, free);
@@ -249,11 +280,13 @@ pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage)
		while (pkg_files(pkg, &file) == EPKG_OK) {
			if ((lib = strstr(file->path, s->item)) != NULL &&
			    strlen(lib) == strlen(s->item) && lib[-1] == '/') {
-
				pkg_debug(2, "remove %s from required shlibs as "
+
				pkg_debug(2,
+
				    "remove %s from required shlibs as "
				    "the package %s provides this file itself",
				    s->item, pkg->name);

-
				tll_remove_and_free(pkg->shlibs_required, s, free);
+
				tll_remove_and_free(pkg->shlibs_required, s,
+
				    free);
				break;
			}
		}
modified libpkg/pkg_abi_macho.c
@@ -1,41 +1,21 @@
/*-
 * Copyright (c) 2024 Keve Müller <kevemueller@users.github.com>
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <errno.h>

#include "private/binfmt_macho.h"
-

#include "private/pkg.h"
#include "private/event.h"

-

/**
 * Routines to support pkg_abi.c functions when dealing with Mach-O files.
-
 * Supports getting ABI and ALTABI from the binary's load commands. Cave: picks first binary in FAT collection.
-
 * Supports getting shared libary information. Picks right binary in FAT collection based on ABI.
-
 * Supports FreeBSD naming of architectures.
+
 * Supports getting ABI and ALTABI from the binary's load commands. Cave: picks
+
 * first binary in FAT collection. Supports getting shared libary information.
+
 * Picks right binary in FAT collection based on ABI. Supports FreeBSD naming of
+
 * architectures.
 */

/**** CPU -> FreeBSD MACHINE_ARCH conversion ****/
@@ -90,12 +70,138 @@ cputype_to_freebsd_machine_arch(const cpu_type_subtype_t cpu)
	}
}

+
static cpu_type_subtype_t
+
freebsd_machine_arch_to_cputype(const char *archname) {
+
	cpu_type_subtype_t cpu = { 0 };
+

+
	if (!strcmp("aarch64", archname)) {
+
		cpu.type = CPU_TYPE_ARM;
+
		cpu.type_is64 = true;
+
	} else if (!strcmp("amd64", archname)) {
+
		cpu.type = CPU_TYPE_X86;
+
		cpu.type_is64 = true;
+
		cpu.subtype_x86 = CPU_SUBTYPE_X86_ALL;
+
	} else if (!strcmp("arm", archname)) {
+
		cpu.type = CPU_TYPE_ARM;
+
		cpu.subtype_arm = CPU_SUBTYPE_ARM_ALL;
+
	} else if (!strcmp("armeb", archname)) {
+
		cpu.type = CPU_TYPE_ARM;
+
		cpu.subtype_arm = CPU_SUBTYPE_ARM_V5;
+
	} else if (!strcmp("armv6", archname)) {
+
		cpu.type = CPU_TYPE_ARM;
+
		cpu.subtype_arm = CPU_SUBTYPE_ARM_V6;
+
	} else if (!strcmp("armv7", archname)) {
+
		cpu.type = CPU_TYPE_ARM;
+
		cpu.subtype_arm = CPU_SUBTYPE_ARM_V7;
+
	} else if (!strcmp("i386", archname)) {
+
		cpu.type = CPU_TYPE_X86;
+
		cpu.subtype_x86 = CPU_SUBTYPE_X86_ALL;
+
	} else if (!strcmp("powerpc", archname)) {
+
		cpu.type = CPU_TYPE_POWERPC;
+
		cpu.subtype_ppc = CPU_SUBTYPE_POWERPC_ALL;
+
	} else if (!strcmp("powerpc64", archname)) {
+
		cpu.type = CPU_TYPE_POWERPC;
+
		cpu.type_is64 = true;
+
		cpu.subtype_ppc = CPU_SUBTYPE_POWERPC_ALL;
+
	} else {
+
		// alpha
+
		// ia64
+
		// mips*
+
		// pc98
+
		// sparc64
+
		cpu.type = CPU_TYPE_ANY;
+
	}
+
	return cpu;
+
}
+

+

+
/**
+
 * Using the passed mf descriptor, match the best entry using oi->name as a hint.
+
 * No hint or no architecture in hint -> first entry. Debug1 warning if this is not precise match (there were multiple to choose from)
+
 * Hint -> always match, even if single architecture in file. Notice if match fails and return null.
+
 */
+
static const fat_arch_t *
+
match_entry(macho_file_t *mf, struct os_info *oi)
+
{
+
	const fat_arch_t *p = mf->arch;
+
	// we can change the content of oi->abi freely
+
	char *abisep = oi->abi;
+
	/*const char *osname = */strsep(&abisep, ":");
+
	/*const char *version_str = */ strsep(&abisep, ":");
+
	const char *archname = strsep(&abisep, ":");
+
	if (archname) {	
+
		const cpu_type_subtype_t cpu_hint = freebsd_machine_arch_to_cputype(archname);
+
		const fat_arch_t *p_end = p + mf->narch;
+
		while (p < p_end) {
+
			// do not match cpu_hint.type == CPU_TYPE_ANY which is used if the 
+
			// archname hint was not recognized
+
			if (p->cpu.type == cpu_hint.type &&
+
			    p->cpu.type_is64 == cpu_hint.type_is64) {
+
				switch (cpu_hint.type) {
+
				case CPU_TYPE_ARM:
+
					if (p->cpu.subtype_arm ==
+
						CPU_SUBTYPE_ARM_ALL ||
+
					    cpu_hint.subtype_arm ==
+
						CPU_SUBTYPE_ARM_ALL ||
+
					    p->cpu.subtype_arm ==
+
						cpu_hint.subtype_arm) {
+
						return p;
+
					}
+
					break;
+
				case CPU_TYPE_POWERPC:
+
					if (p->cpu.subtype_ppc ==
+
						CPU_SUBTYPE_POWERPC_ALL ||
+
					    cpu_hint.subtype_ppc ==
+
						CPU_SUBTYPE_POWERPC_ALL ||
+
					    p->cpu.subtype_ppc ==
+
						cpu_hint.subtype_ppc) {
+
						return p;
+
					}
+
					break;
+
				case CPU_TYPE_X86:
+
					if (p->cpu.subtype_x86 ==
+
						CPU_SUBTYPE_X86_ALL ||
+
					    cpu_hint.subtype_x86 ==
+
						CPU_SUBTYPE_X86_ALL ||
+
					    p->cpu.subtype_x86 ==
+
						cpu_hint.subtype_x86) {
+
						return p;
+
					}
+
					break;
+
				default:
+
					break;
+
				}
+
			}
+
			pkg_debug(1, "Looking for %s, did not match %s",
+
		    archname, cputype_to_freebsd_machine_arch(p->cpu));
+
			p++;
+
		}
+
		pkg_emit_notice("Scanned %d entr%s, found none matching selector %s",
+
			mf->narch, mf->narch > 1 ? "ies" : "y", archname);
+
		return 0;	
+
	} else if (mf->narch > 1 ) {
+
		pkg_debug(1,"Found %d entries in universal binary, picking first",
+
			mf->narch);
+
	}
+
	return p;
+
}
+

+
/**
+
 * With a not-null, potentially pre-populated os_info structure, fill
+
 * all members of os_info except altabi with values obtained by parsing the Mach-O
+
 * file passed with file descriptor.
+
 *
+
 * Third (architecture) component of oi->abi is used to determine the fat entry to be parsed
+
 * in a universal binary. when not set, the first entry is used.
+
 *
+
 * Returns EPKG_OK if all went fine, EPKG_FATAL if anything went wrong.
+
 * Seeks the file descriptor to an arbitrary position.
+
 */
int
pkg_get_myarch_macho(int fd, struct os_info *oi)
{
	ssize_t x;
-
	char *dest = oi->abi;
-
	size_t sz = sizeof(oi->abi);
+
	pkg_error_t ret = EPKG_FATAL;

	macho_file_t *mf = 0;
	build_version_t *bv = 0;
@@ -104,13 +210,11 @@ pkg_get_myarch_macho(int fd, struct os_info *oi)
		goto cleanup;
	}

-
	if (0 == mf->narch) {
+
	const fat_arch_t *p = match_entry(mf, oi);
+

+
	if (!p) {
		goto cleanup;
	}
-
	if (mf->narch > 1) {
-
		pkg_debug(1, "Found %d entries, picking first", mf->narch);
-
	}
-
	fat_arch_t *p = mf->arch;

	if (-1 == (x = lseek(fd, p->offset, SEEK_SET))) {
		goto cleanup;
@@ -123,96 +227,100 @@ pkg_get_myarch_macho(int fd, struct os_info *oi)
	const bool swap = mh.swap;
	n = 0;
	for (uint32_t ui = mh.ncmds; ui-- > 0;) {
-
			size_t n0 = n;
-
			uint32_t loadcmdtype;
-
			uint32_t loadcmdsize;
-
			READ(u32, loadcmdtype);
-
			READ(u32, loadcmdsize);
-
			enum MachOLoadCommand loadcmd = loadcmdtype &
-
			    ~LC_REQ_DYLD;
-
			switch (loadcmd) {
-
			case LC_BUILD_VERSION:
-
				if (bv) { // overwrite previous LC_VERSION_MIN_X
-
					  // values
-
					free(bv);
-
					bv = 0;
-
				}
-
				READ(build_version, bv);
-
				break;
-
			case LC_VERSION_MIN_IPHONEOS:
-
			case LC_VERSION_MIN_MACOSX:
-
			case LC_VERSION_MIN_TVOS:
-
			case LC_VERSION_MIN_WATCHOS:
-
				if (!bv) {
-
					if ((x = read_min_version(fd, swap,
-
						 loadcmd, &bv)) < 0) {
-
						goto cleanup;
-
					}
-
					n += x;
-
					break;
-
				}
-
				// have seen the more precise
-
				// LC_BUILD_VERSION already
-
				// fall through and disregard this
-
			default:
-
				if (-1 ==
-
				    (x = lseek(fd, loadcmdsize - 8,
-
					 SEEK_CUR))) {
+
		size_t n0 = n;
+
		uint32_t loadcmdtype;
+
		uint32_t loadcmdsize;
+
		READ(u32, loadcmdtype);
+
		READ(u32, loadcmdsize);
+
		enum MachOLoadCommand loadcmd = loadcmdtype & ~LC_REQ_DYLD;
+
		switch (loadcmd) {
+
		case LC_BUILD_VERSION:
+
			if (bv) { // overwrite previous LC_VERSION_MIN_X
+
				  // values
+
				free(bv);
+
				bv = 0;
+
			}
+
			READ(build_version, bv);
+
			break;
+
		case LC_VERSION_MIN_IPHONEOS:
+
		case LC_VERSION_MIN_MACOSX:
+
		case LC_VERSION_MIN_TVOS:
+
		case LC_VERSION_MIN_WATCHOS:
+
			if (!bv) {
+
				if ((x = read_min_version(fd, swap, loadcmd,
+
					 &bv)) < 0) {
					goto cleanup;
				}
-
				n += loadcmdsize - 8;
+
				n += x;
				break;
			}
-
			if (n - n0 != loadcmdsize) {
-
				printf("unprecise read %u != %zu", n - n0,
-
				    loadcmdsize);
-
				errno = EINVAL;
-
				goto cleanup;
-
			}
-
			if (n > mh.sizeofcmds) {
-
				printf("long read %u > %u", n, mh.sizeofcmds);
-
				errno = EINVAL;
-
				goto cleanup;
-
			}
+
			// have seen the more precise
+
			// LC_BUILD_VERSION already
+
			// fall through and disregard this
+
		default:
+
			break;
+
		}
+
		const uint32_t fill = loadcmdsize - (n - n0);
+
		if (fill && -1 == (x = lseek(fd, fill, SEEK_CUR))) {
+
			goto cleanup;
+
		}
+
		n += fill;
+
		if (n > mh.sizeofcmds) {
+
			// we passed the frame boundary of the load commands
+
			pkg_emit_error("Mach-O structure misread.");
+
			errno = EINVAL;
+
			goto cleanup;
+
		}
	}

	if (bv) {
		macho_version_t darwin;
		map_platform_to_darwin(&darwin, bv->platform, bv->minos);
-
		snprintf(dest, sz, "Darwin:%d:%s", darwin.major, cputype_to_freebsd_machine_arch(mh.cpu));
-
		if (oi) {
-
			oi->name = xstrdup("Darwin");
-
			oi->osversion = darwin.major * 100000 + darwin.minor * 1000 + darwin.patch;
-
			if (darwin.patch) {
-
				xasprintf(&oi->version, "%d.%d.%d", darwin.major, darwin.minor, darwin.patch);
-
			} else {
-
				xasprintf(&oi->version, "%d.%d", darwin.major, darwin.minor);
-
			}
-
			xasprintf(&oi->version_major, "%d", darwin.major);
-
			xasprintf(&oi->version_minor, "%d", darwin.minor);
-
			oi->arch = xstrdup(cputype_to_freebsd_machine_arch(
-
				mh.cpu));
+

+
		oi->osversion = darwin.major * 100000 + darwin.minor * 1000 +
+
		    darwin.patch;
+
		oi->ostype = OS_MACOS;
+
		free(oi->name);
+
		oi->name = xstrdup("Darwin");
+
		free(oi->version);
+
		if (darwin.patch) {
+
			xasprintf(&oi->version, "%d.%d.%d", darwin.major,
+
			    darwin.minor, darwin.patch);
+
		} else {
+
			xasprintf(&oi->version, "%d.%d", darwin.major,
+
			    darwin.minor);
		}
-
		return EPKG_OK;
-
	}
+
		free(oi->version_major);
+
		xasprintf(&oi->version_major, "%d", darwin.major);
+
		free(oi->version_minor);
+
		xasprintf(&oi->version_minor, "%d", darwin.minor);
+
		free(oi->arch);
+
		oi->arch = xstrdup(cputype_to_freebsd_machine_arch(mh.cpu));
+
		snprintf(oi->abi, sizeof(oi->abi), "Darwin:%d:%s", darwin.major, cputype_to_freebsd_machine_arch(mh.cpu)); 
+
		// not populating oi->altabi, derived later by caller.
+
		snprintf(oi->str_osversion, sizeof(oi->str_osversion), "%d",
+
		    oi->osversion);

+
		ret = EPKG_OK;
+
	} else {
+
		pkg_emit_notice("No OS version information found in binary.");
+
	}

cleanup:
-
	if (bv) {
-
		free(bv);
-
	}
-
	if (mf) {
-
		free(mf);
-
	}
-
	return EPKG_FATAL;
+
	free(bv);
+
	free(mf);
+
	return ret;
}

-

-
int pkg_analyse_init_macho(__unused const char* stage) {
+
int
+
pkg_analyse_init_macho(__unused const char *stage)
+
{
	return EPKG_OK;
}

-
int pkg_analyse_macho(const bool developer_mode, struct pkg *pkg, const char *fpath) {
+
int
+
pkg_analyse_macho(const bool developer_mode, __unused struct pkg *pkg, __unused const char *fpath)
+
{
	int ret = EPKG_OK;
	// int ret = analyse_macho(pkg, fpath);
	if (developer_mode) {
@@ -223,6 +331,8 @@ int pkg_analyse_macho(const bool developer_mode, struct pkg *pkg, const char *fp
	return ret;
}

-
int pkg_analyse_close_macho() {
+
int
+
pkg_analyse_close_macho()
+
{
	return EPKG_OK;
}
modified libpkg/pkg_create.c
@@ -143,6 +143,7 @@ pkg_create_from_dir(struct pkg *pkg, const char *root,
	}
	ucl_object_unref(obj);
	packing_append_buffer(pkg_archive, manifest, "+MANIFEST", strlen(manifest));
+
	free(manifest);

	counter_init("packing files", nfiles);

modified libpkg/pkg_elf.c
@@ -606,6 +606,71 @@ aeabi_parse_arm_attributes(void *data, size_t length)
#undef MOVE
}

+
static const char *
+
elf_parse_arch(os_type_t ostype, Elf *elf, GElf_Ehdr *ehdr)
+
{
+
	switch (ehdr->e_machine) {
+
	case EM_386:
+
		return ("i386");
+
	case EM_X86_64:
+
		switch (ostype) {
+
		case OS_FREEBSD:
+
			return ("amd64");
+
		case OS_DRAGONFLY:
+
			return ("x86:64");
+
		default:
+
			return ("x86_64");
+
		}
+
	case EM_AARCH64:
+
		return ("aarch64");
+
	case EM_ARM:
+
		/* Only support EABI */
+
		if ((ehdr->e_flags & EF_ARM_EABIMASK) == 0) {
+
			return (NULL);
+
		}
+

+
		size_t shstrndx;
+
		elf_getshdrstrndx(elf, &shstrndx);
+

+
		GElf_Shdr shdr;
+
		Elf_Scn *scn = NULL;
+
		while ((scn = elf_nextscn(elf, scn)) != NULL) {
+
			if (gelf_getshdr(scn, &shdr) != &shdr) {
+
				break;
+
			}
+
			const char *sh_name = elf_strptr(elf, shstrndx, shdr.sh_name);
+
			if (sh_name == NULL) {
+
				continue;
+
			}
+
			if (STREQ(".ARM.attributes", sh_name)) {
+
				Elf_Data *data = elf_getdata(scn, NULL);
+
				return (aeabi_parse_arm_attributes(data->d_buf, data->d_size));
+
			}
+
		}
+
		break;
+
	case EM_PPC:
+
		return ("powerpc");
+
	case EM_PPC64:
+
		switch (ehdr->e_ident[EI_DATA]) {
+
		case ELFDATA2MSB:
+
			return ("powerpc64");
+
		case ELFDATA2LSB:
+
			return ("powerpc64le");
+
		}
+
		break;
+
	case EM_RISCV:
+
		switch (ehdr->e_ident[EI_CLASS]) {
+
		case ELFCLASS32:
+
			return ("riscv32");
+
		case ELFCLASS64:
+
			return ("riscv64");
+
		}
+
		break;
+
	}
+

+
	return (NULL);
+
}
+

static bool
elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct os_info *oi)
{
@@ -731,10 +796,8 @@ pkg_get_myarch_elfparse(int fd, struct os_info *oi)
	Elf_Data *data;
	Elf_Scn *scn = NULL;
	int ret = EPKG_OK;
-
	const char *arch,*abi, *endian_corres_str, *wordsize_corres_str, *fpu;
	char *dest = oi->abi;
	size_t sz = sizeof(oi->abi);
-
	size_t dsz;

	if (elf_version(EV_CURRENT) == EV_NONE) {
		pkg_emit_error("ELF library initialization failed: %s",
@@ -777,20 +840,15 @@ pkg_get_myarch_elfparse(int fd, struct os_info *oi)
		goto cleanup;
	}

-
	snprintf(dest, sz, "%s:%s", oi->name, oi->version);
-

-
	wordsize_corres_str = elf_corres_to_string(wordsize_corres,
-
	    (int)elfhdr.e_ident[EI_CLASS]);
-

-
	if (oi->ostype == OS_FREEBSD && elfhdr.e_machine == EM_X86_64)
-
		oi->arch = xstrdup("amd64");
-
	else if (oi->ostype == OS_DRAGONFLY && elfhdr.e_machine == EM_X86_64)
-
		oi->arch = xstrdup("x86:64");
-
	else
-
		oi->arch = xstrdup(elf_corres_to_string(mach_corres, (int) elfhdr.e_machine));
+
	const char *arch = elf_parse_arch(oi->ostype, elf, &elfhdr);
+
	if (arch == NULL) {
+
		ret = EPKG_FATAL;
+
		pkg_emit_error("failed to determine the architecture");
+
		goto cleanup;
+
	}
+
	oi->arch = xstrdup(arch);

-
	dsz = strlen(dest);
-
	snprintf(dest + dsz, sz - dsz, ":%s", oi->arch);
+
	snprintf(dest, sz, "%s:%s:%s", oi->name, oi->version, oi->arch);

cleanup:
	if (elf != NULL)
modified libpkg/pkg_manifest.c
@@ -950,6 +950,7 @@ pkg_emit_object(struct pkg *pkg, short flags)
	if (pkg->abi == NULL && pkg->altabi != NULL)
		pkg->abi = xstrdup(pkg->altabi);
	pkg_arch_to_legacy(pkg->abi, legacyarch, BUFSIZ);
+
	free(pkg->altabi);
	pkg->altabi = xstrdup(legacyarch);
	dbg(4, "Emitting basic metadata");
	MANIFEST_EXPORT_FIELD(top, pkg, name, string);
modified libpkg/pkgdb.c
@@ -916,10 +916,19 @@ _dbdir_mkdir(const char *path, mode_t mode)
	return (mkdirat(dfd, _dbdir_trim_path(path), mode));
}

-
static int
+
static char *
_dbdir_getcwd(char *path, size_t sz)
{
-
	return (snprintf(path, sz, "/"));
+
	if (0 == sz) {
+
		errno = EINVAL;
+
	} else 	if (sz >= 2) {
+
		path[0] = '/';
+
		path[1] = '\0';
+
		return path;
+
	} else {
+
		errno = ERANGE;
+
	}
+
	return 0;
}

void
modified libpkg/private/binfmt.h
@@ -1,5 +1,13 @@
+
/*-
+
 * Copyright (c) 2024 Keve Müller <kevemueller@users.github.com>
+
 *
+
 * SPDX-License-Identifier: BSD-2-Clause
+
 */
+

#pragma once

+
#include "private/pkg.h"
+

int pkg_get_myarch_elfparse(int fd, struct os_info *oi);
int pkg_analyse_init_elf(const char* stage);
int pkg_analyse_elf(const bool developer_mode, struct pkg *pkg, const char *fpath);
modified libpkg/private/binfmt_macho.h
@@ -1,26 +1,7 @@
/*-
 * Copyright (c) 2024 Keve Müller <kevemueller@users.github.com>
 *
-
 * Redistribution and use in source and binary forms, with or without
-
 * modification, are permitted provided that the following conditions
-
 * are met:
-
 * 1. Redistributions of source code must retain the above copyright
-
 *    notice, this list of conditions and the following disclaimer
-
 *    in this position and unchanged.
-
 * 2. Redistributions in binary form must reproduce the above copyright
-
 *    notice, this list of conditions and the following disclaimer in the
-
 *    documentation and/or other materials provided with the distribution.
-
 *
-
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
-
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
-
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
-
 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
-
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
-
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
-
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
 * SPDX-License-Identifier: BSD-2-Clause
 */

#ifndef _PKG_BINFMT_MACHO_H
modified libpkg/private/elf_tables.h
@@ -50,26 +50,6 @@ static const struct _elf_corres wordsize_corres[] = {
	{ -1, NULL},
};

-
static const struct _elf_corres endian_corres[] = {
-
	{ ELFDATA2MSB, "eb" },
-
	{ ELFDATA2LSB, "el" },
-
	{ -1, NULL}
-
};
-

-
static const struct _elf_corres os_corres[] = {
-
	{ ELFOSABI_FREEBSD, "freebsd" },
-
	{ -1, NULL }
-
};
-

-
#ifndef EF_MIPS_ABI
-
#define EF_MIPS_ABI	0x0000F000
-
#endif
-
#ifndef EF_ARM_VFP_FLOAT
-
#define EF_ARM_VFP_FLOAT	0x00000400
-
#endif
-
#define E_MIPS_ABI_O32	0x00001000
-
#define E_MIPS_ABI_N32	0x00000020
-

#define NT_VERSION	1
#define NT_ARCH	2
#define NT_GNU_ABI_TAG	1
modified libpkg/repo/binary/Makefile.autosetup
@@ -17,6 +17,7 @@ LOCAL_CFLAGS= -I$(top_srcdir)/libpkg \
		-I$(top_builddir)/

VPATH=	$(top_srcdir)/libpkg/repo/binary
+
.PATH:	$(top_srcdir)/libpkg/repo/binary

@if HAVE_PKG_LIBARCHIVE
LOCAL_CFLAGS+=	@PKG_LIBARCHIVE_CFLAGS@
modified mk/common.mk
@@ -15,7 +15,7 @@ CFLAGS+= -Werror=return-type
DEPFILES_NONEMPTY=	$(DEPFILES) /nonexistent
-include $(DEPFILES_NONEMPTY:=)

-
.SUFFIXES: .pico .in .bin .binin .so.1 .so.1in
+
.SUFFIXES: .pico .in .bin .binin .so.1 .so.1in .suppress.in .suppress

.c.o:
	$(CC) -Wall -Wextra -std=gnu11 -D_GNU_SOURCE=1 -MT $@ -MD -MP -MF $*.Tpo -o $@ -c $(CFLAGS) $(LOCAL_CFLAGS) $<
@@ -34,3 +34,6 @@ DEPFILES_NONEMPTY= $(DEPFILES) /nonexistent

.so.1in.so.1:
	cp $< $@
+

+
.suppress.in.suppress:
+
	cp $< $@
modified tests/Makefile.autosetup
@@ -68,13 +68,24 @@ TESTS_SH= \
	frontend/triggers.sh

#
-
# Those files simple binaries obtained from
+
# These files are mostly simple binaries obtained from
# int main(void) { return 0; }
#
+
# The freebsd-*.bin files are copies of /usr/bin/uname from official
+
# 14.1 release artifacts for the given architecture.
+


TESTS_SHELL_BINS= \
	frontend/dfly.bin \
-
	frontend/fbsd.bin \
+
	frontend/freebsd-aarch64.bin \
+
	frontend/freebsd-amd64.bin \
+
	frontend/freebsd-armv6.bin \
+
	frontend/freebsd-armv7.bin \
+
	frontend/freebsd-i386.bin \
+
	frontend/freebsd-powerpc.bin \
+
	frontend/freebsd-powerpc64.bin \
+
	frontend/freebsd-powerpc64le.bin \
+
	frontend/freebsd-riscv64.bin \
	frontend/linux.bin \
	frontend/macos.bin \
	frontend/macos106.bin \
modified tests/frontend/abi.sh
@@ -13,17 +13,32 @@ native_body() {
	if [ "$thisarch" = "unknown" -o "${OS}" = "Darwin" ]; then
		thisarch=$(uname -m)
	fi
-
	if [ "${OS}" = "Linux" ]; then
-
		version=$(readelf -n /bin/uname  | awk '/ABI: / { split($NF, a, "."); print a[1]"."a[2] }')
-
	else
-
		version=$(uname -r | cut -d. -f1)
-
	fi
-
	_expected="${OS}:${version}:$(echo $thisarch | sed s/x86_64/amd64/)\n"
+
	thisabi=$thisarch
+
	case "${OS}" in
+
		Linux)
+
			version=$(readelf -n /bin/uname  | awk '/ABI: / { split($NF, a, "."); print a[1]"."a[2] }')
+
			;;
+
		Darwin)
+
			# without a hint, the first arch is selected, which happens to be consistently x86_64
+
			thisarch="amd64"
+
			thisabi="x86:64"
+
			version=$(uname -r | cut -d. -f1)
+
			;;
+
		FreeBSD)
+
			version=$(uname -r | cut -d. -f1)
+
			thisarch=$(echo "${thisarch}" | sed s/x86_64/amd64/)
+
			thisabi=$(echo "${thisarch}" | sed s/amd64/x86:64/)
+
			;;
+
		*)
+
			version=$(uname -r | cut -d. -f1)
+
			;;
+
	esac
+
	_expected="${OS}:${version}:${thisarch}\n"
	atf_check \
		-o inline:"${_expected}" \
		pkg config abi

-
	_expected="$(uname -s | tr '[:upper:]' '[:lower:]'):${version}:$(echo $thisarch | sed 's/x86_64/x86:64/; s/amd64/x86:64/')\n"
+
	_expected="$(uname -s | tr '[:upper:]' '[:lower:]'):${version}:${thisabi}\n"
	atf_check \
		-o inline:"${_expected}" \
		pkg config altabi
@@ -45,15 +60,96 @@ override_body() {

elfparse_body() {
	# ELF parsing now works across platforms
-
	_expected="FreeBSD:13:amd64\n"
+

+
	_expected="FreeBSD:14:aarch64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-aarch64.bin config abi
+

+
	_expected="freebsd:14:aarch64:64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-aarch64.bin config altabi
+

+
	_expected="FreeBSD:14:amd64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-amd64.bin config abi
+

+
	_expected="freebsd:14:x86:64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-amd64.bin config altabi
+

+
	_expected="FreeBSD:13:armv6\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-armv6.bin config abi
+

+
	_expected="freebsd:13:armv6:32:el:eabi:hardfp\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-armv6.bin config altabi
+

+
	_expected="FreeBSD:14:armv7\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-armv7.bin config abi
+

+
	_expected="freebsd:14:armv7:32:el:eabi:hardfp\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-armv7.bin config altabi
+

+
	_expected="FreeBSD:14:i386\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-i386.bin config abi
+

+
	_expected="freebsd:14:x86:32\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-i386.bin config altabi
+

+
	_expected="FreeBSD:14:powerpc\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc.bin config abi
+

+
	_expected="freebsd:14:powerpc:32:eb\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc.bin config altabi
+

+
	_expected="FreeBSD:14:powerpc64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc64.bin config abi
+

+
	_expected="freebsd:14:powerpc:64:eb\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc64.bin config altabi
+

+
	_expected="FreeBSD:14:powerpc64le\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc64le.bin config abi
+

+
	_expected="freebsd:14:powerpc:64:el\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-powerpc64le.bin config altabi
+

+
	_expected="FreeBSD:14:riscv64\n"
	atf_check \
		-o inline:"${_expected}" \
-
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/fbsd.bin config abi
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-riscv64.bin config abi

-
	_expected="freebsd:13:x86:64\n"
+
	_expected="freebsd:14:riscv:64:hf\n"
	atf_check \
		-o inline:"${_expected}" \
-
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/fbsd.bin config altabi
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/freebsd-riscv64.bin config altabi

	_expected="dragonfly:5.10:x86:64\n"
	atf_check \
@@ -108,6 +204,7 @@ machoparse_body() {
		-o inline:"${_expected}" \
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macos150.bin config altabi

+
	# macosfat.bin has amd64 as its first entry
	_expected="Darwin:24:amd64\n"
	atf_check \
		-o inline:"${_expected}" \
@@ -117,4 +214,92 @@ machoparse_body() {
	atf_check \
		-o inline:"${_expected}" \
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin config altabi
+

+
	# explicitely select an existing fat entry
+
	_expected="Darwin:24:amd64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin#amd64 config abi
+

+
	_expected="darwin:24:x86:64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin#amd64 config altabi
+

+
	_expected="Darwin:24:aarch64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin#aarch64 config abi
+

+
	_expected="darwin:24:aarch64:64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin#aarch64 config altabi
+

+
	# explicitely select a fat entry that is not in the ABI_FILE
+
	_expected="Scanned 2 entries, found none matching selector i386\n"
+
	atf_check \
+
		-s exit:1 \
+
		-o inline:"${_expected}" \
+
		-e match:"Unable to determine ABI" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin#i386 config abi
+

+
	atf_check \
+
		-s exit:1 \
+
		-o inline:"${_expected}" \
+
		-e match:"Unable to determine ABI" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin#i386 config altabi
+

+
	# explicitely select a fat entry that is not a valid architecture, hence not in the ABI_FILE
+
	_expected="Scanned 2 entries, found none matching selector abc\n"
+
	atf_check \
+
		-s exit:1 \
+
		-o inline:"${_expected}" \
+
		-e match:"Unable to determine ABI" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin#abc config abi
+

+
	atf_check \
+
		-s exit:1 \
+
		-o inline:"${_expected}" \
+
		-e match:"Unable to determine ABI" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin#abc config altabi
+

+
	# if the binary is not universal, selecting the first entry is not commentable
+
	_expected="Darwin:24:aarch64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		-e not-match:"picking first" \
+
		pkg -d -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macos.bin config abi
+

+
	_expected="darwin:24:aarch64:64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		-e not-match:"picking first" \
+
		pkg -d -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macos.bin config altabi
+

+
	_expected="Scanned 1 entry, found none matching selector abc\n"
+
	atf_check \
+
		-s exit:1 \
+
		-o inline:"${_expected}" \
+
		-e match:"Unable to determine ABI" \
+
		pkg -d -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macos.bin#abc config abi
+

+
	atf_check \
+
		-s exit:1 \
+
		-o inline:"${_expected}" \
+
		-e match:"Unable to determine ABI" \
+
		pkg -d -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macos.bin#abc config altabi
+

+
	# if the binary is universal, selecting the first entry is to be commented
+
	_expected="Darwin:24:amd64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		-e match:"picking first" \
+
		pkg -d -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin config abi
+

+
	_expected="darwin:24:x86:64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		-e match:"picking first" \
+
		pkg -d -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin config altabi
}
deleted tests/frontend/fbsd.binin
modified tests/frontend/fingerprint.sh
@@ -18,16 +18,17 @@ setup() {
		atf_skip_on Linux Test fails on Linux
		atf_check -o save:repo.pub -e ignore \
			pkg key --create repo.key
+
		keyform=""
		_typecmd=""
		;;
	ecc)
-
		atf_skip_on Darwin Test fails on Darwin
		atf_skip_on Linux Test fails on Linux
		atf_check -o ignore -e ignore \
			openssl ecparam -genkey -name secp256k1 -out repo.key -outform DER
		chmod 0400 repo.key
		atf_check -o ignore -e ignore \
-
			openssl ec -in repo.key -pubout -out repo.pub -outform DER
+
			openssl ec -inform DER -in repo.key -pubout -out repo.pub -outform DER
+
		keyform="-keyform DER"
		_typecmd='printf "%s\n%s\n" "TYPE" "ecdsa"'
		;;
	esac
@@ -47,7 +48,7 @@ read -t 2 sum

$_typecmd
echo SIGNATURE
-
echo -n \$sum | /usr/bin/openssl dgst -sign repo.key -sha256 -binary
+
echo -n \$sum | openssl dgst $keyform -sign repo.key -sha256 -binary
echo
echo CERT
cat repo.pub
added tests/frontend/freebsd-aarch64.binin
added tests/frontend/freebsd-amd64.binin
added tests/frontend/freebsd-armv6.binin
added tests/frontend/freebsd-armv7.binin
added tests/frontend/freebsd-i386.binin
added tests/frontend/freebsd-powerpc.binin
added tests/frontend/freebsd-powerpc64.binin
added tests/frontend/freebsd-powerpc64le.binin
added tests/frontend/freebsd-riscv64.binin
modified tests/frontend/key.sh
@@ -69,11 +69,17 @@ key_sign_body() {
		# Generate a key with pkg
		atf_check -o save:repo.pub -e ignore \
		    pkg key --create -t "$signer" repo.key
-

+
		
		atf_check -o save:msg.sig \
		    pkg key --sign -t "$signer" repo.key < msg

-
		atf_check -o ignore openssl dgst -sha256 -verify repo.pub \
+
		if [ $signer = ecdsa ]; then
+
			keyform="-keyform DER"
+
		else
+
			keyform=""
+
		fi
+

+
		atf_check -o ignore openssl dgst -sha256 $keyform -verify repo.pub \
		    -signature msg.sig msg
	done
}
modified tests/frontend/pkg.sh
@@ -21,6 +21,15 @@ pkg_no_database_body() {

pkg_config_defaults_body()
{
+
	case "${OS}" in
+
	FreeBSD|DragonFly)
+
		MATCH_ALTABI='^ *ALTABI = "[a-zA-Z0-9]+:[a-z\.A-Z0-9]+:[a-zA-Z0-9]+:[a-zA-Z0-9:]+";$'
+
		;;
+
	*)
+
		MATCH_ALTABI='^ *ALTABI = "[a-zA-Z0-9]+:[a-z\.A-Z0-9]+:[a-zA-Z0-9_]+;$'
+
		;;
+
	esac
+

	atf_check \
	    -o match:'^ *PKG_DBDIR = "/var/db/pkg";$' \
	    -o match:'^ *PKG_CACHEDIR = "/var/cache/pkg";$' \
@@ -30,7 +39,7 @@ pkg_config_defaults_body()
	    -o match:'^ *ASSUME_ALWAYS_YES = false;$' \
	    -o match:'^ *PLIST_KEYWORDS_DIR = "";$' \
	    -o match:'^ *SYSLOG = true;$' \
-
	    -o match:'^ *ALTABI = "[a-zA-Z0-9]+:[a-z\.A-Z0-9]+:[a-zA-Z0-9]+:[a-zA-Z0-9:]+";$' \
+
	    -o match:"${MATCH_ABI}" \
	    -o match:'^ *DEVELOPER_MODE = false;$' \
	    -o match:'^ *VULNXML_SITE = "https://vuxml.freebsd.org/freebsd/vuln.xml.xz";$' \
	    -o match:'^ *FETCH_RETRY = 3;$' \
modified tests/frontend/pubkey.sh
@@ -25,7 +25,7 @@ ecc_test() {
			openssl ecparam -genkey -name secp256k1 -out repo.key -outform DER
		chmod 0400 repo.key
		atf_check -o ignore -e ignore \
-
			openssl ec -in repo.key -pubout -out repo.pub -outform DER
+
			openssl ec -inform DER -in repo.key -pubout -out repo.pub -outform DER
		;;
	esac

modified tests/lib/pkg_elf.c
@@ -60,7 +60,7 @@ ATF_TC_BODY(analyse_elf, tc)
	ATF_REQUIRE_STREQ(tll_front(p->shlibs_provided), "libtestfbsd.so.1");
	free(binpath);

-
	xasprintf(&binpath, "%s/Makefile.autosetup", atf_tc_get_config_var(tc, "srcdir"));
+
	xasprintf(&binpath, "%s/Makefile", atf_tc_get_config_var(tc, "srcdir"));
	ATF_REQUIRE_EQ(pkg_analyse_elf(false, p, binpath), EPKG_END);
	ATF_REQUIRE_EQ(tll_length(p->shlibs_provided), 1);
	free(binpath);