Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Merge remote-tracking branch 'freebsd/main'
Shawn Webb committed 1 year ago
commit 84c221457de9b1f5264a2cc4114524bf73106179
parent c62eec6
62 files changed +2368 -2468
modified .builds/debian.yml
@@ -1,5 +1,6 @@
image: debian/testing
packages:
+
  - libcurl4-openssl-dev
  - libsqlite3-dev
  - libbsd-dev
  - libarchive-tools
@@ -25,7 +26,7 @@ tasks:
  - configure: |
      mkdir build
      cd build
-
      ../pkg/configure --default-format=txz
+
      ../pkg/configure --default-format=txz --with-libarchive.pc --with-libcurl --with-openssl.pc
  - build: |
      cd build
      make
modified .github/workflows/build.yaml
@@ -1,13 +1,10 @@
name: build
-
# GitHub action to compile pkg on ubuntu-24.04, ubuntu-latest/22.04 (amd64) and macos-latest (arm64)
+
# GitHub action to compile pkg on ubuntu-24.04, ubuntu-latest/22.04 (amd64) and macos-latest (aarch64)
#  * set-up prerequisites
#  * configure && make && make check && make install
#  * upload installed binaries as well as kyua reports as build artefact
#
-
# We run in a matrix with os/number of workers, to demonstrate the errors on MacOSX when running 
-
# pkg repo multi-threaded.
-
# Intended to increase awareness in issues with MacOS builds of pkg.
-

+
# We run in a matrix with os/sanitize flags.

on:
    pull_request:
@@ -21,7 +18,7 @@ permissions:

jobs:
    build:
-
        name: build ${{ matrix.workers-count }} ${{ matrix.build-os }} ${{ matrix.compiler }}
+
        name: build ${{ join(matrix.sanitize, '+') }} ${{ matrix.build-os }} ${{ matrix.compiler }}
        runs-on: "${{ matrix.build-os }}"
        strategy:
            fail-fast: false
@@ -30,14 +27,20 @@ jobs:
                - ubuntu-24.04
                - ubuntu-latest
                - macos-latest
-
                workers-count:
-
                - 0
-
                - 1
+
                sanitize:
+
                - ""
+
                - [ "asan", "lsan" ]
+
                - ubsan
+
                - tsan
                exclude:
-
                  - build-os: ubuntu-24.04
-
                    workers-count: 1
-
                  - build-os: ubuntu-latest
-
                    workers-count: 1
+
                - build-os: macos-latest
+
                  sanitize: ubsan # No space left on device
+
                - build-os: ubuntu-latest
+
                  sanitize: [ "asan", "lsan" ]
+
                - build-os: ubuntu-latest
+
                  sanitize: ubsan
+
                - build-os: ubuntu-latest
+
                  sanitize: tsan
                include:
                - build-os: macos-latest
                  compiler: clang-19
@@ -110,7 +113,8 @@ jobs:
            #

            brew update --quiet || true
-
            HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=Y brew install ${{ join(matrix.pkgs, ' ') }}
+
            brew remove pkg-config@0.29.2 || true # otherwise we get spurious errors with pkgconf
+
            brew install ${{ join(matrix.pkgs, ' ') }}

            # kyua was kicked out of brew due to lack of activity
            # we patch away the disabled line and install the last built binary version
@@ -131,14 +135,23 @@ jobs:
            echo "CC=${{ matrix.llvm-bindir }}/clang" >> "${GITHUB_ENV}"
            echo "CXX=${{ matrix.llvm-bindir }}/clang++" >> "${GITHUB_ENV}"
            echo "CPP=${{ matrix.llvm-bindir }}/clang-cpp" >> "${GITHUB_ENV}"
-
            # this is miracolously not picked up by automake as the default
+
            # this is miraculously not picked up by automake as the default
            echo "CC_FOR_BUILD=${{ matrix.llvm-bindir }}/clang" >> "${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}"

        - name: build pkg
          run: |
-
            echo Building pkg
+
            CFG_OPTS=""
+
            for i in ${{ join(matrix.sanitize, ' ') }}; do
+
              CFG_OPTS="${CFG_OPTS} --with-${i}"
+
            done
+
            echo Building pkg with ${{ matrix.sanitize }} .. ${CFG_OPTS} 
+
            echo uname -a: $(uname -a)
+
            echo uname -m: $(uname -m)
+
            echo uname -p: $(uname -p)
+
            echo NPROC="${NPROC}"
            echo CC="${CC}"
            echo CPP="${CPP}"
            echo PKG_CONFIG_PATH="${PKG_CONFIG_PATH}"
@@ -146,33 +159,36 @@ jobs:
            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
-
            make
+
            ${GITHUB_WORKSPACE}/src.pkg/configure --prefix=${INST_PKG} --with-libarchive.pc --with-libcurl --with-openssl.pc ${CFG_OPTS}
+
            make -j${NPROC}

-
        - name: test&instal pkg
+
        - name: test&install pkg
          run: |
-
            echo Checking and  pkg
+
            echo Checking and installing pkg
            cd "${BUILD_PKG}"
-
            if WORKERS_COUNT=${{ matrix.workers-count }} make check; then
+
            if make check; then
              echo "All mandatory checks passed"
+
              kyua report --results-filter=xfail,broken,failed >> $GITHUB_STEP_SUMMARY
              kyua report
              kyua report-html
            else
+
              kyua report --results-filter=xfail,broken,failed >> $GITHUB_STEP_SUMMARY
              kyua report --verbose
              kyua report-html
              exit 0
            fi
+
            # only install non-debug builds
            make install

        - name: tar build & test reports
          run: |
            test -d ${INST_PKG} && tar cvf pkg-${{ matrix.build-os }}-${{ matrix.compiler }}.tar -C ${INST_PKG} .
-
            tar cvf pkg-${{ matrix.build-os }}-${{ matrix.compiler }}-report${{ matrix.workers-count }}.tar -C "${BUILD_PKG}/html" .
+
            tar cvf pkg-${{ matrix.build-os }}-${{ matrix.compiler }}-report${{ join(matrix.sanitize, '_') }}.tar -C "${BUILD_PKG}/html" .

        - name: archive build artefacts
          uses: actions/upload-artifact@v4
          with:
-
              name: pkg-test${{ matrix.workers-count }}-${{ matrix.build-os }}-${{ matrix.compiler }}
+
              name: pkg-test${{ join(matrix.sanitize, '_') }}-${{ matrix.build-os }}-${{ matrix.compiler }}
              path: pkg*.tar
              compression-level: 0
              retention-days: 10
modified .gitignore
@@ -6,7 +6,6 @@
*.pico
*.po
*.Po
-
*.So
*.lo
*.la
*.core
@@ -63,7 +62,6 @@ scripts/sbin/pkg2ng
/external/libucl/autom4te.cache
/external/yxml/Makefile
/external/liblua/Makefile
-
/external/libmachista/Makefile
/external/libfetch/Makefile
/external/libelf/Makefile
/external/sqlite/Makefile
@@ -92,6 +90,7 @@ scripts/sbin/pkg2ng
!/tests/frontend/*.sh
!/tests/frontend/*.in
!/tests/frontend/*.binin
+
!/tests/frontend/*.so.*
/tests/frontend/test_environment.sh
/tests/lua
/tests/metalog
modified NEWS
@@ -1,3 +1,18 @@
+
Changes from 1.21.99.3 to 1.21.99.4
+
- ABI detection related fixes
+
- Lots of fixs for MacOS
+
- Fix host component handling in file:// URLs
+
- build system: add --with-tsan support
+
- fix threads on MacOS
+
- pkg -vv now shows bundled/external libraries version
+
- pkg: -r command can be used multiple times to only enable
+
  the specified repositories.
+
- UI: small improvements in error messages
+
- repositories: new pkg repositories command to list configured
+
  repositories
+
- vuxml: now fetched over https
+
- check: now default on the -s option when no options is passed.
+

Changes from 1.21.99.2 to 1.21.99.3
- alias: prime-origins is now uniq
- curl: improve debug output
modified README.md
@@ -1,35 +1,20 @@
-
pkg - a binary package manager for FreeBSD
-
==========================================
+
pkg - a package manager for FreeBSD
+
====================================
+

+
 * Sourcehut FreeBSD: [![builds.sr.ht status](https://builds.sr.ht/~bapt/pkg/commits/master/freebsd.svg)](https://builds.sr.ht/~bapt/pkg/commits/master/freebsd?)
+
 * Sourcehut Alpine: [![builds.sr.ht status](https://builds.sr.ht/~bapt/pkg/commits/master/alpine.svg)](https://builds.sr.ht/~bapt/pkg/commits/master/alpine?)
+
 * Sourcehut Debian: [![builds.sr.ht status](https://builds.sr.ht/~bapt/pkg/commits/master/debian.svg)](https://builds.sr.ht/~bapt/pkg/commits/master/debian?)
+
 * Github Actions: [![build](https://github.com/freebsd/pkg/actions/workflows/build.yaml/badge.svg)](https://github.com/freebsd/pkg/actions/workflows/build.yaml)

Table of Contents:
------------------

* [libpkg](#libpkg)
* [pkg package format](#pkgfmt)
-
* [Local Database](#localdb)
* [Installing packages](#pkginst)
-
* [Upgrading packages](#pkgupg)
-
* [Deleting packages](#pkgdel)
-
* [Installing pkg](#installpkg)
* [pkg bootstrap](#pkgbootstrap)
-
* [pkg in Ports](#pkgports)
-
* [Building pkg using sources from Git](#pkggit)
-
* [A quick usage introduction to pkg](#usageintro)
-
* [Getting help on the commands usage](#pkghelp)
-
* [Querying the local package database](#pkginfo)
-
* [Installing packages](#pkginstalling)
-
* [Working with a remote package repository](#pkgrepos)
-
* [Working with multiple remote package repositories](#multirepos)
-
* [Updating remote repositories](#pkgupdate)
-
* [Searching in remote package repositories](#pkgsearch)
-
* [Installing from remote repositories](#pkginstall)
-
* [Creating a package repository](#pkgcreate)
* [Additional resources](#resources)

-
SourceHut CI:
-
[![builds.sr.ht status](https://builds.sr.ht/~bapt/pkg/commits/master/freebsd.svg)](https://builds.sr.ht/~bapt/pkg/commits/master/freebsd?)
-
[![builds.sr.ht status](https://builds.sr.ht/~bapt/pkg/commits/master/alpine.svg)](https://builds.sr.ht/~bapt/pkg/commits/master/alpine?)
-
[![builds.sr.ht status](https://builds.sr.ht/~bapt/pkg/commits/master/debian.svg)](https://builds.sr.ht/~bapt/pkg/commits/master/debian?)

<a name="libpkg"></a>
### libpkg
@@ -49,154 +34,11 @@ The tar archive itself is composed of two types of elements:
* the special files at the beginning of the archive, starting with a "+"
* the data.

-
#### The metadata
-

-
pkg uses several files for metadata:
-

-
* +COMPACT\_MANIFEST
-
* +MANIFEST
-

-
##### COMPACT\_MANIFEST
-

-
This is a subset of the information included in the main MANIFEST,
-
omitting the lists of files, checksums, directories and scripts.
-
It contains the information used to build the repository catalogue.
-

-
##### MANIFEST
-

-
The manifest is in [UCL](https://github.com/vstakhov/libucl) format, it contains all the
-
information about the package:
-

-
	name: foo
-
	version: 1.0
-
	origin: category/foo
-
	comment: this is foo package
-
	arch: i386
-
	www: http://www.foo.org
-
	maintainer: foo@bar.org
-
	prefix: /usr/local
-
	licenselogic: or
-
	licenses: [MIT, MPL]
-
	flatsize: 482120
-
	users: [USER1, USER2]
-
	groups: [GROUP1, GROUP2]
-
	options: { OPT1: off, OPT2: on }
-
	desc: <<EOD
-
	  This is the description
-
	  Of foo
-
	  
-
	  A component of bar
-
	EOD
-
	categories: [bar, plop]
-
	deps: {
-
	  libiconv: {origin: converters/libiconv, version: 1.13.1_2};
-
	  perl: {origin: lang/perl5.12, version: 5.12.4 };
-
	}
-
	files: {
-
	  /usr/local/bin/foo: 'sha256sum',
-
	  /usr/local/bin/i_am_a_link: 'sha256sum';
-
	  /usr/local/share/foo-1.0/foo.txt: 'sha256sum;
-
	}
-
	directories: {
-
	  /usr/local/share/foo-1.0 : 'y';
-
	}
-
	scripts: {
-
	  post-install: <<EOD
-
	    #!/bin/sh
-
	    echo post-install
-
	EOD
-
	  pre-install: <<EOD
-
	    #!/bin/sh
-
	    echo pre-install
-
	EOD
-
	}
-

-
Valid scripts are:
-

-
* pre-install
-
* post-install
-
* install
-
* pre-deinstall
-
* post-deinstall
-
* deinstall
-

-
Script *MUST* be in sh format.
-
Nothing else will work.
-
The shebang is not required.
-

-
When the manifest is read by pkg\_create files and dirs can use an
-
alternate format:
-

-
	files: {
-
	  /usr/local/bin/foo: 'sha256sum',
-
	  /usr/local/bin/bar: {sum: 'sha256sum', uname: baruser, gname: foogroup, perm: 0644 }
-
	}
-
	directories: {
-
	  /usr/local/share/foo-1.0: 'y',
-
	  /path/to/directory: {uname: foouser, gname: foogroup, perm: 0755}
-
	}
-

-

-
This allows overriding the users, groups and mode of files and
-
directories during package creation.
-
So, for example, this allows to creation of a package containing
-
root-owned files without being packaged by the root user.
-

-
<a name="localdb"></a>
-
### Local database
-

-
When a package is installed, it is registered in a SQLite database.
-

-
The SQLite database allows fast queries and ACID transactions.  It also
-
allows finding the reverse dependencies reliably without needing the
-
__+REQUIRED_BY__ hack.
-

-
In order to save space the MTREE is only stored once, which saves 18K per
-
installed package.
-

-
pkg supports a `register` command to register packages into the SQLite
-
database from the ports. The register command can execute the install script,
-
show pkg-message, ...
-

<a name="pkginst"></a>
### Installing packages

-
`pkg add` can install a package archive from the local disk, or from a
-
remote FTP/HTTP server.
-

-
If only a package name is given, it will search the repository catalogues
-
and download and install the package if it exists. Any dependencies will be
-
downloaded and installed first.
-

-
This is possible because we have the dependency information in the
-
catalogue of the remote repository.
-

-
`pkg add` will check if the user attempts to install a package built
-
for another arch or release.
-

-
<a name="pkgupg"></a>
-
### Upgrading packages
-

-
pkg also supports upgrades of binary packages.
-

-
pkg will compare the versions of installed packages and those available in
-
the repository. It will compute the proper update order and apply them.
-

-
<a name="pkgdel"></a>
-
### Deleting packages
-

-
`pkg delete` will remove a package, and (depending on the command line
-
arguments) any other packages that depend on what you're trying to
-
delete.
-

-
Directory leftovers are automatically removed if they are empty and
-
not in the MTREE.
-

-
<a name="installpkg"></a>
-
## Installing pkg
-

-
There are three ways to install pkg: two for general day-to-day use,
-
and the third if you want to help with pkg development.
+
pkg can install a package archive from the local disk, remote HTTP server or
+
remote SSH server.

<a name="pkgbootstrap"></a>
### Pkg bootstrap
@@ -215,261 +57,12 @@ pkg(8) is installed without triggering the installation, and
conversely, `pkg bootstrap[-f]` to install pkg(8) (or force it to be
reinstalled) without performing any other actions.

-
<a name="pkgports"></a>
-
### pkg in Ports
-

-
pkg-1.0 release was committed to the ports tree on 30th August 2012,
-
and a series of further releases are planned.  To install the latest
-
release version:
-

-
	$ make -C /usr/ports/ports-mgmt/pkg install clean
-
	$ echo "WITH_PKG=yes" >> /etc/make.conf
-

-

-
<a name="pkggit"></a>
-
### Building pkg using sources from Git [FreeBSD]
-

-
In order to build pkg from source, you will need to have GNU
-
autotools and some other tools installed.
-

-
	# pkg install autoconf automake libtool pkgconf
-

-
The next thing to do is to get the pkg sources installed on your machine.
-
You can grab a development snapshot of pkg from the [pkg GitHub repository][1]
-

-
To get the latest version of pkg from the Git repo, just clone it:
-

-
	% git clone https://github.com/freebsd/pkg
-

-
or
-

-
	% git clone git@github.com:freebsd/pkg.git
-

-
Or you can take an already tagged release of pkg from the above web
-
page as well.
-
Just open your browser and download the release you want.
-

-
Once you have the pkg sources, installing it is fairly easy:
-

-
	% cd pkg
-
	% ./configure
-
	% make
-
	# make install
-

-
Now you should have the latest pkg installed on your system.  Note
-
that this build and install procedure does not update the local
-
package database at all, so you will get some odd effects due to the
-
packaging system being misled into thinking an older version of pkg is
-
installed.
-

-
Note: if you're running anything other than FreeBSD or DragonFly, you
-
will need to do some porting work.  The pkg(8) codebase should be
-
reasonably portable onto anything with a c99 compiler, POSIX compliant
-
system and capable of running GNU autotools.  However, various places
-
in the pkg(8) code make assumptions about OS specific behaviour.  If
-
you do try anything like this, we'd be very interested to hear how you
-
get on.
-

-
<a name="usageintro"></a>
-
## A quick usage introduction to pkg
-

-
In this section of the document we will try to give a quick and dirty
-
introduction on the practical usage of pkg - installing packages,
-
searching in remote package repositories, updating remote package
-
repositories and installing from them, etc.
-

-
<a name="pkghelp"></a>
-
### Getting help on the commands usage
-

-
In order to get help on any of the pkg commands you should use the `pkg help <command>`
-
command, which will take the man page of the specified command.
-

-
In order to get the available commands in pkg, just execute `pkg help`
-

-
	# pkg help
-
	# pkg help <command>
-

-
<a name="pkginfo"></a>
-
### Querying the local package database
-

-
In order to get information about installed packages use the `pkg
-
info` command.
-

-
`pkg info` will query the local package database and display
-
information about the package you are interested in.
-

-
To list all install/registered packages in the local database, use
-
this command:
-

-
	# pkg info -a
-

-
For more information on querying the local package database, please
-
refer to *pkg-info(1)* man page.
-

-
<a name="pkginstalling"></a>
-
### Installing packages
-

-
Packages are installed either from a repository, from the results of a
-
local compilation of software via the ports or from a pkg tarball
-
independently obtained from some other source.
-

-
A repository is a collection of packages which have been gathered
-
together, had a catalogue created and then published, typically by
-
exposing the repository via HTTP or some other networking protocol.
-
You can also publish a repository from a local or NFS mounted
-
filesystem (using file:// style URLs) or via SSH (using ssh:// URLs.)
-

-
<a name="pkgrepos"></a>
-
### Working with a remote package repository
-

-
While pkg(8) can deal with individual package tarballs, the real power
-
comes from the use of repositories, which publish a 'catalogue' of
-
meta-data about the packages they contain.
-

-
You can configure pkg(8) to use one or several repositories.
-
Supported versions of FreeBSD now contain a default configuration out
-
of the box: `/etc/pkg/FreeBSD.conf` which is setup to install packages
-
from the official package repositories.
-

-
To add additional repositories, create a per-repository configuration
-
file in `/usr/local/etc/pkg/repos` -- it doesn't matter what the
-
filename is other than it must match '*.conf' and you should add a
-
'priority' setting indicating the preference order.  This is just an
-
integer, where higher values indicate the more preferred repositories.
-
Priority defaults to 0 unless explicitly stated.  This is the value
-
for the default `/etc/pkg/FreeBSD.conf`
-

-
To disable the default FreeBSD.conf, create a file
-
`/usr/local/etc/pkg/repos/FreeBSD.conf` with the contents:
-

-
```
-
FreeBSD: { enabled: no }
-
```
-

-
To check quickly what repositories you have configured, run `pkg -vv`.
-

-
See *pkg.conf(5)* for details of the format of `pkg.conf` and the
-
per-repository `repo.conf` files.  See *pkg-repository(5)* for more
-
details about package repositories and how to work with them.
-

-
Note that the old style of setting _PACKAGESITE_ in pkg.conf is
-
no-longer supported.  Setting _PACKAGESITE_ in the environment has
-
meaning for the pkg(7) shim, but is ignored by pkg(8).
-

-
<a name="pkgupdate"></a>
-
### Updating from remote repositories
-

-
Then fetch the repository catalogues using the command:
-

-
	# pkg update
-

-
For more information on updating from remote repositories, please
-
refer to *pkg-update(1)*.
-

-
This will fetch the remote package database to your local system. Now
-
in order to install packages from the remote repository, you can use
-
the `pkg install` command:
-

-
	# pkg install zsh cfengine3
-

-
<a name="multirepos"></a>
-
### Working with multiple repositories
-

-
If you have more than one repository defined, then you probably want
-
to install some packages from a specific repository, but allow others
-
to be obtained from whatever repository has them available.
-

-
You can install a package from a specific repository:
-

-
    # pkg install -r myrepo zsh
-

-
where `myrepo` is one of the tags shown in the `pkg -vv` output.
-
pkg(8) will automatically create an annotation showing which
-
repository a package came from, similarly to the effect of running:
-

-
    # pkg annotate -A pkgname repository myrepo
-

-
pkg(8) will attempt to use the same repository for any updates to this
-
package, even if there are more recent versions available from other
-
repositories.  This is usually the desired behaviour.  Otherwise see
-
the documentation for `CONSERVATIVE_UPGRADE` in pkg.conf(5).
-

-
<a name="pkgsearch"></a>
-
### Searching in remote package repositories
-

-
You can search in the remote package repositories using the `pkg
-
search` command.
-

-
If you have multiple repositories configured, `pkg search` will return
-
results from searching each of them.  Use the `-r reponame` option to
-
confine your search to a specific repository.
-

-
An example search for a package could be done like this:
-

-
	# pkg search -x apache
-

-
For more information on the repositories search, please refer to
-
*pkg-search(1)*
-

-
<a name="pkginstall"></a>
-
### Installing from remote repositories
-

-
pkg(8) will install a package from the highest priority repository
-
that contains the package and that allows the solver to satisfy the
-
package dependencies.  This may entail reinstalling existing packages
-
from a different repository.
-

-
The process continues until the package is fetched and installed, or
-
all remote repositories fail to fetch the package.
-

-
Remote installations of packages using pkg are done by the `pkg
-
install` command.
-

-
Here's an example installation of few packages:
-

-
	# pkg install www/apache22
-
	# pkg install zsh
-
	# pkg install perl5-5.18.2_4
-

-
Or you could also install the packages using only one command, like this:
-

-
	# pkg install www/apache22 zsh perl5-5.18.2_4
-

-
For more information on the remote package installs, please refer to
-
*pkg-install(1)*
-

-
<a name="pkgcreate"></a>
-
### Creating a package repository
-

-
You can also use pkg, so that you create a package repository.
-

-
In order to create a package repository you need to use the `pkg
-
create` command.
-

-
Here's an example that will create a repository of all your currently
-
installed packages:
-

-
	# cd /path/with/enough/space
-
	# pkg create -a
-
	# pkg repo .
-

-
The above commands will create a repository of all packages on your system.
-

-
Now you can share your repo with other people by letting them know of
-
your repository :)
-

<a name="resources"></a>
### Additional resources

-
* The Git repository of [pkg is hosted on GitHub][1]
-

-
* The [pkg Wiki page][2]
+
* The Git repository of [pkg is hosted on GitHub](https://github.com/freebsd/pkg)

To contact us, you can find us in the **#pkg** channel on [Libera Chat IRC Network](https://libera.chat/).

If you hit a bug when using pkg, you can always submit an issue in the
-
[pkg issue tracker][3].
-

-
[1]: https://github.com/freebsd/pkg
-
[2]: http://wiki.freebsd.org/pkg
-
[3]: https://github.com/freebsd/pkg/issues
+
[pkg issue tracker](https://github.com/freebsd/pkg/issues).
modified auto.def
@@ -102,7 +102,7 @@ cc-with { -libs { -llzma }} {
	}
}
if {[string match *-freebsd* [get-define host]]} {
-
	define pkg_freebsd
+
	define pkgos_freebsd
	cc-with { -libs { -lmd }} {
		if {![cc-check-functions SHA256_Data]} {
			user-error "Unable to find libmd"
@@ -213,14 +213,6 @@ if {![cc-check-functions dlclose]} {
	}
}

-
if {![cc-check-functions __res_query]} {
-
	cc-with { -libs { -lresolv }} {
-
		if {[cc-check-functions __res_query]} {
-
			define-feature LIBRESOLV
-
		}
-
	}
-
}
-

cc-check-includes link.h machine/endian.h osreldate.h readpassphrase.h \
	sys/procctl.h sys/statfs.h sys/statvfs.h libutil.h

@@ -228,19 +220,23 @@ cc-check-includes link.h machine/endian.h osreldate.h readpassphrase.h \
cc-check-includes dirent.h sys/sockio.h

#endian stuff
-
foreach header [list endian.h sys/endian.h] {
-
	if {[cc-check-includes $header]} {
-
		cc-with [list -includes $header] {
-
			cc-check-decls be16dec be16enc be32dec be32enc be64dec be64enc \
-
				le16dec le16enc le32dec le32enc le64dec le64enc
+
foreach fct [list be16dec be16enc be32dec be32enc be64dec be64enc le16dec le16enc le32dec le32enc le64dec le64enc] {
+
	foreach header [list endian.h sys/endian.h machine/endian.h] {
+
		if {[cc-check-includes $header]} {
+
			cc-with [list -includes $header] {
+
				if {[cc-check-decls $fct]} {
+
					break
+
				}
+
			}
		}
	}
}

if {[string match *-darwin* [get-define host]]} {
-
	define libmachista
+
	define pkgos_darwin
	define waflags ""
	define nowaflags ""
+
	define libelf-internal
} else {
# libelf
	define waflags "-Wl,-whole-archive"
@@ -394,7 +390,7 @@ make-template Makefile.autosetup Makefile
foreach dir [list external/blake2 external/picosat \
	external/linenoise external/sqlite \
	external compat libpkg libpkg/repo libpkg/repo/binary src \
-
	external/libucl external/libelf external/libmachista tests docs \
+
	external/libucl external/libelf tests docs \
	external/liblua external/yxml scripts external/libcurl external/libder \
	external/libecc] {
	make-template $dir/Makefile.autosetup $dir/Makefile
modified external/Makefile.autosetup
@@ -1,8 +1,5 @@
include @builddir@/mk/defs.mk
DIRS=	blake2 picosat linenoise sqlite libucl liblua yxml libder libecc
-
@if libmachista
-
DIRS+=	libmachista
-
@endif
@if libelf-internal
DIRS+=	libelf
@endif
modified external/libelf/_libelf_config.h
@@ -36,6 +36,10 @@
#define	LIBELF_ARCH		EM_386
#define	LIBELF_BYTEORDER	ELFDATA2LSB
#define	LIBELF_CLASS		ELFCLASS32
+
#elif   defined(__aarch64__)
+
#define LIBELF_ARCH             EM_AARCH64
+
#define LIBELF_BYTEORDER        ELFDATA2LSB
+
#define LIBELF_CLASS            ELFCLASS64
#endif

#endif	/* __DragonFly__ */
deleted external/libmachista/LICENSE
@@ -1,52 +0,0 @@
-
Copyright (c) 2011 Clemens Lang <cal@macports.org>
-
Copyright (c) 2011 - 2014 Landon Fuller <landonf@macports.org>
-
Copyright (c) 2004 - 2014, The MacPorts Project.
-
Copyright (c) 2002 - 2003, Apple Inc.
-
All rights reserved.
-

-
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.
-
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.
-
3. Neither the name of Apple Inc., The MacPorts Project nor the
-
   names of its contributors may be used to endorse or promote products
-
   derived from this software without specific prior written permission.
-

-
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
-

-
hashmap.c is subject to the following license:
-

-
Copyright (c) 2011 Christoph Erhardt. All rights reserved.
-

-
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.
-
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 CHRISTOPH ERHARDT ``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 CHRISTOPH ERHARDT OR CONTRIBUTORS 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.
deleted external/libmachista/Makefile.autosetup
@@ -1,8 +0,0 @@
-
include @builddir@/mk/defs.mk
-
LIB=	machista
-
SRCS=	libmachista.c \
-
	hashmap.c
-

-
VPATH=	$(top_srcdir)/external/libmachista
-

-
include $(MK)/static-lib.mk
deleted external/libmachista/hashmap.c
@@ -1,295 +0,0 @@
-
/* vim:expandtab:tw=80:ts=2:sts=2:sw=2
-
 */
-
/*-
-
 * Copyright (c) 2011 Christoph Erhardt. All rights reserved.
-
 *
-
 * 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.
-
 * 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 CHRISTOPH ERHARDT ``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 CHRISTOPH ERHARDT OR CONTRIBUTORS 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.
-
 */
-
/*-
-
 * Modified by Clemens Lang to accept values of arbitrary type.
-
 */
-

-

-
#ifndef _BSD_SOURCE
-
  #define _BSD_SOURCE
-
#endif
-
#ifndef _CRT_NONSTDC_NO_DEPRECATE
-
  #define _CRT_NONSTDC_NO_DEPRECATE
-
#endif
-

-
#include "hashmap.h"
-
#include <limits.h>
-
#include <stdint.h>
-
#include <string.h>
-

-

-
static const size_t INITIAL_CAPACITY = 16; /* Must be a power of 2 */
-
static const size_t MAXIMUM_CAPACITY = (1U << 31);
-
static const float  LOAD_FACTOR      = 0.75;
-

-

-
typedef struct HashMapEntry {
-
  char                *key;
-
  const void          *value;
-
  struct HashMapEntry *next;
-
  uint32_t             hash;
-
} HashMapEntry;
-

-
struct HashMap {
-
  HashMapEntry **table;
-
  size_t         capacity;
-
  size_t         size;
-
  size_t         threshold;
-
  void         (*freeFunc)(const void *);
-
};
-

-

-
static void setTable(HashMap *map, HashMapEntry **table, size_t capacity) {
-
  map->table     = table;
-
  map->capacity  = capacity;
-
  map->threshold = (size_t) (capacity * LOAD_FACTOR);
-
}
-

-

-
static uint32_t doHash(const char key[]) {
-
  size_t   length;
-
  size_t   i;
-
  uint32_t h = 0;
-
  if (key == NULL)
-
    return 0;
-
  length = strlen(key);
-
  for (i = 0; i < length; ++i) {
-
    h = (31 * h) + key[i];
-
  }
-
  h ^= (h >> 20) ^ (h >> 12);
-
  return h ^ (h >> 7) ^ (h >> 4);
-
}
-

-

-
static size_t indexFor(uint32_t hash, size_t length) {
-
  return hash & (length - 1);
-
}
-

-

-
static int isHit(HashMapEntry *e, const char key[], uint32_t hash) {
-
  return (e->hash == hash
-
          && (e->key == key || (key != NULL && strcmp(e->key, key) == 0)));
-
}
-

-

-
static void copyOrFree(void (*freeFunc)(const void *),
-
                       const void *value, const void **valPtr) {
-
  if (valPtr != NULL)
-
    *valPtr = value;
-
  else
-
    freeFunc(value);
-
}
-

-

-
static int updateValue(HashMap *map, HashMapEntry *e, const void *newVal,
-
                       const void **oldValPtr) {
-
  copyOrFree(map->freeFunc, e->value, oldValPtr);
-
  e->value = newVal;
-
  return 1;
-
}
-

-

-
/* Creates a hash map. */
-
HashMap *hashMapCreate(void (*freeFunc)(const void *)) {
-
  HashMapEntry **table;
-
  HashMap       *map = malloc(sizeof(*map));
-
  if (map == NULL)
-
    return NULL;
-
  table = calloc(INITIAL_CAPACITY, sizeof(*map->table));
-
  if (table == NULL) {
-
    free(map);
-
    return NULL;
-
  }
-
  setTable(map, table, INITIAL_CAPACITY);
-
  map->size = 0;
-
  map->freeFunc = freeFunc;
-
  return map;
-
}
-

-

-
/* Inserts a key-value pair into a hash map. */
-
int hashMapPut(HashMap *map, const char key[], const void * const value,
-
               const void **oldValPtr) {
-

-
  HashMapEntry  *e;
-
  size_t         newCapacity;
-
  HashMapEntry **newTable;
-
  size_t         i;
-

-
  /* If an entry with the same key exists, update it */
-
  uint32_t hash  = doHash(key);
-
  size_t   index = indexFor(hash, map->capacity);
-
  for (e = map->table[index]; e != NULL; e = e->next) {
-
    if (isHit(e, key, hash) == 0)
-
      continue;
-
    return updateValue(map, e, value, oldValPtr);
-
  }
-

-
  /* Create a new entry */
-
  e = calloc(1, sizeof(HashMapEntry)); /* Must be zeroed */
-
  if (e == NULL)
-
    return 0;
-

-
  /* Copy key and value into the entry */
-
  if (key != NULL) {
-
    e->key = strdup(key);
-
    if (e->key == NULL) {
-
      free(e);
-
      return 0;
-
    }
-
  }
-
  if (updateValue(map, e, value, oldValPtr) == 0) {
-
    free(e->key);
-
    free(e);
-
    return 0;
-
  }
-

-
  /* Insert entry into the table */
-
  e->hash = hash;
-
  e->next = map->table[index];
-
  map->table[index] = e;
-
  if (map->size++ < map->threshold)
-
    return 1;
-

-
  /* If the size exceeds the threshold, double the table's capacity */
-
  newCapacity = 2 * map->capacity;
-
  if (map->capacity == MAXIMUM_CAPACITY) {
-
    map->threshold = UINT_MAX;
-
    return 1;
-
  }
-
  newTable = calloc(newCapacity, sizeof(*newTable));
-
  if (newTable == NULL)
-
    return 0;
-

-
  /* Copy entries from the old table into the new one */
-
  for (i = 0; i < map->capacity; ++i) {
-
    HashMapEntry *next;
-
    for (e = map->table[i]; e != NULL; e = next) {
-
      index   = indexFor(e->hash, newCapacity);
-
      next    = e->next;
-
      e->next = newTable[index];
-
      newTable[index] = e;
-
    }
-
  }
-

-
  /* Release the old table and set the new one */
-
  free(map->table);
-
  setTable(map, newTable, newCapacity);
-
  return 1;
-
}
-

-

-
/* Performs a hash map lookup. */
-
const void *hashMapGet(HashMap *map, const char key[]) {
-
  HashMapEntry *e;
-
  uint32_t      hash  = doHash(key);
-
  size_t        index = indexFor(hash, map->capacity);
-
  for (e = map->table[index]; e != NULL; e = e->next) {
-
    if (isHit(e, key, hash))
-
      return e->value;
-
  }
-
  return NULL;
-
}
-

-

-
/* Checks whether a hash map contains an entry with a certain key. */
-
int hashMapContainsKey(HashMap *map, const char key[]) {
-
  HashMapEntry *e;
-
  uint32_t      hash  = doHash(key);
-
  size_t        index = indexFor(hash, map->capacity);
-
  for (e = map->table[index]; e != NULL; e = e->next) {
-
    if (isHit(e, key, hash))
-
      return 1;
-
  }
-
  return 0;
-
}
-

-

-
/* Removes a key-value pair from a hash map. */
-
void hashMapRemove(HashMap *map, const char key[], const void **valPtr) {
-
  uint32_t      hash  = doHash(key);
-
  size_t        index = indexFor(hash, map->capacity);
-
  HashMapEntry *prev  = map->table[index];
-
  HashMapEntry *e     = prev;
-
  while (e != NULL) {
-
    HashMapEntry *next = e->next;
-
    if (isHit(e, key, hash)) {
-
      map->size--;
-
      if (prev == e)
-
        map->table[index] = next;
-
      else
-
        prev->next = next;
-
      break;
-
    }
-
    prev = e;
-
    e    = next;
-
  }
-
  if (e == NULL) {
-
    copyOrFree(map->freeFunc, NULL, valPtr);
-
    return;
-
  }
-
  free(e->key);
-
  copyOrFree(map->freeFunc, e->value, valPtr);
-
  free(e);
-
}
-

-

-
/* Returns the number of elements stored in a hash map. */
-
size_t hashMapSize(const HashMap *map) {
-
  return map->size;
-
}
-

-

-
/* Checks whether a hash map is empty. */
-
int hashMapIsEmpty(const HashMap *map) {
-
  return (map->size == 0);
-
}
-

-

-
/* Removes all entries from a hash map. */
-
void hashMapClear(HashMap *map) {
-
  size_t i;
-
  for (i = 0; i < map->capacity; ++i) {
-
    HashMapEntry *e;
-
    HashMapEntry *next;
-
    for (e = map->table[i]; e != NULL; e = next) {
-
      free(e->key);
-
      map->freeFunc(e->value);
-
      next = e->next;
-
      free(e);
-
    }
-
    map->table[i] = NULL;
-
  }
-
}
-

-

-
/* Destroys a hash map. */
-
void hashMapDestroy(HashMap *map) {
-
  if (map == NULL)
-
    return;
-
  hashMapClear(map);
-
  free(map->table);
-
  free(map);
-
}
deleted external/libmachista/hashmap.h
@@ -1,135 +0,0 @@
-
/* vim:tw=80:expandtab
-
 */
-
/**
-
 * @file  hashmap.h
-
 * @brief A hash map implementation in C.
-
 * @author Christoph Erhardt <erhardt@cs.fau.de>
-
 */
-

-
/*-
-
 * Copyright (c) 2011 Christoph Erhardt. All rights reserved.
-
 *
-
 * 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.
-
 * 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 CHRISTOPH ERHARDT ``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 CHRISTOPH ERHARDT OR CONTRIBUTORS 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.
-
 */
-
/*-
-
 * Modified by Clemens Lang to accept values of arbitrary type.
-
 */
-

-

-
#ifndef HASHMAP_H
-
#define HASHMAP_H
-

-

-
#include <stdlib.h>
-

-

-
/** Hash map type. */
-
typedef struct HashMap HashMap;
-

-

-
/**
-
 * @brief Creates a hash map.
-
 *
-
 * The keys and values managed in the map can be arbitrary C strings.
-
 * @param freeFunc Function to call in order to free a stored value
-
 * @return Pointer to the newly created hash map, or @c NULL on error.
-
 */
-
HashMap *hashMapCreate(void (*freeFunc)(const void *));
-

-
/**
-
 * @brief Inserts a key-value pair into a hash map.
-
 *
-
 * Both key and value are copied internally, so the caller can reuse the
-
 * original variables.
-
 * If oldValPtr is @c NULL, the previously stored value corresponding to the key
-
 * is freed. Otherwise it is written into @c *valPtr and the caller is
-
 * responsible for freeing it.
-
 * @param map       Hash map.
-
 * @param key       Key.
-
 * @param value     Value.
-
 * @param oldValPtr Output parameter receiving the previously stored value
-
 *                  corresponding to the key (@c NULL if no mapping existed
-
 *                  before).
-
 * @return Nonzero on success, 0 on error.
-
 */
-
int hashMapPut(HashMap *map, const char key[], const void * const value,
-
               const void **oldValPtr);
-

-
/**
-
 * @brief Performs a hash map lookup.
-
 *
-
 * The returned value must not be freed or otherwise manipulated by the caller.
-
 * @param map Hash map.
-
 * @param key Key.
-
 * @return Value corresponding to the key on success, @c NULL if no matching
-
 *         entry was found.
-
 */
-
const void *hashMapGet(HashMap *map, const char key[]);
-

-
/**
-
 * @brief Checks whether a hash map contains an entry with a certain key.
-
 * @param map Hash map.
-
 * @param key Key.
-
 * @return Nonzero if the map contains an entry with the given key, 0 if it does
-
 *         not.
-
 */
-
int hashMapContainsKey(HashMap *map, const char key[]);
-

-
/**
-
 * @brief Removes a key-value pair from a hash map and frees the stored key.
-
 *
-
 * If @c valPtr is @c NULL, the internally stored value corresponding to the key
-
 * is freed. Otherwise it is written into @c *valPtr and the caller is
-
 * responsible for freeing it.
-
 * @param map    Hash map.
-
 * @param key    Key.
-
 * @param valPtr Output parameter receiving the internally stored value
-
 *               corresponding to the key.
-
 */
-
void hashMapRemove(HashMap *map, const char key[], const void **valPtr);
-

-
/**
-
 * @brief Returns the number of elements stored in a hash map.
-
 * @param map Hash map.
-
 * @return Number of elements stored in the map.
-
 */
-
size_t hashMapSize(const HashMap *map);
-

-
/**
-
 * @brief Checks whether a hash map is empty.
-
 * @param map Hash map.
-
 * @return Nonzero if the map contains no entries, 0 otherwise.
-
 */
-
int hashMapIsEmpty(const HashMap *map);
-

-
/**
-
 * @brief Removes all entries from a hash map.
-
 * @param map Hash map.
-
 */
-
void hashMapClear(HashMap *map);
-

-
/**
-
 * @brief Destroys a hash map.
-
 * @param map Hash map to be destroyed.
-
 */
-
void hashMapDestroy(HashMap *map);
-

-

-
#endif /* HASHMAP_H */
deleted external/libmachista/libmachista.c
@@ -1,569 +0,0 @@
-
/*
-
 * -*- coding: utf-8; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=c:et:sw=4:ts=4:sts=4:tw=100
-
 * libmachista.c
-
 * $Id: libmachista.c 120067 2014-05-14 22:18:53Z cal@macports.org $
-
 *
-
 * Copyright (c) 2011 The MacPorts Project
-
 * Copyright (c) 2011 Landon Fuller <landonf@macports.org>
-
 * Copyright (c) 2011 Clemens Lang <cal@macports.org>
-
 * All rights reserved.
-
 *
-
 * 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.
-
 * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
-
 */
-

-
#ifdef HAVE_CONFIG_H
-
#include <pkg_config.h>
-
#endif
-

-
/* required for asprintf(3) on OS X */
-
#define _DARWIN_C_SOURCE
-
/* required for asprintf(3) on Linux */
-
#define _GNU_SOURCE
-

-
#include <stdbool.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-

-
#include <fcntl.h>
-
#include <sys/mman.h>
-
#include <sys/stat.h>
-
#include <unistd.h>
-

-
#include <err.h>
-
#include <string.h>
-
#include <strings.h>
-

-
#ifdef __MACH__
-
#include <mach-o/fat.h>
-
#include <mach-o/loader.h>
-

-
#include <libkern/OSAtomic.h>
-
#endif
-

-
#include "libmachista.h"
-
#include "hashmap.h"
-

-
#ifdef __MACH__
-
/* Tiger compatibility */
-
#ifndef LC_RPATH
-
#define LC_RPATH       (0x1c | LC_REQ_DYLD)    /* runpath additions */
-
/*
-
 * The rpath_command contains a path which at runtime should be added to
-
 * the current run path used to find @rpath prefixed dylibs.
-
 */
-
struct rpath_command {
-
    uint32_t     cmd;       /* LC_RPATH */
-
    uint32_t     cmdsize;   /* includes string */
-
    union lc_str path;      /* path to add to run path */
-
};
-
#endif
-
#ifndef LC_REEXPORT_DYLIB
-
#define LC_REEXPORT_DYLIB (0x1f | LC_REQ_DYLD) /* load and re-export dylib */
-
#endif
-
#endif /* __MACH__ */
-

-
typedef struct macho_input {
-
    const void *data;
-
    size_t length;
-
} macho_input_t;
-

-
/* This is macho_handle_t. The corresponding typedef is in the header */
-
struct macho_handle {
-
    HashMap *result_map;
-
};
-

-
#ifdef __MACH__
-
/* Verify that the given range is within bounds. */
-
static const void *macho_read (macho_input_t *input, const void *address, size_t length) {
-
    if ((((uint8_t *) address) - ((uint8_t *) input->data)) + length > input->length) {
-
       // warnx("Short read parsing Mach-O input");
-
        return NULL;
-
    }
-

-
    return address;
-
}
-

-
/* Verify that address + offset + length is within bounds. */
-
static const void *macho_offset (macho_input_t *input, const void *address, size_t offset, size_t length) {
-
    void *result = ((uint8_t *) address) + offset;
-
    return macho_read(input, result, length);
-
}
-
#endif
-

-
/* return a human readable formatted version number. the result must be free()'d. */
-
char *macho_format_dylib_version (uint32_t version) {
-
    char *result;
-
    asprintf(&result, "%"PRIu32".%"PRIu32".%"PRIu32, (version >> 16) & 0xFFFF, (version >> 8) & 0xFF, version & 0xFF);
-
    return result;
-
}
-

-
#ifdef __MACH__
-
const char *macho_get_arch_name (cpu_type_t cputype) {
-
    const NXArchInfo *archInfo = NXGetArchInfoFromCpuType(cputype, CPU_SUBTYPE_MULTIPLE);	
-
    if (!archInfo) {
-
        return NULL;
-
    }
-
    return archInfo->name;
-
#else
-
const char *macho_get_arch_name (cpu_type_t cputype UNUSED) {
-
    return NULL;
-
#endif
-
}
-

-
#ifdef __MACH__
-
/* Some byteswap wrappers */
-
static uint32_t macho_swap32 (uint32_t input) {
-
    return OSSwapInt32(input);
-
}
-

-
static uint32_t macho_nswap32(uint32_t input) {
-
    return input;
-
}
-

-
/* Creates a new macho_t.
-
 * Returns NULL on failure or a pointer to a 0-initialized macho_t on success */
-
static macho_t *create_macho_t (void) {
-
    macho_t *mt = malloc(sizeof(macho_t));
-
    if (mt == NULL)
-
        return NULL;
-

-
    memset(mt, 0, sizeof(macho_t));
-
    return mt;
-
}
-

-
/* Creates a new macho_arch_t.
-
 * Returns NULL on failure or a pointer to a 0-initialized macho_arch_t on success */
-
static macho_arch_t *create_macho_arch_t (void) {
-
    macho_arch_t *mat = malloc(sizeof(macho_arch_t));
-
    if (mat == NULL)
-
        return NULL;
-
    
-
    memset(mat, 0, sizeof(macho_arch_t));
-
    return mat;
-
}
-

-
/* Creates a new macho_loadcmd_t.
-
 * Returns NULL on failure or a pointer to a 0-initialized macho_loadcmd_t on success */
-
static macho_loadcmd_t *create_macho_loadcmd_t (void) {
-
    macho_loadcmd_t *mlt = malloc(sizeof(macho_loadcmd_t));
-
    if (mlt == NULL)
-
        return NULL;
-

-
    memset(mlt, 0, sizeof(macho_loadcmd_t));
-
    return mlt;
-
}
-
#endif
-

-
/* Frees a previously allocated macho_loadcmd_t and all it's associated resources */
-
static void free_macho_loadcmd_t (macho_loadcmd_t *mlt) {
-
    if (mlt == NULL)
-
        return;
-

-
    free(mlt->mlt_install_name);
-
    free(mlt);
-
}
-

-
/* Frees a previously allocated macho_arch_t and all it's associated resources */
-
static void free_macho_arch_t (macho_arch_t *mat) {
-
    if (mat == NULL)
-
        return;
-

-
    macho_loadcmd_t *current = mat->mat_loadcmds;
-
    while (current != NULL) {
-
        macho_loadcmd_t *freeme = current;
-
        current = current->next;
-
        free_macho_loadcmd_t(freeme);
-
    }
-

-
    free(mat->mat_install_name);
-
    free(mat->mat_rpath);
-
    free(mat);
-
}
-

-
/* Frees a previously allocated macho_t and all it's associated resources */
-
static void free_macho_t (macho_t *mt) {
-
    if (mt == NULL)
-
        return;
-

-
    macho_arch_t *current = mt->mt_archs;
-
    while (current != NULL) {
-
        macho_arch_t *freeme = current;
-
        current = current->next;
-
        free_macho_arch_t(freeme);
-
    }
-

-
    free(mt);
-
}
-

-
#ifdef __MACH__
-
/* Creates a new element in the architecture list of a macho_t (mt_archs), increases the counter of
-
 * architectures (mt_arch_count) and returns a pointer to the newly allocated element or NULL on
-
 * error */
-
static macho_arch_t *macho_archlist_append (macho_t *mt) {
-
    macho_arch_t *old_head = mt->mt_archs;
-

-
    macho_arch_t *new_head = create_macho_arch_t();
-
    if (new_head == NULL)
-
        return NULL;
-
    new_head->next = old_head;
-
    mt->mt_archs = new_head;
-

-
    return mt->mt_archs;
-
}
-

-
/* Creates a new element in the load command list of a macho_arch_t (mat_loadcmds), increases the
-
 * counter of load commands (mat_loadcmd_count) and returns a pointer to the newly allocated element
-
 * or NULL on error */
-
static macho_loadcmd_t *macho_loadcmdlist_append (macho_arch_t *mat) {
-
    macho_loadcmd_t *old_head = mat->mat_loadcmds;
-

-
    macho_loadcmd_t *new_head = create_macho_loadcmd_t();
-
    if (new_head == NULL)
-
        return NULL;
-
    new_head->next = old_head;
-
    mat->mat_loadcmds = new_head;
-

-
    return mat->mat_loadcmds;
-
}
-
#endif
-

-
/* Parse a Mach-O header */
-
#ifdef __MACH__
-
static int parse_macho (macho_t *mt, macho_input_t *input) {
-
    /* Read the file type. */
-
    const uint32_t *magic = macho_read(input, input->data, sizeof(uint32_t));
-
    if (magic == NULL)
-
        return MACHO_ERANGE;
-

-
    /* Parse the Mach-O header */
-
    bool universal = false;
-
    uint32_t (*swap32)(uint32_t) = macho_nswap32;
-

-
    const struct mach_header *header;
-
    const struct mach_header_64 *header64;
-
    size_t header_size;
-
    const struct fat_header *fat_header;
-

-
    macho_arch_t *mat = NULL;
-
    switch (*magic) {
-
        case MH_CIGAM:
-
            swap32 = macho_swap32;
-
            // Fall-through
-

-
        case MH_MAGIC:
-

-
            header_size = sizeof(*header);
-
            header = macho_read(input, input->data, header_size);
-
            if (header == NULL)
-
                return MACHO_ERANGE;
-
            mat = macho_archlist_append(mt);
-
            if (mat == NULL)
-
                return MACHO_EMEM;
-

-
            /* 32-bit Mach-O */
-
            mat->mat_cputype = swap32(header->cputype);
-
            mat->mat_cpusubtype = swap32(header->cpusubtype);
-
            break;
-

-

-
        case MH_CIGAM_64:
-
            swap32 = macho_swap32;
-
            // Fall-through
-

-
        case MH_MAGIC_64:
-
            header_size = sizeof(*header64);
-
            header64 = macho_read(input, input->data, sizeof(*header64));
-
            if (header64 == NULL)
-
                return MACHO_ERANGE;
-
            mat = macho_archlist_append(mt);
-
            if (mat == NULL)
-
                return MACHO_EMEM;
-

-
            /* The 64-bit header is a direct superset of the 32-bit header */
-
            header = (struct mach_header *) header64;
-

-
            /* 64-bit Macho-O */
-
            mat->mat_cputype = swap32(header->cputype);
-
            mat->mat_cpusubtype = swap32(header->cpusubtype);
-
            break;
-

-
        case FAT_CIGAM:
-
        case FAT_MAGIC:
-
            fat_header = macho_read(input, input->data, sizeof(*fat_header));
-
            universal = true;
-
            /* Universal binary */
-
            break;
-

-
        default:
-
            /* Unknown binary type */
-
            //warnx("Unknown Mach-O magic: 0x%" PRIx32 "", *magic);
-
            return MACHO_EMAGIC;
-
    }
-

-
    /* Parse universal file. */
-
    if (universal) {
-
        uint32_t nfat = OSSwapBigToHostInt32(fat_header->nfat_arch);
-
        const struct fat_arch *archs = macho_offset(input, fat_header, sizeof(struct fat_header), sizeof(struct fat_arch));
-
        if (archs == NULL)
-
            return MACHO_ERANGE;
-

-
        for (uint32_t i = 0; i < nfat; i++) { // foreach architecture
-
            const struct fat_arch *arch = macho_read(input, archs + i, sizeof(struct fat_arch));
-
            if (arch == NULL)
-
                return MACHO_ERANGE;
-

-
            /* Fetch a pointer to the architecture's Mach-O header. */
-
            macho_input_t arch_input;
-
            arch_input.length = OSSwapBigToHostInt32(arch->size);
-
            arch_input.data = macho_offset(input, input->data, OSSwapBigToHostInt32(arch->offset), arch_input.length);
-
            if (arch_input.data == NULL)
-
                return MACHO_ERANGE;
-

-
            /* Parse the architecture's Mach-O header */
-
            int res = parse_macho(mt, &arch_input);
-
            if (res != MACHO_SUCCESS)
-
                return res;
-
        }
-

-
        return MACHO_SUCCESS;
-
    }
-

-
    /* Copy the architecture */
-
    mat->mat_cputype = swap32(header->cputype);
-
    mat->mat_cpusubtype = swap32(header->cpusubtype);
-

-
    /* Parse the Mach-O load commands */
-
    uint32_t ncmds = swap32(header->ncmds);
-

-
    /* Setup to jump over the header on the first pass through instead of the previous command */
-
    const struct load_command *cmd = (void *)header;
-
    uint32_t cmdsize = header_size;
-

-
    /* Iterate over the load commands */
-
    for (uint32_t i = 0; i < ncmds; i++) {
-
        /* Load the next command */
-
        cmd = macho_offset(input, cmd, cmdsize, sizeof(struct load_command));
-
        if (cmd == NULL)
-
            return MACHO_ERANGE;
-

-
        /* Load the full command */
-
        cmdsize = swap32(cmd->cmdsize);
-
        cmd = macho_read(input, cmd, cmdsize);
-
        if (cmd == NULL)
-
            return MACHO_ERANGE;
-

-
        /* Handle known types */
-
        uint32_t cmd_type = swap32(cmd->cmd);
-
        switch (cmd_type) {
-
            case LC_RPATH: {
-
                /* Copy the rpath */
-
                if (cmdsize < sizeof(struct rpath_command)) {
-
                    //warnx("Incorrect cmd size");
-
                    return MACHO_ERANGE;
-
                }
-

-
                size_t pathlen = cmdsize - sizeof(struct rpath_command);
-
                const void *pathptr = macho_offset(input, cmd, sizeof(struct rpath_command), pathlen);
-
                if (pathptr == NULL)
-
                    return MACHO_ERANGE;
-

-
                mat->mat_rpath = malloc(pathlen);
-
                if (mat->mat_rpath == NULL)
-
                    return MACHO_EMEM;
-
                strlcpy(mat->mat_rpath, pathptr, pathlen);
-
                break;
-
            }
-

-
            case LC_ID_DYLIB:
-
            case LC_LOAD_WEAK_DYLIB:
-
            case LC_REEXPORT_DYLIB:
-
            case LC_LOAD_DYLIB: {
-
                const struct dylib_command *dylib_cmd = (const struct dylib_command *) cmd;
-

-
                /* Extract the install name */
-
                if (cmdsize < sizeof(struct dylib_command)) {
-
                    //warnx("Incorrect name size");
-
                    return MACHO_ERANGE;
-
                }
-

-
                size_t namelen = cmdsize - sizeof(struct dylib_command);
-
                const void *nameptr = macho_offset(input, cmd, sizeof(struct dylib_command), namelen);
-
                if (nameptr == NULL)
-
                    return MACHO_ERANGE;
-

-
                if (cmd_type == LC_ID_DYLIB) {
-
                    /* Copy install name */
-
                    mat->mat_install_name = malloc(namelen);
-
                    if (mat->mat_install_name == NULL)
-
                        return MACHO_EMEM;
-
                    strlcpy(mat->mat_install_name, nameptr, namelen);
-

-
                    /* Copy version numbers (raw, for easier comparison) */
-
                    mat->mat_version = swap32(dylib_cmd->dylib.current_version);
-
                    mat->mat_comp_version = swap32(dylib_cmd->dylib.compatibility_version);
-
                } else {
-
                    /* Append loadcmd to list of loadcommands */
-
                    macho_loadcmd_t *mlt = macho_loadcmdlist_append(mat);
-
                    if (mlt == NULL)
-
                        return MACHO_EMEM;
-

-
                    /* Copy install name */
-
                    mlt->mlt_install_name = malloc(namelen);
-
                    if (mlt->mlt_install_name == NULL)
-
                        return MACHO_EMEM;
-
                    strlcpy(mlt->mlt_install_name, nameptr, namelen);
-

-
                    /* Copy version numbers (raw, for easier comparison) */
-
                    mlt->mlt_version = swap32(dylib_cmd->dylib.current_version);
-
                    mlt->mlt_comp_version = swap32(dylib_cmd->dylib.compatibility_version);
-

-
                    /* Copy command type */
-
                    mlt->mlt_type = cmd_type;
-
                }
-
                break;
-
            }
-

-
            default:
-
                break;
-
        }
-
    }
-

-
    return MACHO_SUCCESS;
-
}
-
#endif
-

-
/* Parse a (possible Mach-O) file. For a more detailed description, see the header */
-
#ifdef __MACH__
-
int macho_parse_file(macho_handle_t *handle, const char *filepath, const macho_t **res) {
-
    int fd;
-
    struct stat st;
-
    void *data;
-
    macho_input_t input_file;
-

-
    /* Check hashmap for precomputed results */
-
    const macho_t *cached_res = hashMapGet(handle->result_map, filepath);
-
    if (cached_res != NULL) {
-
        *res = cached_res;
-
        return MACHO_SUCCESS;
-
    }
-

-
    
-
    /* Open input file */
-
    if ((fd = open(filepath, O_RDONLY)) < 0) {
-
        return MACHO_EFILE;
-
    }
-

-
    /* Get file length */
-
    if (fstat(fd, &st) != 0) {
-
        close(fd);
-
        return MACHO_EFILE;
-
    }
-

-
    /* Map file into address space */
-
    if ((data = mmap(NULL, st.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0)) == MAP_FAILED) {
-
        close(fd);
-
        return MACHO_EMMAP;
-
    }
-

-
    /* Parse file */
-
    input_file.data = data;
-
    input_file.length = st.st_size;
-

-
    *res = create_macho_t();
-
    if (*res == NULL)
-
        return MACHO_EMEM;
-

-
    /* The output parameter *res should be read-only for the user of the lib only, but writable for
-
     * us */
-
    int ret = parse_macho((macho_t *)*res, &input_file);
-
    if (ret == MACHO_SUCCESS) {
-
        /* Insert into hashmap for caching */
-
        if (0 == hashMapPut(handle->result_map, filepath, *res, NULL)) {
-
            free_macho_t((macho_t *)*res);
-
            *res = NULL;
-
            ret = MACHO_EMEM;
-
        }
-
    } else {
-
        /* An error occured, free mt */
-
        free_macho_t((macho_t *)*res);
-
        *res = NULL;
-
    }
-

-
    /* Cleanup */
-
    munmap(data, st.st_size);
-
    close(fd);
-

-
    return ret;
-
#else
-
int macho_parse_file(macho_handle_t *handle UNUSED, const char *filepath UNUSED, const macho_t **res UNUSED) {
-
    return 0;
-
#endif
-
}
-

-
/* Create a new macho_handle_t. More information on this function is available in the header */
-
macho_handle_t *macho_create_handle (void) {
-
    macho_handle_t *mht = malloc(sizeof(macho_handle_t));
-
    if (mht == NULL)
-
        return NULL;
-
    mht->result_map = hashMapCreate((void (*)(const void *))free_macho_t);
-
    if (mht->result_map == NULL) {
-
        free(mht);
-
        return NULL;
-
    }
-
    return mht;
-
}
-

-
/* Release a macho_handle_t. For more documentation, see the header */
-
void macho_destroy_handle(macho_handle_t *handle) {
-
    if (handle == NULL)
-
        return;
-
    
-
    hashMapDestroy(handle->result_map);
-

-
    free(handle);
-
}
-

-
/* Returns string representation of the MACHO_* error code constants */
-
const char *macho_strerror(int err) {
-
    int num;
-
#ifdef HAVE_FLS
-
    num = fls(err);
-
#else
-
    /* Tiger compatibility, see #42186 */
-
    num = 0;
-
    while (err > 0) {
-
        err >>= 1;
-
        num++;
-
    }
-
#endif
-

-
    static char *errors[] = {
-
        /* 0x00 */ "Success",
-
        /* 0x01 */ "Error opening or reading file",
-
        /* 0x02 */ "Error mapping file into memory",
-
        /* 0x04 */ "Error allocating memory",
-
        /* 0x08 */ "Premature end of data, possibly corrupt file",
-
        /* 0x10 */ "Not a Mach-O file",
-
    };
-
    return errors[num];
-
}
-

deleted external/libmachista/libmachista.h
@@ -1,150 +0,0 @@
-
/*
-
 * -*- coding: utf-8; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- vim:fenc=utf-8:filetype=c:et:sw=4:ts=4:sts=4:tw=100
-
 * libmachista.h
-
 * $Id$
-
 *
-
 * Copyright (c) 2011 The MacPorts Project
-
 * Copyright (c) 2011 Clemens Lang <cal@macports.org>
-
 * All rights reserved.
-
 *
-
 * 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.
-
 * 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 COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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.
-
 */
-

-
#ifndef __LIBMACHISTA_H__
-
#define __LIBMACHISTA_H__
-

-
/*
-
 * This is a library to parse Mach-O files in single architecture _and_ universal variant and return
-
 * a list of architectures and their load commands and properties
-
 * The name a pun: machista is the spanish translation of "macho".
-
 */
-

-
#ifdef __MACH__
-
#include <mach-o/arch.h>
-
#else
-
typedef int cpu_type_t;
-
#endif
-
#include <inttypes.h>
-

-
#define MACHO_SUCCESS   (0x00)
-
#define MACHO_EFILE     (0x01)
-
#define MACHO_EMMAP     (0x02)
-
#define MACHO_EMEM      (0x04)
-
#define MACHO_ERANGE    (0x08)
-
#define MACHO_EMAGIC    (0x10)
-

-
/* Blind structure; this essentially contains the hash map used to cache
-
 * entries, but users should not have to look into this structure. struct
-
 * macho_handle is defined in libmachista.c */
-
typedef struct macho_handle macho_handle_t;
-

-
/** Structure describing a load command within a Mach-O file */
-
typedef struct macho_loadcmd {
-
    char *mlt_install_name;         /* install name of the library to be loaded by this load command */
-
    uint32_t mlt_type;              /* type of the load command; see mach-o/loader.h for possible
-
                                       values */
-
    uint32_t mlt_comp_version;      /* compatibility version of the file to be loaded by this
-
                                       command (at build time of this file) */
-
    uint32_t mlt_version;           /* version of the library to be loaded by this command (at build
-
                                       time of this file) */
-
    struct macho_loadcmd *next;     /* pointer to the next entry in the linked list of
-
                                       macho_loadcmd_t's (NULL if there's no further element) */
-
} macho_loadcmd_t;
-

-
/** Stucture describing an architecture within a Mach-O file */
-
typedef struct macho_arch {
-
    char *mat_install_name;         /* install name of the library or NULL if none */
-
    char *mat_rpath;                /* rpath of the binary of NULL if none */
-
    cpu_type_t mat_cputype;         /* cpu_type_t describing the CPU this part of the binary is
-
                                       intended for */
-
    cpu_type_t mat_cpusubtype;      /* cpu_subtype_t describing the CPU subtype this part of the
-
                                       binary is intended for */
-
    uint32_t mat_comp_version;      /* compatibility version of this part of the binary */
-
    uint32_t mat_version;           /* current version of this part of the binary */
-
    macho_loadcmd_t *mat_loadcmds;  /* array of macho_loadcmd_t's describing the different load
-
                                       commands */
-
    struct macho_arch *next;        /* pointer to the next entry in the linked list of
-
                                       macho_arch_t's (NULL if there's no further element) */
-
} macho_arch_t;
-

-
/** Structure describing a Mach-O file */
-
typedef struct macho {
-
    macho_arch_t *mt_archs;         /* linked list of macho_arch_t's describing the different
-
                                       architectures */
-
} macho_t;
-

-
/**
-
 * Creates and returns a macho_handle_t to be passed to subsequent calls to macho_parse_file. No
-
 * assumptions should be made about the contents of a macho_handle_t; it is declared to be a blind
-
 * structure.
-
 *
-
 * Returns either a pointer to a valid macho_handle_t or NULL on failure. errno will be set on
-
 * failure. The resources associated with a macho_handle_t must be freed by passing it to
-
 * macho_destroy_handle.
-
 */
-
macho_handle_t *macho_create_handle(void);
-

-
/**
-
 * Frees resources associated with a macho_handle_t and invalidates all results returned by
-
 * macho_parse_file called with this handle.
-
 */
-
void macho_destroy_handle(macho_handle_t *handle);
-

-
/**
-
 * Formats a dylib version number given by an uint32_t into a human-readable format and returns a
-
 * Pointer to the beginning of that string. The result is either a valid pointer or NULL on error
-
 * (in which case the errno is set to indicate the error). The pointer must be free()'d after use.
-
 */
-
char *macho_format_dylib_version(uint32_t version);
-

-
/**
-
 * Returns a readable version of any cpu_type_t constant. Returns a valid pointer to the first
-
 * character in a 0-terminated string or NULL on error. The pointer must not be free()'d after use.
-
 */
-
const char *macho_get_arch_name(cpu_type_t cputype);
-

-
/**
-
 * Parses the Mach-O file indicated by filepath and writes a pointer to a macho_t describing the
-
 * Mach-O file into the location idicated by res. Returns MACHO_SUCCESS on success or any of the
-
 * following error codes on error:
-
 *
-
 * code             description                                     errno set?
-
 * MACHO_EFILE      error stat()'ing, opening or reading the file   yes
-
 * MACHO_EMMAP      error mmap()'ing the file                       yes
-
 * MACHO_EMEM       error allocating memory                         yes
-
 * MACHO_ERANGE     unexpected end of file                          no
-
 * MACHO_EMAGIC     unknown magic number/not a Mach-O file          no
-
 *
-
 * On error, the contents of res are undefined and should not be used. The memory associated with
-
 * the result *res will be free()'d and should thus not be used after calling macho_destroy_handle
-
 * on the macho_handle_t used for the call. *res should also never be modified or otherwise
-
 * free()'d.
-
 */
-
int macho_parse_file(macho_handle_t *handle, const char *filepath, const macho_t **res);
-

-
/**
-
 * Returns a string representation of the MACHO_* error code constants
-
 */
-
const char *macho_strerror(int err);
-

-
#endif
-

modified external/libucl/src/ucl_hash.h
@@ -32,7 +32,7 @@ struct ucl_hash_node_s;
typedef struct ucl_hash_node_s ucl_hash_node_t;

typedef int (*ucl_hash_cmp_func) (const void* void_a, const void* void_b);
-
typedef void (*ucl_hash_free_func) (void *ptr);
+
typedef void (*ucl_hash_free_func) (ucl_object_t *ptr);
typedef void* ucl_hash_iter_t;


modified libpkg/Makefile.autosetup
@@ -32,6 +32,10 @@ SRCS= backup_lib.c \
	pkg_jobs_conflicts.c pkg_ports.c \
	pkg_solve.c \
	pkgdb.c \
+
	pkg_abi.c \
+
	pkg_elf.c \
+
	pkg_abi_macho.c \
+
	binfmt_macho.c \
	ssh.c elfhints.c \
	pkg_arch.c \
	pkg_cudf.c \
@@ -118,22 +122,14 @@ LOCAL_LDFLAGS+= -lfts
@if HAVE_LIBDL
LOCAL_LDFLAGS+= -ldl
@endif
-
@if HAVE_LIBRESOLV
-
LOCAL_LDFLAGS+= -lresolv
-
@endif

-
@if libmachista
-
LOCAL_CFLAGS+= -I$(top_srcdir)/external/libmachista
-
STATIC_LIBS+=	$(top_builddir)/external/libmachista/libmachista.a
-
LOCAL_LDFLAGS+=	-L$(top_builddir)/external/libmachista -lmachista_pic \
-
		-larchive -lresolv
-
SRCS+=		pkg_macho.c
-
@else
-
SRCS+=		pkg_elf.c
-
@if pkg_freebsd
+
@if pkgos_darwin
+
LOCAL_LDFLAGS+=	-lresolv
+
@else 
+
@if pkgos_freebsd
LOCAL_LDFLAGS+=	-Wl,--version-script=$(top_srcdir)/libpkg/libpkg.ver,--undefined-version 
@else
-
# --undefined-version is a FreeBSD ld option
+
### --undefined-version is a FreeBSD ld option
LOCAL_LDFLAGS+=	-Wl,--version-script=$(top_srcdir)/libpkg/libpkg.ver
@endif
@endif
@@ -186,7 +182,7 @@ all: lib$(LIB)_flat.a

lib$(LIB)$(LIBSOEXT): $(STATIC_LIBS)

-
@if libmachista
+
@if pkgos_darwin
lib$(LIB)_flat.a: $(STATIC_LIBS)
	libtool -static -o lib$(LIB)_flat.a $(STATIC_LIBS)
@else
added libpkg/binfmt_macho.c
@@ -0,0 +1,676 @@
+
/*-
+
 * 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.
+
 */
+

+
#ifdef HAVE_CONFIG_H
+
#include "pkg_config.h"
+
#endif
+

+
#ifdef HAVE_SYS_ENDIAN_H
+
#include <sys/endian.h>
+
#elif HAVE_ENDIAN_H
+
#include <endian.h>
+
#elif HAVE_MACHINE_ENDIAN_H
+
#include <machine/endian.h>
+
#endif
+
#include <errno.h>
+
#include <fcntl.h>
+
#include <stdio.h>
+
#include <stdlib.h>
+
#include <string.h>
+
#include <unistd.h>
+

+
#include <bsd_compat.h>
+
#include "private/binfmt_macho.h"
+

+
/**
+
 * Minimal Mach-O binary file parser for both FAT as well as plain binaries with
+
 * sufficient functionality to handle architecture, OS, file type, library
+
 * dependencies.
+
 * As well as utility functions to convert data into different formats.
+
 */
+

+
/**** Readers ****/
+

+
static ssize_t
+
read_fully(const int fd, const size_t len, void *dest)
+
{
+
	unsigned char *p = dest;
+
	size_t n = len;
+
	ssize_t x;
+
	while (n > 0) {
+
		if ((x = read(fd, p, n)) < 0) {
+
			return x;
+
		}
+
		n -= x;
+
		p += x;
+
	}
+
	return len;
+
}
+

+
ssize_t
+
read_u32(const int fd, const bool swap, uint32_t *dest)
+
{
+
	unsigned char buf[4];
+
	ssize_t x;
+
	if ((x = read_fully(fd, sizeof(buf), buf)) < 0) {
+
		return x;
+
	}
+
	if (swap) {
+
		*dest = le32dec(buf);
+
	} else {
+
		*dest = be32dec(buf);
+
	}
+
	return x;
+
}
+

+
static ssize_t
+
read_u64(const int fd, const bool swap, uint64_t *dest)
+
{
+
	unsigned char buf[8];
+
	ssize_t x;
+
	if ((x = read_fully(fd, sizeof(buf), buf)) < 0) {
+
		return x;
+
	}
+
	if (swap) {
+
		*dest = le64dec(buf);
+
	} else {
+
		*dest = be64dec(buf);
+
	}
+
	return x;
+
}
+

+
static ssize_t
+
read_cpu_type(const int fd, const bool swap, cpu_type_subtype_t *dest)
+
{
+
	ssize_t n = 0, x;
+
	uint32_t cputype;
+
	uint32_t cpusubtype;
+

+
	READ(u32, cputype);
+
	READ(u32, cpusubtype);
+
	dest->type = cputype & ~CPU_ARCH_MASK;
+
	dest->type_is64 = (cputype & CPU_ARCH_MASK) == CPU_ARCH_ABI64;
+
	dest->type_is64_32 = (cputype & CPU_ARCH_MASK) == CPU_ARCH_ABI64_32;
+
	dest->subtype_islib64 = (cpusubtype & CPU_SUBTYPE_MASK) ==
+
	    CPU_SUBTYPE_LIB64;
+
	switch (dest->type) {
+
	case CPU_TYPE_ARM:
+
		dest->subtype_arm = cpusubtype & ~CPU_SUBTYPE_MASK;
+
		break;
+
	case CPU_TYPE_X86:
+
		dest->subtype_x86 = cpusubtype & ~CPU_SUBTYPE_MASK;
+
		break;
+
	case CPU_TYPE_POWERPC:
+
		dest->subtype_ppc = cpusubtype & ~CPU_SUBTYPE_MASK;
+
		break;
+
	default:
+
		errno = EINVAL;
+
		return -1;
+
	}
+
	return n;
+
}
+

+
static ssize_t
+
read_fat_arch(const int fd, const uint32_t magic, fat_arch_t *dest)
+
{
+
	ssize_t n = 0, x;
+
	const bool swap = magic == FAT_CIGAM || magic == FAT_CIGAM_64;
+

+
	READ(cpu_type, dest->cpu);
+
	uint32_t align;
+
	uint32_t reserved;
+

+
	switch (magic) {
+
	case FAT_MAGIC:
+
	case FAT_CIGAM:;
+
		uint32_t offset32;
+
		uint32_t size32;
+
		READ(u32, offset32);
+
		READ(u32, size32);
+
		READ(u32, align); // bits
+

+
		dest->offset = offset32;
+
		dest->size = size32;
+
		dest->align = align;
+
		break;
+
	case FAT_MAGIC_64:
+
	case FAT_CIGAM_64:
+
		READ(u64, dest->offset);
+
		READ(u64, dest->size);
+
		READ(u32, align);
+
		READ(u32, reserved);
+
		dest->align = align;
+
		break;
+
	default:
+
		errno = EINVAL;
+
		return -1;
+
	}
+
	return n;
+
}
+

+
static ssize_t
+
read_version(const int fd, const bool swap, macho_version_t *dest)
+
{
+
	ssize_t n = 0, x;
+

+
	uint32_t version;
+
	READ(u32, version);
+
	dest->major = (version >> 16) & 0xffff;
+
	dest->minor = (version >> 8) & 0xff;
+
	dest->patch = version & 0xff;
+
	return n;
+
}
+

+
ssize_t
+
read_min_version(const int fd, const bool swap, const uint32_t loadcmd,
+
    build_version_t **dest)
+
{
+
	ssize_t n = 0, x;
+

+
	*dest = malloc(sizeof(build_version_t));
+
	(*dest)->ntools = 0;
+
	switch (loadcmd) {
+
	case LC_VERSION_MIN_IPHONEOS:
+
		(*dest)->platform = PLATFORM_IOS;
+
		break;
+
	case LC_VERSION_MIN_MACOSX:
+
		(*dest)->platform = PLATFORM_MACOS;
+
		break;
+
	case LC_VERSION_MIN_TVOS:
+
		(*dest)->platform = PLATFORM_TVOS;
+
		break;
+
	case LC_VERSION_MIN_WATCHOS:
+
		(*dest)->platform = PLATFORM_WATCHOS;
+
		break;
+
	default:
+
		return -1;
+
	}
+
	READ(version, (*dest)->minos);
+
	READ(version, (*dest)->sdk);
+
	return n;
+
}
+

+
static ssize_t
+
read_path(const int fd, const bool swap, const uint32_t loadcmdsize,
+
    char **dest)
+
{
+
	ssize_t n = 0, x;
+

+
	uint32_t name_ofs;
+
	READ(u32, name_ofs);
+
	if (-1 == (x = lseek(fd, name_ofs - 12, SEEK_CUR))) {
+
		return x;
+
	}
+
	n += name_ofs - 12;
+
	*dest = malloc(loadcmdsize - name_ofs + 1);
+
	if ((x = read_fully(fd, loadcmdsize - name_ofs, *dest)) < 0) {
+
		free(*dest);
+
		*dest = 0;
+
		return x;
+
	}
+
	n += x;
+
	(*dest)[loadcmdsize - name_ofs] = '\0';
+
	return n;
+
}
+

+
static ssize_t
+
read_dylib(const int fd, const bool swap, const uint32_t loadcmdsize,
+
    dylib_t **dest)
+
{
+
	ssize_t n = 0, x;
+

+
	uint32_t name_ofs;
+
	uint32_t timestamp;
+
	macho_version_t current_version;
+
	macho_version_t compatibility_version;
+

+
	READ(u32, name_ofs);
+
	READ(u32, timestamp);
+
	READ(version, current_version);
+
	READ(version, compatibility_version);
+

+
	if (-1 == (x = lseek(fd, name_ofs - 24, SEEK_CUR))) {
+
		return x;
+
	}
+
	n += name_ofs - 24;
+

+
	*dest = malloc(sizeof(dylib_t) + loadcmdsize - name_ofs + 1);
+
	(*dest)->timestamp = timestamp;
+
	(*dest)->current_version = current_version;
+
	(*dest)->compatibility_version = compatibility_version;
+
	if ((x = read_fully(fd, loadcmdsize - name_ofs, (*dest)->path)) < 0) {
+
		free(*dest);
+
		*dest = 0;
+
		return x;
+
	}
+
	n += x;
+
	(*dest)->path[loadcmdsize - name_ofs] = '\0';
+
	return n;
+
}
+

+
ssize_t
+
read_build_version(const int fd, const bool swap, build_version_t **dest)
+
{
+
	ssize_t n = 0, x;
+

+
	uint32_t platform;
+
	macho_version_t minos;
+
	macho_version_t sdk;
+
	uint32_t ntools;
+

+
	READ(u32, platform);
+
	READ(version, minos);
+
	READ(version, sdk);
+
	READ(u32, ntools);
+

+
	*dest = malloc(
+
	    sizeof(build_version_t) + ntools * sizeof(tool_version_t));
+
	(*dest)->platform = platform;
+
	(*dest)->minos = minos;
+
	(*dest)->sdk = sdk;
+
	(*dest)->ntools = ntools;
+
	tool_version_t *p = (*dest)->tools;
+

+
	for (; ntools-- > 0; p++) {
+
		uint32_t tool;
+
		READ(u32, tool);
+
		p->tool = tool;
+
		READ(version, p->version);
+
	}
+
	return n;
+
}
+

+
ssize_t
+
read_macho_header(const int fd, macho_header_t *dest)
+
{
+
	ssize_t n = 0, x;
+
	uint32_t reserved;
+

+
	if ((x = read_u32(fd, false, &dest->magic) < 0)) {
+
		return x;
+
	}
+
	n += x;
+

+
	const bool swap = dest->swap = dest->magic == MH_CIGAM ||
+
	    dest->magic == MH_CIGAM_64;
+

+
	READ(cpu_type, dest->cpu);
+
	READ(u32, dest->filetype);
+
	READ(u32, dest->ncmds);
+
	READ(u32, dest->sizeofcmds);
+
	READ(u32, dest->flags);
+
	switch (dest->magic) {
+
	case MH_MAGIC_64:
+
	case MH_CIGAM_64:
+
		READ(u32, reserved);
+
		break;
+
	default:
+
		break;
+
	}
+
	return n;
+
}
+

+
ssize_t
+
read_macho_file(const int fd, macho_file_t **dest)
+
{
+
	ssize_t n = 0, x;
+

+
	uint32_t magic;
+
	if ((x = read_u32(fd, false, &magic)) < 0) {
+
		return x;
+
	}
+
	n += x;
+

+
	const bool swap = magic == FAT_CIGAM || magic == FAT_CIGAM_64 ||
+
	    magic == MH_CIGAM || magic == MH_CIGAM_64;
+

+
	uint32_t nfat_arch;
+
	fat_arch_t *p;
+
	switch (magic) {
+
	case FAT_MAGIC:
+
	case FAT_MAGIC_64:
+
	case FAT_CIGAM:
+
	case FAT_CIGAM_64:
+
		READ(u32, nfat_arch);
+
		*dest = malloc(
+
		    sizeof(macho_file_t) + nfat_arch * sizeof(fat_arch_t));
+
		(*dest)->magic = magic;
+
		(*dest)->narch = nfat_arch;
+
		p = (*dest)->arch;
+

+
		while (nfat_arch-- > 0) {
+
			if ((x = read_fat_arch(fd, magic, p)) < 0) {
+
				free(*dest);
+
				*dest = 0;
+
				return x;
+
			}
+
			n += x;
+
			p++;
+
		}
+
		break;
+

+
	case MH_MAGIC:
+
	case MH_MAGIC_64:
+
	case MH_CIGAM:
+
	case MH_CIGAM_64:
+
		nfat_arch = 1;
+
		*dest = malloc(
+
		    sizeof(macho_file_t) + nfat_arch * sizeof(fat_arch_t));
+
		(*dest)->magic = magic;
+
		(*dest)->narch = nfat_arch;
+
		p = (*dest)->arch;
+
		READ(cpu_type, p->cpu);
+
		off_t xo;
+
		if (-1 == (xo = lseek(fd, 0, SEEK_END))) {
+
			free(*dest);
+
			*dest = 0;
+
			return xo;
+
		}
+
		p->offset = 0;
+
		p->size = xo;
+
		p->align = 0; // number of trailing zero bits in size;
+
		n = xo;
+
		break;
+
	default:
+
		errno = EINVAL;
+
		return -1;
+
	}
+
	return n;
+
}
+

+
/**** OS -> Kernel conversion ****/
+

+
static macho_version_t macos_to_darwin[][2] = {
+
	// macOS Sequoia
+
	{ { 15, 2, 0 }, { 24, 2, 0 } },
+
	{ { 15, 1, 0 }, { 24, 1, 0 } },
+
	{ { 15, 0, 0 }, { 24, 0, 0 } },
+
	// macOS Sonoma
+
	{ { 14, 6, 0 }, { 23, 6, 0 } },
+
	{ { 14, 5, 0 }, { 23, 4, 0 } },
+
	{ { 14, 4, 0 }, { 23, 5, 0 } },
+
	{ { 14, 3, 0 }, { 23, 3, 0 } },
+
	{ { 14, 2, 0 }, { 23, 2, 0 } },
+
	{ { 14, 1, 0 }, { 23, 1, 0 } },
+
	{ { 14, 0, 0 }, { 23, 0, 0 } },
+
	// macOS Ventura
+
	{ { 13, 5, 0 }, { 22, 6, 0 } },
+
	{ { 13, 4, 0 }, { 22, 5, 0 } },
+
	{ { 13, 3, 0 }, { 22, 4, 0 } },
+
	{ { 13, 2, 0 }, { 22, 3, 0 } },
+
	{ { 13, 1, 0 }, { 22, 2, 0 } },
+
	{ { 13, 0, 0 }, { 22, 1, 0 } },
+
	// macOS Monterey
+
	{ { 12, 5, 0 }, { 21, 6, 0 } },
+
	{ { 12, 4, 0 }, { 21, 5, 0 } },
+
	{ { 12, 3, 0 }, { 21, 4, 0 } },
+
	{ { 12, 2, 0 }, { 21, 3, 0 } },
+
	{ { 12, 1, 0 }, { 21, 2, 0 } },
+
	{ { 12, 0, 1 }, { 21, 1, 0 } },
+
	{ { 12, 0, 0 }, { 21, 0, 1 } },
+
	// macOS Big Sur
+
	{ { 11, 5, 0 }, { 20, 6, 0 } },
+
	{ { 11, 4, 0 }, { 20, 5, 0 } },
+
	{ { 11, 3, 0 }, { 20, 4, 0 } },
+
	{ { 11, 2, 0 }, { 20, 3, 0 } },
+
	{ { 11, 1, 0 }, { 20, 2, 0 } },
+
	{ { 11, 0, 0 }, { 20, 1, 0 } },
+
	// macOS Catalina
+
	{ { 10, 15, 6 }, { 19, 6, 0 } },
+
	{ { 10, 15, 5 }, { 19, 5, 0 } },
+
	{ { 10, 15, 4 }, { 19, 4, 0 } },
+
	{ { 10, 15, 3 }, { 19, 3, 0 } },
+
	{ { 10, 15, 2 }, { 19, 2, 0 } },
+
	{ { 10, 15, 0 }, { 19, 0, 0 } },
+
	// macOS Mojave
+
	{ { 10, 14, 6 }, { 18, 7, 0 } },
+
	{ { 10, 14, 5 }, { 18, 6, 0 } },
+
	{ { 10, 14, 4 }, { 18, 5, 0 } },
+
	{ { 10, 14, 1 }, { 18, 2, 0 } },
+
	{ { 10, 14, 0 }, { 18, 0, 0 } },
+
	// macOS High Sierra
+
	{ { 10, 13, 6 }, { 17, 7, 0 } },
+
	{ { 10, 13, 5 }, { 17, 6, 0 } },
+
	{ { 10, 13, 4 }, { 17, 5, 0 } },
+
	{ { 10, 13, 3 }, { 17, 4, 0 } },
+
	{ { 10, 13, 2 }, { 17, 3, 0 } },
+
	{ { 10, 13, 1 }, { 17, 2, 0 } },
+
	{ { 10, 13, 0 }, { 17, 0, 0 } },
+
	// macOS Sierra
+
	{ { 10, 12, 6 }, { 16, 7, 0 } },
+
	{ { 10, 12, 5 }, { 16, 6, 0 } },
+
	{ { 10, 12, 4 }, { 16, 5, 0 } },
+
	{ { 10, 12, 3 }, { 16, 4, 0 } },
+
	{ { 10, 12, 2 }, { 16, 3, 0 } },
+
	{ { 10, 12, 1 }, { 16, 1, 0 } },
+
	{ { 10, 12, 0 }, { 16, 0, 0 } },
+
	// OS X El Capitan
+
	{ { 10, 11, 6 }, { 15, 6, 0 } },
+
	{ { 10, 11, 5 }, { 15, 5, 0 } },
+
	{ { 10, 11, 4 }, { 15, 4, 0 } },
+
	{ { 10, 11, 3 }, { 15, 3, 0 } },
+
	{ { 10, 11, 2 }, { 15, 2, 0 } },
+
	{ { 10, 11, 0 }, { 15, 0, 0 } },
+
	// OS X Yosemite
+
	{ { 10, 10, 5 }, { 14, 5, 0 } },
+
	{ { 10, 10, 4 }, { 14, 4, 0 } },
+
	{ { 10, 10, 3 }, { 14, 3, 0 } },
+
	{ { 10, 10, 2 }, { 14, 1, 0 } },
+
	{ { 10, 10, 0 }, { 14, 0, 0 } },
+
	// OS X Mavericks
+
	{ { 10, 9, 5 }, { 13, 4, 0 } },
+
	{ { 10, 9, 4 }, { 13, 3, 0 } },
+
	{ { 10, 9, 3 }, { 13, 2, 0 } },
+
	{ { 10, 9, 2 }, { 13, 1, 0 } },
+
	{ { 10, 9, 0 }, { 13, 0, 0 } },
+
	// OS X Mountain Lion
+
	{ { 10, 8, 5 }, { 12, 5, 0 } }, // Build 12F45 switched to 12.6
+
	{ { 10, 8, 4 }, { 12, 4, 0 } },
+
	{ { 10, 8, 3 }, { 12, 3, 0 } },
+
	{ { 10, 8, 2 }, { 12, 2, 0 } },
+
	{ { 10, 8, 1 }, { 12, 1, 0 } },
+
	{ { 10, 8, 0 }, { 12, 0, 0 } },
+
	// OS X Lion
+
	{ { 10, 7, 5 }, { 11, 4, 2 } },
+
	{ { 10, 7, 4 }, { 11, 4, 0 } },
+
	{ { 10, 7, 3 }, { 11, 3, 0 } },
+
	{ { 10, 7, 2 }, { 11, 2, 0 } },
+
	{ { 10, 7, 1 }, { 11, 1, 0 } },
+
	{ { 10, 7, 0 }, { 11, 0, 0 } },
+
	// Mac OS X Snow Leopard
+
	{ { 10, 6, 8 }, { 10, 8, 0 } },
+
	{ { 10, 6, 7 }, { 10, 7, 0 } },
+
	{ { 10, 6, 6 }, { 10, 6, 0 } },
+
	{ { 10, 6, 5 }, { 10, 5, 0 } },
+
	{ { 10, 6, 4 }, { 10, 4, 0 } },
+
	{ { 10, 6, 3 }, { 10, 3, 0 } },
+
	{ { 10, 6, 2 }, { 10, 2, 0 } },
+
	{ { 10, 6, 1 }, { 10, 1, 0 } },
+
	{ { 10, 6, 0 }, { 10, 0, 0 } },
+
	// Mac OS X Leopard
+
	{ { 10, 5, 8 }, { 9, 8, 0 } },
+
	{ { 10, 5, 7 }, { 9, 7, 0 } },
+
	{ { 10, 5, 6 }, { 9, 6, 0 } },
+
	{ { 10, 5, 5 }, { 9, 5, 0 } },
+
	{ { 10, 5, 4 }, { 9, 4, 0 } },
+
	{ { 10, 5, 3 }, { 9, 3, 0 } },
+
	{ { 10, 5, 2 }, { 9, 2, 0 } },
+
	{ { 10, 5, 1 }, { 9, 1, 0 } }, // Build 9B2117 switched to 9.1.1
+
	{ { 10, 5, 0 }, { 9, 0, 0 } },
+
	// Mac OS X Tiger
+
	{ { 10, 4, 11 }, { 8, 11, 0 } },
+
	{ { 10, 4, 10 }, { 8, 10, 0 } },
+
	{ { 10, 4, 9 }, { 8, 9, 0 } },
+
	{ { 10, 4, 8 }, { 8, 8, 0 } },
+
	{ { 10, 4, 7 }, { 8, 7, 0 } },
+
	{ { 10, 4, 6 }, { 8, 6, 0 } },
+
	{ { 10, 4, 5 }, { 8, 5, 0 } },
+
	{ { 10, 4, 4 }, { 8, 4, 0 } },
+
	{ { 10, 4, 3 }, { 8, 3, 0 } },
+
	{ { 10, 4, 2 }, { 8, 2, 0 } },
+
	{ { 10, 4, 1 }, { 8, 1, 0 } },
+
	{ { 10, 4, 0 }, { 8, 0, 0 } },
+
	// Mac OS X Panther
+
	{ { 10, 3, 9 }, { 7, 9, 0 } },
+
	{ { 10, 3, 8 }, { 7, 8, 0 } },
+
	{ { 10, 3, 7 }, { 7, 7, 0 } },
+
	{ { 10, 3, 6 }, { 7, 6, 0 } },
+
	{ { 10, 3, 5 }, { 7, 5, 0 } },
+
	{ { 10, 3, 4 }, { 7, 4, 0 } },
+
	{ { 10, 3, 3 }, { 7, 3, 0 } },
+
	{ { 10, 3, 2 }, { 7, 2, 0 } },
+
	{ { 10, 3, 1 }, { 7, 1, 0 } },
+
	{ { 10, 3, 0 }, { 7, 0, 0 } },
+
	// Mac OS X Jaguar
+
	{ { 10, 2, 8 }, { 6, 8, 0 } },
+
	{ { 10, 2, 7 }, { 6, 7, 0 } },
+
	{ { 10, 2, 6 }, { 6, 6, 0 } },
+
	{ { 10, 2, 5 }, { 6, 5, 0 } },
+
	{ { 10, 2, 4 }, { 6, 4, 0 } },
+
	{ { 10, 2, 3 }, { 6, 3, 0 } },
+
	{ { 10, 2, 2 }, { 6, 2, 0 } },
+
	{ { 10, 2, 1 }, { 6, 1, 0 } },
+
	{ { 10, 2, 0 }, { 6, 0, 0 } },
+
	// Mac OS X 10.1 Puma
+
	{ { 10, 1, 5 }, { 5, 5, 0 } },
+
	{ { 10, 1, 4 }, { 5, 4, 0 } },
+
	{ { 10, 1, 3 }, { 5, 3, 0 } },
+
	{ { 10, 1, 2 }, { 5, 2, 0 } },
+
	{ { 10, 1, 1 }, { 5, 1, 0 } },
+
	{ { 10, 1, 0 }, { 1, 4, 1 } },
+
	// Mac OS X 10.0 Cheetah
+
	{ { 10, 0, 1 }, { 1, 3, 1 } },
+
	{ { 10, 0, 0 }, { 1, 3, 0 } },
+
	// Mac OS X Public Beta
+
	// {{x,y,z}}, {1,2,1}},
+
	// Mac OS X Server 1.0
+
	{ { 1, 0, 2 }, { 0, 3, 0 } },
+
	{ { 1, 0, 1 }, { 0, 2, 0 } },
+
	{ { 1, 0, 0 }, { 0, 1, 0 } },
+
	// EOA
+
	{ { 0, 0, 0 }, { 0, 0, 0 } },
+
};
+

+
static macho_version_t ios_to_darwin[][2] = {
+
	// iOS 18, iPadOS 18, tvOS 18
+
	{ { 18, 0, 0 }, { 24, 0, 0 } },
+
	// iOS 17, iPadOS 17, tvOS 17
+
	{ { 17, 5, 0 }, { 23, 5, 0 } },
+
	{ { 17, 4, 0 }, { 23, 4, 0 } },
+
	{ { 17, 3, 0 }, { 23, 3, 0 } },
+
	{ { 17, 2, 0 }, { 23, 2, 0 } },
+
	{ { 17, 1, 0 }, { 23, 1, 0 } },
+
	{ { 17, 0, 0 }, { 23, 0, 0 } },
+
	// iOS 16, iPadOS 16, tvOS 16
+
	{ { 16, 6, 0 }, { 22, 6, 0 } },
+
	{ { 16, 5, 0 }, { 22, 5, 0 } },
+
	{ { 16, 4, 0 }, { 22, 4, 0 } },
+
	{ { 16, 3, 0 }, { 22, 3, 0 } },
+
	{ { 16, 2, 0 }, { 22, 2, 0 } },
+
	{ { 16, 1, 0 }, { 22, 1, 0 } },
+
	{ { 16, 0, 0 }, { 22, 0, 0 } },
+
	// iOS 15, iPadOS 15, tvOS 15
+
	{ { 15, 6, 0 }, { 21, 6, 0 } },
+
	{ { 15, 5, 0 }, { 21, 5, 0 } },
+
	{ { 15, 4, 0 }, { 21, 4, 0 } },
+
	{ { 15, 3, 0 }, { 21, 3, 0 } },
+
	{ { 15, 2, 0 }, { 21, 2, 0 } },
+
	{ { 15, 0, 0 }, { 21, 1, 0 } },
+
	// iOS 15.0 beta 1 -> 21.0.0
+
	// iOS 14, iPadOS 14, tvOS 14
+
	{ { 14, 7, 0 }, { 20, 6, 0 } },
+
	{ { 14, 6, 0 }, { 20, 5, 0 } },
+
	{ { 14, 5, 0 }, { 20, 4, 0 } },
+
	{ { 14, 4, 0 }, { 20, 3, 0 } },
+
	{ { 14, 3, 0 }, { 20, 2, 0 } },
+
	{ { 14, 0, 0 }, { 20, 0, 0 } },
+
	// iOS 13
+
	{ { 13, 6, 0 }, { 19, 6, 0 } },
+
	{ { 13, 5, 0 }, { 19, 5, 0 } },
+
	{ { 13, 3, 1 }, { 19, 3, 0 } },
+
	{ { 13, 3, 0 }, { 19, 2, 0 } },
+
	// iOS 12
+
	{ { 12, 1, 0 }, { 18, 2, 0 } },
+
	// iOS 11
+
	{ { 11, 4, 1 }, { 17, 7, 0 } },
+
	// iOS 10
+
	{ { 10, 3, 3 }, { 16, 6, 0 } },
+
	{ { 10, 3, 0 }, { 16, 3, 0 } },
+
	{ { 10, 0, 1 }, { 16, 0, 0 } },
+
	// iOS 9
+
	{ { 9, 3, 3 }, { 15, 6, 0 } },
+
	{ { 9, 0, 0 }, { 15, 0, 0 } },
+
	// iOS 7, iOS 8
+
	{ { 7, 0, 0 }, { 14, 0, 0 } },
+
	// iOS 6
+
	{ { 6, 0, 0 }, { 13, 0, 0 } },
+
	// iOS 4.3
+
	{ { 4, 3, 0 }, { 11, 0, 0 } },
+
	// iPhone OS 3
+
	{ { 3, 0, 0 }, { 10, 0, 0 } },
+
	// iPhone OS 1
+
	{ { 1, 0, 0 }, { 9, 0, 0 } },
+
	// EOA
+
	{ { 0, 0, 0 }, { 0, 0, 0 } },
+
};
+

+
int
+
map_platform_to_darwin(macho_version_t *darwin,
+
    const enum MachoPlatform platform, const macho_version_t version)
+
{
+
	macho_version_t *p;
+
	switch (platform) {
+
	case PLATFORM_MACOS:
+
		p = macos_to_darwin[0];
+
		break;
+

+
	case PLATFORM_IOS:
+
	case PLATFORM_IOSSIMULATOR:
+
	case PLATFORM_TVOS:
+
	case PLATFORM_TVOSSIMULATOR:
+
		p = ios_to_darwin[0];
+
		break;
+

+
	case PLATFORM_WATCHOS:
+
	case PLATFORM_WATCHOSSIMULATOR:
+
		darwin->major = version.major + 13;
+
		darwin->minor = version.minor;
+
		darwin->patch = 0;
+
		return 0;
+

+
	default:
+
		return -1;
+
	}
+
	while (p->major > version.major || p->minor > version.minor ||
+
	    p->patch > version.patch) {
+
		p += 2;
+
	}
+
	p++;
+
	if (0 == p->major && 0 == p->minor && 0 == p->patch) {
+
		return -1;
+
	}
+
	*darwin = *p;
+
	return 0;
+
}
modified libpkg/elfhints.c
@@ -315,9 +315,8 @@ int shlib_list_from_rpath(const char *rpath_str, const char *dirpath)
int
shlib_list_from_elf_hints(const char *hintsfile)
{
-
#if defined __FreeBSD__ || defined __DragonFly__
-
	read_elf_hints(hintsfile, 1);
-
#endif
+
	if (ctx.oi->ostype == OS_FREEBSD || ctx.oi->ostype == OS_DRAGONFLY)
+
		read_elf_hints(hintsfile, 1);

	return (scan_dirs_for_shlibs(&shlibs, ndirs, dirs, true));
}
modified libpkg/pkg.c
@@ -56,7 +56,7 @@ pkg_free(struct pkg *pkg)
	free(pkg->version);
	free(pkg->maintainer);
	free(pkg->www);
-
	free(pkg->arch);
+
	free(pkg->altabi);
	free(pkg->abi);
	free(pkg->uid);
	free(pkg->digest);
@@ -252,8 +252,8 @@ pkg_set_s(struct pkg *pkg, pkg_attr attr, const char *str)
		}
		break;
	case PKG_ATTR_ARCH:
-
		free(pkg->arch);
-
		pkg->arch = xstrdup(str);
+
		free(pkg->altabi);
+
		pkg->altabi = xstrdup(str);
		break;
	case PKG_ATTR_ABI:
		free(pkg->abi);
added libpkg/pkg_abi.c
@@ -0,0 +1,279 @@
+
/*-
+
 * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
+
 * All rights reserved.
+
 *
+
 * 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.
+
 */
+
#ifdef HAVE_CONFIG_H
+
#include "pkg_config.h"
+
#endif
+

+
#include <ctype.h>
+
#include <paths.h>
+
#include <unistd.h>
+

+
#include "pkg.h"
+

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

+
#define _PATH_UNAME "/usr/bin/uname"
+

+
/* All possibilities on FreeBSD as of 5/26/2014 */
+
struct arch_trans {
+
	const char *elftype;
+
	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" },
+
	/* All the ARM stuff */
+
	{ "armv6:32:el:eabi:hardfp", "armv6" },
+
	{ "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" },
+
	/* And RISC-V */
+
	{ "riscv:32:hf", "riscv32" },
+
	{ "riscv:32:sf", "riscv32sf" },
+
	{ "riscv:64:hf", "riscv64" },
+
	{ "riscv:64:sf", "riscv64sf" },
+

+
	{ NULL, NULL }
+
};
+

+
static int
+
pkg_get_myarch_fromfile(struct os_info *oi)
+
{
+
	char rooted_abi_file[PATH_MAX];
+
	const char *abi_files[] = {
+
		getenv("ABI_FILE"),
+
		_PATH_UNAME,
+
		_PATH_BSHELL,
+
	};
+
	int i, fd;
+

+
	/*
+
	 * Perhaps not yet needed, but it may be in the future that there's no
+
	 * need to check root under some conditions where there is a rootdir.
+
	 * This also helps alleviate some excessive wrapping later.
+
	 */
+
	bool checkroot = ctx.pkg_rootdir != NULL;
+
	for (fd = -1, i = 0; i < NELEM(abi_files); i++) {
+
		if (abi_files[i] == NULL)
+
			continue;
+
		/*
+
		 * 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)
+
				break;
+
		}
+
		if ((fd = open(abi_files[i], 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);
+
	}
+

+
	int ret = pkg_get_myarch_elfparse(fd, oi);
+
	if (EPKG_OK != ret) {
+
		lseek(fd, 0, SEEK_SET);
+
		ret = pkg_get_myarch_macho(fd, oi);
+
	}
+

+
	close(fd);
+
	return ret;
+
}
+

+
int
+
pkg_get_myarch_with_legacy(struct os_info *oi)
+
{
+
	if (oi == NULL)
+
		return (EPKG_FATAL);
+
	int err = pkg_get_myarch_fromfile(oi);
+
	if (err) {
+
		free(oi->name);
+
		return (err);
+
	}
+

+
	pkg_arch_to_legacy(oi->abi, oi->altabi, sizeof(oi->abi));
+

+
	if (oi->ostype == OS_DRAGONFLY) {
+
		size_t dsz;
+

+
		dsz = strlen(oi->abi);
+
		for (int i = 0; i < dsz; i++)
+
			oi->abi[i] = tolower(oi->abi[i]);
+
		return (0);
+
	}
+

+
	return (0);
+
}
+

+
int
+
pkg_arch_to_legacy(const char *arch, char *dest, size_t sz)
+
{
+
	int i = 0;
+
	struct arch_trans *arch_trans;
+

+
	memset(dest, '\0', sz);
+
	/* Lower case the OS */
+
	while (arch[i] != ':' && arch[i] != '\0') {
+
		dest[i] = tolower(arch[i]);
+
		i++;
+
	}
+
	if (arch[i] == '\0')
+
		return (0);
+

+
	dest[i++] = ':';
+

+
	/* Copy the version */
+
	while (arch[i] != ':' && arch[i] != '\0') {
+
		dest[i] = arch[i];
+
		i++;
+
	}
+
	if (arch[i] == '\0')
+
		return (0);
+

+
	dest[i++] = ':';
+

+
	for (arch_trans = machine_arch_translation; arch_trans->elftype != NULL;
+
	    arch_trans++) {
+
		if (STREQ(arch + i, arch_trans->archid)) {
+
			strlcpy(dest + i, arch_trans->elftype,
+
			    sz - (arch + i - dest));
+
			return (0);
+
		}
+
	}
+
	strlcpy(dest + i, arch + i, sz - (arch + i  - dest));
+

+
	return (0);
+
}
+

+
int
+
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];
+
	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;
+

+
	if (tll_length(pkg->shlibs_required) != 0) {
+
		tll_free_and_free(pkg->shlibs_required, free);
+
	}
+

+
	if (tll_length(pkg->shlibs_provided) != 0) {
+
		tll_free_and_free(pkg->shlibs_provided, free);
+
	}
+

+
	ret = pkg_analyse_init(stage);
+
	if (ret != EPKG_OK) {
+
		goto cleanup;
+
	}
+

+
	/* Assume no architecture dependence, for contradiction */
+
	if (ctx.developer_mode)
+
		pkg->flags &= ~(PKG_CONTAINS_ELF_OBJECTS |
+
				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);
+
		else
+
			strlcpy(fpath, file->path, sizeof(fpath));
+

+
		ret = pkg_analyse(ctx.developer_mode, pkg, fpath);
+
		if (EPKG_WARN == ret) {
+
			failures = true;
+
		}
+
	}
+

+
	/*
+
	 * Do not depend on libraries that a package provides itself
+
	 */
+
	tll_foreach(pkg->shlibs_required, s) {
+
		if (stringlist_contains(&pkg->shlibs_provided, s->item)) {
+
			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);
+
			continue;
+
		}
+
		file = NULL;
+
		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 "
+
				    "the package %s provides this file itself",
+
				    s->item, pkg->name);
+

+
				tll_remove_and_free(pkg->shlibs_required, s, free);
+
				break;
+
			}
+
		}
+
	}
+

+
	/*
+
	 * if the package is not supposed to provide share libraries then
+
	 * drop the provided one
+
	 */
+
	if (pkg_kv_get(&pkg->annotations, "no_provide_shlib") != NULL) {
+
		tll_free_and_free(pkg->shlibs_provided, free);
+
	}
+

+
	if (failures)
+
		goto cleanup;
+

+
	ret = EPKG_OK;
+

+
cleanup:
+
	ret = pkg_analyse_close();
+

+
	return (ret);
+
}
added libpkg/pkg_abi_macho.c
@@ -0,0 +1,228 @@
+
/*-
+
 * 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.
+
 */
+

+
#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.
+
 */
+

+
/**** CPU -> FreeBSD MACHINE_ARCH conversion ****/
+

+
static const char *
+
cputype_to_freebsd_machine_arch(const cpu_type_subtype_t cpu)
+
{
+
	switch (cpu.type) {
+
	case CPU_TYPE_ARM:
+
		if (cpu.type_is64_32) {
+
			return "aarch64-x32";
+
		} else if (cpu.type_is64) {
+
			return "aarch64";
+
		} else {
+
			switch (cpu.subtype_arm) {
+
			case CPU_SUBTYPE_ARM_V7:
+
			case CPU_SUBTYPE_ARM_V7S:
+
			case CPU_SUBTYPE_ARM_V7K:
+
			case CPU_SUBTYPE_ARM_V7M:
+
			case CPU_SUBTYPE_ARM_V7EM:
+
				return "armv7";
+
			case CPU_SUBTYPE_ARM_V6:
+
			case CPU_SUBTYPE_ARM_V6M:
+
				return "armv6";
+
			case CPU_SUBTYPE_ARM_XSCALE:
+
			case CPU_SUBTYPE_ARM_V5:
+
			case CPU_SUBTYPE_ARM_V4T:
+
				return "armeb";
+
			case CPU_SUBTYPE_ARM_ALL:
+
			default:
+
				return "arm";
+
			}
+
		}
+
	case CPU_TYPE_POWERPC:
+
		if (cpu.type_is64_32) {
+
			return "powerpc64-x32";
+
		} else if (cpu.type_is64) {
+
			return "powerpc64";
+
		} else {
+
			return "powerpc";
+
		}
+
	case CPU_TYPE_X86:
+
		if (cpu.type_is64_32) {
+
			return "amd64-x32";
+
		} else if (cpu.type_is64) {
+
			return "amd64";
+
		} else {
+
			return "i386";
+
		}
+
	default:
+
		return "unknown";
+
	}
+
}
+

+
int
+
pkg_get_myarch_macho(int fd, struct os_info *oi)
+
{
+
	ssize_t x;
+
	char *dest = oi->abi;
+
	size_t sz = sizeof(oi->abi);
+

+
	macho_file_t *mf = 0;
+
	build_version_t *bv = 0;
+

+
	if ((x = read_macho_file(fd, &mf)) < 0) {
+
		goto cleanup;
+
	}
+

+
	if (0 == mf->narch) {
+
		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;
+
	}
+
	size_t n = 0;
+
	macho_header_t mh;
+
	if ((x = read_macho_header(fd, &mh)) < 0) {
+
		goto cleanup;
+
	}
+
	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))) {
+
					goto cleanup;
+
				}
+
				n += loadcmdsize - 8;
+
				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;
+
			}
+
	}
+

+
	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));
+
		}
+
		return EPKG_OK;
+
	}
+

+

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

+

+
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 ret = EPKG_OK;
+
	// int ret = analyse_macho(pkg, fpath);
+
	if (developer_mode) {
+
		if (ret != EPKG_OK && ret != EPKG_END) {
+
			return EPKG_WARN;
+
		}
+
	}
+
	return ret;
+
}
+

+
int pkg_analyse_close_macho() {
+
	return EPKG_OK;
+
}
modified libpkg/pkg_add.c
@@ -1192,7 +1192,7 @@ pkg_add_check_pkg_archive(struct pkgdb *db, struct pkg *pkg,
	struct pkg	*pkg_inst = NULL;
	bool	fromstdin;

-
	arch = pkg->abi != NULL ? pkg->abi : pkg->arch;
+
	arch = pkg->abi != NULL ? pkg->abi : pkg->altabi;

	if (!is_valid_abi(arch, true) && (flags & PKG_ADD_FORCE) == 0) {
		return (EPKG_FATAL);
modified libpkg/pkg_attributes.c
@@ -3,7 +3,7 @@
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2013 Matthew Seaman <matthew@FreeBSD.org>
 * All rights reserved.
-
 * 
+
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
@@ -13,7 +13,7 @@
 * 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.
@@ -244,7 +244,7 @@ pkg_get_element(struct pkg *p, pkg_attr a)
		e->type = PKG_STR;
		break;
	case PKG_ATTR_ARCH:
-
		e->string = p->arch;
+
		e->string = p->altabi;
		e->type = PKG_STR;
		break;
	case PKG_ATTR_VERSION:
modified libpkg/pkg_checksum.c
@@ -205,7 +205,7 @@ pkg_checksum_generate(struct pkg *pkg, char *dest, size_t destlen,
	if (inc_version && !is_group)
		tll_push_back(entries, pkg_kv_new("version", pkg->version));
	if (!is_group)
-
		tll_push_back(entries, pkg_kv_new("arch", pkg->arch));
+
		tll_push_back(entries, pkg_kv_new("arch", pkg->altabi));

	while (pkg_options(pkg, &option) == EPKG_OK) {
		tll_push_back(entries, pkg_kv_new(option->key, option->value));
modified libpkg/pkg_config.c
@@ -58,7 +58,7 @@
#define PORTSDIR "/usr/ports"
#endif
#ifndef DEFAULT_VULNXML_URL
-
#define DEFAULT_VULNXML_URL "http://vuxml.freebsd.org/freebsd/vuln.xml.xz"
+
#define DEFAULT_VULNXML_URL "https://vuxml.freebsd.org/freebsd/vuln.xml.xz"
#endif

#ifdef	OSMAJOR
@@ -83,13 +83,13 @@ struct pkg_ctx ctx = {
	.pkg_dbdirfd = -1,
	.pkg_reposdirfd = -1,
	.devnullfd = -1,
-
	.osversion = 0,
	.backup_libraries = false,
	.triggers = true,
	.compression_format = NULL,
	.compression_level = -1,
	.compression_threads = -1,
	.defer_triggers = false,
+
	.oi = NULL,
};

struct config_entry {
@@ -99,10 +99,7 @@ struct config_entry {
	const char *desc;
};

-
static char myabi[BUFSIZ], myabi_legacy[BUFSIZ];
-
#ifdef __FreeBSD__
-
static char myosversion[BUFSIZ];
-
#endif
+
static struct os_info oi = { 0 };
static struct pkg_repo *repos = NULL;
ucl_object_t *config = NULL;

@@ -176,13 +173,13 @@ static struct config_entry c[] = {
	{
		PKG_STRING,
		"ABI",
-
		myabi,
+
		oi.abi,
		"Override the automatically detected ABI",
	},
	{
		PKG_STRING,
		"ALTABI",
-
		myabi_legacy,
+
		oi.altabi,
		"Override the automatically detected old-form ABI",
	},
	{
@@ -440,7 +437,7 @@ static struct config_entry c[] = {
	{
		PKG_INT,
		"OSVERSION",
-
		myosversion,
+
		oi.str_osversion,
		"FreeBSD OS version",
	},
	{
@@ -874,7 +871,7 @@ walk_repo_obj(const ucl_object_t *obj, const char *file, pkg_init_flags flags)

static void
load_repo_file(int dfd, const char *repodir, const char *repofile,
-
    pkg_init_flags flags, struct os_info *oi)
+
    pkg_init_flags flags)
{
	struct ucl_parser *p;
	ucl_object_t *obj = NULL;
@@ -889,23 +886,22 @@ load_repo_file(int dfd, const char *repodir, const char *repofile,

	myarch_legacy = pkg_object_string(pkg_config_get("ALTABI"));
	ucl_parser_register_variable (p, "ALTABI", myarch_legacy);
-
#ifdef __FreeBSD__
-
	ucl_parser_register_variable(p, "OSVERSION", myosversion);
-
#endif
-
	if (oi->name != NULL) {
-
		ucl_parser_register_variable(p, "OSNAME", oi->name);
+
	if (oi.ostype == OS_FREEBSD)
+
		ucl_parser_register_variable(p, "OSVERSION", oi.str_osversion);
+
	if (oi.name != NULL) {
+
		ucl_parser_register_variable(p, "OSNAME", oi.name);
	}
-
	if (oi->version != NULL) {
-
		ucl_parser_register_variable(p, "RELEASE", oi->version);
+
	if (oi.version != NULL) {
+
		ucl_parser_register_variable(p, "RELEASE", oi.version);
	}
-
	if (oi->version_major != NULL) {
-
		ucl_parser_register_variable(p, "VERSION_MAJOR", oi->version_major);
+
	if (oi.version_major != NULL) {
+
		ucl_parser_register_variable(p, "VERSION_MAJOR", oi.version_major);
	}
-
	if (oi->version_minor != NULL) {
-
		ucl_parser_register_variable(p, "VERSION_MINOR", oi->version_minor);
+
	if (oi.version_minor != NULL) {
+
		ucl_parser_register_variable(p, "VERSION_MINOR", oi.version_minor);
	}
-
	if (oi->arch != NULL) {
-
		ucl_parser_register_variable(p, "ARCH", oi->arch);
+
	if (oi.arch != NULL) {
+
		ucl_parser_register_variable(p, "ARCH", oi.arch);
	}

	errno = 0;
@@ -959,7 +955,7 @@ configfile(const struct dirent *dp)
}

static void
-
load_repo_files(const char *repodir, pkg_init_flags flags, struct os_info *oi)
+
load_repo_files(const char *repodir, pkg_init_flags flags)
{
	struct dirent **ent;
	int nents, i, fd;
@@ -970,7 +966,7 @@ load_repo_files(const char *repodir, pkg_init_flags flags, struct os_info *oi)

	nents = scandir(repodir, &ent, configfile, alphasort);
	for (i = 0; i < nents; i++) {
-
		load_repo_file(fd, repodir, ent[i]->d_name, flags, oi);
+
		load_repo_file(fd, repodir, ent[i]->d_name, flags);
		free(ent[i]);
	}
	if (nents >= 0)
@@ -979,19 +975,19 @@ load_repo_files(const char *repodir, pkg_init_flags flags, struct os_info *oi)
}

static void
-
load_repositories(const char *repodir, pkg_init_flags flags, struct os_info *oi)
+
load_repositories(const char *repodir, pkg_init_flags flags)
{
	const pkg_object *reposlist, *cur;
	pkg_iter it = NULL;

	if (repodir != NULL) {
-
		load_repo_files(repodir, flags, oi);
+
		load_repo_files(repodir, flags);
		return;
	}

	reposlist = pkg_config_get("REPOS_DIR");
	while ((cur = pkg_object_iterate(reposlist, &it)))
-
		load_repo_files(pkg_object_string(cur), flags, oi);
+
		load_repo_files(pkg_object_string(cur), flags);
}

bool
@@ -1098,7 +1094,6 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
	bool fatal_errors = false;
	int conffd = -1;
	char *tmp = NULL;
-
	struct os_info oi;
	size_t ukeylen;
	int err = EPKG_OK;
	const char *envabi;
@@ -1114,16 +1109,12 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
	memset(&oi, 0, sizeof(oi));
	envabi = getenv("ABI");
	if (envabi == NULL) {
-
		pkg_get_myarch(myabi, BUFSIZ, &oi);
-
		pkg_get_myarch_legacy(myabi_legacy, BUFSIZ);
+
		pkg_get_myarch_with_legacy(&oi);
	} else {
-
		strlcpy(myabi, envabi, sizeof(myabi));
-
		pkg_arch_to_legacy(myabi, myabi_legacy, BUFSIZ);
+
		strlcpy(oi.abi, envabi, sizeof(oi.abi));
+
		pkg_arch_to_legacy(oi.abi, oi.altabi, sizeof(oi.abi));
	}
-
#ifdef __FreeBSD__
-
	ctx.osversion = oi.osversion;
-
	snprintf(myosversion, sizeof(myosversion), "%d", ctx.osversion);
-
#endif
+
	ctx.oi = &oi;
	if (parsed != false) {
		pkg_emit_error("pkg_init() must only be called once");
		err = EPKG_FATAL;
@@ -1231,11 +1222,10 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
	}

	p = ucl_parser_new(0);
-
	ucl_parser_register_variable (p, "ABI", myabi);
-
	ucl_parser_register_variable (p, "ALTABI", myabi_legacy);
-
#ifdef __FreeBSD__
-
	ucl_parser_register_variable(p, "OSVERSION", myosversion);
-
#endif
+
	ucl_parser_register_variable (p, "ABI", oi.abi);
+
	ucl_parser_register_variable (p, "ALTABI", oi.altabi);
+
	if (oi.ostype == OS_FREEBSD)
+
		ucl_parser_register_variable(p, "OSVERSION", oi.str_osversion);
	if (oi.name != NULL) {
		ucl_parser_register_variable(p, "OSNAME", oi.name);
	}
@@ -1423,9 +1413,6 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)

	dbg(1, "pkg initialized");

-
#ifdef __FreeBSD__
-
	ctx.osversion = pkg_object_int(pkg_config_get("OSVERSION"));
-
#endif
	/* Start the event pipe */
	evpipe = pkg_object_string(pkg_config_get("EVENT_PIPE"));
	if (evpipe != NULL)
@@ -1465,7 +1452,7 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
		setenv("HTTP_USER_AGENT", "pkg/"PKGVERSION, 1);

	/* load the repositories */
-
	load_repositories(reposdir, flags, &oi);
+
	load_repositories(reposdir, flags);

	object = ucl_object_find_key(config, "REPOSITORIES");
	while ((cur = ucl_iterate_object(object, &it, true))) {
modified libpkg/pkg_create.c
@@ -565,13 +565,10 @@ fixup_abi(struct pkg *pkg, const char *rootdir, bool testing)

	/* if no arch autodetermine it */
	if (pkg->abi == NULL) {
-
#ifdef __FreeBSD__
-
		char *osversion;
-
		xasprintf(&osversion, "%d", ctx.osversion);
-
		pkg_kv_add(&pkg->annotations, "FreeBSD_version", osversion, "annotation");
-
#endif
-
		arch = pkg_object_string(pkg_config_get("ABI"));
-
		pkg->abi = xstrdup(arch);
+
		if (ctx.oi->ostype == OS_FREEBSD) {
+
			pkg_kv_add(&pkg->annotations, "FreeBSD_version", xstrdup(ctx.oi->str_osversion), "annotation");
+
		}
+
		pkg->abi = xstrdup(ctx.oi->abi);
		defaultarch = true;
	}

modified libpkg/pkg_elf.c
@@ -1,28 +1,8 @@
/*-
-
 * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
-
 * All rights reserved.
-
 * 
-
 * 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
 */

#ifdef HAVE_CONFIG_H
@@ -66,12 +46,12 @@
#include "private/event.h"
#include "private/elf_tables.h"
#include "private/ldconfig.h"
+
#include "private/binfmt.h"

#ifndef NT_ABI_TAG
#define NT_ABI_TAG 1
#endif

-
#define _PATH_UNAME "/usr/bin/uname"

/* FFR: when we support installing a 32bit package on a 64bit host */
#define _PATH_ELF32_HINTS       "/var/run/ld-elf32.so.hints"
@@ -166,7 +146,7 @@ shlib_valid_abi(const char *fpath, GElf_Ehdr *hdr)
	 */
	arch[0] = '\0';
	wordsize[0] = '\0';
-
	p = pkg_object_string(pkg_config_get("ALTABI"));
+
	p = pkg_object_string(pkg_config_get("ABI"));
	for(semicolon = 0; semicolon < 3 && p != NULL; semicolon ++, p ++) {
		p = strchr(p, ':');
		if (p != NULL) {
@@ -283,6 +263,12 @@ analyse_elf(struct pkg *pkg, const char *fpath)
		return (EPKG_FATAL);
	}

+
	if (elf_version(EV_CURRENT) == EV_NONE) {
+
		pkg_emit_error("ELF library initialization failed: %s",
+
		    elf_errmsg(-1));
+
		return (EPKG_FATAL);
+
	}
+

	if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
		ret = EPKG_FATAL;
		pkg_debug(1, "elf_begin() for %s failed: %s", fpath,
@@ -301,8 +287,8 @@ analyse_elf(struct pkg *pkg, const char *fpath)
		pkg->flags |= PKG_CONTAINS_ELF_OBJECTS;

	if (gelf_getehdr(e, &elfhdr) == NULL) {
-
		ret = EPKG_FATAL;
-
		pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1));
+
		ret = EPKG_WARN;
+
		pkg_debug(1, "getehdr() failed: %s.", elf_errmsg(-1));
		goto cleanup;
	}

@@ -464,103 +450,6 @@ analyse_fpath(struct pkg *pkg, const char *fpath)
	return (EPKG_OK);
}

-
int
-
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];
-
	const char *lib;
-
	bool failures = false;
-

-
	if (tll_length(pkg->shlibs_required) != 0) {
-
		tll_free_and_free(pkg->shlibs_required, free);
-
	}
-

-
	if (tll_length(pkg->shlibs_provided) != 0) {
-
		tll_free_and_free(pkg->shlibs_provided, free);
-
	}
-

-
	if (elf_version(EV_CURRENT) == EV_NONE)
-
		return (EPKG_FATAL);
-

-
	shlib_list_init();
-

-
	if (stage != NULL && pkg_object_bool(pkg_config_get("ALLOW_BASE_SHLIBS"))) {
-
		/* Do not check the return */
-
		shlib_list_from_stage(stage);
-
	}
-

-
	ret = shlib_list_from_elf_hints(_PATH_ELF_HINTS);
-
	if (ret != EPKG_OK)
-
		goto cleanup;
-

-
	/* Assume no architecture dependence, for contradiction */
-
	if (ctx.developer_mode)
-
		pkg->flags &= ~(PKG_CONTAINS_ELF_OBJECTS |
-
				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);
-
		else
-
			strlcpy(fpath, file->path, sizeof(fpath));
-

-
		ret = analyse_elf(pkg, fpath);
-
		if (ctx.developer_mode) {
-
			if (ret != EPKG_OK && ret != EPKG_END) {
-
				failures = true;
-
				continue;
-
			}
-
			analyse_fpath(pkg, fpath);
-
		}
-
	}
-

-
	/*
-
	 * Do not depend on libraries that a package provides itself
-
	 */
-
	tll_foreach(pkg->shlibs_required, s) {
-
		if (stringlist_contains(&pkg->shlibs_provided, s->item)) {
-
			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);
-
			continue;
-
		}
-
		file = NULL;
-
		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 "
-
				    "the package %s provides this file itself",
-
				    s->item, pkg->name);
-

-
				tll_remove_and_free(pkg->shlibs_required, s, free);
-
				break;
-
			}
-
		}
-
	}
-

-
	/*
-
	 * if the package is not supposed to provide share libraries then
-
	 * drop the provided one
-
	 */
-
	if (pkg_kv_get(&pkg->annotations, "no_provide_shlib") != NULL) {
-
		tll_free_and_free(pkg->shlibs_provided, free);
-
	}
-

-
	if (failures)
-
		goto cleanup;
-

-
	ret = EPKG_OK;
-

-
cleanup:
-
	shlib_list_free();
-

-
	return (ret);
-
}
-

static const char *
elf_corres_to_string(const struct _elf_corres* m, int e)
{
@@ -666,7 +555,7 @@ aeabi_parse_arm_attributes(void *data, size_t length)

			/*
			 * These tag values come from:
-
			 * 
+
			 *
			 * Addenda to, and Errata in, the ABI for the
			 * ARM Architecture. Release 2.08, section 2.3.
			 */
@@ -698,7 +587,7 @@ aeabi_parse_arm_attributes(void *data, size_t length)
				MOVE_TAG(1);
			} else if ((tag >= 7 && tag <= 31) || tag == 34 ||
			    tag == 36 || tag == 38 || tag == 42 || tag == 44 ||
-
			    tag == 64 || tag == 66 || tag == 68 || tag == 70) { 
+
			    tag == 64 || tag == 66 || tag == 68 || tag == 70) {
				/* Skip the uleb128 data */
				while (*section & (1 << 7) && length != 0)
					MOVE_TAG(1);
@@ -724,6 +613,7 @@ elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct os_info *oi)
	char *src;
	uint32_t gnu_abi_tag[4];
	char *note_os[6] = {"Linux", "GNU", "Solaris", "FreeBSD", "NetBSD", "Syllable"};
+
	int note_ost[6] = {OS_LINUX, OS_GNU, OS_SOLARIS, OS_FREEBSD, OS_NETBSD, OS_SYLLABLE};
	char *(*pnote_os)[6] = &note_os;
	char invalid_osname[] = "Unknown";
	uint32_t version = 0;
@@ -777,15 +667,26 @@ elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct os_info *oi)
				src += 4;
			}
		}
-
		if (gnu_abi_tag[0] < 6)
+
		if (gnu_abi_tag[0] < 6) {
			oi->name = xstrdup((*pnote_os)[gnu_abi_tag[0]]);
-
		else
+
			oi->ostype = note_ost[gnu_abi_tag[0]];
+
		} else {
			oi->name = xstrdup(invalid_osname);
+
			oi->ostype = OS_UNKNOWN;
+
		}
	} else {
-
		if (note.n_namesz == 0)
+
		if (note.n_namesz == 0) {
			oi->name = xstrdup(invalid_osname);
-
		else
+
			oi->ostype = OS_UNKNOWN;
+
		} else {
			oi->name = xstrdup(src);
+
			if (STREQ(src, "FreeBSD"))
+
				oi->ostype = OS_FREEBSD;
+
			else if (STREQ(src, "DragonFly"))
+
				oi->ostype = OS_DRAGONFLY;
+
			else if (STREQ(src, "NetBSD"))
+
				oi->ostype = OS_NETBSD;
+
		}
		src += roundup2(note.n_namesz, 4);
		if (elfhdr->e_ident[EI_DATA] == ELFDATA2MSB)
			version = be32dec(src);
@@ -795,91 +696,52 @@ elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct os_info *oi)

	free(oi->version);
	if (version_style == 2) {
-
		xasprintf(&oi->version, "%d.%d.%d", gnu_abi_tag[1],
-
		    gnu_abi_tag[2], gnu_abi_tag[3]);
+
		if (oi->ostype == OS_LINUX) {
+
			xasprintf(&oi->version, "%d.%d", gnu_abi_tag[1],
+
			    gnu_abi_tag[2]);
+
		} else {
+
			xasprintf(&oi->version, "%d.%d.%d", gnu_abi_tag[1],
+
			    gnu_abi_tag[2], gnu_abi_tag[3]);
+
		}
	} else {
-
		if (oi->osversion == 0)
+
		if (oi->osversion == 0) {
			oi->osversion = version;
-
#ifdef __DragonFly__
-
		xasprintf(&oi->version, "%d.%d", version / 100000, (((version / 100 % 1000)+1)/2)*2);
-
#endif
-
#ifdef __NetBSD__
-
		xasprintf(&oi->version, "%d", (version + 1000000) / 100000000);
-
#endif
-
		xasprintf(&oi->version_major, "%d", version / 100000);
-
		xasprintf(&oi->version_minor, "%d", (version / 1000 % 100));
-
		xasprintf(&oi->version, "%d", version / 100000);
+
			snprintf(oi->str_osversion, sizeof(oi->str_osversion), "%d", version);
+
		}
+
		if (oi->ostype == OS_DRAGONFLY) {
+
			xasprintf(&oi->version, "%d.%d", version / 100000, (((version / 100 % 1000)+1)/2)*2);
+
		} else if (oi->ostype == OS_NETBSD) {
+
			xasprintf(&oi->version, "%d", (version + 1000000) / 100000000);
+
		} else {
+
			xasprintf(&oi->version_major, "%d", version / 100000);
+
			xasprintf(&oi->version_minor, "%d", (version / 1000 % 100));
+
			xasprintf(&oi->version, "%d", version / 100000);
+
		}
	}

	return (true);
}

-

-
static int
-
pkg_get_myarch_elfparse(char *dest, size_t sz, struct os_info *oi)
+
int
+
pkg_get_myarch_elfparse(int fd, struct os_info *oi)
{
-
	char rooted_abi_file[PATH_MAX];
	Elf *elf = NULL;
	GElf_Ehdr elfhdr;
	GElf_Shdr shdr;
	Elf_Data *data;
	Elf_Scn *scn = NULL;
-
	int fd, i;
	int ret = EPKG_OK;
-
	const char *arch, *abi, *endian_corres_str, *wordsize_corres_str, *fpu;
-
	bool checkroot;
-
	struct os_info loi;
+
	const char *arch,*abi, *endian_corres_str, *wordsize_corres_str, *fpu;
+
	char *dest = oi->abi;
+
	size_t sz = sizeof(oi->abi);
	size_t dsz;

-
	const char *abi_files[] = {
-
		getenv("ABI_FILE"),
-
		_PATH_UNAME,
-
		_PATH_BSHELL,
-
	};
-

-
	arch = NULL;
-

-
	if (oi == NULL) {
-
		memset(&loi, 0, sizeof(loi));
-
		oi = &loi;
-
	}
-

	if (elf_version(EV_CURRENT) == EV_NONE) {
		pkg_emit_error("ELF library initialization failed: %s",
		    elf_errmsg(-1));
		return (EPKG_FATAL);
	}

-
	/*
-
	 * Perhaps not yet needed, but it may be in the future that there's no
-
	 * need to check root under some conditions where there is a rootdir.
-
	 * This also helps alleviate some excessive wrapping later.
-
	 */
-
	checkroot = ctx.pkg_rootdir != NULL;
-
	for (fd = -1, i = 0; i < NELEM(abi_files); i++) {
-
		if (abi_files[i] == NULL)
-
			continue;
-
		/*
-
		 * 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)
-
				break;
-
		}
-
		if ((fd = open(abi_files[i], 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);
-
	}
-

	if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
		ret = EPKG_FATAL;
		pkg_emit_error("elf_begin() failed: %s.", elf_errmsg(-1));
@@ -887,12 +749,11 @@ pkg_get_myarch_elfparse(char *dest, size_t sz, struct os_info *oi)
	}

	if (gelf_getehdr(elf, &elfhdr) == NULL) {
-
		ret = EPKG_FATAL;
-
		pkg_emit_error("getehdr() failed: %s.", elf_errmsg(-1));
+
		ret = EPKG_WARN;
+
		pkg_debug(1, "getehdr() failed: %s.", elf_errmsg(-1));
		goto cleanup;
	}

-

	while ((scn = elf_nextscn(elf, scn)) != NULL) {
		if (gelf_getshdr(scn, &shdr) != &shdr) {
			ret = EPKG_FATAL;
@@ -921,271 +782,49 @@ pkg_get_myarch_elfparse(char *dest, size_t sz, struct os_info *oi)
	wordsize_corres_str = elf_corres_to_string(wordsize_corres,
	    (int)elfhdr.e_ident[EI_CLASS]);

-
	arch = elf_corres_to_string(mach_corres, (int) elfhdr.e_machine);
-

-
	switch (elfhdr.e_machine) {
-
	case EM_ARM:
-
		endian_corres_str = elf_corres_to_string(endian_corres,
-
		    (int)elfhdr.e_ident[EI_DATA]);
+
	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));

-
		if (elfhdr.e_flags & EF_ARM_VFP_FLOAT)
-
			fpu = "hardfp";
-
		else
-
			fpu = "softfp";
-

-
		if ((elfhdr.e_flags & 0xFF000000) != 0) {
-
			const char *sh_name = NULL;
-
			size_t shstrndx;
-

-
			/* This is an EABI file, the conformance level is set */
-
			abi = "eabi";
-

-
			/* Find which TARGET_ARCH we are building for. */
-
			elf_getshdrstrndx(elf, &shstrndx);
-
			while ((scn = elf_nextscn(elf, scn)) != NULL) {
-
				sh_name = NULL;
-
				if (gelf_getshdr(scn, &shdr) != &shdr) {
-
					scn = NULL;
-
					break;
-
				}
-

-
				sh_name = elf_strptr(elf, shstrndx,
-
				    shdr.sh_name);
-
				if (sh_name == NULL)
-
					continue;
-
				if (STREQ(".ARM.attributes", sh_name))
-
					break;
-
			}
-
			if (scn != NULL && sh_name != NULL) {
-
				data = elf_getdata(scn, NULL);
-
				/*
-
				 * Prior to FreeBSD 10.0 libelf would return
-
				 * NULL from elf_getdata on the .ARM.attributes
-
				 * section. As this was the first release to
-
				 * get armv6 support assume a NULL value means
-
				 * arm.
-
				 *
-
				 * This assumption can be removed when 9.x
-
				 * is unsupported.
-
				 */
-
				if (data != NULL) {
-
					arch = aeabi_parse_arm_attributes(
-
					    data->d_buf, data->d_size);
-
					if (arch == NULL) {
-
						ret = EPKG_FATAL;
-
						pkg_emit_error(
-
						    "unknown ARM ARCH");
-
						goto cleanup;
-
					}
-
				}
-
			} else {
-
				ret = EPKG_FATAL;
-
				pkg_emit_error("Unable to find the "
-
				    ".ARM.attributes section");
-
				goto cleanup;
-
			}
-

-
		} else if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_NONE) {
-
			/*
-
			 * EABI executables all have this field set to
-
			 * ELFOSABI_NONE, therefore it must be an oabi file.
-
			 */
-
			abi = "oabi";
-
                } else {
-
			/*
-
			 * We may have failed to positively detect the ABI,
-
			 * set the ABI to unknown. If we end up here one of
-
			 * the above cases should be fixed for the binary.
-
			 */
-
			ret = EPKG_FATAL;
-
			pkg_emit_error("unknown ARM ABI");
-
			goto cleanup;
-
		}
-
		dsz = strlen(dest);
-
		snprintf(dest + dsz, sz - dsz,
-
		    ":%s:%s:%s:%s:%s", arch, wordsize_corres_str,
-
		    endian_corres_str, abi, fpu);
-
		break;
-
	case EM_MIPS:
-
		/*
-
		 * this is taken from binutils sources:
-
		 * include/elf/mips.h
-
		 * mapping is figured out from binutils:
-
		 * gas/config/tc-mips.c
-
		 */
-
		switch (elfhdr.e_flags & EF_MIPS_ABI) {
-
			case E_MIPS_ABI_O32:
-
				abi = "o32";
-
				break;
-
			case E_MIPS_ABI_N32:
-
				abi = "n32";
-
				break;
-
			default:
-
				if (elfhdr.e_ident[EI_DATA] == ELFCLASS32)
-
					abi = "o32";
-
				else if (elfhdr.e_ident[EI_DATA] == ELFCLASS64)
-
					abi = "n64";
-
				else
-
					abi = "unknown";
-
				break;
-
		}
-
		endian_corres_str = elf_corres_to_string(endian_corres,
-
		    (int)elfhdr.e_ident[EI_DATA]);
-

-
		dsz = strlen(dest);
-
		snprintf(dest + dsz, sz - dsz, ":%s:%s:%s:%s",
-
		    arch, wordsize_corres_str, endian_corres_str, abi);
-
		break;
-
#if defined(EM_RISCV) && defined(EF_RISCV_FLOAT_ABI_MASK)
-
	case EM_RISCV:
-
		switch (elfhdr.e_flags & EF_RISCV_FLOAT_ABI_MASK) {
-
			case EF_RISCV_FLOAT_ABI_SOFT:
-
				abi = "sf";
-
				break;
-
			case EF_RISCV_FLOAT_ABI_DOUBLE:
-
				abi = "hf";
-
				break;
-
			default:
-
				abi = "unknown";
-
				break;
-
		}
-
		dsz = strlen(dest);
-
		snprintf(dest + dsz, sz - dsz, ":%s:%s:%s",
-
		    arch, wordsize_corres_str, abi);
-
		break;
-
#endif
-
	case EM_PPC:
-
	case EM_PPC64:
-
		endian_corres_str = elf_corres_to_string(endian_corres,
-
		    (int)elfhdr.e_ident[EI_DATA]);
-

-
		dsz = strlen(dest);
-
		snprintf(dest + dsz, sz - dsz, ":%s:%s:%s",
-
		    arch, wordsize_corres_str, endian_corres_str);
-
		break;
-
	default:
-
		dsz = strlen(dest);
-
		snprintf(dest + dsz, sz - dsz, ":%s:%s",
-
		    arch, wordsize_corres_str);
-
		break;
-
	}
+
	dsz = strlen(dest);
+
	snprintf(dest + dsz, sz - dsz, ":%s", oi->arch);

cleanup:
	if (elf != NULL)
		elf_end(elf);
-
	if (oi == &loi) {
-
		free(oi->name);
-
		free(oi->version);
-
		free(oi->version_major);
-
		free(oi->version_minor);
-
		free(oi->arch);
-
	}
-
	close(fd);
	return (ret);
}

-
int
-
pkg_arch_to_legacy(const char *arch, char *dest, size_t sz)
-
{
-
	int i = 0;
-
	struct arch_trans *arch_trans;
-

-
	memset(dest, '\0', sz);
-
	/* Lower case the OS */
-
	while (arch[i] != ':' && arch[i] != '\0') {
-
		dest[i] = tolower(arch[i]);
-
		i++;
-
	}
-
	if (arch[i] == '\0')
-
		return (0);
-

-
	dest[i++] = ':';
-

-
	/* Copy the version */
-
	while (arch[i] != ':' && arch[i] != '\0') {
-
		dest[i] = arch[i];
-
		i++;
-
	}
-
	if (arch[i] == '\0')
-
		return (0);
+
int pkg_analyse_init_elf(const char* stage) {
+
	if (elf_version(EV_CURRENT) == EV_NONE)
+
		return (EPKG_FATAL);

-
	dest[i++] = ':';
+
	shlib_list_init();

-
	for (arch_trans = machine_arch_translation; arch_trans->elftype != NULL;
-
	    arch_trans++) {
-
		if (STREQ(arch + i, arch_trans->archid)) {
-
			strlcpy(dest + i, arch_trans->elftype,
-
			    sz - (arch + i - dest));
-
			return (0);
-
		}
+
	if (stage != NULL && pkg_object_bool(pkg_config_get("ALLOW_BASE_SHLIBS"))) {
+
		/* Do not check the return */
+
		shlib_list_from_stage(stage);
	}
-
	strlcpy(dest + i, arch + i, sz - (arch + i  - dest));
-

-
	return (0);
-
}
-

-
int
-
pkg_get_myarch_legacy(char *dest, size_t sz)
-
{
-
	int i, err;
-
	size_t dsz;

-
	err = pkg_get_myarch_elfparse(dest, sz, NULL);
-
	if (err)
-
		return (err);
-

-
	dsz = strlen(dest);
-
	for (i = 0; i < dsz; i++)
-
		dest[i] = tolower(dest[i]);
-

-
	return (0);
+
	int ret = shlib_list_from_elf_hints(_PATH_ELF_HINTS);
+
	return ret;
}

-
int
-
pkg_get_myarch(char *dest, size_t sz, struct os_info *oi)
-
{
-
	struct arch_trans *arch_trans;
-
	char *arch_tweak;
-
	int err;
-

-
	err = pkg_get_myarch_elfparse(dest, sz, oi);
-
	if (err) {
-
		if (oi) {
-
			free(oi->name);
-
		}
-
		return (err);
-
	}
-

-
#ifdef __DragonFly__
-
	size_t dsz;
-

-
	dsz = strlen(dest);
-
	if (strncasecmp(dest, "DragonFly", 9) == 0) {
-
		for (int i = 0; i < dsz; i++)
-
			dest[i] = tolower(dest[i]);
-
		return (0);
-
	}
-
#endif
-

-
	/* Translate architecture string back to regular OS one */
-
	arch_tweak = strchr(dest, ':');
-
	if (arch_tweak == NULL)
-
		return (0);
-
	arch_tweak++;
-
	arch_tweak = strchr(arch_tweak, ':');
-
	if (arch_tweak == NULL)
-
		return (0);
-
	arch_tweak++;
-
	for (arch_trans = machine_arch_translation; arch_trans->elftype != NULL;
-
	    arch_trans++) {
-
		if (STREQ(arch_tweak, arch_trans->elftype)) {
-
			strlcpy(arch_tweak, arch_trans->archid,
-
			    sz - (arch_tweak - dest));
-
			oi->arch = xstrdup(arch_tweak);
-
			break;
+
int pkg_analyse_elf(const bool developer_mode, struct pkg *pkg, const char *fpath) {
+
		int ret = analyse_elf(pkg, fpath);
+
		if (developer_mode) {
+
			if (ret != EPKG_OK && ret != EPKG_END) {
+
				return EPKG_WARN;
+
			}
+
			analyse_fpath(pkg, fpath);
		}
-
	}
-

-
	return (0);
+
		return ret;
}

+
int pkg_analyse_close_elf() {
+
	shlib_list_free();
+
	return EPKG_OK;
+
}
modified libpkg/pkg_jobs.c
@@ -1081,10 +1081,10 @@ pkg_jobs_need_upgrade(struct pkg *rp, struct pkg *lp)
		return (true);

	/* Compare archs */
-
	if (!STREQ(lp->arch, rp->arch)) {
+
	if (!STREQ(lp->abi, rp->abi)) {
		free(rp->reason);
		xasprintf(&rp->reason, "ABI changed: '%s' -> '%s'",
-
		    lp->arch, rp->arch);
+
		    lp->abi, rp->abi);
		assert(rp->reason != NULL);
		return (true);
	}
modified libpkg/pkg_macho.c
@@ -47,6 +47,7 @@
#include "pkg.h"
#include "private/pkg.h"
#include "private/event.h"
+
#include "private/binfmt.h"

static const char * const system_dylib_prefixes[] = {
	"/System/",
@@ -107,7 +108,7 @@ analyse_macho(struct pkg *pkg, const char *fpath,
			xasprintf(&libname, "%s.%s", march->mat_install_name, ai->name);
			pkg_addshlib_provided(pkg, libname);
			is_shlib = true;
-
		
+


		/* Now find all dependencies */
		for (macho_loadcmd_t *cmd = march->mat_loadcmds; cmd != NULL; cmd = cmd->next) {
modified libpkg/pkg_manifest.c
@@ -101,7 +101,7 @@ static struct pkg_manifest_key {
	{ "abi",                 offsetof(struct pkg, abi),
			TYPE_SHIFT(UCL_STRING), pkg_string},

-
	{ "arch",                offsetof(struct pkg, arch),
+
	{ "arch",                offsetof(struct pkg, altabi),
			TYPE_SHIFT(UCL_STRING), pkg_string},

	{ "categories",          MANIFEST_CATEGORIES,
@@ -947,10 +947,10 @@ pkg_emit_object(struct pkg *pkg, short flags)
	ucl_object_t *map, *seq, *submap;
	ucl_object_t *top = ucl_object_typed_new(UCL_OBJECT);

-
	if (pkg->abi == NULL && pkg->arch != NULL)
-
		pkg->abi = xstrdup(pkg->arch);
+
	if (pkg->abi == NULL && pkg->altabi != NULL)
+
		pkg->abi = xstrdup(pkg->altabi);
	pkg_arch_to_legacy(pkg->abi, legacyarch, BUFSIZ);
-
	pkg->arch = xstrdup(legacyarch);
+
	pkg->altabi = xstrdup(legacyarch);
	dbg(4, "Emitting basic metadata");
	MANIFEST_EXPORT_FIELD(top, pkg, name, string);
	MANIFEST_EXPORT_FIELD(top, pkg, origin, string);
@@ -959,7 +959,8 @@ pkg_emit_object(struct pkg *pkg, short flags)
	MANIFEST_EXPORT_FIELD(top, pkg, maintainer, string);
	MANIFEST_EXPORT_FIELD(top, pkg, www, string);
	MANIFEST_EXPORT_FIELD(top, pkg, abi, string);
-
	MANIFEST_EXPORT_FIELD(top, pkg, arch, string);
+
	/* We need to keep altabi named arch in the manifest */
+
	ucl_object_insert_key(top, ucl_object_fromstring(pkg->altabi), "arch", 0, false);
	MANIFEST_EXPORT_FIELD(top, pkg, prefix, string);
	MANIFEST_EXPORT_FIELD(top, pkg, sum, string);
	MANIFEST_EXPORT_FIELD(top, pkg, flatsize, int);
modified libpkg/pkg_printf.c
@@ -2,7 +2,7 @@
 * Copyright (c) 2012-2015 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2014-2020 Baptiste Daroussin <bapt@FreeBSD.org>
 * All rights reserved.
-
 * 
+
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
@@ -12,7 +12,7 @@
 * 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.
@@ -68,7 +68,7 @@
 * Dp pkg_dir      Directory permissions
 * Dt pkg_dir      Try flag (@dirrmtry in plist)
 * Du pkg_dir      User owner of directory
-
 * 
+
 *
 * E
 *
 * F  pkg          List of files
@@ -77,7 +77,7 @@
 * Fn pkg_file     File path name
 * Fp pkg_file     File permissions
 * Fs pkg_file     File SHA256 checksum
-
 * Fu pkg_file     User owner of file 
+
 * Fu pkg_file     User owner of file
 *
 * G  pkg          List of groups
 * Gn pkg_group    Group name
@@ -852,7 +852,7 @@ static const struct pkg_printf_fmt fmt[] = {
 * %A -- Annotations.  Free-form tag+value text that can be added to
 * packages.  Optionally accepts per-field format in %{ %| %} Default
 * %{%An: %Av\n%|%}
-
 */  
+
 */
xstring *
format_annotations(xstring *buf, const void *data, struct percent_esc *p)
{
@@ -1342,7 +1342,7 @@ format_repo_ident(xstring *buf, const void *data, struct percent_esc *p)
 * %O -- Options. list of {option,value} tuples. Optionally accepts
 * following per-field format in %{ %| %}, where %On is replaced by the
 * option name and %Ov by the value.  Default %{%On %Ov\n%|%}
-
 */ 
+
 */
xstring *
format_options(xstring *buf, const void *data, struct percent_esc *p)
{
@@ -1424,7 +1424,7 @@ format_altabi(xstring *buf, const void *data, struct percent_esc *p)
{
	const struct pkg	*pkg = data;

-
	return (string_val(buf, pkg->arch, p));
+
	return (string_val(buf, pkg->altabi, p));
}

/*
@@ -2073,7 +2073,7 @@ gen_format(char *buf, size_t buflen, unsigned flags, const char *tail)

	if (buflen - bp < tlen + 2)
		return (NULL);
-
	
+

	if (flags & PP_EXPLICIT_PLUS)
		buf[bp++] = '+';

@@ -2533,9 +2533,9 @@ format_trailer(const char *f, struct percent_esc *p)
				fputc(*f2, p->sep_fmt->fp);
				fflush(p->sep_fmt->fp);
			}
-
			
+

		}
-
		
+

		if (done) {
			f = f1;
		} else {
@@ -2789,7 +2789,7 @@ read_oct_byte(xstring *buf, const char *f)
		}

		f++;
-
	} 
+
	}
done:
	fputc(val, buf->fp);

@@ -2863,7 +2863,7 @@ process_escape(xstring *buf, const char *f)

const char *
process_format_trailer(xstring *buf, struct percent_esc *p,
-
		       const char *f, const struct pkg *pkg, 
+
		       const char *f, const struct pkg *pkg,
		       const void *data, int count, unsigned context)
{
	const char		*fstart;
@@ -3037,7 +3037,7 @@ pkg_vdprintf(int fd, const char * restrict format, va_list ap)
	fflush(buf->fp);
	if (buf && strlen(buf->buf) > 0) {
		count = dprintf(fd, "%s", buf->buf);
-
	} else 
+
	} else
		count = -1;
	if (buf)
		xstring_free(buf);
@@ -3103,7 +3103,7 @@ pkg_vsnprintf(char * restrict str, size_t size, const char * restrict format,
 * Allocate a string buffer ret sufficiently big to contain formatted
 * data data from pkg as indicated by the format code format
 * @param ret location of pointer to be set to point to buffer containing
-
 * result 
+
 * result
 * @param ... Varargs list of struct pkg etc. supplying the data
 * @param format String with embedded %-escapes indicating what to output
 * @return count of the number of characters printed
@@ -3125,7 +3125,7 @@ pkg_asprintf(char **ret, const char * restrict format, ...)
 * Allocate a string buffer ret sufficiently big to contain formatted
 * data data from pkg as indicated by the format code format
 * @param ret location of pointer to be set to point to buffer containing
-
 * result 
+
 * result
 * @param ap Varargs list of struct pkg etc. supplying the data
 * @param format String with embedded %-escapes indicating what to output
 * @return count of the number of characters printed
modified libpkg/pkg_solve.c
@@ -300,10 +300,10 @@ pkg_solve_handle_provide (struct pkg_solve_problem *problem,
		if (pr->is_shlib) {
			libfound = stringlist_contains(&pkg->shlibs_provided, pr->provide);
			/* Skip incompatible ABI as well */
-
			if (libfound && !STREQ(pkg->arch, orig->arch)) {
+
			if (libfound && !STREQ(pkg->abi, orig->abi)) {
				dbg(2, "require %s: package %s-%s(%c) provides wrong ABI %s, "
					"wanted %s", pr->provide, pkg->name, pkg->version,
-
					pkg->type == PKG_INSTALLED ? 'l' : 'r', pkg->arch, orig->arch);
+
					pkg->type == PKG_INSTALLED ? 'l' : 'r', pkg->abi, orig->abi);
				continue;
			}
		}
modified libpkg/pkgdb.c
@@ -1662,7 +1662,7 @@ pkgdb_register_pkg(struct pkgdb *db, struct pkg *pkg, int forced,
		return (EPKG_FATAL);

	/* Prefer new ABI over old one */
-
	arch = pkg->abi != NULL ? pkg->abi : pkg->arch;
+
	arch = pkg->abi != NULL ? pkg->abi : pkg->altabi;

	/*
	 * Insert package record
modified libpkg/pkgdb_iterator.c
@@ -976,7 +976,7 @@ populate_pkg(sqlite3_stmt *stmt, struct pkg *pkg) {
	}

	pkg_arch_to_legacy(pkg->abi, legacyarch, BUFSIZ);
-
	pkg->arch = xstrdup(legacyarch);
+
	pkg->altabi = xstrdup(legacyarch);
}

static struct load_on_flag {
modified libpkg/pkgvec.h
@@ -7,6 +7,7 @@
#pragma once

#include <stdbool.h>
+
#include <stdlib.h>
#include <stddef.h>

#define pkgvec_t(Type) \
@@ -16,31 +17,37 @@
	memset((v), 0, sizeof(*(v)))

#define pkgvec_free(v) \
-
	free((v)->d);
+
	do { \
+
		free((v)->d); \
+
		(v)->d == NULL; \
+
		memset((v), 0, sizeof(*(v))); \
+
	} while (0)

#define pkgvec_free_and_free(v, free_func)            \
	do {                                          \
		for (size_t _i; _i < (v)->len ; _i++) { \
			free_func((v)->d[_i]);          \
+
			(v)->d[_i] = NULL;   \
		}                                     \
-
		free((v)->d);                           \
+
		pkgvec_free((v)); \
	} while(0)

#define pkgvec_first(v) \
	(v)->d[0]

#define pkgvec_last(v) \
-
	(v)->d[d->len -1]
+
	(v)->d[(v)->len -1]

-
#define pkgvec_clear \
+
#define pkgvec_clear(v) \
	(v)->len = 0

#define pkgvec_clear_and_free(v, free_func) \
	do {                                          \
		for (size_t _i; _i < (v)->len ; _i++) { \
			free_func((v)->d[_i]);          \
+
			(v)->d[_i] = NULL;   \
		}                                     \
-
		(v)->len = 0                            \
+
		(v)->len = 0;                            \
	} while (0)

#define pkgvec_push(v, _d)                                            \
added libpkg/private/binfmt.h
@@ -0,0 +1,12 @@
+
#pragma once
+

+
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);
+
int pkg_analyse_close_elf();
+

+
int pkg_get_myarch_macho(int fd, struct os_info *oi);
+
int pkg_analyse_init_macho(const char* stage);
+
int pkg_analyse_macho(const bool developer_mode, struct pkg *pkg, const char *fpath);
+
int pkg_analyse_close_macho();
+

added libpkg/private/binfmt_macho.h
@@ -0,0 +1,324 @@
+
/*-
+
 * 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.
+
 */
+

+
#ifndef _PKG_BINFMT_MACHO_H
+
#define _PKG_BINFMT_MACHO_H
+

+
#include <sys/types.h>
+

+
#include <stdbool.h>
+
#include <stdint.h>
+

+
/**** Magic numbers & constants ****/
+

+
// Constants for magic (big&little endian)
+
#define MH_MAGIC     0xFEEDFACEu
+
#define MH_CIGAM     0xCEFAEDFEu
+
#define MH_MAGIC_64  0xFEEDFACFu
+
#define MH_CIGAM_64  0xCFFAEDFEu
+
#define FAT_MAGIC    0xCAFEBABEu
+
#define FAT_CIGAM    0xBEBAFECAu
+
#define FAT_MAGIC_64 0xCAFEBABFu
+
#define FAT_CIGAM_64 0xBFBAFECAu
+

+
// Masks for CPUType capability bits
+
static const uint32_t CPU_ARCH_MASK = 0xff000000u;
+
static const uint32_t CPU_ARCH_ABI64 = 0x01000000u; // 64 bit ABI
+
static const uint32_t CPU_ARCH_ABI64_32 =
+
    0x02000000u; // ILP32 ABI on 64-bit hardware
+

+
// Masks for the CPUSubType
+
static const uint32_t CPU_SUBTYPE_MASK =
+
    0xff000000u; // Mask for architecture bits
+
static const uint32_t CPU_SUBTYPE_LIB64 = 0x80000000u; // 64 bit libraries
+
// static const uint32_t  CPU_SUBTYPE_MULTIPLE = ~0u;
+

+
// // arm64e uses the capability bits to encode ptrauth ABI information.
+
// // Bit 63 marks the binary as Versioned.
+
// CPU_SUBTYPE_ARM64E_VERSIONED_PTRAUTH_ABI_MASK = 0x80000000U,
+
// // Bit 62 marks the binary as using a kernel ABI.
+
// CPU_SUBTYPE_ARM64E_KERNEL_PTRAUTH_ABI_MASK = 0x40000000U,
+
// // Bits [59:56] hold the 4-bit ptrauth ABI version.
+
// CPU_SUBTYPE_ARM64E_PTRAUTH_MASK = 0x0f000000U,
+

+
enum CPUType {
+
	CPU_TYPE_ANY = -1,
+
	CPU_TYPE_VAX = 1,
+
	CPU_TYPE_ROMP,
+
	CPU_TYPE_NS32032 = 4,
+
	CPU_TYPE_NS32332,
+
	CPU_TYPE_MC680x0,
+
	CPU_TYPE_X86,
+
	CPU_TYPE_MIPS,
+
	CPU_TYPE_NS32352,
+
	CPU_TYPE_MC98000,
+
	CPU_TYPE_HPPA,
+
	CPU_TYPE_ARM,
+
	CPU_TYPE_MC88000,
+
	CPU_TYPE_SPARC,
+
	CPU_TYPE_I860BE,
+
	CPU_TYPE_I860LE,
+
	CPU_TYPE_RS6000,
+
	CPU_TYPE_POWERPC
+
};
+

+
enum CPUSubTypeX86 {
+
	CPU_SUBTYPE_X86_INVALID = -1,
+
	CPU_SUBTYPE_X86_ALL = 3,
+
	CPU_SUBTYPE_486 = 4,
+
	CPU_SUBTYPE_486SX = 0x84,
+
	CPU_SUBTYPE_586 = 5,
+
	CPU_SUBTYPE_PENTPRO = 0x16,
+
	CPU_SUBTYPE_PENTII_M3 = 0x36,
+
	CPU_SUBTYPE_PENTII_M5 = 0x56,
+
	CPU_SUBTYPE_CELERON = 0x67,
+
	CPU_SUBTYPE_CELERON_MOBILE = 0x77,
+
	CPU_SUBTYPE_PENTIUM_3 = 0x08,
+
	CPU_SUBTYPE_PENTIUM_3_M = 0x18,
+
	CPU_SUBTYPE_PENTIUM_3_XEON = 0x28,
+
	CPU_SUBTYPE_PENTIUM_M = 0x09,
+
	CPU_SUBTYPE_PENTIUM_4 = 0x0a,
+
	CPU_SUBTYPE_PENTIUM_4_M = 0x1a,
+
	CPU_SUBTYPE_ITANIUM = 0x0b,
+
	CPU_SUBTYPE_ITANIUM_2 = 0x1b,
+
	CPU_SUBTYPE_XEON = 0x0c,
+
	CPU_SUBTYPE_XEON_MP = 0x1c
+
};
+

+
enum CPUSubTypeARM {
+
	CPU_SUBTYPE_ARM_INVALID = -1,
+
	CPU_SUBTYPE_ARM_ALL,
+
	CPU_SUBTYPE_ARM64_V8,
+
	CPU_SUBTYPE_ARM64E,
+
	CPU_SUBTYPE_ARM_V4T = 5,
+
	CPU_SUBTYPE_ARM_V6,
+
	CPU_SUBTYPE_ARM_V5,
+
	CPU_SUBTYPE_ARM_V5TEJ = CPU_SUBTYPE_ARM_V5,
+
	CPU_SUBTYPE_ARM_XSCALE,
+
	CPU_SUBTYPE_ARM_V7,
+
	CPU_SUBTYPE_ARM_V7S = 11,
+
	CPU_SUBTYPE_ARM_V7K,
+
	CPU_SUBTYPE_ARM_V6M = 14,
+
	CPU_SUBTYPE_ARM_V7M,
+
	CPU_SUBTYPE_ARM_V7EM
+
};
+

+
enum CPUSubTypePPC {
+
	CPU_SUBTYPE_POWERPC_ALL = 0,
+
	CPU_SUBTYPE_POWERPC_601,
+
	CPU_SUBTYPE_POWERPC_602,
+
	CPU_SUBTYPE_POWERPC_603,
+
	CPU_SUBTYPE_POWERPC_603e,
+
	CPU_SUBTYPE_POWERPC_603ev,
+
	CPU_SUBTYPE_POWERPC_604,
+
	CPU_SUBTYPE_POWERPC_604e,
+
	CPU_SUBTYPE_POWERPC_620,
+
	CPU_SUBTYPE_POWERPC_750,
+
	CPU_SUBTYPE_POWERPC_7400,
+
	CPU_SUBTYPE_POWERPC_7450,
+
	CPU_SUBTYPE_POWERPC_970 = 100,
+

+
	CPU_SUBTYPE_MC980000_ALL = CPU_SUBTYPE_POWERPC_ALL,
+
	CPU_SUBTYPE_MC98601 = CPU_SUBTYPE_POWERPC_601
+
};
+

+
enum MachOFileType {
+
	MH_OBJECT = 0x1,
+
	MH_EXECUTE = 0x2,
+
	MH_FVMLIB = 0x3,
+
	MH_CORE = 0x4,
+
	MH_PRELOAD = 0x5,
+
	MH_DYLIB = 0x6,
+
	MH_DYLINKER = 0x7,
+
	MH_BUNDLE = 0x8,
+
	MH_DYLIB_STUB = 0x9,
+
	MH_DSYM = 0xA,
+
	MH_KEXT_BUNDLE = 0xB,
+
	MH_FILESET = 0xC
+
};
+

+
static const uint32_t LC_REQ_DYLD = 0x80000000u; // required load command flag
+

+
enum MachOLoadCommand {
+
	LC_SEGMENT = 1,
+
	LC_SYMTAB,
+
	LC_SYMSEG,
+
	LC_THREAD,
+
	LC_UNIXTHREAD,
+
	LC_LOADFVMLIB,
+
	LC_IDFVMLIB,
+
	LC_IDENT,
+
	LC_FVMFILE,
+
	LC_PREPAGE,
+
	LC_DYSYMTAB,
+
	LC_LOAD_DYLIB,
+
	LC_ID_DYLIB,
+
	LC_LOAD_DYLINKER,
+
	LC_ID_DYLINKER,
+
	LC_PREBOUND_DYLIB,
+
	LC_ROUTINES,
+
	LC_SUB_FRAMEWORK,
+
	LC_SUB_UMBRELLA,
+
	LC_SUB_CLIENT,
+
	LC_SUB_LIBRARY,
+
	LC_TWOLEVEL_HINTS,
+
	LC_PREBIND_CKSUM,
+
	LC_LOAD_WEAK_DYLIB,
+
	LC_SEGMENT_64,
+
	LC_ROUTINES_64,
+
	LC_UUID,
+
	LC_RPATH,
+
	LC_CODE_SIGNATURE,
+
	LC_SEGMENT_SPLIT_INFO,
+
	LC_REEXPORT_DYLIB,
+
	LC_LAZY_LOAD_DYLIB,
+
	LC_ENCRYPTION_INFO,
+
	LC_DYLD_INFO,
+
	LC_DYLD_INFO_ONLY = LC_DYLD_INFO,
+
	LC_LOAD_UPWARD_DYLIB,
+
	LC_VERSION_MIN_MACOSX,
+
	LC_VERSION_MIN_IPHONEOS,
+
	LC_FUNCTION_STARTS,
+
	LC_DYLD_ENVIRONMENT,
+
	LC_MAIN,
+
	LC_DATA_IN_CODE,
+
	LC_SOURCE_VERSION,
+
	LC_DYLIB_CODE_SIGN_DRS,
+
	LC_ENCRYPTION_INFO_64,
+
	LC_LINKER_OPTION,
+
	LC_LINKER_OPTIMIZATION_HINT,
+
	LC_VERSION_MIN_TVOS,
+
	LC_VERSION_MIN_WATCHOS,
+
	LC_NOTE,
+
	LC_BUILD_VERSION,
+
	LC_DYLD_EXPORTS_TRIE,
+
	LC_DYLD_CHAINED_FIXUPS,
+
	LC_FILESET_ENTRY,
+
	LC_ATOM_INFO
+
};
+

+
enum MachoPlatform {
+
	PLATFORM_UNKNOWN = 0,
+
	PLATFORM_MACOS,
+
	PLATFORM_IOS,
+
	PLATFORM_TVOS,
+
	PLATFORM_WATCHOS,
+
	PLATFORM_BRIDGEOS,
+
	PLATFORM_MACCATALYST,
+
	PLATFORM_IOSSIMULATOR,
+
	PLATFORM_TVOSSIMULATOR,
+
	PLATFORM_WATCHOSSIMULATOR,
+
	PLATFORM_DRIVERKIT,
+
	PLATFORM_XROS,
+
	PLATFORM_XROS_SIMULATOR
+
};
+

+
enum MachoTool { TOOL_CLANG = 1, TOOL_SWIFT, TOOL_LD, TOOL_LLD };
+

+
/**** Unpacked structures ****/
+

+
typedef struct cpu_type_subtype {
+
	enum CPUType type;
+
	bool type_is64;
+
	bool type_is64_32;
+
	union {
+
		enum CPUSubTypeX86 subtype_x86;
+
		enum CPUSubTypeARM subtype_arm;
+
		enum CPUSubTypePPC subtype_ppc;
+
	};
+
	bool subtype_islib64;
+
} cpu_type_subtype_t;
+

+
typedef struct fat_arch {
+
	struct cpu_type_subtype cpu;
+
	uint64_t offset;
+
	uint64_t size;
+
	uint_fast8_t align;
+
} fat_arch_t;
+

+
typedef struct macho_file {
+
	uint32_t magic;
+
	uint32_t narch;
+
	fat_arch_t arch[];
+
} macho_file_t;
+

+
typedef struct macho_header {
+
	uint32_t magic;
+
	bool swap;
+
	cpu_type_subtype_t cpu;
+
	enum MachOFileType filetype;
+
	uint32_t ncmds;
+
	uint32_t sizeofcmds;
+
	uint32_t flags;
+
} macho_header_t;
+

+
typedef struct macho_version {
+
	uint_fast16_t major;
+
	uint_fast16_t minor;
+
	uint_fast16_t patch;
+
} macho_version_t;
+

+
typedef struct tool_version {
+
	enum MachoTool tool;
+
	macho_version_t version;
+
} tool_version_t;
+

+
typedef struct build_version {
+
	enum MachoPlatform platform;
+
	macho_version_t minos;
+
	macho_version_t sdk;
+
	uint32_t ntools;
+
	tool_version_t tools[];
+
} build_version_t;
+

+
typedef struct dylib {
+
	uint32_t timestamp;
+
	macho_version_t current_version;
+
	macho_version_t compatibility_version;
+
	char path[];
+
} dylib_t;
+

+
/**** Function prototypes ****/
+

+
/* utility */
+
int map_platform_to_darwin(macho_version_t *darwin,
+
    const enum MachoPlatform platform, const macho_version_t version);
+

+
/* readers */
+
ssize_t read_macho_file(const int fd, macho_file_t **dest);
+
ssize_t read_macho_header(const int fd, macho_header_t *dest);
+
ssize_t read_build_version(const int fd, const bool swap,
+
    build_version_t **dest);
+
ssize_t read_min_version(const int fd, const bool swap, const uint32_t loadcmd,
+
    build_version_t **dest);
+

+
#define READ(f, var)                              \
+
	if ((x = read_##f(fd, swap, &var)) < 0) { \
+
		return x;                         \
+
	}                                         \
+
	n += x
+
ssize_t read_u32(const int fd, const bool swap, uint32_t *dest);
+

+
#endif

\ No newline at end of file
modified libpkg/private/elf_tables.h
@@ -1,7 +1,7 @@
/*-
 * Copyright (c) 2012 Olivier Houchard <cognet@FreeBSD.org>
 * All rights reserved.
-
 * 
+
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
@@ -11,7 +11,7 @@
 * 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.
@@ -31,8 +31,8 @@ struct _elf_corres {
};

static const struct _elf_corres mach_corres[] = {
-
	{ EM_386, "x86" },
-
	{ EM_X86_64, "x86" },
+
	{ EM_386, "i386" },
+
	{ EM_X86_64, "x86_64" },
	{ EM_AARCH64, "aarch64" },
	{ EM_ARM, "arm" },
	{ EM_MIPS, "mips" },
@@ -74,38 +74,6 @@ static const struct _elf_corres os_corres[] = {
#define NT_ARCH	2
#define NT_GNU_ABI_TAG	1

-
/* All possibilities on FreeBSD as of 5/26/2014 */
-
struct arch_trans {
-
	const char *elftype;
-
	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" },
-
	/* All the ARM stuff */
-
	{ "armv6:32:el:eabi:hardfp", "armv6" },
-
	{ "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" },
-
	/* And RISC-V */
-
	{ "riscv:32:hf", "riscv32" },
-
	{ "riscv:32:sf", "riscv32sf" },
-
	{ "riscv:64:hf", "riscv64" },
-
	{ "riscv:64:sf", "riscv64sf" },

-
	{ NULL, NULL }
-
};

#endif /* ELF_TABLES_H_ */
modified libpkg/private/pkg.h
@@ -4,26 +4,7 @@
 * Copyright (c) 2013 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2013-2017 Vsevolod Stakhov <vsevolod@FreeBSD.org>
 *
-
 * 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_PRIVATE_H
@@ -125,6 +106,18 @@ typedef enum {
	IPV6,
} ip_version_t;

+
typedef enum {
+
	OS_UNKNOWN = 0,
+
	OS_DRAGONFLY,
+
	OS_FREEBSD,
+
	OS_GNU,
+
	OS_LINUX,
+
	OS_MACOS,
+
	OS_NETBSD,
+
	OS_SYLLABLE,
+
	OS_SOLARIS,
+
} os_type_t;
+

struct pkg_kvlist {
	kvlist_t *list;
};
@@ -143,6 +136,19 @@ struct pkg_stringlist_iterator {
	void *cur;
};

+
struct os_info {
+
	int osversion;
+
	int ostype;
+
	char *name;
+
	char *version;
+
	char *version_major;
+
	char *version_minor;
+
	char *arch;
+
	char abi[BUFSIZ];
+
	char altabi[BUFSIZ];
+
	char str_osversion[BUFSIZ];
+
};
+

struct pkg_ctx {
	int eventpipe;
	int64_t debug_level;
@@ -160,7 +166,6 @@ struct pkg_ctx {
	int dbdirfd;
	int pkg_dbdirfd;
	int pkg_reposdirfd;
-
	int osversion;
	bool archive_symlink;
	bool backup_libraries;
	const char *backup_library_path;
@@ -170,6 +175,7 @@ struct pkg_ctx {
	bool defer_triggers;
	bool repo_accept_legacy_pkg;
	ip_version_t ip;
+
	struct os_info *oi;
	bool ischrooted;
};

@@ -205,7 +211,7 @@ struct pkg {
	char			*old_version;
	char			*maintainer;
	char			*www;
-
	char			*arch;
+
	char			*altabi;
	char			*abi;
	char			*uid;
	char			*digest;
@@ -631,17 +637,7 @@ typedef enum {
	PKG_RC_STOP
} pkg_rc_attr;

-
struct os_info {
-
	int osversion;
-
	char *name;
-
	char *version;
-
	char *version_major;
-
	char *version_minor;
-
	char *arch;
-
};
-

-
int pkg_get_myarch(char *pkgarch, size_t sz, struct os_info *);
-
int pkg_get_myarch_legacy(char *pkgarch, size_t sz);
+
int pkg_get_myarch_with_legacy(struct os_info *);

/**
 * Remove and unregister the package.
modified libpkg/repo/binary/update.c
@@ -141,7 +141,7 @@ pkg_repo_binary_add_pkg(struct pkg *pkg, sqlite3 *sqlite, bool forced)
	const char		*arch;
	int64_t			 package_id;

-
	arch = pkg->abi != NULL ? pkg->abi : pkg->arch;
+
	arch = pkg->abi != NULL ? pkg->abi : pkg->altabi;

try_again:
	if ((ret = pkg_repo_binary_run_prstatement(PKG,
@@ -380,7 +380,7 @@ pkg_repo_binary_add_from_ucl(sqlite3 *sqlite, ucl_object_t *o, struct pkg_repo *

	if (pkg->digest == NULL || !pkg_checksum_is_valid(pkg->digest, strlen(pkg->digest)))
		pkg_checksum_calculate(pkg, NULL, false, true, false);
-
	abi = pkg->abi != NULL ? pkg->abi : pkg->arch;
+
	abi = pkg->abi != NULL ? pkg->abi : pkg->altabi;
	if (abi == NULL || !is_valid_abi(abi, true)) {
		rc = EPKG_FATAL;
		pkg_emit_error("repository %s contains packages with wrong ABI: %s",
@@ -425,7 +425,7 @@ pkg_repo_binary_add_from_manifest(const char *buf, sqlite3 *sqlite, size_t len,

	if (pkg->digest == NULL || !pkg_checksum_is_valid(pkg->digest, strlen(pkg->digest)))
		pkg_checksum_calculate(pkg, NULL, false, true, false);
-
	abi = pkg->abi != NULL ? pkg->abi : pkg->arch;
+
	abi = pkg->abi != NULL ? pkg->abi : pkg->altabi;
	if (abi == NULL || !is_valid_abi(abi, true)) {
		rc = EPKG_FATAL;
		pkg_emit_error("repository %s contains packages with wrong ABI: %s",
modified libpkg/utils.c
@@ -335,20 +335,29 @@ check_for_hardlink(hardlinks_t *hl, struct stat *st)
	return (false);
}

-
bool
-
is_valid_abi(const char *arch, bool emit_error) {
-
	const char *myarch, *myarch_legacy;
+
/*
+
 * ABI validation:
+
 * - lowest match (case insensitive)
+
 * - glob matching
+
 *
+
 * A package which is valid for installation on any FreeBSD now simply has
+
 * to define itself as: abi: "FreeBSD" or "FreeBSD:*"
+
 * A package which is valid for installation on any FreeBSD 15 regarless of
+
 * the arch
+
 * abi: "FreeBSD:15" or "FreeBSD:15:*"
+
 *
+
 */

-
	myarch = pkg_object_string(pkg_config_get("ABI"));
-
	myarch_legacy = pkg_object_string(pkg_config_get("ALTABI"));
+
bool
+
is_valid_abi(const char *testabi, bool emit_error)
+
{
+
	const char *abi = ctx.oi->abi;

-
	if (fnmatch(arch, myarch, FNM_CASEFOLD) == FNM_NOMATCH &&
-
	    fnmatch(arch, myarch_legacy, FNM_CASEFOLD) == FNM_NOMATCH &&
-
	    strncasecmp(arch, myarch, strlen(myarch)) != 0 &&
-
	    strncasecmp(arch, myarch_legacy, strlen(myarch_legacy)) != 0) {
+
	if (strncasecmp(testabi, abi, strlen(testabi)) != 0 &&
+
	    fnmatch(testabi, abi, FNM_CASEFOLD) == FNM_NOMATCH) {
		if (emit_error)
			pkg_emit_error("wrong architecture: %s instead of %s",
-
			    arch, myarch);
+
			    testabi, abi);
		return (false);
	}

@@ -358,7 +367,8 @@ is_valid_abi(const char *arch, bool emit_error) {
bool
is_valid_os_version(struct pkg *pkg)
{
-
#ifdef __FreeBSD__
+
	if (ctx.oi->ostype != OS_FREEBSD)
+
		return (true);
	const char *fbsd_version;
	const char *errstr = NULL;
	int fbsdver;
@@ -376,8 +386,8 @@ is_valid_os_version(struct pkg *pkg)
			    fbsd_version, pkg->name);
			return (false);
		}
-
		if (fbsdver > ctx.osversion) {
-
			if (fbsdver - ctx.osversion < 100000) {
+
		if (fbsdver > ctx.oi->osversion) {
+
			if (fbsdver - ctx.oi->osversion < 100000) {
				/* Negligible difference, ask user to enforce */
				if (osver_mismatch_allowed == -1) {
					snprintf(query_buf, sizeof(query_buf),
@@ -386,7 +396,7 @@ is_valid_os_version(struct pkg *pkg)
							"- package: %d\n"
							"- running userland: %d\n"
							"Ignore the mismatch and continue? ", pkg->name,
-
							fbsdver, ctx.osversion);
+
							fbsdver, ctx.oi->osversion);
					ret = pkg_emit_query_yesno(false, query_buf);
					osver_mismatch_allowed = ret;
				}
@@ -399,16 +409,12 @@ is_valid_os_version(struct pkg *pkg)
					"- package: %d\n"
					"- running kernel: %d\n",
					pkg->name,
-
					fbsdver, ctx.osversion);
+
					fbsdver, ctx.oi->osversion);
				return (false);
			}
		}
	}
	return (true);
-
#else
-
	return (true);
-
#endif
-

}

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

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

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

.binin.bin:
	cp $< $@
+

+
.so.1in.so.1:
+
	cp $< $@
modified src/Makefile.autosetup
@@ -22,6 +22,7 @@ SRCS= add.c \
	query.c \
	register.c \
	repo.c \
+
	repositories.c \
	rquery.c \
	search.c \
	set.c \
@@ -68,10 +69,6 @@ OTHER_LIBS+= -lfts
OTHER_LIBS+=	-ldl
@endif

-
@if HAVE_LIBRESOLV
-
OTHER_LIBS+=	-lresolv
-
@endif
-

@if HAVE_LIBMD
OTHER_LIBS+=	-lmd
@endif
@@ -88,7 +85,7 @@ LOCAL_CFLAGS+= @PKG_LIBCURL_CFLAGS@
OTHER_LIBS+=	@PKG_LIBCURL_LDFLAGS@ @PKG_LIBCURL_LIBS@
@endif

-
@if libmachista
+
@if pkgos_darwin
LOCAL_LDFLAGS=	$(LIBPKGFLAT) $(LIBS) $(OTHER_LIBS) -lresolv
STATIC_LDFLAGS=	$(LIBPKGFLAT) $(LIBS) $(OTHER_LIBS) -lresolv
# OSX doesn't support static binaries, sigh
modified src/check.c
@@ -322,6 +322,10 @@ exec_check(int argc, char **argv)
	argc -= optind;
	argv += optind;

+
	if (!(dcheck || checksums)) {
+
		checksums = true;
+
		flags |= PKG_LOAD_FILES;
+
	}
	/* Default to all packages if no pkg provided */
	if (argc == 0 && (dcheck || checksums)) {
		match = MATCH_ALL;
modified src/main.c
@@ -1,32 +1,12 @@
/*-
-
 * Copyright (c) 2011-2013 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2011-2012 Julien Laffaye <jlaffaye@FreeBSD.org>
 * Copyright (c) 2011 Will Andrews <will@FreeBSD.org>
 * Copyright (c) 2011-2012 Marin Atanasov Nikolov <dnaeon@gmail.com>
 * Copyright (c) 2014-2015 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2014 Vsevolod Stakhov <vsevolod@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * 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
 */

#ifdef HAVE_CONFIG_H
@@ -100,6 +80,7 @@ static struct commands {
	{ "register", "Registers a package into the local database", exec_register, usage_register},
	{ "remove", "Deletes packages from the database and the system", exec_delete, usage_delete},
	{ "repo", "Creates a package repository catalogue", exec_repo, usage_repo},
+
	{ "repositories", "Show repositories information", exec_repositories, usage_repositories},
	{ "rquery", "Queries information in repository catalogues", exec_rquery, usage_rquery},
	{ "search", "Performs a search of package repository catalogues", exec_search, usage_search},
	{ "set", "Modifies information about packages in the local database", exec_set, usage_set},
@@ -302,64 +283,11 @@ show_plugin_info(void)
static void
show_repository_info(void)
{
-
	const char	*mirror, *sig;
	struct pkg_repo	*repo = NULL;

	printf("\nRepositories:\n");
-
	while (pkg_repos(&repo) == EPKG_OK) {
-
		switch (pkg_repo_mirror_type(repo)) {
-
		case SRV:
-
			mirror = "SRV";
-
			break;
-
		case HTTP:
-
			mirror = "HTTP";
-
			break;
-
		case NOMIRROR:
-
			mirror = "NONE";
-
			break;
-
		default:
-
			mirror = "-unknown-";
-
			break;
-
		}
-
		switch (pkg_repo_signature_type(repo)) {
-
		case SIG_PUBKEY:
-
			sig = "PUBKEY";
-
			break;
-
		case SIG_FINGERPRINT:
-
			sig = "FINGERPRINTS";
-
			break;
-
		case SIG_NONE:
-
			sig = "NONE";
-
			break;
-
		default:
-
			sig = "-unknown-";
-
			break;
-
		}
-

-
		printf("  %s: { \n    %-16s: \"%s\",\n    %-16s: %s,\n"
-
		       "    %-16s: %u",
-
		    pkg_repo_name(repo),
-
                    "url", pkg_repo_url(repo),
-
		    "enabled", pkg_repo_enabled(repo) ? "yes" : "no",
-
		    "priority", pkg_repo_priority(repo));
-

-
		if (pkg_repo_mirror_type(repo) != NOMIRROR)
-
			printf(",\n    %-16s: \"%s\"",
-
			    "mirror_type", mirror);
-
		if (pkg_repo_signature_type(repo) != SIG_NONE)
-
			printf(",\n    %-16s: \"%s\"",
-
			    "signature_type", sig);
-
		if (pkg_repo_fingerprints(repo) != NULL)
-
			printf(",\n    %-16s: \"%s\"",
-
			    "fingerprints", pkg_repo_fingerprints(repo));
-
		if (pkg_repo_key(repo) != NULL)
-
			printf(",\n    %-16s: \"%s\"",
-
			    "pubkey", pkg_repo_key(repo));
-
		if (pkg_repo_ip_version(repo) != 0)
-
			printf(",\n    %-16s: %u",
-
				"ip_version", pkg_repo_ip_version(repo));
-
		printf("\n  }\n");
-
	}
+
	while (pkg_repos(&repo) == EPKG_OK)
+
		print_repository(repo, true);
}

static void
modified src/pkgcli.h
@@ -1,28 +1,8 @@
/*-
-
 * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
+
 * Copyright (c) 2011-2024 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2013 Matthew Seaman <matthew@FreeBSD.org>
-
 * All rights reserved.
 *
-
 * 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 _PKGCLI_H
@@ -115,6 +95,10 @@ int exec_register(int argc, char **argv);
int exec_repo(int, char **);
void usage_repo(void);

+
/* pkg repo */
+
int exec_repositories(int, char **);
+
void usage_repositories(void);
+

/* pkg rquery */
int exec_rquery(int, char **);
void usage_rquery(void);
@@ -278,6 +262,7 @@ void job_status_end(xstring *);

int event_callback(void *data, struct pkg_event *ev);
int print_pkg(struct pkg *p, void *ctx);
+
void print_repository(struct pkg_repo *repo, bool pad);
void progressbar_start(const char *pmsg);
void progressbar_tick(int64_t current, int64_t total);
void progressbar_stop(void);
added src/repositories.c
@@ -0,0 +1,90 @@
+
/*-
+
 * Copyright(c) 2024 Baptiste Daroussin <bapt@FreeBSD.org>
+
 *
+
 * SPDX-License-Identifier: BSD-2-Clause
+
 */
+

+
#include <getopt.h>
+
#include <stdio.h>
+
#include <stdbool.h>
+
#include <unistd.h>
+

+
#include <pkg.h>
+

+
#include "pkgcli.h"
+

+
void
+
usage_repositories(void)
+
{
+
        fprintf(stderr, "Usage: pkg repositories [-edl] [repository]\n\n");
+
}
+

+

+
typedef enum {
+
	REPO_SHOW_ALL = 0,
+
	REPO_SHOW_ENABLED = 1U << 0,
+
	REPO_SHOW_DISABLED = 1U << 1,
+
} repo_show_t;
+

+
int
+
exec_repositories(int argc, char **argv)
+
{
+
	const char *r = NULL;
+
	struct pkg_repo *repo = NULL;
+
	bool list_only = false;
+
	repo_show_t rs = REPO_SHOW_ALL;
+
	int ch;
+

+
	struct option longopts[] = {
+
		{ "list",	no_argument,	NULL,	'l' },
+
		{ "enabled",	no_argument,	NULL,	'e' },
+
		{ "disabled",	no_argument,	NULL,	'd' },
+
		{ NULL,		0,		NULL,	0   },
+
	};
+

+
	while ((ch = getopt_long(argc, argv, "+led", longopts, NULL)) != -1) {
+
                switch (ch) {
+
		case 'l':
+
			list_only = true;
+
			break;
+
		case 'e':
+
			rs |= REPO_SHOW_ENABLED;
+
			break;
+
		case 'd':
+
			rs |= REPO_SHOW_DISABLED;
+
			break;
+
		default:
+
			usage_repositories();
+
			return (EXIT_FAILURE);
+
		}
+
	}
+

+
	if (rs == REPO_SHOW_ALL)
+
		rs |= REPO_SHOW_DISABLED|REPO_SHOW_ENABLED;
+

+
	argc -= optind;
+
	argv += optind;
+

+
	if (argc == 1)
+
		r = argv[0];
+

+
	while (pkg_repos(&repo) == EPKG_OK) {
+
		if (r && !STREQ(r, pkg_repo_name(repo)))
+
			continue;
+
		if (pkg_repo_enabled(repo)) {
+
			if ((rs & REPO_SHOW_ENABLED) == 0)
+
				continue;
+
		} else {
+
			if ((rs & REPO_SHOW_DISABLED) == 0)
+
				continue;
+
		}
+
		if (list_only) {
+
			printf("%s\n", pkg_repo_name(repo));
+
			continue;
+
		}
+
		print_repository(repo, false);
+
	}
+

+

+
	return (EXIT_SUCCESS);
+
}
modified src/utils.c
@@ -5,26 +5,7 @@
 * Copyright (c) 2012-2015 Matthew Seaman <matthew@FreeBSD.org>
 * Copyright (c) 2013-2016 Vsevolod Stakhov <vsevolod@FreeBSD.org>
 *
-
 * 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
 */

#ifdef HAVE_CONFIG_H
@@ -1105,3 +1086,63 @@ print_pkg(struct pkg *p, void *ctx)

	return 0;
}
+

+
void
+
print_repository(struct pkg_repo *repo, bool pad)
+
{
+
	const char	*mirror, *sig;
+

+
	switch (pkg_repo_mirror_type(repo)) {
+
		case SRV:
+
			mirror = "SRV";
+
			break;
+
		case HTTP:
+
			mirror = "HTTP";
+
			break;
+
		case NOMIRROR:
+
			mirror = "NONE";
+
			break;
+
		default:
+
			mirror = "-unknown-";
+
			break;
+
	}
+
	switch (pkg_repo_signature_type(repo)) {
+
		case SIG_PUBKEY:
+
			sig = "PUBKEY";
+
			break;
+
		case SIG_FINGERPRINT:
+
			sig = "FINGERPRINTS";
+
			break;
+
		case SIG_NONE:
+
			sig = "NONE";
+
			break;
+
		default:
+
			sig = "-unknown-";
+
			break;
+
	}
+

+
	printf("%s%s: { \n    %-16s: \"%s\",\n    %-16s: %s,\n"
+
			"    %-16s: %u",
+
			pad ? "  " : "",
+
			pkg_repo_name(repo),
+
			"url", pkg_repo_url(repo),
+
			"enabled", pkg_repo_enabled(repo) ? "yes" : "no",
+
			"priority", pkg_repo_priority(repo));
+

+
	if (pkg_repo_mirror_type(repo) != NOMIRROR)
+
		printf(",\n    %-16s: \"%s\"",
+
				"mirror_type", mirror);
+
	if (pkg_repo_signature_type(repo) != SIG_NONE)
+
		printf(",\n    %-16s: \"%s\"",
+
				"signature_type", sig);
+
	if (pkg_repo_fingerprints(repo) != NULL)
+
		printf(",\n    %-16s: \"%s\"",
+
				"fingerprints", pkg_repo_fingerprints(repo));
+
	if (pkg_repo_key(repo) != NULL)
+
		printf(",\n    %-16s: \"%s\"",
+
				"pubkey", pkg_repo_key(repo));
+
	if (pkg_repo_ip_version(repo) != 0)
+
		printf(",\n    %-16s: %u",
+
				"ip_version", pkg_repo_ip_version(repo));
+
	printf("\n  }\n");
+
}
modified tests/Makefile.autosetup
@@ -12,7 +12,9 @@ TESTS= \
	lua \
	ssh \
	utils \
-
	metalog
+
	metalog \
+
	vec \
+
	pkg_elf

TESTS_SH= \
	frontend/pkg.sh \
@@ -65,9 +67,22 @@ TESTS_SH= \
	frontend/http.sh \
	frontend/triggers.sh

+
#
+
# Those files simple binaries obtained from
+
# int main(void) { return 0; }
+
#
+

TESTS_SHELL_BINS= \
	frontend/dfly.bin \
-
	frontend/fbsd.bin
+
	frontend/fbsd.bin \
+
	frontend/linux.bin \
+
	frontend/macos.bin \
+
	frontend/macos106.bin \
+
	frontend/macos150.bin \
+
	frontend/macosfat.bin \
+
	frontend/libtestfbsd.so.1 \
+
	frontend/libtest2fbsd.so.1 \
+
	frontend/libfoo.so.1

lua_OBJS=	lib/lua.o
merge_OBJS=	lib/merge.o
@@ -82,6 +97,8 @@ packing_OBJS= lib/packing.o
ssh_OBJS=	lib/ssh.o
utils_OBJS=	lib/utils.o
metalog_OBJS=	lib/metalog.o
+
vec_OBJS=	lib/vec.o
+
pkg_elf_OBJS=	lib/pkg_elf.o

SRCS=	\
	$(packing_OBJS:.o=.c) \
@@ -95,7 +112,9 @@ SRCS= \
	$(pkg_validation_OBJS:.o=.c) \
	$(ssh_OBJS:.o=.c) \
	$(utils_OBJS:.o=.c) \
-
	$(metalog_OBJS:.o=.c)
+
	$(metalog_OBJS:.o=.c) \
+
	$(vec_OBJS:.o=.c) \
+
	$(pkg_elf_OBJS:.o=.c)

include $(MK)/common.mk

@@ -134,9 +153,6 @@ OTHER_LIBS+= -lfts
@if HAVE_LIBDL
OTHER_LIBS+=	-ldl
@endif
-
@if HAVE_LIBRESOLV
-
OTHER_LIBS+=	-lresolv
-
@endif
@if PKG_LIBCURL_LIBS
CFLAGS+=	@PKG_LIBCURL_CFLAGS@
LIBS+=	@PKG_LIBCURL_LDFLAGS@ @PKG_LIBCURL_LIBS@
@@ -150,7 +166,7 @@ OTHER_LIBS+= -lssl -lcrypto


# Hack to determine we are on osx
-
@if libmachista
+
@if pkgos_darwin
OTHER_LIBS+=	-lresolv
@endif

modified tests/cocci/README.md
@@ -23,7 +23,7 @@ From the pkg's source root (use _libpkg_ or _src_ as `$DIR`):

	% spatch -I . -I /usr/include -I /usr/local/include -I libpkg -I src       \
		-I external/blake2  -I external/yxml      -I external/include     \
-
		-I external/libelf  -I external/libfetch       -I external/libmachista \
+
		-I external/libelf  -I external/libfetch        \
		-I external/libsbuf -I external/libucl/include -I external/linenoise   \
		-I external/picosat -I external/sqlite         \
		-in_place -sp_file ./tests/cocci/$TESTFILE.cocci -dir $DIR
modified tests/frontend/abi.sh
@@ -2,23 +2,119 @@

. $(atf_get_srcdir)/test_environment.sh
tests_init \
-
	basic
-

-
basic_body() {
-
	_uname_s="$(uname -s)"
-
	_expected="TODO: implement me"
-
	if [ "${_uname_s}" = "Darwin" ]; then
-
			# The FreeBSD ELF ABI_FILE should is ignored on non-ELF platforms:
-
		_expected="${_uname_s}:$(uname -r | cut -d. -f1):$(uname -p)\n"
+
	elfparse \
+
	machoparse \
+
	native \
+
	override
+

+
native_body() {
+
	OS=$(uname -s)
+
	thisarch=$(uname -p)
+
	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
-
		# Otherwise the ABI should be parsed from the ELF file.
-
		_expected="FreeBSD:13:amd64\n"
+
		version=$(uname -r | cut -d. -f1)
	fi
+
	_expected="${OS}:${version}:$(echo $thisarch | sed s/x86_64/amd64/)\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"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg config altabi
+
}
+

+
override_body() {
+
	_expected="FreeBSD:12:powerpc\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		-e ignore \
+
		pkg -o ABI=FreeBSD:12:powerpc config abi
+

+
	_expected="freebsd:12:powerpc:32:eb\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		-e ignore \
+
		pkg -o ABI=FreeBSD:12:powerpc config altabi
+
}
+

+
elfparse_body() {
+
	# ELF parsing now works across platforms
+
	_expected="FreeBSD:13:amd64\n"
	atf_check \
		-o inline:"${_expected}" \
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/fbsd.bin config abi

-
#	atf_check \
-
#		-o inline:"dragonfly:5.10:x86:64\n" \
-
#		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/dfly.bin config abi
+
	_expected="freebsd:13:x86:64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/fbsd.bin config altabi
+

+
	_expected="dragonfly:5.10:x86:64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/dfly.bin config abi
+

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

+
	_expected="Linux:3.2:x86_64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/linux.bin config abi
+

+
	_expected="linux:3.2:x86_64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/linux.bin config altabi
+
}
+

+
machoparse_body() {
+
	# Macho-O parsing now works across platforms
+
	_expected="Darwin:24:aarch64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -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}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macos.bin config altabi
+

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

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

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

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

+
	_expected="Darwin:24:amd64\n"
+
	atf_check \
+
		-o inline:"${_expected}" \
+
		pkg -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}" \
+
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin config altabi
}
added tests/frontend/libfoo.so.1in
added tests/frontend/libtest2fbsd.so.1in
added tests/frontend/libtestfbsd.so.1in
added tests/frontend/linux.binin
added tests/frontend/macos.binin
added tests/frontend/macos106.binin
added tests/frontend/macos150.binin
added tests/frontend/macosfat.binin
modified tests/frontend/pkg.sh
@@ -32,7 +32,7 @@ pkg_config_defaults_body()
	    -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:'^ *DEVELOPER_MODE = false;$' \
-
	    -o match:'^ *VULNXML_SITE = "http://vuxml.freebsd.org/freebsd/vuln.xml.xz";$' \
+
	    -o match:'^ *VULNXML_SITE = "https://vuxml.freebsd.org/freebsd/vuln.xml.xz";$' \
	    -o match:'^ *FETCH_RETRY = 3;$' \
	    -o match:'^ *PKG_PLUGINS_DIR = ".*lib/pkg/";$' \
	    -o match:'^ *PKG_ENABLE_PLUGINS = true;$' \
added tests/lib/pkg_elf.c
@@ -0,0 +1,84 @@
+
/*-
+
 * Copyright(c) 2024 Baptiste Daroussin <bapt@FreeBSD.org>
+
 *
+
 * SPDX-License-Identifier: BSD-2-Clause
+
 */
+

+
#include <sys/types.h>
+

+
#include <string.h>
+

+
#include <atf-c.h>
+
#include <private/pkg.h>
+
#include <private/binfmt.h>
+
#include <xstring.h>
+
#include <tllist.h>
+
#include <pkg.h>
+

+
#ifndef __unused
+
# ifdef __GNUC__
+
# define __unused __attribute__ ((__unused__))
+
# else
+
# define __unused
+
# endif
+
#endif
+

+
xstring *msg;
+

+
ATF_TC_WITHOUT_HEAD(analyse_elf);
+

+
int
+
event_callback(void *data __unused, struct pkg_event *ev)
+
{
+
	switch (ev->type) {
+
	case PKG_EVENT_ERROR:
+
		xstring_reset(msg);
+
		fprintf(msg->fp, "%s", ev->e_pkg_error.msg);
+
		break;
+
	default:
+
		/* IGNORE */
+
		break;
+
	}
+

+
	return (0);
+
}
+

+
ATF_TC_BODY(analyse_elf, tc)
+
{
+
	struct pkg *p = NULL;
+
	char *binpath = NULL;
+

+
	xasprintf(&binpath, "%s/frontend/libtestfbsd.so.1", atf_tc_get_config_var(tc, "srcdir"));
+

+
	ATF_REQUIRE_EQ(EPKG_OK, pkg_new(&p, PKG_INSTALLED));
+
	ATF_REQUIRE(p != NULL);
+

+
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 0);
+
	ATF_REQUIRE_EQ(tll_length(p->shlibs_provided), 0);
+
	ATF_REQUIRE_EQ(pkg_analyse_elf(false, p, binpath), EPKG_OK);
+
	ATF_REQUIRE_EQ(tll_length(p->shlibs_provided), 1);
+
	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"));
+
	ATF_REQUIRE_EQ(pkg_analyse_elf(false, p, binpath), EPKG_END);
+
	ATF_REQUIRE_EQ(tll_length(p->shlibs_provided), 1);
+
	free(binpath);
+

+
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 0);
+
	xasprintf(&binpath, "%s/frontend/libtest2fbsd.so.1", atf_tc_get_config_var(tc, "srcdir"));
+
	ATF_REQUIRE_EQ(pkg_analyse_elf(false, p, binpath), EPKG_OK);
+
	ATF_REQUIRE_EQ(tll_length(p->shlibs_provided), 2);
+
	ATF_REQUIRE_STREQ(tll_back(p->shlibs_provided), "libtest2fbsd.so.1");
+
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 1);
+
	ATF_REQUIRE_STREQ(tll_front(p->shlibs_required), "libfoo.so.1");
+
	free(binpath);
+

+
}
+

+
ATF_TP_ADD_TCS(tp)
+
{
+
	ATF_TP_ADD_TC(tp, analyse_elf);
+

+
	return (atf_no_error());
+
}
added tests/lib/vec.c
@@ -0,0 +1,128 @@
+
/*-
+
 * Copyright(c) 2024 Baptiste Daroussin <bapt@FreeBSD.org>
+
 *
+
 * SPDX-License-Identifier: BSD-2-Clause
+
 */
+

+
#include <atf-c.h>
+
#include <private/utils.h>
+
#include <pkgvec.h>
+
#include <xmalloc.h>
+

+
ATF_TC_WITHOUT_HEAD(c_charv_t);
+
ATF_TC_WITHOUT_HEAD(c_charv_contains);
+
ATF_TC_WITHOUT_HEAD(charv_t);
+

+
ATF_TC_BODY(c_charv_t, tc)
+
{
+
	c_charv_t list;
+

+
	pkgvec_init(&list);
+
	ATF_REQUIRE_EQ_MSG(list.d, NULL, "pkgvec_init failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 0, "pkgvec_init failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 0, "pkgvec_init failed");
+

+
	pkgvec_push(&list, "test1");
+
	ATF_REQUIRE_MSG(list.d != NULL, "pkgvec_push failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 1, "pkgvec_push failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 1, "pkgvec_push failed");
+

+
	pkgvec_push(&list, "test2");
+
	ATF_REQUIRE_MSG(list.d != NULL, "pkgvec_push2 failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 2, "pkgvec_push2 failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 2, "pkgvec_push2 failed");
+

+
	pkgvec_push(&list, "test3");
+
	ATF_REQUIRE_MSG(list.d != NULL, "pkgvec_push3 failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 4, "pkgvec_push3 failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 3, "pkgvec_push3 failed");
+

+
	ATF_REQUIRE_STREQ_MSG(pkgvec_first(&list), "test1", "pkgvec_first failed");
+
	ATF_REQUIRE_STREQ_MSG(pkgvec_last(&list), "test3", "pkgvec_last failed");
+

+
	pkgvec_clear(&list);
+
	ATF_REQUIRE_MSG(list.d != NULL, "pkgvec_clear failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 4, "pkgvec_clear failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 0, "pkgvec_clear failed");
+

+
	pkgvec_free(&list);
+
	ATF_REQUIRE_EQ_MSG(list.d, NULL, "pkgvec_free failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 0, "pkgvec_free failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 0, "pkgvec_free failed");
+
}
+

+
ATF_TC_BODY(charv_t, tc)
+
{
+
	charv_t list;
+

+
	pkgvec_init(&list);
+
	ATF_REQUIRE_EQ_MSG(list.d, NULL, "pkgvec_init failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 0, "pkgvec_init failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 0, "pkgvec_init failed");
+

+
	pkgvec_push(&list, xstrdup("test1"));
+
	ATF_REQUIRE_MSG(list.d != NULL, "pkgvec_push failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 1, "pkgvec_push failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 1, "pkgvec_push failed");
+

+
	pkgvec_push(&list, xstrdup("test2"));
+
	ATF_REQUIRE_MSG(list.d != NULL, "pkgvec_push2 failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 2, "pkgvec_push2 failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 2, "pkgvec_push2 failed");
+

+
	pkgvec_push(&list, xstrdup("test3"));
+
	ATF_REQUIRE_MSG(list.d != NULL, "pkgvec_push3 failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 4, "pkgvec_push3 failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 3, "pkgvec_push3 failed");
+

+
	ATF_REQUIRE_STREQ_MSG(pkgvec_first(&list), "test1", "pkgvec_first failed");
+
	ATF_REQUIRE_STREQ_MSG(pkgvec_last(&list), "test3", "pkgvec_last failed");
+

+
	pkgvec_clear_and_free(&list, free);
+
	ATF_REQUIRE_MSG(list.d != NULL, "pkgvec_clear failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 4, "pkgvec_clear failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 0, "pkgvec_clear failed");
+

+
	pkgvec_free_and_free(&list, free);
+
	ATF_REQUIRE_EQ_MSG(list.d, NULL, "pkgvec_free failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 0, "pkgvec_free failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 0, "pkgvec_free failed");
+
}
+

+
ATF_TC_BODY(c_charv_contains, tc)
+
{
+
	c_charv_t list;
+

+
	pkgvec_init(&list);
+
	ATF_REQUIRE_EQ_MSG(list.d, NULL, "pkgvec_init failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 0, "pkgvec_init failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 0, "pkgvec_init failed");
+

+
	pkgvec_push(&list, "test1");
+
	ATF_REQUIRE_MSG(list.d != NULL, "pkgvec_push failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 1, "pkgvec_push failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 1, "pkgvec_push failed");
+

+
	pkgvec_push(&list, "test2");
+
	ATF_REQUIRE_MSG(list.d != NULL, "pkgvec_push2 failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 2, "pkgvec_push2 failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 2, "pkgvec_push2 failed");
+

+
	pkgvec_push(&list, "test3");
+
	ATF_REQUIRE_MSG(list.d != NULL, "pkgvec_push3 failed");
+
	ATF_REQUIRE_EQ_MSG(list.cap, 4, "pkgvec_push3 failed");
+
	ATF_REQUIRE_EQ_MSG(list.len, 3, "pkgvec_push3 failed");
+

+
	ATF_REQUIRE_EQ_MSG(c_charv_contains(&list, "Test3", true), false, "c_charv_contains not case sensitive");
+
	ATF_REQUIRE_EQ_MSG(c_charv_contains(&list, "Test3", false), true, "c_charv_contains not case insensitive");
+
	ATF_REQUIRE_EQ_MSG(c_charv_contains(&list, "aest3", false), false, "c_charv_contains should not find anything");
+
}
+

+
ATF_TP_ADD_TCS(tp)
+
{
+
	ATF_TP_ADD_TC(tp, c_charv_t);
+
	ATF_TP_ADD_TC(tp, charv_t);
+
	ATF_TP_ADD_TC(tp, c_charv_contains);
+

+
	return (atf_no_error());
+
}