Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Merge remote-tracking branch 'upstream/main'
Shawn Webb committed 1 year ago
commit 25ee7d0d33e6f70e72371ea62ba37b5f33884eae
parent 834d09c
56 files changed +2075 -2302
modified Leak.suppress.in
@@ -16,7 +16,587 @@ leak:BIO_new_ex
# UCL should be investigated first within UCL, there is plenty to look at
leak:ucl_parser_add_fd

+
# atf 0.22 introduced leaks in the test-code
+
# https://github.com/freebsd/atf/issues/77
+
leak:atf_map_init_charpp
+
leak:atf_tp_get_tcs
+
leak:atf_utils_wait
+

## FIXME: Temporarily suppress inside pkg source

# this could be a dangling pointer false positive report, the whole function should be re-structured
-
leak:pkgdb_open_all2

\ No newline at end of file
+
leak:pkgdb_open_all2
+

+
# UCL objects are copied around and not properly freed
+
#Direct leak of 64 byte(s) in 1 object(s) allocated from:
+
#    #0 0x000104ab0f12 in malloc+0x82 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xdff12)
+
#    #1 0x000103585784 in ucl_object_new_full ucl_util.c:3009
+
#    #2 0x000103585754 in ucl_object_typed_new ucl_util.c:3000
+
#    #3 0x0001037eddcf in pkg_ini pkg_config.c:1268
+
#    #4 0x0001030fb427 in main main.c:674
+
#    #5 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
#
+
#Indirect leak of 64 byte(s) in 1 object(s) allocated from:
+
#    #0 0x000104ab0f12 in malloc+0x82 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xdff12)
+
#    #1 0x000103588d19 in ucl_object_copy_internal ucl_util.c:3603
+
#    #2 0x00010357efb9 in ucl_object_copy ucl_util.c:3667
+
#    #3 0x0001037eddf0 in pkg_ini pkg_config.c:1269
+
#    #4 0x0001030fb427 in main main.c:674
+
#    #5 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
#
+
#Indirect leak of 40 byte(s) in 1 object(s) allocated from:
+
#    #0 0x000104ab1217 in calloc+0x87 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xe0217)
+
#    #1 0x0001035290b2 in kh_init_ucl_hash_node ucl_hash.c:117
+
#    #2 0x000103528fe8 in ucl_hash_create ucl_hash.c:246
+
#    #3 0x000103580e51 in ucl_object_insert_key_common ucl_util.c:2410
+
#    #4 0x00010357e617 in ucl_object_insert_key ucl_util.c:2546
+
#    #5 0x0001037ede53 in pkg_ini pkg_config.c:1269
+
#    #6 0x0001030fb427 in main main.c:674
+
#    #7 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
#
+
#Indirect leak of 32 byte(s) in 1 object(s) allocated from:
+
#    #0 0x000104ab1117 in realloc+0x87 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xe0117)
+
#    #1 0x0001035316f6 in kh_resize_ucl_hash_node ucl_hash.c:117
+
#    #2 0x00010352b851 in kh_put_ucl_hash_node ucl_hash.c:117
+
#    #3 0x000103529eb2 in ucl_hash_insert ucl_hash.c:333
+
#    #4 0x000103583a56 in ucl_hash_insert_object ucl_internal.h:486
+
#    #5 0x0001035812e1 in ucl_object_insert_key_common ucl_util.c:2443
+
#    #6 0x00010357e617 in ucl_object_insert_key ucl_util.c:2546
+
#    #7 0x0001037ede53 in pkg_ini pkg_config.c:1269
+
#    #8 0x0001030fb427 in main main.c:674
+
#    #9 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
#
+
#Indirect leak of 32 byte(s) in 1 object(s) allocated from:
+
#    #0 0x000104ab1117 in realloc+0x87 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xe0117)
+
#    #1 0x000103531635 in kh_resize_ucl_hash_node ucl_hash.c:117
+
#    #2 0x00010352b851 in kh_put_ucl_hash_node ucl_hash.c:117
+
#    #3 0x000103529eb2 in ucl_hash_insert ucl_hash.c:333
+
#    #4 0x000103583a56 in ucl_hash_insert_object ucl_internal.h:486
+
#    #5 0x0001035812e1 in ucl_object_insert_key_common ucl_util.c:2443
+
#    #6 0x00010357e617 in ucl_object_insert_key ucl_util.c:2546
+
#    #7 0x0001037ede53 in pkg_ini pkg_config.c:1269
+
#    #8 0x0001030fb427 in main main.c:674
+
#    #9 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
#
+
#Indirect leak of 24 byte(s) in 1 object(s) allocated from:
+
#    #0 0x000104ab0f12 in malloc+0x82 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xdff12)
+
#    #1 0x000103529ed4 in ucl_hash_insert ucl_hash.c:335
+
#    #2 0x000103583a56 in ucl_hash_insert_object ucl_internal.h:486
+
#    #3 0x0001035812e1 in ucl_object_insert_key_common ucl_util.c:2443
+
#    #4 0x00010357e617 in ucl_object_insert_key ucl_util.c:2546
+
#    #5 0x0001037ede53 in pkg_ini pkg_config.c:1269
+
#    #6 0x0001030fb427 in main main.c:674
+
#    #7 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
#
+
#Indirect leak of 24 byte(s) in 1 object(s) allocated from:
+
#    #0 0x000104ab0f12 in malloc+0x82 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xdff12)
+
#    #1 0x000103528f39 in ucl_hash_create ucl_hash.c:237
+
#    #2 0x000103580e51 in ucl_object_insert_key_common ucl_util.c:2410
+
#    #3 0x00010357e617 in ucl_object_insert_key ucl_util.c:2546
+
#    #4 0x0001037ede53 in pkg_ini pkg_config.c:1269
+
#    #5 0x0001030fb427 in main main.c:674
+
#    #6 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
#
+
#Indirect leak of 8 byte(s) in 1 object(s) allocated from:
+
#    #0 0x000104ab0f12 in malloc+0x82 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xdff12)
+
#    #1 0x00010357502d in ucl_copy_key_trash ucl_util.c:507
+
#    #2 0x00010358123a in ucl_object_insert_key_common ucl_util.c:2437
+
#    #3 0x00010357e617 in ucl_object_insert_key ucl_util.c:2546
+
#    #4 0x0001037ede53 in pkg_ini pkg_config.c:1269
+
#    #5 0x0001030fb427 in main main.c:674
+
#    #6 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
#
+
#Indirect leak of 4 byte(s) in 1 object(s) allocated from:
+
#    #0 0x000104ab0f12 in malloc+0x82 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xdff12)
+
#    #1 0x000103531522 in kh_resize_ucl_hash_node ucl_hash.c:117
+
#    #2 0x00010352b851 in kh_put_ucl_hash_node ucl_hash.c:117
+
#    #3 0x000103529eb2 in ucl_hash_insert ucl_hash.c:333
+
#    #4 0x000103583a56 in ucl_hash_insert_object ucl_internal.h:486
+
#    #5 0x0001035812e1 in ucl_object_insert_key_common ucl_util.c:2443
+
#    #6 0x00010357e617 in ucl_object_insert_key ucl_util.c:2546
+
#    #7 0x0001037ede53 in pkg_ini pkg_config.c:1269
+
#    #8 0x0001030fb427 in main main.c:674
+
#    #9 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
leak:pkg_ini
+

+
# Freeing the iterator was not considered
+
#Direct leak of 16 byte(s) in 1 object(s) allocated from:
+
#    #0 0x00010dac7217 in calloc+0x87 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xe0217)
+
#    #1 0x00010c8a6e7c in xcalloc xmalloc.h:19
+
#    #2 0x00010c8a6f9a in pkg_kvlist_iterator pkg_attributes.c:179
+
#    #3 0x00010c0f5a7e in do_show annotate.c:150
+
#    #4 0x00010c0f4f4d in exec_annotate annotate.c:353
+
#    #5 0x00010c1121f2 in main main.c:809
+
#    #6 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
#Direct leak of 8 byte(s) in 1 object(s) allocated from:
+
#    #0 0x00010dac7217 in calloc+0x87 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xe0217)
+
#    #1 0x00010c8a6e7c in xcalloc xmalloc.h:19
+
#    #2 0x00010c8a8a5c in pkg_get_element pkg_attributes.c:312
+
#    #3 0x00010c0f5e6e in pkg_get_kv pkg.h:1822
+
#    #4 0x00010c0f5a71 in do_show annotate.c:149
+
#    #5 0x00010c0f4f4d in exec_annotate annotate.c:353
+
#    #6 0x00010c1121f2 in main main.c:809
+
#    #7 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
leak:pkg_kvlist_iterator
+
leak:pkg_get_element
+

+
# Purging TREEs after use was not considered
+
#Direct leak of 16 byte(s) in 1 object(s) allocated from:
+
#    #0 0x00010b871f12 in malloc+0x82 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xdff12)
+
#    #1 0x00010a5e8db4 in xmalloc xmalloc.h:11
+
#    #2 0x00010a5e890f in pkg_conflicts_append_chain pkg_jobs_conflicts.c:446
+
#    #3 0x00010a66cf21 in pkg_jobs_check_conflicts pkg_jobs.c:2341
+
#    #4 0x00010a65f588 in pkg_jobs_check_and_solve_conflicts pkg_jobs.c:1899
+
#    #5 0x00010a65f244 in pkg_jobs_solve pkg_jobs.c:1942
+
#    #6 0x000109eb7f00 in exec_install install.c:224
+
#    #7 0x000109ebd1f2 in main main.c:809
+
#    #8 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
leak:pkg_conflicts_append_chain
+

+
# repo->meta not properly freed
+
#Direct leak of 176 byte(s) in 1 object(s) allocated from:
+
#    #0 0x000105cff217 in calloc+0x87 (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0xe0217)
+
#    #1 0x0001049ec95c in xcalloc xmalloc.h:19
+
#    #2 0x0001049eb050 in pkg_repo_meta_parse pkg_repo_meta.c:257
+
#    #3 0x0001049eada5 in pkg_repo_meta_load pkg_repo_meta.c:389
+
#    #4 0x000104a4f8b3 in pkg_repo_fetch_meta pkg_repo.c:1152
+
#    #5 0x00010437bd29 in pkg_repo_binary_update_proceed update.c:543
+
#    #6 0x00010437b641 in pkg_repo_binary_update update.c:748
+
#    #7 0x000104a233b2 in pkg_update pkg_repo_update.c:54
+
#    #8 0x00010435d458 in pkgcli_update update.c:86
+
#    #9 0x00010435df62 in exec_update update.c:195
+
#    #10 0x00010434a1e2 in main main.c:809
+
#    #11 0x7ff8018b92cc in start+0x70c (dyld:x86_64+0xfffffffffff4f2cc)
+
leak:pkg_repo_binary_update_proceed
+

+
# iterator leaks memory
+
#Indirect leak of 17 byte(s) in 1 object(s) allocated from:
+
#    #0 0x562dc63e9f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: ba3136032c30dc1e82d451990c7e921feef19d31)
+
#    #1 0x562dc6604a04 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x562dc66031bb in populate_pkg /home/runner/work/pkg/pkg/src.pkg/libpkg/pkgdb_iterator.c:855:16
+
#    #3 0x562dc6601012 in pkgdb_sqlite_it_next /home/runner/work/pkg/pkg/src.pkg/libpkg/pkgdb_iterator.c:1072:3
+
#    #4 0x562dc6600955 in pkgdb_it_next /home/runner/work/pkg/pkg/src.pkg/libpkg/pkgdb_iterator.c:1121:11
+
#    #5 0x562dc656cc1d in pkg_jobs_universe_get_local /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs_universe.c:90:6
+
#    #6 0x562dc656e87a in pkg_jobs_universe_process_deps /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs_universe.c:252:11
+
#    #7 0x562dc656e2a0 in pkg_jobs_universe_process_item /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs_universe.c:608:8
+
#    #8 0x562dc6570600 in pkg_jobs_universe_process /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs_universe.c:658:10
+
#    #9 0x562dc65485ee in jobs_solve_partial_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:1635:13
+
#    #10 0x562dc6542bb8 in jobs_solve_install_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:1672:14
+
#    #11 0x562dc653f624 in pkg_jobs_run_solver /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:1864:9
+
#    #12 0x562dc653f187 in pkg_jobs_solve /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:1918:12
+
#    #13 0x562dc6459b88 in exec_install /home/runner/work/pkg/pkg/src.pkg/src/install.c:224:6
+
#    #14 0x562dc645eb64 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #15 0x7f9dc3e2a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #16 0x7f9dc3e2a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #17 0x562dc6367444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: ba3136032c30dc1e82d451990c7e921feef19d31)
+
leak:pkgdb_it_next
+

+
# repo metadata is leaked
+
#Indirect leak of 8 byte(s) in 1 object(s) allocated from:
+
#    #0 0x562397070f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: ba3136032c30dc1e82d451990c7e921feef19d31)
+
#    #1 0x5623972c82e4 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x5623972c7ab1 in pkg_repo_meta_set_default /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_repo_meta.c:67:18
+
#    #3 0x5623972c5f1e in pkg_repo_meta_parse /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_repo_meta.c:259:2
+
#    #4 0x5623972c5c7f in pkg_repo_meta_load /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_repo_meta.c:389:10
+
#    #5 0x562397913304 in pkg_repo_binary_open /home/runner/work/pkg/pkg/src.pkg/libpkg/repo/binary/init.c:161:7
+
#    #6 0x562397909ef4 in pkg_repo_binary_update /home/runner/work/pkg/pkg/src.pkg/libpkg/repo/binary/update.c:716:6
+
#    #7 0x562397290bf4 in pkg_update /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_repo_update.c:54:11
+
#    #8 0x5623970f78fc in pkgcli_update /home/runner/work/pkg/pkg/src.pkg/src/update.c:86:13
+
#    #9 0x5623970fbe26 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:350:17
+
#    #10 0x5623970e5b64 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #11 0x7fae3fe2a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #12 0x7fae3fe2a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #13 0x562396fee444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: ba3136032c30dc1e82d451990c7e921feef19d31)
+
leak:pkg_repo_binary_update
+

+

+
# Leak during signature
+
#Indirect leak of 64 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55ec4d2c5293 in malloc (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1e5293) (BuildId: 2bd55d3c70bbeee491903cf8e0a5e4b4835de4a6)
+
#    #1 0x55ec4d5f6dcd in libder_obj_alloc_internal /home/runner/work/pkg/pkg/src.pkg/external/libder/libder/libder_obj.c:138:8
+
#    #2 0x55ec4d5f7133 in libder_obj_alloc_simple /home/runner/work/pkg/pkg/src.pkg/external/libder/libder/libder_obj.c:107:8
+
#    #3 0x55ec4d4e69db in ecc_write_signature_component /home/runner/work/pkg/pkg/src.pkg/libpkg/pkgsign_ecc.c:425:9
+
#    #4 0x55ec4d4e6636 in ecc_write_signature /home/runner/work/pkg/pkg/src.pkg/libpkg/pkgsign_ecc.c:462:7
+
#    #5 0x55ec4d4e3775 in ecc_sign_data /home/runner/work/pkg/pkg/src.pkg/libpkg/pkgsign_ecc.c:1097:6
+
#    #6 0x55ec4d4e398d in ecc_sign /home/runner/work/pkg/pkg/src.pkg/libpkg/pkgsign_ecc.c:1122:8
+
#    #7 0x55ec4d4e89f4 in pkgsign_sign /home/runner/work/pkg/pkg/src.pkg/libpkg/pkgsign.c:177:9
+
#    #8 0x55ec4d3f56c8 in pack_sign /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_repo_create.c:1066:6
+
#    #9 0x55ec4d3f531a in pkg_repo_pack_db /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_repo_create.c:1172:9
+
#    #10 0x55ec4d3f3a5d in pkg_repo_create_pack_and_sign /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_repo_create.c:724:6
+
#    #11 0x55ec4d3f0810 in pkg_repo_create /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_repo_create.c:960:10
+
#    #12 0x55ec4d32d33f in exec_repo /home/runner/work/pkg/pkg/src.pkg/src/repo.c:126:6
+
#    #13 0x55ec4d321b74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #14 0x7fd89d82a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #15 0x7fd89d82a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #16 0x55ec4d22a444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 2bd55d3c70bbeee491903cf8e0a5e4b4835de4a6)
+
leak:ecc_sign
+

+
# Leak in jobs solver
+
#Direct leak of 24 byte(s) in 1 object(s) allocated from:
+
#    #0 0x56483b6c647d in calloc (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1e547d) (BuildId: 2bd55d3c70bbeee491903cf8e0a5e4b4835de4a6)
+
#    #1 0x56483b831dcc in xcalloc /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:19:14
+
#    #2 0x56483b838029 in pkg_jobs_universe_get_remote /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs_universe.c:139:13
+
#    #3 0x56483b832bb0 in pkg_jobs_universe_process_deps /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs_universe.c:277:12
+
#    #4 0x56483b832276 in pkg_jobs_universe_process_item /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs_universe.c:604:8
+
#    #5 0x56483b834620 in pkg_jobs_universe_process /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs_universe.c:658:10
+
#    #6 0x56483b80c04b in jobs_solve_full_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:1583:3
+
#    #7 0x56483b806b99 in jobs_solve_install_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:1668:14
+
#    #8 0x56483b803644 in pkg_jobs_run_solver /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:1864:9
+
#    #9 0x56483b8031a7 in pkg_jobs_solve /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:1918:12
+
#    #10 0x56483b738fe2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:381:6
+
#    #11 0x56483b722b74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #12 0x7f76dba2a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #13 0x7f76dba2a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #14 0x56483b62b444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 2bd55d3c70bbeee491903cf8e0a5e4b4835de4a6)
+
leak:pkg_jobs_run_solver
+

+
# reponames not freed
+
leak:exec_fetch
+

+
# abi leaked after fixup_abi
+
#Direct leak of 8 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55c5bb2e2293 in malloc (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1e5293) (BuildId: 2bd55d3c70bbeee491903cf8e0a5e4b4835de4a6)
+
#    #1 0x7f063768f937  (/lib/x86_64-linux-gnu/libc.so.6+0x8f937) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #2 0x55c5bb26d5fa in vasprintf (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1705fa) (BuildId: 2bd55d3c70bbeee491903cf8e0a5e4b4835de4a6)
+
#    #3 0x55c5bb4a0a6c in xasprintf /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:55:6
+
#    #4 0x55c5bb49ff0c in fixup_abi /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_create.c:573:4
+
#    #5 0x55c5bb49f28b in pkg_create /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_create.c:411:2
+
#    #6 0x55c5bb32eac3 in exec_create /home/runner/work/pkg/pkg/src.pkg/src/create.c:345:8
+
#    #7 0x55c5bb33eb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #8 0x7f063762a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #9 0x7f063762a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #10 0x55c5bb247444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 2bd55d3c70bbeee491903cf8e0a5e4b4835de4a6)
+
leak:exec_create
+

+

+
# pkg structures leaked
+
#Direct leak of 4912 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4bf47d in calloc (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1e547d) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb6e39bc in xcalloc /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:19:14
+
#    #2 0x55becb6e387d in pkg_new /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:31:9
+
#    #3 0x55becb70b78b in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:56:7
+
#    #4 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #5 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #6 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #7 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #8 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #9 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #10 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #11 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #12 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #13 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #14 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #15 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Direct leak of 67 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4bf293 in malloc (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1e5293) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x7f84be68f937  (/lib/x86_64-linux-gnu/libc.so.6+0x8f937) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #2 0x55becb44a5fa in vasprintf (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1705fa) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #3 0x55becb6d427c in xasprintf /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:55:6
+
#    #4 0x55becb6d5c9c in pkg_checksum_generate_fileat /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_checksum.c:837:2
+
#    #5 0x55becb70b711 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:48:8
+
#    #6 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #7 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #8 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #9 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #10 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #11 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #12 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #13 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #14 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #15 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #16 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #17 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 8360 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4bf47d in calloc (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1e547d) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb6e39bc in xcalloc /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:19:14
+
#    #2 0x55becb6f00be in pkg_addfile_attr /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:552:6
+
#    #3 0x55becb6efd0a in pkg_addfile /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:525:10
+
#    #4 0x55becb70c3e5 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:77:2
+
#    #5 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #6 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #7 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #8 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #9 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #10 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #11 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #12 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #13 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #14 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #15 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #16 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 3072 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4bf47d in calloc (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1e547d) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb5d540c in xcalloc /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:19:14
+
#    #2 0x55becb5d536e in pkghash_new /home/runner/work/pkg/pkg/src.pkg/libpkg/pkghash.c:52:19
+
#    #3 0x55becb6f02bb in pkg_addfile_attr /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:570:2
+
#    #4 0x55becb6efd0a in pkg_addfile /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:525:10
+
#    #5 0x55becb70c3e5 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:77:2
+
#    #6 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #7 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #8 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #9 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #10 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #11 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #12 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #13 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #14 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #15 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #16 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #17 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 67 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4a6f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb6ead24 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x55becb6f00f7 in pkg_addfile_attr /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:556:12
+
#    #3 0x55becb6efd0a in pkg_addfile /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:525:10
+
#    #4 0x55becb70c3e5 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:77:2
+
#    #5 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #6 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #7 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #8 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #9 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #10 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #11 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #12 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #13 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #14 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #15 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #16 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 61 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4a6f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb70c724 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x55becb70b8ca in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:62:15
+
#    #3 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #4 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #5 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #6 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #7 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #8 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #9 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #10 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #11 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #12 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #13 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #14 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 61 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4a6f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb70c724 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x55becb70b86f in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:61:18
+
#    #3 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #4 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #5 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #6 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #7 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #8 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #9 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #10 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #11 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #12 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #13 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #14 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 32 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4bf293 in malloc (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1e5293) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb5d53c4 in xmalloc /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:11:14
+
#    #2 0x55becb5d52d1 in pkghash_new /home/runner/work/pkg/pkg/src.pkg/libpkg/pkghash.c:48:19
+
#    #3 0x55becb6f02bb in pkg_addfile_attr /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:570:2
+
#    #4 0x55becb6efd0a in pkg_addfile /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:525:10
+
#    #5 0x55becb70c3e5 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:77:2
+
#    #6 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #7 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #8 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #9 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #10 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #11 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #12 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #13 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #14 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #15 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #16 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #17 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 24 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4bf293 in malloc (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1e5293) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb6f5934 in pkg_addshlib_provided /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:936:2
+
#    #2 0x55becb643fcd in analyse_elf /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_elf.c:321:5
+
#    #3 0x55becb643534 in pkg_analyse_elf /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_elf.c:772:13
+
#    #4 0x55becb648d30 in pkg_analyse_files /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_abi.c:490:9
+
#    #5 0x55becb70c492 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:80:2
+
#    #6 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #7 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #8 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #9 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #10 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #11 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #12 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #13 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #14 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #15 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #16 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #17 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 20 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4a6f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb5d6ff4 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x55becb5d5e58 in pkghash_set_entry /home/runner/work/pkg/pkg/src.pkg/libpkg/pkghash.c:115:9
+
#    #3 0x55becb5d5ac3 in pkghash_add /home/runner/work/pkg/pkg/src.pkg/libpkg/pkghash.c:151:10
+
#    #4 0x55becb6f03b6 in pkg_addfile_attr /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:570:2
+
#    #5 0x55becb6efd0a in pkg_addfile /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:525:10
+
#    #6 0x55becb70c3e5 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:77:2
+
#    #7 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #8 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #9 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #10 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #11 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #12 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #13 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #14 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #15 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #16 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #17 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #18 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 17 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4a6f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb70c724 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x55becb70b814 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:60:17
+
#    #3 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #4 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #5 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #6 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #7 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #8 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #9 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #10 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #11 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #12 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #13 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #14 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 17 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4a6f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb70c724 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x55becb70b7b9 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:59:15
+
#    #3 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #4 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #5 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #6 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #7 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #8 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #9 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #10 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #11 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #12 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #13 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #14 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 15 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4a6f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb70c724 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x55becb70b925 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:63:21
+
#    #3 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #4 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #5 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #6 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #7 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #8 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #9 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #10 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #11 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #12 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #13 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #14 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 15 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4a6f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb70c724 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x55becb70c400 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:79:17
+
#    #3 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #4 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #5 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #6 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #7 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #8 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #9 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #10 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #11 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #12 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #13 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #14 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 14 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4a6f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb6ead24 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x55becb6f5941 in pkg_addshlib_provided /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg.c:936:2
+
#    #3 0x55becb643fcd in analyse_elf /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_elf.c:321:5
+
#    #4 0x55becb643534 in pkg_analyse_elf /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_elf.c:772:13
+
#    #5 0x55becb648d30 in pkg_analyse_files /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_abi.c:490:9
+
#    #6 0x55becb70c492 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:80:2
+
#    #7 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #8 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #9 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #10 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #11 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #12 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #13 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #14 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #15 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #16 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #17 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #18 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 4 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4a6f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb70c724 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x55becb70b980 in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:64:14
+
#    #3 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #4 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #5 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #6 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #7 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #8 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #9 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #10 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #11 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #12 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #13 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #14 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#
+
#Indirect leak of 2 byte(s) in 1 object(s) allocated from:
+
#    #0 0x55becb4a6f9e in strdup (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x1ccf9e) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
#    #1 0x55becb70c724 in xstrdup /home/runner/work/pkg/pkg/src.pkg/libpkg/xmalloc.h:35:12
+
#    #2 0x55becb70b9db in register_backup /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:65:17
+
#    #3 0x55becb70b334 in backup_library /home/runner/work/pkg/pkg/src.pkg/libpkg/backup_lib.c:163:3
+
#    #4 0x55becb68935f in pkg_add_cleanup_old /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1298:7
+
#    #5 0x55becb67f8e1 in pkg_add_common /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1481:7
+
#    #6 0x55becb68065d in pkg_add_upgrade /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_add.c:1599:9
+
#    #7 0x55becb60a9e1 in pkg_jobs_handle_install /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2032:13
+
#    #8 0x55becb5fe88b in pkg_jobs_execute /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2134:14
+
#    #9 0x55becb5fcff3 in pkg_jobs_apply /home/runner/work/pkg/pkg/src.pkg/libpkg/pkg_jobs.c:2196:9
+
#    #10 0x55becb5321f2 in exec_upgrade /home/runner/work/pkg/pkg/src.pkg/src/upgrade.c:401:14
+
#    #11 0x55becb51bb74 in main /home/runner/work/pkg/pkg/src.pkg/src/main.c:809:9
+
#    #12 0x7f84be62a1c9  (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #13 0x7f84be62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 6d64b17fbac799e68da7ebd9985ddf9b5cb375e6)
+
#    #14 0x55becb424444 in _start (/home/runner/work/pkg/pkg/build.pkg/src/pkg+0x14a444) (BuildId: 237ea5dd207e51baca5b1cbcc9176924eae0ad89)
+
leak:backup_library
+

+
# fakerepo->url never freed
+
leak:pkg_fetch_file_to_fd
+

+
# hash not freed
+
leak:trigger_check_match
+

+
# Lua memory is never returned
+
leak:l_alloc
+

+
# Test is leaking
+
leak:atfu_parse_plist_body
+
leak:atfu_parse_keyword_body
+
leak:atfu_charv_t_body
+
leak:atfu_execute_body
+
leak:atfu_readdir_body

\ No newline at end of file
modified README.md
@@ -54,7 +54,7 @@ database and then proceed to run the command you originally requested.

More recent versions of pkg(7) understand `pkg -N` as a test to see if
pkg(8) is installed without triggering the installation, and
-
conversely, `pkg bootstrap[-f]` to install pkg(8) (or force it to be
+
conversely, `pkg bootstrap [-f]` to install pkg(8) (or force it to be
reinstalled) without performing any other actions.

<a name="resources"></a>
modified UndefinedBehaviour.suppress.in
@@ -1,9 +1,6 @@
#
-
# These are errors that need to be taken care of, but in the sprit of
-
# "Put Your Own Oxygen Mask on First", we provide here a suppression list for
-
# _external_ sources.
+
# Suppress errors that are recognized but fix is considered beyond the scope of this project.
+
# (e.g. in external source).
#
-

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

\ No newline at end of file
+
# For syntax see: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#issue-suppression
+
#

\ No newline at end of file
modified external/picosat/picosat.c
@@ -3429,7 +3429,8 @@ satisfied (PS * ps)
    return 0;
  assert (!ps->conflict);
  assert (bcp_queue_is_empty (ps));
-
  return ps->thead == ps->trail + ps->max_var;	/* all assigned */
+
  return (ps->thead == ps->trail && 0 == ps->max_var)
+
      || (ps->trail && ps->thead == ps->trail + ps->max_var); /* all assigned */
}

static void
modified libpkg/Makefile.autosetup
@@ -36,7 +36,8 @@ SRCS= backup_lib.c \
	pkg_elf.c \
	pkg_abi_macho.c \
	binfmt_macho.c \
-
	ssh.c elfhints.c \
+
	ssh.c \
+
	system_shlibs.c \
	pkg_arch.c \
	pkg_cudf.c \
	pkg_jobs_universe.c  pkg_printf.c \
modified libpkg/binfmt_macho.c
@@ -61,8 +61,14 @@ read_fully(const int fd, const size_t len, void *dest)
	ssize_t x;
	while (n > 0) {
		if ((x = read(fd, p, n)) < 0) {
+
			if ( EAGAIN == errno) {
+
				continue;
+
			}
			return x;
		}
+
		if ( 0 == x) {
+
			return -1;
+
		}
		n -= x;
		p += x;
	}
@@ -212,7 +218,7 @@ read_min_version(const int fd, const bool swap, const uint32_t loadcmd,
	return n;
}

-
static ssize_t
+
ssize_t
read_path(const int fd, const bool swap, const uint32_t loadcmdsize,
    char **dest)
{
@@ -235,7 +241,7 @@ read_path(const int fd, const bool swap, const uint32_t loadcmdsize,
	return n;
}

-
static ssize_t
+
ssize_t
read_dylib(const int fd, const bool swap, const uint32_t loadcmdsize,
    dylib_t **dest)
{
deleted libpkg/elfhints.c
@@ -1,558 +0,0 @@
-
/*-
-
 * Copyright (c) 1998 John D. Polstra
-
 * Copyright (c) 2012 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.
-
 * 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 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 AUTHOR 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.
-
 *
-
 * $FreeBSD: stable/8/sbin/ldconfig/elfhints.c 76224 2001-05-02 23:56:21Z obrien $
-
 */
-

-
#include <bsd_compat.h>
-
#include <sys/mman.h>
-
#include <sys/stat.h>
-
#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
-

-
#ifdef __APPLE__
-
#include <libkern/OSByteOrder.h>
-
#define be32toh(n) OSSwapBigToHostInt32(n)
-
#define le32toh(n) OSSwapLittleToHostInt32(n)
-
#endif
-

-
#include <assert.h>
-
#include <ctype.h>
-
#include <dirent.h>
-
#include <err.h>
-
#include <errno.h>
-
#include <fcntl.h>
-
#include <stdio.h>
-
#include <stdlib.h>
-
#include <string.h>
-
#include <unistd.h>
-

-
#include "pkg.h"
-
#include "private/pkg.h"
-
#include "private/ldconfig.h"
-

-
#define MAXDIRS		1024		/* Maximum directories in path */
-
#define MAXFILESIZE	(16*1024)	/* Maximum hints file size */
-

-
struct shlib {
-
	const char	*name;
-
	char		 path[];
-
};
-

-
static int	shlib_list_add(pkghash **shlib_list,
-
				const char *dir, const char *shlib_file);
-
static int	scan_dirs_for_shlibs(pkghash **shlib_list,
-
				     int numdirs, const char **dirlist,
-
	                             bool strictnames);
-
static void	add_dir(const char *, const char *, int);
-
static void	read_dirs_from_file(const char *, const char *);
-
static void	read_elf_hints(const char *, int);
-
static void	write_elf_hints(const char *);
-

-
static const char	*dirs[MAXDIRS];
-
static int		 ndirs;
-
static int		 is_be;
-
int			 insecure;
-

-
#define COND_SWAP(n) (is_be ? be32toh(n) : le32toh(n))
-

-
/* Known shlibs on the standard system search path.  Persistent,
-
   common to all applications */
-
static pkghash *shlibs = NULL;
-

-
/* Known shlibs on the specific RPATH or RUNPATH of one binary.
-
   Evanescent. */
-
static pkghash *rpath = NULL;
-

-
void
-
shlib_list_init(void)
-
{
-
	assert(pkghash_count(shlibs) == 0);
-
}
-

-
void
-
rpath_list_init(void)
-
{
-
	assert(pkghash_count(rpath) == 0);
-
}
-

-
static int
-
shlib_list_add(pkghash **shlib_list, const char *dir,
-
    const char *shlib_file)
-
{
-
	struct shlib	*sl;
-
	size_t path_len, dir_len;
-

-
	/* If shlib_file is already in the shlib_list table, don't try
-
	 * and add it again */
-
	if (pkghash_get(*shlib_list, shlib_file) != NULL)
-
		return (EPKG_OK);
-

-
	path_len = strlen(dir) + strlen(shlib_file) + 2;
-

-
	sl = xcalloc(1, sizeof(struct shlib) + path_len);
-

-
	strlcpy(sl->path, dir, path_len);
-
	dir_len = strlcat(sl->path, "/", path_len);
-
	strlcat(sl->path, shlib_file, path_len);
-

-
	sl->name = sl->path + dir_len;
-

-
	pkghash_safe_add(*shlib_list, sl->name, sl, free);
-

-
	return (EPKG_OK);
-
}
-

-
const char *
-
shlib_list_find_by_name(const char *shlib_file)
-
{
-
	struct shlib *sl;
-

-
	sl = pkghash_get_value(rpath, shlib_file);
-
	if (sl != NULL)
-
		return (sl->path);
-

-
	sl = pkghash_get_value(shlibs, shlib_file);
-
	if (sl != NULL)
-
		return (sl->path);
-

-
	return (NULL);
-
}
-

-
void
-
shlib_list_free(void)
-
{
-

-
	pkghash_destroy(shlibs);
-
	shlibs = NULL;
-
}
-

-
void
-
rpath_list_free(void)
-
{
-

-
	pkghash_destroy(rpath);
-
	rpath = NULL;
-
}
-

-
static void
-
add_dir(const char *hintsfile, const char *name, int trusted)
-
{
-
	struct stat 	stbuf;
-
	int		i;
-

-
	/* Do some security checks */
-
	if (!trusted && !insecure) {
-
		if (stat(name, &stbuf) == -1) {
-
			warn("%s", name);
-
			return;
-
		}
-
		if (stbuf.st_uid != 0) {
-
			warnx("%s: ignoring directory not owned by root", name);
-
			return;
-
		}
-
		if ((stbuf.st_mode & S_IWOTH) != 0) {
-
			warnx("%s: ignoring world-writable directory", name);
-
			return;
-
		}
-
		if ((stbuf.st_mode & S_IWGRP) != 0) {
-
			warnx("%s: ignoring group-writable directory", name);
-
			return;
-
		}
-
	}
-

-
	for (i = 0;  i < ndirs;  i++)
-
		if (STREQ(dirs[i], name))
-
			return;
-
	if (ndirs >= MAXDIRS)
-
		errx(1, "\"%s\": Too many directories in path", hintsfile);
-
	dirs[ndirs++] = name;
-
}
-

-
static int
-
scan_dirs_for_shlibs(pkghash **shlib_list, int numdirs,
-
		     const char **dirlist, bool strictnames)
-
{
-
	int	i;
-

-
	/* Expect shlibs to follow the name pattern libfoo.so.N if
-
	   strictnames is true -- ie. when searching the default
-
	   library search path.
-

-
	   Otherwise, allow any name ending in .so or .so.N --
-
	   ie. when searching RPATH or RUNPATH and assuming it
-
	   contains private shared libraries which can follow just
-
	   about any naming convention */
-

-
	for (i = 0;  i < numdirs;  i++) {
-
		DIR		*dirp;
-
		struct dirent	*dp;
-

-
		if ((dirp = opendir(dirlist[i])) == NULL)
-
			continue;
-
		while ((dp = readdir(dirp)) != NULL) {
-
			int		 len;
-
			int		 ret;
-
			const char	*vers;
-

-
			/* Only regular files and sym-links. On some
-
			   filesystems d_type is not set, on these the d_type
-
			   field will be DT_UNKNOWN. */
-
			if (dp->d_type != DT_REG && dp->d_type != DT_LNK &&
-
			    dp->d_type != DT_UNKNOWN)
-
				continue;
-

-
			len = strlen(dp->d_name);
-
			if (strictnames) {
-
				/* Name can't be shorter than "libx.so" */
-
				if (len < 7 ||
-
				    strncmp(dp->d_name, "lib", 3) != 0)
-
					continue;
-
			}
-

-
			vers = dp->d_name + len;
-
			while (vers > dp->d_name &&
-
			       (isdigit(*(vers-1)) || *(vers-1) == '.'))
-
				vers--;
-
			if (vers == dp->d_name + len) {
-
				if (strncmp(vers - 3, ".so", 3) != 0)
-
					continue;
-
			} else if (vers < dp->d_name + 3 ||
-
			    strncmp(vers - 3, ".so.", 4) != 0)
-
				continue;
-

-
			/* We have a valid shared library name. */
-
			ret = shlib_list_add(shlib_list, dirlist[i],
-
					      dp->d_name);
-
			if (ret != EPKG_OK) {
-
				closedir(dirp);
-
				return ret;
-
			}
-
		}
-
		closedir(dirp);
-
	}
-
	return 0;
-
}
-

-
#define ORIGIN	"$ORIGIN"
-

-
int shlib_list_from_rpath(const char *rpath_str, const char *dirpath)
-
{
-
	const char    **dirlist;
-
	char	       *buf;
-
	size_t		buflen;
-
	int		i, numdirs;
-
	int		ret;
-
	const char     *c, *cstart;
-

-
	/* The special token $ORIGIN should be replaced by the
-
	   dirpath: adjust buflen calculation to account for this */
-

-
	numdirs = 1;
-
	for (c = rpath_str; *c != '\0'; c++)
-
		if (*c == ':')
-
			numdirs++;
-
	buflen = numdirs * sizeof(char *) + strlen(rpath_str) + 1;
-
	i = strlen(dirpath) - strlen(ORIGIN);
-
	if (i > 0)
-
		buflen += i * numdirs;
-

-
	dirlist = xcalloc(1, buflen);
-
	buf = (char *)dirlist + numdirs * sizeof(char *);
-

-
	buf[0] = '\0';
-
	cstart = rpath_str;
-
	while ( (c = strstr(cstart, ORIGIN)) != NULL ) {
-
		strncat(buf, cstart, c - cstart);
-
		strlcat(buf, dirpath, buflen);
-
		cstart = c + strlen(ORIGIN);
-
	}
-
	strlcat(buf, cstart, buflen);
-

-
	i = 0;
-
	while ((c = strsep(&buf, ":")) != NULL) {
-
		if (strlen(c) > 0)
-
			dirlist[i++] = c;
-
	}
-

-
	assert(i <= numdirs);
-

-
	ret = scan_dirs_for_shlibs(&rpath, i, dirlist, false);
-

-
	free(dirlist);
-

-
	return (ret);
-
}
-

-
int
-
shlib_list_from_elf_hints(const char *hintsfile)
-
{
-
	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));
-
}
-

-
static const char *stage_dirs[] = {
-
	"/lib",
-
	"/usr/lib",
-
};
-

-
void
-
shlib_list_from_stage(const char *stage)
-
{
-
	int i;
-
	char *dir;
-

-
	if (stage == NULL)
-
		return;
-

-
	for (i = 0; i < NELEM(stage_dirs); i++) {
-
		xasprintf(&dir, "%s%s", stage, stage_dirs[i]);
-
		scan_dirs_for_shlibs(&shlibs, 1, (const char **)&dir, true);
-
		free(dir);
-
	}
-
}
-

-
void
-
list_elf_hints(const char *hintsfile)
-
{
-
	int	i;
-
	int	nlibs;
-

-
	read_elf_hints(hintsfile, 1);
-
	printf("%s:\n", hintsfile);
-
	printf("\tsearch directories:");
-
	for (i = 0;  i < ndirs;  i++)
-
		printf("%c%s", i == 0 ? ' ' : ':', dirs[i]);
-
	putchar('\n');
-

-
	nlibs = 0;
-
	for (i = 0;  i < ndirs;  i++) {
-
		DIR		*dirp;
-
		struct dirent	*dp;
-

-
		if ((dirp = opendir(dirs[i])) == NULL)
-
			continue;
-
		while ((dp = readdir(dirp)) != NULL) {
-
			int		 len;
-
			int		 namelen;
-
			const char	*name;
-
			const char	*vers;
-

-
			/* Name can't be shorter than "libx.so.0" */
-
			if ((len = strlen(dp->d_name)) < 9 ||
-
			    strncmp(dp->d_name, "lib", 3) != 0)
-
				continue;
-
			name = dp->d_name + 3;
-
			vers = dp->d_name + len;
-
			while (vers > dp->d_name && isdigit(*(vers-1)))
-
				vers--;
-
			if (vers == dp->d_name + len)
-
				continue;
-
			if (vers < dp->d_name + 4 ||
-
			    strncmp(vers - 4, ".so.", 4) != 0)
-
				continue;
-

-
			/* We have a valid shared library name. */
-
			namelen = (vers - 4) - name;
-
			printf("\t%d:-l%.*s.%s => %s/%s\n", nlibs,
-
			    namelen, name, vers, dirs[i], dp->d_name);
-
			nlibs++;
-
		}
-
		closedir(dirp);
-
	}
-
}
-

-
static void
-
read_dirs_from_file(const char *hintsfile, const char *listfile)
-
{
-
	FILE	*fp;
-
	char	 buf[MAXPATHLEN];
-
	int	 linenum;
-

-
	if ((fp = fopen(listfile, "re")) == NULL)
-
		err(1, "%s", listfile);
-

-
	linenum = 0;
-
	while (fgets(buf, sizeof buf, fp) != NULL) {
-
		char	*cp, *sp;
-

-
		linenum++;
-
		cp = buf;
-
		/* Skip leading white space. */
-
		while (isspace(*cp))
-
			cp++;
-
		if (*cp == '#' || *cp == '\0')
-
			continue;
-
		sp = cp;
-
		/* Advance over the directory name. */
-
		while (!isspace(*cp) && *cp != '\0')
-
			cp++;
-
		/* Terminate the string and skip trailing white space. */
-
		if (*cp != '\0') {
-
			*cp++ = '\0';
-
			while (isspace(*cp))
-
				cp++;
-
		}
-
		/* Now we had better be at the end of the line. */
-
		if (*cp != '\0')
-
			warnx("%s:%d: trailing characters ignored",
-
			    listfile, linenum);
-

-
		sp = xstrdup(sp);
-
		add_dir(hintsfile, sp, 0);
-
	}
-

-
	fclose(fp);
-
}
-

-
static void
-
read_elf_hints(const char *hintsfile, int must_exist)
-
{
-
	int	 		 fd;
-
	struct stat		 s;
-
	void			*mapbase;
-
	struct elfhints_hdr	*hdr;
-
	char			*strtab;
-
	char			*dirlist;
-
	char			*p;
-

-
	if ((fd = open(hintsfile, O_RDONLY)) == -1) {
-
		if (errno == ENOENT && !must_exist)
-
			return;
-
		err(1, "Cannot open \"%s\"", hintsfile);
-
	}
-
	if (fstat(fd, &s) == -1)
-
		err(1, "Cannot stat \"%s\"", hintsfile);
-
	if (s.st_size > MAXFILESIZE)
-
		errx(1, "\"%s\" is unreasonably large", hintsfile);
-
	/*
-
	 * We use a read-write, private mapping so that we can null-terminate
-
	 * some strings in it without affecting the underlying file.
-
	 */
-
	mapbase = mmap(NULL, s.st_size, PROT_READ|PROT_WRITE,
-
	    MAP_PRIVATE, fd, 0);
-
	if (mapbase == MAP_FAILED)
-
		err(1, "Cannot mmap \"%s\"", hintsfile);
-
	close(fd);
-

-
	hdr = (struct elfhints_hdr *)mapbase;
-
	is_be = be32toh(hdr->magic) == ELFHINTS_MAGIC;
-
	if (COND_SWAP(hdr->magic) != ELFHINTS_MAGIC)
-
		errx(1, "\"%s\": invalid file format", hintsfile);
-
	if (COND_SWAP(hdr->version) != 1)
-
		errx(1, "\"%s\": unrecognized file version (%d)", hintsfile,
-
		    COND_SWAP(hdr->version));
-

-
	strtab = (char *)mapbase + COND_SWAP(hdr->strtab);
-
	dirlist = strtab + COND_SWAP(hdr->dirlist);
-

-
	if (*dirlist != '\0')
-
		while ((p = strsep(&dirlist, ":")) != NULL)
-
			add_dir(hintsfile, p, 1);
-
}
-

-
void
-
update_elf_hints(const char *hintsfile, int argc, char **argv, int merge)
-
{
-
	int	i;
-

-
	if (merge)
-
		read_elf_hints(hintsfile, 0);
-
	else
-
		// remove when FreeBSD switches to LE for all architectures
-
		is_be = be32toh(1) == 1;
-
	for (i = 0;  i < argc;  i++) {
-
		struct stat	s;
-

-
		if (stat(argv[i], &s) == -1)
-
			warn("warning: %s", argv[i]);
-
		else if (S_ISREG(s.st_mode))
-
			read_dirs_from_file(hintsfile, argv[i]);
-
		else
-
			add_dir(hintsfile, argv[i], 0);
-
	}
-
	write_elf_hints(hintsfile);
-
}
-

-
static void
-
write_elf_hints(const char *hintsfile)
-
{
-
	struct elfhints_hdr	 hdr;
-
	char			*tempname;
-
	int			 fd;
-
	FILE			*fp;
-
	int			 i;
-

-
	xasprintf(&tempname, "%s.XXXXXX", hintsfile);
-
	if ((fd = mkstemp(tempname)) ==  -1)
-
		err(1, "mkstemp(%s)", tempname);
-
	if (fchmod(fd, 0444) == -1)
-
		err(1, "fchmod(%s)", tempname);
-
	if ((fp = fdopen(fd, "wb")) == NULL)
-
		err(1, "fdopen(%s)", tempname);
-

-
	hdr.magic = COND_SWAP(ELFHINTS_MAGIC);
-
	hdr.version = COND_SWAP(1);
-
	hdr.strtab = COND_SWAP(sizeof hdr);
-
	hdr.strsize = 0;
-
	hdr.dirlist = 0;
-
	memset(hdr.spare, 0, sizeof hdr.spare);
-

-
	/* Count up the size of the string table. */
-
	if (ndirs > 0) {
-
		hdr.strsize += strlen(dirs[0]);
-
		for (i = 1;  i < ndirs;  i++)
-
			hdr.strsize += 1 + strlen(dirs[i]);
-
	}
-
	hdr.dirlistlen = COND_SWAP(hdr.strsize);
-
	hdr.strsize++;	/* For the null terminator */
-
	hdr.strsize = COND_SWAP(hdr.strsize);
-

-
	/* Write the header. */
-
	if (fwrite(&hdr, 1, sizeof hdr, fp) != sizeof hdr)
-
		err(1, "%s: write error", tempname);
-
	/* Write the strings. */
-
	if (ndirs > 0) {
-
		if (fputs(dirs[0], fp) == EOF)
-
			err(1, "%s: write error", tempname);
-
		for (i = 1;  i < ndirs;  i++)
-
			if (fprintf(fp, ":%s", dirs[i]) < 0)
-
				err(1, "%s: write error", tempname);
-
	}
-
	if (putc('\0', fp) == EOF || fclose(fp) == EOF)
-
		err(1, "%s: write error", tempname);
-

-
	if (rename(tempname, hintsfile) == -1)
-
		err(1, "rename %s to %s", tempname, hintsfile);
-
	free(tempname);
-
}
modified libpkg/fetch_libcurl.c
@@ -448,7 +448,7 @@ do_retry:
		if (lurl) {
			pkg_dbg(PKG_DBG_FETCH, 2, "CURL> attempting to fetch from %s\n", lurl);
		}
-
		pkg_dbg(PKG_DBG_FETCH, 2, "CURL> retries left: %ld\n", retry);
+
		pkg_dbg(PKG_DBG_FETCH, 2, "CURL> retries left: %"PRId64"\n", retry);
	}
	curl_easy_setopt(cl, CURLOPT_HTTPAUTH, (long)CURLAUTH_ANY);
	if (userpasswd != NULL) {
deleted libpkg/fetch_libfetch.c
@@ -1,250 +0,0 @@
-
/*-
-
 * Copyright (c) 2020-2022 Baptiste Daroussin <bapt@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.
-
 */
-

-

-
#include <sys/param.h>
-
#include <sys/wait.h>
-
#include <sys/socket.h>
-
#include <sys/time.h>
-

-
#include <ctype.h>
-
#include <fcntl.h>
-
#include <errno.h>
-
#include <stdio.h>
-
#include <string.h>
-
#include <fetch.h>
-
#include <paths.h>
-
#include <poll.h>
-
#include <xstring.h>
-

-
#include <bsd_compat.h>
-

-
#include "pkg.h"
-
#include "private/event.h"
-
#include "private/pkg.h"
-
#include "private/fetch.h"
-
#include "private/utils.h"
-

-
static void
-
gethttpmirrors(struct pkg_repo *repo, const char *url, bool withdoc) {
-
	FILE *f;
-
	char *line = NULL, *walk;
-
	size_t linecap = 0;
-
	ssize_t linelen;
-
	struct http_mirror *m;
-
	struct url *u;
-

-
	if ((f = fetchGetURL(url, "")) == NULL)
-
		return;
-

-
	while ((linelen = getline(&line, &linecap, f)) > 0) {
-
		if (strncmp(line, "URL:", 4) == 0) {
-
			walk = line;
-
			/* trim '\n' */
-
			if (walk[linelen - 1] == '\n')
-
				walk[linelen - 1 ] = '\0';
-

-
			walk += 4;
-
			while (isspace(*walk)) {
-
				walk++;
-
			}
-
			if (*walk == '\0')
-
				continue;
-

-
			if ((u = fetchParseURL(walk)) != NULL) {
-
				m = xmalloc(sizeof(struct http_mirror));
-
				m->reldoc = withdoc;
-
				m->url = u;
-
				LL_APPEND(repo->http, m);
-
			}
-
		}
-
	}
-

-
	free(line);
-
	fclose(f);
-
	return;
-
}
-

-
static int
-
fetch_connect(struct pkg_repo *repo, struct url *u)
-
{
-
	struct url *repourl;
-
	xstring *fetchOpts = NULL;
-
	int64_t max_retry, retry;
-
	int64_t fetch_timeout;
-
	int retcode = EPKG_OK;
-
	char docpath[MAXPATHLEN];
-
	char zone[MAXHOSTNAMELEN + 24];
-
	char *doc, *reldoc, *opts;
-
	struct dns_srvinfo *srv_current = NULL;
-
	struct http_mirror *http_current = NULL;
-
	struct url_stat st;
-

-
	max_retry = pkg_object_int(pkg_config_get("FETCH_RETRY"));
-
	fetch_timeout = pkg_object_int(pkg_config_get("FETCH_TIMEOUT"));
-

-
	fetchTimeout = (int)MIN(fetch_timeout, INT_MAX);
-

-
	repourl = fetchParseURL(repo->url);
-
	if (repourl == NULL) {
-
		pkg_emit_error("%s: parse error", repo->url);
-
		fetchFreeURL(u);
-
		return (EPKG_FATAL);
-
	}
-
	retry = max_retry;
-
	doc = u->doc;
-
	reldoc = doc + strlen(repourl->doc);
-
	fetchFreeURL(repourl);
-
	pkg_dbg(PKG_DBG_FETCH, "Fetch > libfetch: connecting");
-

-
	while (repo->fh == NULL) {
-
		if (repo != NULL && repo->mirror_type == SRV &&
-
		    (strncmp(u->scheme, "http", 4) == 0)) {
-
			if (repo->srv == NULL) {
-
				snprintf(zone, sizeof(zone),
-
				    "_%s._tcp.%s", u->scheme, u->host);
-
				repo->srv = dns_getsrvinfo(zone);
-
			}
-

-
			srv_current = repo->srv;
-
			} else if (repo != NULL && repo->mirror_type == HTTP &&
-
			    strncmp(u->scheme, "http", 4) == 0) {
-
				if (u->port == 0) {
-
					if (STREQ(u->scheme, "https"))
-
						u->port = 443;
-
					else
-
						u->port = 80;
-
				}
-
				snprintf(zone, sizeof(zone),
-
				    "%s://%s:%d", u->scheme, u->host, u->port);
-
				if (repo->http == NULL)
-
					gethttpmirrors(repo, zone, false);
-
				if (repo->http == NULL)
-
					gethttpmirrors(repo, repo->url, true);
-

-
				http_current = repo->http;
-
			}
-
		if (repo != NULL && repo->mirror_type == SRV && repo->srv != NULL) {
-
			strlcpy(u->host, srv_current->host, sizeof(u->host));
-
			u->port = srv_current->port;
-
		} else if (repo != NULL && repo->mirror_type == HTTP && repo->http != NULL) {
-
			strlcpy(u->scheme, http_current->url->scheme, sizeof(u->scheme));
-
			strlcpy(u->host, http_current->url->host, sizeof(u->host));
-
			snprintf(docpath, sizeof(docpath), "%s%s",
-
			    http_current->url->doc, http_current->reldoc ? reldoc : doc);
-
			u->doc = docpath;
-
			u->port = http_current->url->port;
-
		}
-
		fetchOpts = xstring_new();
-
	        fputc('i', fetchOpts->fp);
-
		if (repo != NULL) {
-
			if ((repo->flags & REPO_FLAGS_USE_IPV4) ==
-
			    REPO_FLAGS_USE_IPV4)
-
				fputc('4', fetchOpts->fp);
-
			else if ((repo->flags & REPO_FLAGS_USE_IPV6) ==
-
			    REPO_FLAGS_USE_IPV6)
-
				fputc('6', fetchOpts->fp);
-
		}
-

-
		if (ctx.debug_level >= 4)
-
			fputc('v', fetchOpts->fp);
-

-
		opts = xstring_get(fetchOpts);
-
		pkg_dbg(PKG_DBG_FETCH, "Fetch: fetching from: %s://%s%s%s%s with opts \"%s\"",
-
		    u->scheme,
-
		    u->user,
-
		    u->user[0] != '\0' ? "@" : "",
-
		    u->host,
-
		    u->doc,
-
		    opts);
-

-
		repo->fh = fetchXGet(u, &st, opts);
-
		u->ims_time = st.mtime;
-
		if (repo->fh == NULL) {
-
			if (fetchLastErrCode == FETCH_OK) {
-
				retcode = EPKG_UPTODATE;
-
				goto cleanup;
-
			}
-
			--retry;
-
			if (retry <= 0 || fetchLastErrCode == FETCH_UNAVAIL) {
-
				 if (!repo->silent)
-
					pkg_emit_error("%s://%s%s%s%s: %s",
-
					    u->scheme,
-
					    u->user,
-
					    u->user[0] != '\0' ? "@" : "",
-
					    u->host,
-
					    u->doc,
-
					    fetchLastErrString);
-
				retcode = EPKG_FATAL;
-
				goto cleanup;
-
			}
-
			if (repo != NULL && repo->mirror_type == SRV && repo->srv != NULL) {
-
				srv_current = srv_current->next;
-
				if (srv_current == NULL)
-
					srv_current = repo->srv;
-
			} else if (repo != NULL && repo->mirror_type == HTTP && repo->http != NULL) {
-
				http_current = repo->http->next;
-
				if (http_current == NULL)
-
					http_current = repo->http;
-
			}
-
		}
-
	}
-
cleanup:
-
	u->doc = doc;
-
	if (retcode != EPKG_OK && repo->fh != NULL) {
-
		fclose(repo->fh);
-
		repo->fh = NULL;
-
	}
-
	return (retcode);
-
}
-

-
int
-
fetch_open(struct pkg_repo *repo, struct url *u, off_t *sz, time_t *t)
-
{
-
	int retcode = EPKG_FATAL;
-

-
	pkg_dbg(PKG_DBG_FETCH, "opening libfetch fetcher");
-
	if (repo->fh == NULL)
-
		retcode = fetch_connect(repo, u);
-

-
	if (retcode == EPKG_OK)
-
		*sz = u->length;
-

-
	return (retcode);
-
}
-

-
int
-
libfetch_fetch(struct pkg_repo *repo, int dest, const char *url, struct url *u, off_t sz, time_t *t)
-
{
-
	int ret;
-

-
	ret = stdio_fetch(repo, dest, url, u, sz, t);
-

-
	if (ret == EPKG_OK && ferror(repo->fh)) {
-
		pkg_emit_error("%s: %s", url, fetchLastErrString);
-
		return (EPKG_FATAL);
-
	}
-
	return (ret);
-
}
modified libpkg/pkg.c
@@ -103,6 +103,8 @@ pkg_free(struct pkg *pkg)
	tll_free_and_free(pkg->message, pkg_message_free);
	tll_free_and_free(pkg->annotations, pkg_kv_free);

+
	tll_free_and_free(pkg->dir_to_del, free);
+

	if (pkg->rootfd != -1)
		close(pkg->rootfd);

@@ -902,6 +904,13 @@ pkg_addshlib_required(struct pkg *pkg, const char *name)
	assert(pkg != NULL);
	assert(name != NULL && name[0] != '\0');

+
	if (match_ucl_lists(name,
+
	    pkg_config_get("SHLIB_REQUIRE_IGNORE_GLOB"),
+
	    pkg_config_get("SHLIB_REQUIRE_IGNORE_REGEX"))) {
+
		dbg(3, "ignoring shlib %s required by package %s", name, pkg->name);
+
		return (EPKG_OK);
+
	}
+

	/* silently ignore duplicates in case of shlibs */
	tll_foreach(pkg->shlibs_required, s) {
		if (STREQ(s->item, name))
modified libpkg/pkg_abi.c
@@ -1,28 +1,12 @@
/*-
 * Copyright (c) 2011-2012 Baptiste Daroussin <bapt@FreeBSD.org>
 * Copyright (c) 2012-2013 Matthew Seaman <matthew@FreeBSD.org>
-
 * All rights reserved.
+
 * Copyright (c) 2024 The FreeBSD Foundation
 *
-
 * 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 was developed in part by Isaac Freund <ifreund@freebsdfoundation.org>
+
 * under sponsorship from the FreeBSD Foundation.
 *
-
 * 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
#include "pkg_config.h"
@@ -30,12 +14,15 @@

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

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

#define _PATH_UNAME "/usr/bin/uname"

@@ -62,8 +49,256 @@ static struct arch_trans machine_arch_translation[] = { { "x86:32", "i386" },

	{ NULL, NULL } };

-
static int
-
pkg_get_myarch_fromfile(struct os_info *oi)
+
static struct {
+
	enum pkg_os os;
+
	const char *string;
+
} os_string_table[] = {
+
	{ PKG_OS_UNKNOWN, "Unknown" },
+
	{ PKG_OS_FREEBSD, "FreeBSD" },
+
	{ PKG_OS_NETBSD, "NetBSD" },
+
	{ PKG_OS_DRAGONFLY, "dragonfly" },
+
	{ PKG_OS_LINUX, "Linux" },
+
	{ PKG_OS_DARWIN, "Darwin" },
+
	{ -1, NULL },
+
};
+

+
/* This table does not include PKG_ARCH_AMD64 as the string translation of
+
   that arch is os-dependent. */
+
static struct {
+
	enum pkg_arch arch;
+
	const char *string;
+
} arch_string_table[] = {
+
	{ PKG_ARCH_UNKNOWN, "unknown"},
+
	{ PKG_ARCH_I386, "i386"},
+
	{ PKG_ARCH_ARMV6, "armv6"},
+
	{ PKG_ARCH_ARMV7, "armv7"},
+
	{ PKG_ARCH_AARCH64, "aarch64"},
+
	{ PKG_ARCH_POWERPC, "powerpc"},
+
	{ PKG_ARCH_POWERPC64, "powerpc64"},
+
	{ PKG_ARCH_POWERPC64LE, "powerpc64le"},
+
	{ PKG_ARCH_RISCV32, "riscv32"},
+
	{ PKG_ARCH_RISCV64, "riscv64"},
+
	{ -1, NULL },
+
};
+

+
const char *
+
pkg_os_to_string(enum pkg_os os)
+
{
+
	for (size_t i = 0; os_string_table[i].string != NULL; i++) {
+
		if (os == os_string_table[i].os) {
+
			return os_string_table[i].string;
+
		}
+
	}
+
	assert(0);
+
}
+

+
enum pkg_os
+
pkg_os_from_string(const char *string)
+
{
+
	for (size_t i = 0; os_string_table[i].string != NULL; i++) {
+
		if (STREQ(string, os_string_table[i].string)) {
+
			return os_string_table[i].os;
+
		}
+
	}
+
	return (PKG_OS_UNKNOWN);
+
}
+

+
/* Returns true if the OS uses "amd64" rather than "x86_64" */
+
static bool
+
pkg_os_uses_amd64_name(enum pkg_os os)
+
{
+
	switch (os) {
+
	case PKG_OS_FREEBSD:
+
		return (true);
+
	case PKG_OS_DARWIN:
+
	case PKG_OS_NETBSD:
+
	case PKG_OS_LINUX:
+
		return (false);
+
	case PKG_OS_DRAGONFLY:
+
	case PKG_OS_UNKNOWN:
+
	default:
+
		assert(0);
+
	}
+
}
+

+
const char *
+
pkg_arch_to_string(enum pkg_os os, enum pkg_arch arch)
+
{
+
	if (arch == PKG_ARCH_AMD64) {
+
		if (os == PKG_OS_DRAGONFLY) {
+
			return ("x86:64");
+
		} else if (pkg_os_uses_amd64_name(os)) {
+
			return ("amd64");
+
		} else {
+
			return ("x86_64");
+
		}
+
	}
+

+
	for (size_t i = 0; arch_string_table[i].string != NULL; i++) {
+
		if (arch == arch_string_table[i].arch) {
+
			return arch_string_table[i].string;
+
		}
+
	}
+

+
	assert(0);
+
}
+

+
enum pkg_arch
+
pkg_arch_from_string(enum pkg_os os, const char *string)
+
{
+
	if (os == PKG_OS_DRAGONFLY) {
+
		if (STREQ(string, "x86:64")) {
+
			return (PKG_ARCH_AMD64);
+
		}
+
	} else if (pkg_os_uses_amd64_name(os)) {
+
		if (STREQ(string, "amd64")) {
+
			return (PKG_ARCH_AMD64);
+
		}
+
	} else {
+
		if (STREQ(string, "x86_64")) {
+
			return (PKG_ARCH_AMD64);
+
		}
+
	}
+

+
	for (size_t i = 0; arch_string_table[i].string != NULL; i++) {
+
		if (STREQ(string, arch_string_table[i].string)) {
+
			return arch_string_table[i].arch;
+
		}
+
	}
+

+
	return (PKG_ARCH_UNKNOWN);
+
}
+

+
bool
+
pkg_abi_string_only_major_version(enum pkg_os os)
+
{
+
	switch (os) {
+
	case PKG_OS_FREEBSD:
+
	case PKG_OS_NETBSD:
+
	case PKG_OS_DARWIN:
+
		return (true);
+
	case PKG_OS_DRAGONFLY:
+
	case PKG_OS_LINUX:
+
		return (false);
+
	case PKG_OS_UNKNOWN:
+
	default:
+
		assert (0);
+
	}
+
}
+

+
char *
+
pkg_abi_to_string(const struct pkg_abi *abi)
+
{
+
	char *ret;
+
	if (pkg_abi_string_only_major_version(abi->os)) {
+
		xasprintf(&ret, "%s:%d:%s", pkg_os_to_string(abi->os),
+
		    abi->major, pkg_arch_to_string(abi->os, abi->arch));
+
	} else {
+
		xasprintf(&ret, "%s:%d.%d:%s", pkg_os_to_string(abi->os),
+
		    abi->major, abi->minor,
+
		    pkg_arch_to_string(abi->os, abi->arch));
+
	}
+
	return (ret);
+
}
+

+
bool
+
pkg_abi_from_string(struct pkg_abi *abi, const char *string)
+
{
+
	*abi = (struct pkg_abi){0};
+

+
	bool ret = false;
+

+
	char *copy = xstrdup(string);
+

+
	char *iter = copy;
+
	char *os = strsep(&iter, ":");
+
	assert(os != NULL);
+
	abi->os = pkg_os_from_string(os);
+
	if (abi->os == PKG_OS_UNKNOWN) {
+
		pkg_emit_error("Unknown OS '%s' in ABI string", os);
+
		goto out;
+
	}
+

+
	char *version = strsep(&iter, ":");
+
	if (version == NULL) {
+
		pkg_emit_error("Invalid ABI string '%s', "
+
		    "missing version and architecture", string);
+
		goto out;
+
	}
+
	const char *errstr = NULL;
+
	if (pkg_abi_string_only_major_version(abi->os)) {
+
		abi->major = strtonum(version, 1, INT_MAX, &errstr);
+
	} else {
+
		/* XXX add tests for this */
+
		char *major = strsep(&version, ".");
+
		char *minor = strsep(&version, ".");
+

+
		assert(major != NULL);
+
		if (minor == NULL) {
+
			pkg_emit_error("Invalid ABI string %s, "
+
			    "missing minor OS version", string);
+
			goto out;
+
		}
+

+
		abi->major = strtonum(major, 1, INT_MAX, &errstr);
+
		if (errstr != NULL) {
+
			abi->minor = strtonum(minor, 1, INT_MAX, &errstr);
+
		}
+
	}
+
	if (errstr != NULL) {
+
		pkg_emit_error("Invalid version in ABI string '%s'", string);
+
		goto out;
+
	}
+

+
	/* DragonFlyBSD continues to use the legacy/altabi format.
+
	   For example: dragonfly:5.10:x86:64
+
	   This means we can't use strsep again since that would split the arch
+
	   string for dragonfly. */
+
	char *arch = iter;
+
	if (arch == NULL) {
+
		pkg_emit_error("Invalid ABI string '%s', "
+
		    "missing architecture", string);
+
		goto out;
+
	}
+

+
	abi->arch = pkg_arch_from_string(abi->os, arch);
+
	if (abi->arch == PKG_ARCH_UNKNOWN) {
+
		pkg_emit_error("Unknown architecture '%s' in ABI string", arch);
+
		goto out;
+
	}
+

+
	if (abi->os == PKG_OS_DRAGONFLY && abi->arch != PKG_ARCH_AMD64) {
+
		pkg_emit_error("Invalid ABI string '%s', "
+
		    "only x86:64 is supported on dragonfly.", string);
+
		goto out;
+
	}
+

+
	ret = true;
+
out:
+
	free(copy);
+
	return (ret);
+
}
+

+
void
+
pkg_abi_set_freebsd_osversion(struct pkg_abi *abi, int osversion)
+
{
+
	assert(abi->os == PKG_OS_FREEBSD);
+

+
	abi->major = osversion / 100000;
+
	abi->minor = (osversion / 1000) % 100;
+
	abi->patch = osversion % 1000;
+
}
+

+
int
+
pkg_abi_get_freebsd_osversion(struct pkg_abi *abi)
+
{
+
	assert(abi->os == PKG_OS_FREEBSD);
+

+
	return (abi->major * 100000) + (abi->minor * 1000) + abi->patch;
+
}
+

+
int
+
pkg_abi_from_file(struct pkg_abi *abi)
{
	char rooted_abi_file[PATH_MAX];
	const char *abi_files[] = {
@@ -125,26 +360,37 @@ pkg_get_myarch_fromfile(struct os_info *oi)
		return EPKG_FATAL;
	}

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

-
	int ret = pkg_get_myarch_elfparse(fd, oi);
+
	int ret = pkg_elf_abi_from_fd(fd, abi);
	if (EPKG_OK != ret) {
		if (-1 == lseek(fd, 0, SEEK_SET)) {
			pkg_emit_errno("Error seeking file", work_abi_file);
			ret = EPKG_FATAL;
+
			goto close_out;
+
		}
+

+
		enum pkg_arch arch_hint = PKG_ARCH_UNKNOWN;
+
		if (work_arch_hint[0]) {
+
			arch_hint = pkg_arch_from_string(PKG_OS_DARWIN, work_arch_hint);
+
			if (arch_hint == PKG_ARCH_UNKNOWN) {
+
				pkg_emit_error("Invalid ABI_FILE architecture hint %s",
+
				    work_arch_hint);
+
				ret = EPKG_FATAL;
+
				goto close_out;
+
			}
		}
-
		ret = pkg_get_myarch_macho(fd, oi);
+

+
		ret = pkg_macho_abi_from_fd(fd, abi, arch_hint);
		if (EPKG_OK != ret) {
			pkg_emit_error(
-
			    "Unable to determine the ABI, %s cannot be parsed.",
+
			    "Unable to determine ABI, %s cannot be parsed.",
			    work_abi_file);
			ret = EPKG_FATAL;
+
			goto close_out;
		}
	}

+
close_out:
	if (close(fd)) {
		pkg_emit_errno("Error closing file", work_abi_file);
		ret = EPKG_FATAL;
@@ -153,32 +399,6 @@ pkg_get_myarch_fromfile(struct os_info *oi)
}

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) {
-
		pkg_debug(1, "Error %d when trying to determine myarch.", 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;
@@ -227,10 +447,19 @@ pkg_analyse_files(struct pkgdb *db __unused, struct pkg *pkg, const char *stage)
	const char *lib;
	bool failures = false;

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

+
	if (0 == strncmp(pkg->abi, "Darwin", 6)) {
+
		pkg_analyse_init=pkg_analyse_init_macho;
+
		pkg_analyse=pkg_analyse_macho;
+
		pkg_analyse_close=pkg_analyse_close_macho;
+
	} else {
+
		pkg_analyse_init=pkg_analyse_init_elf;
+
		pkg_analyse=pkg_analyse_elf;
+
		pkg_analyse_close=pkg_analyse_close_elf;
+
	}

	if (tll_length(pkg->shlibs_required) != 0) {
		tll_free_and_free(pkg->shlibs_required, free);
modified libpkg/pkg_abi_macho.c
@@ -6,29 +6,28 @@

#include <errno.h>

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

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

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

-
static const char *
-
cputype_to_freebsd_machine_arch(const cpu_type_subtype_t cpu)
+
static enum pkg_arch
+
cputype_to_pkg_arch(const cpu_type_subtype_t cpu)
{
	switch (cpu.type) {
	case CPU_TYPE_ARM:
		if (cpu.type_is64_32) {
-
			return "aarch64-x32";
+
			return (PKG_ARCH_UNKNOWN); /* aarch64-x32 */
		} else if (cpu.type_is64) {
-
			return "aarch64";
+
			return (PKG_ARCH_AARCH64);
		} else {
			switch (cpu.subtype_arm) {
			case CPU_SUBTYPE_ARM_V7:
@@ -36,105 +35,101 @@ cputype_to_freebsd_machine_arch(const cpu_type_subtype_t cpu)
			case CPU_SUBTYPE_ARM_V7K:
			case CPU_SUBTYPE_ARM_V7M:
			case CPU_SUBTYPE_ARM_V7EM:
-
				return "armv7";
+
				return (PKG_ARCH_ARMV7);
			case CPU_SUBTYPE_ARM_V6:
			case CPU_SUBTYPE_ARM_V6M:
-
				return "armv6";
+
				return (PKG_ARCH_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";
+
				return (PKG_ARCH_UNKNOWN);
			}
		}
	case CPU_TYPE_POWERPC:
		if (cpu.type_is64_32) {
-
			return "powerpc64-x32";
+
			return (PKG_ARCH_UNKNOWN); /* powerpc64-x32 */
		} else if (cpu.type_is64) {
-
			return "powerpc64";
+
			return (PKG_ARCH_POWERPC64);
		} else {
-
			return "powerpc";
+
			return (PKG_ARCH_POWERPC);
		}
	case CPU_TYPE_X86:
		if (cpu.type_is64_32) {
-
			return "amd64-x32";
+
			return (PKG_ARCH_UNKNOWN); /* amd64-x32 */
		} else if (cpu.type_is64) {
-
			return "amd64";
+
			return (PKG_ARCH_AMD64);
		} else {
-
			return "i386";
+
			return (PKG_ARCH_I386);
		}
	default:
-
		return "unknown";
+
		return (PKG_ARCH_UNKNOWN);
	}
}

static cpu_type_subtype_t
-
freebsd_machine_arch_to_cputype(const char *archname) {
+
pkg_arch_to_cputype(enum pkg_arch arch) {
	cpu_type_subtype_t cpu = { 0 };

-
	if (!strcmp("aarch64", archname)) {
+
	switch (arch) {
+
	case PKG_ARCH_AARCH64:
		cpu.type = CPU_TYPE_ARM;
		cpu.type_is64 = true;
-
	} else if (!strcmp("amd64", archname)) {
+
		break;
+
	case PKG_ARCH_AMD64:
		cpu.type = CPU_TYPE_X86;
		cpu.type_is64 = true;
		cpu.subtype_x86 = CPU_SUBTYPE_X86_ALL;
-
	} else if (!strcmp("arm", archname)) {
-
		cpu.type = CPU_TYPE_ARM;
-
		cpu.subtype_arm = CPU_SUBTYPE_ARM_ALL;
-
	} else if (!strcmp("armeb", archname)) {
-
		cpu.type = CPU_TYPE_ARM;
-
		cpu.subtype_arm = CPU_SUBTYPE_ARM_V5;
-
	} else if (!strcmp("armv6", archname)) {
+
		break;
+
	case PKG_ARCH_ARMV6:
		cpu.type = CPU_TYPE_ARM;
		cpu.subtype_arm = CPU_SUBTYPE_ARM_V6;
-
	} else if (!strcmp("armv7", archname)) {
+
		break;
+
	case PKG_ARCH_ARMV7:
		cpu.type = CPU_TYPE_ARM;
		cpu.subtype_arm = CPU_SUBTYPE_ARM_V7;
-
	} else if (!strcmp("i386", archname)) {
+
		break;
+
	case PKG_ARCH_I386:
		cpu.type = CPU_TYPE_X86;
		cpu.subtype_x86 = CPU_SUBTYPE_X86_ALL;
-
	} else if (!strcmp("powerpc", archname)) {
+
		break;
+
	case PKG_ARCH_POWERPC:
		cpu.type = CPU_TYPE_POWERPC;
		cpu.subtype_ppc = CPU_SUBTYPE_POWERPC_ALL;
-
	} else if (!strcmp("powerpc64", archname)) {
+
		break;
+
	case PKG_ARCH_POWERPC64:
		cpu.type = CPU_TYPE_POWERPC;
		cpu.type_is64 = true;
		cpu.subtype_ppc = CPU_SUBTYPE_POWERPC_ALL;
-
	} else {
-
		// alpha
-
		// ia64
-
		// mips*
-
		// pc98
-
		// sparc64
+
		break;
+
	case PKG_ARCH_POWERPC64LE:
+
	case PKG_ARCH_RISCV32:
+
	case PKG_ARCH_RISCV64:
+
	case PKG_ARCH_UNKNOWN:
		cpu.type = CPU_TYPE_ANY;
+
		break;
	}
+

	return cpu;
}


/**
-
 * Using the passed mf descriptor, match the best entry using oi->name as a hint.
+
 * Using the passed mf descriptor, match the best entry using the provided hint.
 * No hint or no architecture in hint -> first entry. Debug1 warning if this is not precise match (there were multiple to choose from)
 * Hint -> always match, even if single architecture in file. Notice if match fails and return null.
 */
static const fat_arch_t *
-
match_entry(macho_file_t *mf, struct os_info *oi)
+
match_entry(macho_file_t *mf, enum pkg_arch arch_hint)
{
	const fat_arch_t *p = mf->arch;
-
	// we can change the content of oi->abi freely
-
	char *abisep = oi->abi;
-
	/*const char *osname = */strsep(&abisep, ":");
-
	/*const char *version_str = */ strsep(&abisep, ":");
-
	const char *archname = strsep(&abisep, ":");
-
	if (archname) {	
-
		const cpu_type_subtype_t cpu_hint = freebsd_machine_arch_to_cputype(archname);
+
	if (arch_hint != PKG_ARCH_UNKNOWN) {
+
		const cpu_type_subtype_t cpu_hint = pkg_arch_to_cputype(arch_hint);
		const fat_arch_t *p_end = p + mf->narch;
		while (p < p_end) {
-
			// do not match cpu_hint.type == CPU_TYPE_ANY which is used if the 
-
			// archname hint was not recognized
+
			// do not match cpu_hint.type == CPU_TYPE_ANY which is used if the
+
			// arch_hint was not recognized
			if (p->cpu.type == cpu_hint.type &&
			    p->cpu.type_is64 == cpu_hint.type_is64) {
				switch (cpu_hint.type) {
@@ -145,7 +140,7 @@ match_entry(macho_file_t *mf, struct os_info *oi)
						CPU_SUBTYPE_ARM_ALL ||
					    p->cpu.subtype_arm ==
						cpu_hint.subtype_arm) {
-
						return p;
+
							return p;
					}
					break;
				case CPU_TYPE_POWERPC:
@@ -155,7 +150,7 @@ match_entry(macho_file_t *mf, struct os_info *oi)
						CPU_SUBTYPE_POWERPC_ALL ||
					    p->cpu.subtype_ppc ==
						cpu_hint.subtype_ppc) {
-
						return p;
+
							return p;
					}
					break;
				case CPU_TYPE_X86:
@@ -165,7 +160,7 @@ match_entry(macho_file_t *mf, struct os_info *oi)
						CPU_SUBTYPE_X86_ALL ||
					    p->cpu.subtype_x86 ==
						cpu_hint.subtype_x86) {
-
						return p;
+
							return p;
					}
					break;
				default:
@@ -173,14 +168,16 @@ match_entry(macho_file_t *mf, struct os_info *oi)
				}
			}
			pkg_debug(1, "Looking for %s, did not match %s",
-
		    archname, cputype_to_freebsd_machine_arch(p->cpu));
+
			    pkg_arch_to_string(PKG_OS_DARWIN, arch_hint),
+
			    pkg_arch_to_string(PKG_OS_DARWIN, cputype_to_pkg_arch(p->cpu)));
			p++;
		}
		pkg_emit_notice("Scanned %d entr%s, found none matching selector %s",
-
			mf->narch, mf->narch > 1 ? "ies" : "y", archname);
-
		return 0;	
+
			mf->narch, mf->narch > 1 ? "ies" : "y",
+
			pkg_arch_to_string(PKG_OS_DARWIN, arch_hint));
+
		return 0;
	} else if (mf->narch > 1 ) {
-
		pkg_debug(1,"Found %d entries in universal binary, picking first",
+
		pkg_debug(1,"Found %"PRIu32" entries in universal binary, picking first",
			mf->narch);
	}
	return p;
@@ -191,15 +188,17 @@ match_entry(macho_file_t *mf, struct os_info *oi)
 * all members of os_info except altabi with values obtained by parsing the Mach-O
 * file passed with file descriptor.
 *
-
 * Third (architecture) component of oi->abi is used to determine the fat entry to be parsed
-
 * in a universal binary. when not set, the first entry is used.
+
 * The arch_hint is used to determine the fat entry to be parsed in a universal
+
 * binary. If arch_hint is PKG_ARCH_UNKNOWN, the first entry is used.
 *
 * Returns EPKG_OK if all went fine, EPKG_FATAL if anything went wrong.
 * Seeks the file descriptor to an arbitrary position.
 */
int
-
pkg_get_myarch_macho(int fd, struct os_info *oi)
+
pkg_macho_abi_from_fd(int fd, struct pkg_abi *abi, enum pkg_arch arch_hint)
{
+
	*abi = (struct pkg_abi){0};
+

	ssize_t x;
	pkg_error_t ret = EPKG_FATAL;

@@ -210,7 +209,7 @@ pkg_get_myarch_macho(int fd, struct os_info *oi)
		goto cleanup;
	}

-
	const fat_arch_t *p = match_entry(mf, oi);
+
	const fat_arch_t *p = match_entry(mf, arch_hint);

	if (!p) {
		goto cleanup;
@@ -277,33 +276,22 @@ pkg_get_myarch_macho(int fd, struct os_info *oi)
		macho_version_t darwin;
		map_platform_to_darwin(&darwin, bv->platform, bv->minos);

-
		oi->osversion = darwin.major * 100000 + darwin.minor * 1000 +
-
		    darwin.patch;
-
		oi->ostype = OS_MACOS;
-
		free(oi->name);
-
		oi->name = xstrdup("Darwin");
-
		free(oi->version);
-
		if (darwin.patch) {
-
			xasprintf(&oi->version, "%d.%d.%d", darwin.major,
-
			    darwin.minor, darwin.patch);
+
		abi->os = PKG_OS_DARWIN;
+

+
		abi->major = darwin.major;
+
		abi->minor = darwin.minor;
+
		abi->patch = darwin.patch;
+

+
		abi->arch = cputype_to_pkg_arch(mh.cpu);
+

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

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

cleanup:
@@ -312,6 +300,115 @@ cleanup:
	return ret;
}

+
static int
+
analyse_macho(int fd, struct pkg *pkg)
+
{
+
	ssize_t x;
+
	pkg_error_t ret = EPKG_END;
+

+
	macho_file_t *mf = 0;
+

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

+
	const fat_arch_t *p = match_entry(mf, ctx.abi.arch);
+

+
	if (!p) {
+
		goto cleanup;
+
	}
+

+
	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_RPATH:
+
		case LC_LOAD_DYLINKER:;
+
			char *dylinker = 0;
+
			if ((x = read_path(fd, swap, loadcmdsize,
+
					&dylinker)) < 0) {
+
				goto cleanup;
+
			}
+
			n += x;
+
			pkg_debug(3, "load_dylinker %d: %s\n", loadcmd, dylinker);
+
			free(dylinker);
+
			break;
+
		case LC_ID_DYLIB:   // provides
+
		case LC_LOAD_DYLIB: // requires...
+
		case LC_LOAD_WEAK_DYLIB:
+
		case LC_REEXPORT_DYLIB:
+
		case LC_LAZY_LOAD_DYLIB:
+
		case LC_LOAD_UPWARD_DYLIB:;
+
			dylib_t *dylib = 0;
+
			if ((x = read_dylib(fd, swap, loadcmdsize,
+
					&dylib)) < 0) {
+
				goto cleanup;
+
			}
+
			n += x;
+
			// while under Darwin full path references are recommended and ubiquitous,
+
			// we align with pkg native environment and use only the basename
+
			// this also strips off any @executable_path, @loader_path, @rpath components
+
			const char * basename = strrchr(dylib->path, '/');
+
			basename = basename ? basename + 1 : dylib->path;
+
			pkg_debug(3,
+
				"Adding dynamic library path: %s ts %"PRIu32" current(%"PRIuFAST16", %"PRIuFAST16", %"PRIuFAST16") compat(%"PRIuFAST16", %"PRIuFAST16", %"PRIuFAST16")\n",
+
				dylib->path, dylib->timestamp,
+
				dylib->current_version.major,
+
				dylib->current_version.minor,
+
				dylib->current_version.patch,
+
				dylib->compatibility_version.major,
+
				dylib->compatibility_version.minor,
+
				dylib->compatibility_version.patch);
+

+
			char *lib_with_version;
+
			if (dylib->current_version.patch) {
+
				xasprintf(&lib_with_version, "%s-%"PRIuFAST16".%"PRIuFAST16".%"PRIuFAST16, basename, dylib->current_version.major, dylib->current_version.minor, dylib->current_version.patch);
+
			} else {
+
				xasprintf(&lib_with_version, "%s-%"PRIuFAST16".%"PRIuFAST16, basename, dylib->current_version.major, dylib->current_version.minor);
+
			}
+
			if (LC_ID_DYLIB == loadcmd) {
+
				pkg_addshlib_provided(pkg, lib_with_version);
+
			} else {
+
				pkg_addshlib_required(pkg, lib_with_version);
+
			}
+
			free(lib_with_version);
+
			free(dylib);
+
			break;
+
		default:
+
			break;
+
		}
+
		const uint32_t fill = loadcmdsize - (n - n0);
+
		if (fill && -1 == (x = lseek(fd, fill, SEEK_CUR))) {
+
			goto cleanup;
+
		}
+
		n += fill;
+
		if (n > mh.sizeofcmds) {
+
			// we passed the frame boundary of the load commands
+
			pkg_emit_error("Mach-O structure misread.");
+
			errno = EINVAL;
+
			goto cleanup;
+
		}
+
	}
+

+
cleanup:
+
	free(mf);
+
	return ret;
+
}
+

int
pkg_analyse_init_macho(__unused const char *stage)
{
@@ -319,10 +416,24 @@ pkg_analyse_init_macho(__unused const char *stage)
}

int
-
pkg_analyse_macho(const bool developer_mode, __unused struct pkg *pkg, __unused const char *fpath)
+
pkg_analyse_macho(const bool developer_mode, struct pkg *pkg, const char *fpath)
{
	int ret = EPKG_OK;
-
	// int ret = analyse_macho(pkg, fpath);
+
	pkg_debug(1, "Analysing Mach-O %s", fpath);
+

+
	int fd = open(fpath, O_RDONLY);
+
	if (-1 == fd) {
+
		// pkg_emit_errno("open_pkg_analyse_macho", fpath);
+
		// ret = EPKG_FATAL;
+
		// Be consistent with analyse_elf and return no error if fpath cannot be opened
+
		return ret;
+
	} else {
+
		ret = analyse_macho(fd, pkg);
+
		if (-1 == close(fd)) {
+
			pkg_emit_errno("close_pkg_analyse_macho", fpath);
+
			ret = EPKG_FATAL;
+
		}
+
	}
	if (developer_mode) {
		if (ret != EPKG_OK && ret != EPKG_END) {
			return EPKG_WARN;
modified libpkg/pkg_add.c
@@ -1040,6 +1040,7 @@ backup_file_if_needed(struct pkg *p, struct pkg_file *f)
			free(sum);
			return;
		}
+
		free(sum);
	}

	snprintf(path, sizeof(path), "%s.pkgsave", f->path);
modified libpkg/pkg_config.c
@@ -50,6 +50,7 @@

#include "pkg.h"
#include "private/pkg.h"
+
#include "private/pkg_abi.h"
#include "private/event.h"
#include "private/fetch.h"
#include "pkg_repos.h"
@@ -89,17 +90,14 @@ struct pkg_ctx ctx = {
	.compression_level = -1,
	.compression_threads = -1,
	.defer_triggers = false,
-
	.oi = NULL,
};

struct config_entry {
	uint8_t type;
	const char *key;
	const char *def;
-
	const char *desc;
};

-
static struct os_info oi = { 0 };
static struct pkg_repo *repos = NULL;
ucl_object_t *config = NULL;

@@ -108,307 +106,246 @@ static struct config_entry c[] = {
		PKG_STRING,
		"PKG_DBDIR",
		"/var/db/pkg",
-
		"Where the package databases are stored",
	},
	{
		PKG_STRING,
		"PKG_CACHEDIR",
		"/var/cache/pkg",
-
		"Directory containing cache of downloaded packages",
	},
	{
		PKG_STRING,
		"PORTSDIR",
		"/usr/ports",
-
		"Location of the ports collection",
	},
	{
		PKG_STRING,
		"INDEXDIR",
		NULL,		/* Default to PORTSDIR unless defined */
-
		"Location of the ports INDEX",
	},
	{
		PKG_STRING,
		"INDEXFILE",
		INDEXFILE,
-
		"Filename of the ports INDEX",
	},
	{
		PKG_BOOL,
		"HANDLE_RC_SCRIPTS",
		"NO",
-
		"Automatically handle restarting services",
	},
	{
		PKG_BOOL,
		"DEFAULT_ALWAYS_YES",
		"NO",
-
		"Default to 'yes' for all pkg(8) questions",
	},
	{
		PKG_BOOL,
		"ASSUME_ALWAYS_YES",
		"NO",
-
		"Answer 'yes' to all pkg(8) questions",
	},
	{
		PKG_ARRAY,
		"REPOS_DIR",
		"/etc/pkg/,"PREFIX"/etc/pkg/repos/",
-
		"Location of the repository configuration files"
	},
	{
		PKG_STRING,
		"PLIST_KEYWORDS_DIR",
		NULL,
-
		"Directory containing definitions of plist keywords",
	},
	{
		PKG_BOOL,
		"SYSLOG",
		"YES",
-
		"Log pkg(8) operations via syslog(3)",
-
	},
-
	{
-
		PKG_STRING,
-
		"ABI",
-
		oi.abi,
-
		"Override the automatically detected ABI",
-
	},
-
	{
-
		PKG_STRING,
-
		"ALTABI",
-
		oi.altabi,
-
		"Override the automatically detected old-form ABI",
	},
	{
		PKG_BOOL,
		"DEVELOPER_MODE",
		"NO",
-
		"Add extra strict, pedantic warnings as an aid to package maintainers",
	},
	{
		PKG_STRING,
		"VULNXML_SITE",
		DEFAULT_VULNXML_URL,
-
		"URL giving location of the vulnxml database",
	},
	{
		PKG_INT,
		"FETCH_RETRY",
		"3",
-
		"How many times to retry fetching files",
	},
	{
		PKG_STRING,
		"PKG_PLUGINS_DIR",
		PREFIX"/lib/pkg/",
-
		"Directory which pkg(8) will load plugins from",
	},
	{
		PKG_BOOL,
		"PKG_ENABLE_PLUGINS",
		"YES",
-
		"Activate plugin support",
	},
	{
		PKG_ARRAY,
		"PLUGINS",
		NULL,
-
		"List of plugins that pkg(8) should load",
	},
	{
		PKG_BOOL,
		"DEBUG_SCRIPTS",
		"NO",
-
		"Run shell scripts in verbose mode to facilitate debugging",
	},
	{
		PKG_STRING,
		"PLUGINS_CONF_DIR",
		PREFIX"/etc/pkg/",
-
		"Directory containing plugin configuration data",
	},
	{
		PKG_BOOL,
		"PERMISSIVE",
		"NO",
-
		"Permit package installation despite presence of conflicting packages",
	},
	{
		PKG_BOOL,
		"REPO_AUTOUPDATE",
		"YES",
-
		"Automatically update repository catalogues prior to package updates",
	},
	{
		PKG_STRING,
		"NAMESERVER",
		NULL,
-
		"Use this nameserver when looking up addresses",
	},
	{
		PKG_STRING,
		"HTTP_USER_AGENT",
		"pkg/"PKGVERSION,
-
		"HTTP User-Agent",
	},
	{
		PKG_STRING,
		"EVENT_PIPE",
		NULL,
-
		"Send all events to the specified fifo or Unix socket",
	},
	{
		PKG_INT,
		"FETCH_TIMEOUT",
		"30",
-
		"Number of seconds before fetch(3) times out",
	},
	{
		PKG_BOOL,
		"UNSET_TIMESTAMP",
		"NO",
-
		"Do not include timestamps in the package",
	},
	{
		PKG_STRING,
		"SSH_RESTRICT_DIR",
		NULL,
-
		"Directory the ssh subsystem will be restricted to",
	},
	{
		PKG_OBJECT,
		"PKG_ENV",
		NULL,
-
		"Environment variables pkg will use",
	},
	{
		PKG_STRING,
		"PKG_SSH_ARGS",
		NULL,
-
		"Extras arguments to pass to ssh(1)",
	},
	{
		PKG_INT,
		"DEBUG_LEVEL",
		"0",
-
		"Level for debug messages",
	},
	{
		PKG_OBJECT,
		"ALIAS",
		NULL,
-
		"Command aliases",
	},
	{
		PKG_STRING,
		"CUDF_SOLVER",
		NULL,
-
		"Experimental: tells pkg to use an external CUDF solver",
	},
	{
		PKG_STRING,
		"SAT_SOLVER",
		NULL,
-
		"Experimental: tells pkg to use an external SAT solver",
	},
	{
		PKG_BOOL,
		"RUN_SCRIPTS",
		"YES",
-
		"Run post/pre actions scripts",
	},
	{
		PKG_BOOL,
		"CASE_SENSITIVE_MATCH",
		"NO",
-
		"Match package names case sensitively",
	},
	{
		PKG_INT,
		"LOCK_WAIT",
		"1",
-
		"Wait time to regain a lock if it is not available"
	},
	{
		PKG_INT,
		"LOCK_RETRIES",
		"5",
-
		"Retries performed to obtain a lock"
	},
	{
		PKG_BOOL,
		"SQLITE_PROFILE",
		"NO",
-
		"Profile sqlite queries"
	},
	{
		PKG_INT,
		"WORKERS_COUNT",
		"0",
-
		"How many workers are used for pkg-repo (hw.ncpu if 0)"
	},
	{
		PKG_BOOL,
		"READ_LOCK",
		"NO",
-
		"Use read locking for query database"
	},
	{
		PKG_INT,
		"IP_VERSION",
		"0",
-
		"Restrict network access to IPv4 or IPv6 only"
	},
	{
		PKG_BOOL,
		"AUTOMERGE",
		"YES",
-
		"Automatically merge configuration files"
	},
	{
		PKG_STRING,
		"MERGETOOL",
		NULL,
-
		"Path to a program to be used for solving conflicts during the 3-way merging"
	},
	{
		PKG_STRING,
		"VERSION_SOURCE",
		NULL,
-
		"Version source for pkg-version (I, P, R), default is auto detect"
	},
	{
		PKG_BOOL,
		"CONSERVATIVE_UPGRADE",
		"YES",
-
		"Prefer repos with higher priority during upgrade"
	},
	{
		PKG_BOOL,
		"PKG_CREATE_VERBOSE",
		"NO",
-
		"Enable verbose mode for 'pkg create'",
	},
	{
		PKG_BOOL,
		"AUTOCLEAN",
		"NO",
-
		"Always cleanup the cache directory after install/upgrade",
	},
	{
		PKG_STRING,
		"DOT_FILE",
		NULL,
-
		"Save SAT problem to the specified dot file"
	},
	{
		PKG_OBJECT,
		"REPOSITORIES",
		NULL,
-
		"Repository config in pkg.conf"
	},
	{
		PKG_ARRAY,
@@ -416,126 +353,106 @@ static struct config_entry c[] = {
		"pkg+http,pkg+https,https,http,file,ssh,tcp",
	},
	{
-
		PKG_BOOL,
-
		"ALLOW_BASE_SHLIBS",
-
		"NO",
-
		"Enable base libraries analysis",
-
	},
-
	{
		PKG_INT,
		"WARN_SIZE_LIMIT",
		"1048576", /* 1 meg */
-
		"Ask user when performing changes for more than this limit"
	},
	{
		PKG_STRING,
		"METALOG",
		NULL,
-
		"Write out the METALOG to the specified file",
	},
#ifdef __FreeBSD__
	{
-
		PKG_INT,
-
		"OSVERSION",
-
		oi.str_osversion,
-
		"FreeBSD OS version",
-
	},
-
	{
		PKG_BOOL,
		"IGNORE_OSVERSION",
		"NO",
-
		"Ignore FreeBSD OS version check",
	},
#endif
	{
		PKG_BOOL,
		"BACKUP_LIBRARIES",
		"NO",
-
		"Backup old versions of libraries during an upgrade",
	},
	{
		PKG_STRING,
		"BACKUP_LIBRARY_PATH",
		PREFIX "/lib/compat/pkg",
-
		"Path where pkg will backup libraries",
	},
	{
		PKG_STRING,
		"PKG_TRIGGERS_DIR",
		PREFIX "/share/pkg/triggers",
-
		"Path where the triggers should be installed",
	},
	{
		PKG_BOOL,
		"PKG_TRIGGERS_ENABLE",
		"YES",
-
		"Disable triggers",
	},
	{
		PKG_ARRAY,
		"AUDIT_IGNORE_GLOB",
		NULL,
-
		"List of glob to ignore while autiditing for vulnerabilities",
	},
	{
		PKG_ARRAY,
		"AUDIT_IGNORE_REGEX",
		NULL,
-
		"List of regex to ignore while autiditing for vulnerabilities",
	},
	{
		PKG_STRING,
		"COMPRESSION_FORMAT",
		NULL,
-
		"Set the default compression format for packages creating",
	},
	{
		PKG_INT,
		"COMPRESSION_LEVEL",
		"-1",
-
		"Set the default compression level",
	},
	{
		PKG_BOOL,
		"ARCHIVE_SYMLINK",
		"FALSE",
-
		"Create a symlink to legacy extension for backward compatibility",
	},
	{
		PKG_BOOL,
		"REPO_ACCEPT_LEGACY_PKG",
		"FALSE",
-
		"Accept legacy package extensions when creating the repository",
	},
	{
		PKG_ARRAY,
		"FILES_IGNORE_GLOB",
		NULL,
-
		"patterns of files to not extract from the package",
	},
	{
		PKG_ARRAY,
		"FILES_IGNORE_REGEX",
		NULL,
-
		"patterns of files to not extract from the package",
+
	},
+
	{
+
		PKG_ARRAY,
+
		"SHLIB_REQUIRE_IGNORE_GLOB",
+
		NULL,
+
	},
+
	{
+
		PKG_ARRAY,
+
		"SHLIB_REQUIRE_IGNORE_REGEX",
+
		NULL,
	},
	{
		PKG_ARRAY,
		"PKG_DEBUG_FLAGS",
		"all",
-
		"debug flags to activate",
	},
	{
		PKG_INT,
		"COMPRESSION_THREADS",
		"-1",
-
		"Set the default number of threads used for compression",
	},
	{
		PKG_BOOL,
		"PKG_REINSTALL_ON_OPTIONS_CHANGE",
		"TRUE",
-
		"Decide if packages gets reinstalled when local options does not match remote one",
	}
};

@@ -869,40 +786,79 @@ walk_repo_obj(const ucl_object_t *obj, const char *file, pkg_init_flags flags)
	}
}

+
struct config_parser_vars {
+
	char *abi;
+
	char *altabi;
+
	char *osversion;
+
	char *release;
+
	char *version_major;
+
	char *version_minor;
+
};
+

+
/* Register parser variables based on ctx.abi.
+
 * The returned struct must be free'd with config_parser_variables_free()
+
 * after parsing is complete. */
+
static struct config_parser_vars *
+
config_parser_vars_register(struct ucl_parser *p)
+
{
+
	struct config_parser_vars *vars = xcalloc(1, sizeof(struct config_parser_vars));
+

+
	vars->abi = pkg_abi_to_string(&ctx.abi);
+
	ucl_parser_register_variable(p, "ABI", vars->abi);
+

+
	char altabi_buffer[BUFSIZ];
+
	pkg_arch_to_legacy(vars->abi, altabi_buffer, sizeof(altabi_buffer));
+
	vars->altabi = xstrdup(altabi_buffer);
+
	ucl_parser_register_variable(p, "ALTABI", vars->altabi);
+

+
	if (ctx.abi.os == PKG_OS_FREEBSD) {
+
		xasprintf(&vars->osversion, "%d",
+
		    pkg_abi_get_freebsd_osversion(&ctx.abi));
+
		ucl_parser_register_variable(p, "OSVERSION", vars->osversion);
+
	}
+
	ucl_parser_register_variable(p, "OSNAME", pkg_os_to_string(ctx.abi.os));
+

+
	if (pkg_abi_string_only_major_version(ctx.abi.os)) {
+
		xasprintf(&vars->release, "%d", ctx.abi.major);
+
	} else {
+
		xasprintf(&vars->release, "%d.%d", ctx.abi.major, ctx.abi.minor);
+
	}
+
	ucl_parser_register_variable(p, "RELEASE", vars->release);
+

+
	xasprintf(&vars->version_major, "%d", ctx.abi.major);
+
	ucl_parser_register_variable(p, "VERSION_MAJOR", vars->version_major);
+

+
	xasprintf(&vars->version_minor, "%d", ctx.abi.minor);
+
	ucl_parser_register_variable(p, "VERSION_MINOR", vars->version_minor);
+

+
	ucl_parser_register_variable(p, "ARCH",
+
	    pkg_arch_to_string(ctx.abi.os, ctx.abi.arch));
+

+
	return vars;
+
}
+

+
static void
+
config_parser_vars_free(struct config_parser_vars *vars)
+
{
+
	free(vars->abi);
+
	free(vars->altabi);
+
	free(vars->osversion);
+
	free(vars->release);
+
	free(vars->version_major);
+
	free(vars->version_minor);
+
	free(vars);
+
}
static void
load_repo_file(int dfd, const char *repodir, const char *repofile,
    pkg_init_flags flags)
{
	struct ucl_parser *p;
	ucl_object_t *obj = NULL;
-
	const char *myarch = NULL;
-
	const char *myarch_legacy = NULL;
	int fd;

	p = ucl_parser_new(0);

-
	myarch = pkg_object_string(pkg_config_get("ABI"));
-
	ucl_parser_register_variable (p, "ABI", myarch);
-

-
	myarch_legacy = pkg_object_string(pkg_config_get("ALTABI"));
-
	ucl_parser_register_variable (p, "ALTABI", myarch_legacy);
-
	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_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.arch != NULL) {
-
		ucl_parser_register_variable(p, "ARCH", oi.arch);
-
	}
+
	struct config_parser_vars *parser_vars = config_parser_vars_register(p);

	errno = 0;
	obj = NULL;
@@ -911,28 +867,28 @@ load_repo_file(int dfd, const char *repodir, const char *repofile,
	fd = openat(dfd, repofile, O_RDONLY);
	if (fd == -1) {
		pkg_errno("Unable to open '%s/%s'", repodir, repofile);
-
		return;
+
		goto out_parser_vars;
	}
	if (!ucl_parser_add_fd(p, fd)) {
		pkg_emit_error("Error parsing: '%s/%s': %s", repodir,
		    repofile, ucl_parser_get_error(p));
-
		ucl_parser_free(p);
-
		close(fd);
-
		return;
+
		goto out_fd;
	}
-
	close(fd);

	obj = ucl_parser_get_object(p);
	if (obj == NULL) {
-
		ucl_parser_free(p);
-
		return;
+
		goto out_fd;
	}

-
	ucl_parser_free(p);
	if (obj->type == UCL_OBJECT)
		walk_repo_obj(obj, repofile, flags);

	ucl_object_unref(obj);
+
out_fd:
+
	close(fd);
+
out_parser_vars:
+
	ucl_parser_free(p);
+
	config_parser_vars_free(parser_vars);
}

static int
@@ -994,23 +950,10 @@ bool
pkg_compiled_for_same_os_major(void)
{
#ifdef OSMAJOR
-
	const char	*myabi;
-
	int		 osmajor;
-

	if (getenv("IGNORE_OSMAJOR") != NULL)
		return (true);

-
	myabi = pkg_object_string(pkg_config_get("ABI"));
-
	myabi = strchr(myabi,':');
-
	if (myabi == NULL) {
-
		pkg_emit_error("Invalid ABI");
-
		return (false);
-
	}
-
	myabi++;
-

-
	osmajor = (int) strtol(myabi, NULL, 10);
-

-
	return (osmajor == OSMAJOR);
+
	return (ctx.abi.major == OSMAJOR);
#else
	return (true);		/* Can't tell, so assume yes  */
#endif
@@ -1073,6 +1016,63 @@ config_validate_debug_flags(const ucl_object_t *o)
	return (ret);
}

+
static bool
+
config_init_abi(struct pkg_abi *abi)
+
{
+
	if (getenv("ALTABI") != NULL) {
+
		pkg_emit_notice("Setting ALTABI manually is no longer supported, "
+
		    "set ABI and OSVERSION or ABI_FILE instead.");
+
	}
+

+
	const char *env_abi_file = getenv("ABI_FILE");
+
	const char *env_abi_string = getenv("ABI");
+
	const char *env_osversion_string = getenv("OSVERSION");
+

+
	if (env_abi_file != NULL && env_abi_string != NULL) {
+
		pkg_emit_notice("Both ABI_FILE and ABI are set, ABI_FILE overrides ABI");
+
	}
+

+
	if (env_abi_file != NULL && env_osversion_string != NULL) {
+
		pkg_emit_notice("Both ABI_FILE and OSVERSION are set, ABI_FILE overrides OSVERSION");
+
	}
+

+
	if (env_abi_string != NULL) {
+
		if (!pkg_abi_from_string(abi, env_abi_string)) {
+
			return (false);
+
		}
+

+
		if (abi->os == PKG_OS_FREEBSD) {
+
			if (env_osversion_string == NULL) {
+
				pkg_emit_error("Setting ABI requires setting OSVERSION as well");
+
				return (false);
+
			}
+

+
			const char *errstr = NULL;
+
			int env_osversion = strtonum(env_osversion_string, 1, INT_MAX, &errstr);
+
			if (errstr != NULL) {
+
				pkg_emit_error("Invalid OSVERSION %s, %s", env_osversion_string, errstr);
+
				return (false);
+
			}
+

+
			pkg_abi_set_freebsd_osversion(abi, env_osversion);
+
		} else {
+
			if (env_osversion_string != NULL) {
+
				pkg_emit_notice("OSVERSION is ignored on %s",
+
				    pkg_os_to_string(abi->os));
+
			}
+
		}
+
	} else if (env_osversion_string != NULL) {
+
		pkg_emit_error("Setting OSVERSION requires setting ABI as well");
+
		return (EPKG_FATAL);
+
	} else {
+
		if (pkg_abi_from_file(abi) != EPKG_OK) {
+
			return (false);
+
		}
+
	}
+

+
	return (true);
+
}
+

int
pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
{
@@ -1096,36 +1096,27 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
	char *tmp = NULL;
	size_t ukeylen;
	int err = EPKG_OK;
-
	const char *envabi;

	k = NULL;
	o = NULL;
	if (ctx.rootfd == -1 && (ctx.rootfd = open("/", O_DIRECTORY|O_RDONLY|O_CLOEXEC)) < 0) {
		pkg_emit_error("Impossible to open /");
-
		/* Note: Not goto out since oi.arch hasn't been initialized yet. */
		return (EPKG_FATAL);
	}

-
	memset(&oi, 0, sizeof(oi));
-
	envabi = getenv("ABI");
-
	if (envabi == NULL) {
-
		pkg_get_myarch_with_legacy(&oi);
-
	} else {
-
		strlcpy(oi.abi, envabi, sizeof(oi.abi));
-
		pkg_arch_to_legacy(oi.abi, oi.altabi, sizeof(oi.abi));
-
	}
-
	ctx.oi = &oi;
	if (parsed != false) {
		pkg_emit_error("pkg_init() must only be called once");
-
		err = EPKG_FATAL;
-
		goto out;
+
		return (EPKG_FATAL);
+
	}
+

+
	if (!config_init_abi(&ctx.abi)) {
+
		return (EPKG_FATAL);
	}

	if (((flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4) &&
	    ((flags & PKG_INIT_FLAG_USE_IPV6) == PKG_INIT_FLAG_USE_IPV6)) {
		pkg_emit_error("Invalid flags for pkg_init()");
-
		err = EPKG_FATAL;
-
		goto out;
+
		return (EPKG_FATAL);
	}
	if ((flags & PKG_INIT_FLAG_USE_IPV4) == PKG_INIT_FLAG_USE_IPV4)
		ctx.ip = IPV4;
@@ -1222,25 +1213,8 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
	}

	p = ucl_parser_new(0);
-
	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);
-
	}
-
	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_minor != NULL) {
-
		ucl_parser_register_variable(p, "VERSION_MINOR", oi.version_minor);
-
	}
-
	if (oi.arch != NULL) {
-
		ucl_parser_register_variable(p, "ARCH", oi.arch);
-
	}
+

+
	struct config_parser_vars *parser_vars = config_parser_vars_register(p);

	errno = 0;
	obj = NULL;
@@ -1273,6 +1247,16 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
			continue;
		}

+
		if (strncasecmp(ukey->buf, "ABI", ukeylen) == 0 ||
+
		    strncasecmp(ukey->buf, "ALTABI", ukeylen) == 0 ||
+
		    strncasecmp(ukey->buf, "OSVERSION", ukeylen) == 0) {
+
			pkg_emit_error("Setting %s in pkg.conf is no longer supported. "
+
			    "Set ABI_FILE or ABI and OSVERSION with -o on the "
+
			    "command line or in the environment to configure ABI", ukey->buf);
+
			fatal_errors = true;
+
			continue;
+
		}
+

		/* ignore unknown keys */
		if (object == NULL)
			continue;
@@ -1404,11 +1388,28 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
	ucl_object_unref(obj);
	ucl_parser_free(p);

-
	if (pkg_object_string(pkg_config_get("ABI")) == NULL ||
-
	    STREQ(pkg_object_string(pkg_config_get("ABI")), "unknown")) {
-
		pkg_emit_error("Unable to determine ABI");
-
		err = EPKG_FATAL;
-
		goto out;
+
	{
+
		/* Even though we no longer support setting ABI/ALTABI/OSVERSION
+
		   in the pkg.conf config file, we still need to expose these
+
		   values through e.g. `pkg config ABI`. */
+
		char *abi_string = pkg_abi_to_string(&ctx.abi);
+
		char altabi_string[BUFSIZ];
+
		pkg_arch_to_legacy(abi_string, altabi_string, sizeof(altabi_string));
+

+
		ucl_object_insert_key(config,
+
		    ucl_object_fromstring(abi_string), "ABI", 0, true);
+
		ucl_object_insert_key(config,
+
		    ucl_object_fromstring(altabi_string), "ALTABI", 0, true);
+

+
		free(abi_string);
+

+
		if (ctx.abi.os == PKG_OS_FREEBSD) {
+
			char *osversion;
+
			xasprintf(&osversion, "%d", pkg_abi_get_freebsd_osversion(&ctx.abi));
+
			ucl_object_insert_key(config,
+
			    ucl_object_fromstring(osversion), "OSVERSION", 0, true);
+
			free(osversion);
+
		}
	}

	dbg(1, "pkg initialized");
@@ -1501,11 +1502,8 @@ pkg_ini(const char *path, const char *reposdir, pkg_init_flags flags)
	}

out:
-
	free(oi.arch);
-
	free(oi.name);
-
	free(oi.version);
-
	free(oi.version_major);
-
	free(oi.version_minor);
+
	config_parser_vars_free(parser_vars);
+

	return err;

}
@@ -1577,6 +1575,7 @@ pkg_repo_free(struct pkg_repo *r)
	if (r->fetcher != NULL && r->fetcher->cleanup != NULL)
		r->fetcher->cleanup(r);
	tll_free_and_free(r->env, pkg_kv_free);
+
	free(r->dbpath);
	free(r);
}

modified libpkg/pkg_create.c
@@ -40,6 +40,8 @@
#include "pkg.h"
#include "private/event.h"
#include "private/pkg.h"
+
#include "private/pkg_abi.h"
+
#include "xmalloc.h"

#define TICK	100

@@ -563,14 +565,15 @@ static void
fixup_abi(struct pkg *pkg, const char *rootdir, bool testing)
{
	bool defaultarch = false;
-
	const char *arch;

	/* if no arch autodetermine it */
	if (pkg->abi == NULL) {
-
		if (ctx.oi->ostype == OS_FREEBSD) {
-
			pkg_kv_add(&pkg->annotations, "FreeBSD_version", xstrdup(ctx.oi->str_osversion), "annotation");
+
		if (ctx.abi.os == PKG_OS_FREEBSD) {
+
			char *str_osversion;
+
			xasprintf(&str_osversion, "%d", pkg_abi_get_freebsd_osversion(&ctx.abi));
+
			pkg_kv_add(&pkg->annotations, "FreeBSD_version", str_osversion, "annotation");
		}
-
		pkg->abi = xstrdup(ctx.oi->abi);
+
		pkg->abi = pkg_abi_to_string(&ctx.abi);
		defaultarch = true;
	}

modified libpkg/pkg_elf.c
@@ -23,7 +23,6 @@
#include <sys/stat.h>

#include <assert.h>
-
#include <ctype.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <gelf.h>
@@ -43,167 +42,24 @@

#include "pkg.h"
#include "private/pkg.h"
+
#include "private/pkg_abi.h"
#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

-

-
/* FFR: when we support installing a 32bit package on a 64bit host */
-
#define _PATH_ELF32_HINTS       "/var/run/ld-elf32.so.hints"
+
#define NT_VERSION	1
+
#define NT_ARCH		2
+
#define NT_GNU_ABI_TAG	1

#ifndef roundup2
#define roundup2(x, y)	(((x)+((y)-1))&(~((y)-1))) /* if y is powers of two */
#endif

-
static const char * elf_corres_to_string(const struct _elf_corres* m, int e);
-
static int elf_string_to_corres(const struct _elf_corres* m, const char *s);
-

-
static int
-
filter_system_shlibs(const char *name, char *path, size_t pathlen)
-
{
-
	const char *shlib_path;
-

-
	shlib_path = shlib_list_find_by_name(name);
-
	if (shlib_path == NULL) {
-
		/* dynamic linker could not resolve */
-
		return (EPKG_FATAL);
-
	}
-

-
	if (pkg_object_bool(pkg_config_get("ALLOW_BASE_SHLIBS"))) {
-
		if (strstr(shlib_path, "/lib32/") != NULL)
-
			return (EPKG_END);
-
	} else {
-
		/* match /lib, /lib32, /usr/lib and /usr/lib32 */
-
		if (strncmp(shlib_path, "/lib", 4) == 0 ||
-
		    strncmp(shlib_path, "/usr/lib", 8) == 0)
-
			return (EPKG_END); /* ignore libs from base */
-
	}
-

-
	if (path != NULL)
-
		strncpy(path, shlib_path, pathlen);
-

-
	return (EPKG_OK);
-
}
-

-
/* ARGSUSED */
-
static int
-
add_shlibs_to_pkg(struct pkg *pkg, const char *fpath, const char *name,
-
    bool is_shlib)
-
{
-
	struct pkg_file *file = NULL;
-
	const char *filepath;
-
	size_t fsz, nsz;
-

-
	switch(filter_system_shlibs(name, NULL, 0)) {
-
	case EPKG_OK:		/* A non-system library */
-
		pkg_addshlib_required(pkg, name);
-
		return (EPKG_OK);
-
	case EPKG_END:		/* A system library */
-
		return (EPKG_OK);
-
	default:
-
		/* Ignore link resolution errors if we're analysing a
-
		   shared library. */
-
		if (is_shlib)
-
			return (EPKG_OK);
-

-
		while (pkg_files(pkg, &file) == EPKG_OK) {
-
			filepath = file->path;
-
			fsz = strlen(filepath);
-
			nsz = strlen(name);
-

-
			if (fsz >= nsz &&
-
			    STREQ(&filepath[fsz - nsz], name)) {
-
				pkg_addshlib_required(pkg, name);
-
				return (EPKG_OK);
-
			}
-
		}
-

-
		pkg_emit_notice("(%s-%s) %s - required shared library %s not "
-
		    "found", pkg->name, pkg->version, fpath, name);
-

-
		return (EPKG_FATAL);
-
	}
-
}
-

-
static bool
-
shlib_valid_abi(const char *fpath, GElf_Ehdr *hdr)
-
{
-
	int semicolon;
-
	const char *p, *t;
-
	char arch[64], wordsize[64];
-
	int wclass;
-
	const char *shlib_arch;
-

-
	/*
-
	 * ALTABI string is in format:
-
	 * <osname>:<osversion>:<arch>:<wordsize>[.other]
-
	 * We need here arch and wordsize only
-
	 */
-
	arch[0] = '\0';
-
	wordsize[0] = '\0';
-
	p = pkg_object_string(pkg_config_get("ABI"));
-
	for(semicolon = 0; semicolon < 3 && p != NULL; semicolon ++, p ++) {
-
		p = strchr(p, ':');
-
		if (p != NULL) {
-
			switch(semicolon) {
-
			case 1:
-
				/* We have arch here */
-
				t = strchr(p + 1, ':');
-
				/* Abi line is likely invalid */
-
				if (t == NULL)
-
					return (true);
-
				strlcpy(arch, p + 1, MIN((long)sizeof(arch), t - p));
-
				break;
-
			case 2:
-
				t = strchr(p + 1, ':');
-
				if (t == NULL)
-
					strlcpy(wordsize, p + 1, sizeof(wordsize));
-
				else
-
					strlcpy(wordsize, p + 1, MIN((long)sizeof(wordsize), t - p));
-
				break;
-
			}
-
		}
-
	}
-
	/* Invalid ABI line */
-
	if (arch[0] == '\0' || wordsize[0] == '\0')
-
		return (true);
-

-
	shlib_arch = elf_corres_to_string(mach_corres, (int)hdr->e_machine);
-
	if (shlib_arch == NULL)
-
		return (true);
-

-
	wclass = elf_string_to_corres(wordsize_corres, wordsize);
-
	if (wclass == -1)
-
		return (true);
-

+
static enum pkg_arch elf_parse_arch(Elf *elf, GElf_Ehdr *ehdr);

-
	/*
-
	 * Compare wordsize first as the arch for amd64/i386 is an abmiguous
-
	 * 'x86'
-
	 */
-
	if ((int)hdr->e_ident[EI_CLASS] != wclass) {
-
		pkg_debug(1, "not valid elf class for shlib: %s: %s",
-
		    elf_corres_to_string(wordsize_corres,
-
		    (int)hdr->e_ident[EI_CLASS]),
-
		    fpath);
-
		return (false);
-
	}
-

-
	if (!STREQ(shlib_arch, arch)) {
-
		pkg_debug(1, "not valid abi for shlib: %s: %s", shlib_arch,
-
		    fpath);
-
		return (false);
-
	}
-

-
	return (true);
-
}
-

-
#ifdef __FreeBSD__
static bool
is_old_freebsd_armheader(const GElf_Ehdr *e)
{
@@ -222,7 +78,6 @@ is_old_freebsd_armheader(const GElf_Ehdr *e)
	}
	return (false);
}
-
#endif

#ifndef HAVE_ELF_NOTE
typedef Elf32_Nhdr Elf_Note;
@@ -245,10 +100,6 @@ analyse_elf(struct pkg *pkg, const char *fpath)
	size_t numdyn = 0;
	size_t sh_link = 0;
	size_t dynidx;
-
	const char *shlib;
-
	char *rpath = NULL;
-

-
	bool is_shlib = false;

	int fd;

@@ -343,37 +194,22 @@ analyse_elf(struct pkg *pkg, const char *fpath)
		goto cleanup; /* not a dynamically linked elf: no results */
	}

-
	if (!shlib_valid_abi(fpath, &elfhdr)) {
+
	if (elf_parse_arch(e, &elfhdr) != ctx.abi.arch) {
		ret = EPKG_END;
		goto cleanup; /* Invalid ABI */
	}

-
#ifdef __FreeBSD__
-
	if (elfhdr.e_ident[EI_OSABI] != ELFOSABI_FREEBSD &&
+
	if (ctx.abi.os == PKG_OS_FREEBSD && elfhdr.e_ident[EI_OSABI] != ELFOSABI_FREEBSD &&
	    !is_old_freebsd_armheader(&elfhdr)) {
		ret = EPKG_END;
		goto cleanup;
	}
-
#endif

	if ((data = elf_getdata(dynamic, NULL)) == NULL) {
		ret = EPKG_END; /* Some error occurred, ignore this file */
		goto cleanup;
	}

-
	/* First, scan through the data from the .dynamic section to
-
	   find any RPATH or RUNPATH settings.  These are colon
-
	   separated paths to prepend to the ld.so search paths from
-
	   the ELF hints file.  These always seem to come right after
-
	   the NEEDED shared library entries.
-

-
	   NEEDED entries should resolve to a filename for installed
-
	   executables, but need not resolve for installed shared
-
	   libraries -- additional info from the apps that link
-
	   against them would be required.  Shared libraries are
-
	   distinguished by a DT_SONAME tag */
-

-
	rpath_list_init();
	for (dynidx = 0; dynidx < numdyn; dynidx++) {
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
			ret = EPKG_FATAL;
@@ -382,48 +218,19 @@ analyse_elf(struct pkg *pkg, const char *fpath)
			goto cleanup;
		}

-
		if (dyn->d_tag == DT_SONAME) {
-
			is_shlib = true;
-

-
			/* The file being scanned is a shared library
-
			   *provided* by the package. Record this if
-
			   appropriate */
-
			shlib = elf_strptr(e, sh_link, dyn->d_un.d_val);
-
			if (shlib != NULL && *shlib != '\0')
-
				pkg_addshlib_provided(pkg, shlib);
+
		const char *shlib = elf_strptr(e, sh_link, dyn->d_un.d_val);
+
		if (shlib == NULL || *shlib == '\0') {
+
			continue;
		}

-
		if ((dyn->d_tag == DT_RPATH || dyn->d_tag == DT_RUNPATH) &&
-
		    rpath == NULL)
-
			rpath = elf_strptr(e, sh_link, dyn->d_un.d_val);
-
	}
-
	if (rpath != NULL) {
-
		char *p = xstrdup(fpath);
-
		shlib_list_from_rpath(rpath, get_dirname(p));
-
		free(p);
-
	}
-

-
	/* Now find all of the NEEDED shared libraries. */
-

-
	for (dynidx = 0; dynidx < numdyn; dynidx++) {
-
		if ((dyn = gelf_getdyn(data, dynidx, &dyn_mem)) == NULL) {
-
			ret = EPKG_FATAL;
-
			pkg_emit_error("getdyn() failed for %s: %s", fpath,
-
			    elf_errmsg(-1));
-
			goto cleanup;
+
		if (dyn->d_tag == DT_SONAME) {
+
			pkg_addshlib_provided(pkg, shlib);
+
		} else if (dyn->d_tag == DT_NEEDED) {
+
			pkg_addshlib_required(pkg, shlib);
		}
-

-
		if (dyn->d_tag != DT_NEEDED)
-
			continue;
-

-
		shlib = elf_strptr(e, sh_link, dyn->d_un.d_val);
-

-
		add_shlibs_to_pkg(pkg, fpath, shlib, is_shlib);
	}

cleanup:
-
	rpath_list_free();
-

	if (e != NULL)
		elf_end(e);
	close(fd);
@@ -450,31 +257,7 @@ analyse_fpath(struct pkg *pkg, const char *fpath)
	return (EPKG_OK);
}

-
static const char *
-
elf_corres_to_string(const struct _elf_corres* m, int e)
-
{
-
	int i = 0;
-

-
	for (i = 0; m[i].string != NULL; i++)
-
		if (m[i].elf_nb == e)
-
			return (m[i].string);
-

-
	return ("unknown");
-
}
-

-
static int
-
elf_string_to_corres(const struct _elf_corres* m, const char *s)
-
{
-
	int i = 0;
-

-
	for (i = 0; m[i].string != NULL; i++)
-
		if (STREQ(m[i].string, s))
-
			return (m[i].elf_nb);
-

-
	return (-1);
-
}
-

-
static const char *
+
static enum pkg_arch
aeabi_parse_arm_attributes(void *data, size_t length)
{
	uint32_t sect_len;
@@ -487,19 +270,19 @@ aeabi_parse_arm_attributes(void *data, size_t length)
} while (0)

	if (length == 0 || *section != 'A')
-
		return (NULL);
+
		return (PKG_ARCH_UNKNOWN);
	MOVE(1);

	/* Read the section length */
	if (length < sizeof(sect_len))
-
		return (NULL);
+
		return (PKG_ARCH_UNKNOWN);
	memcpy(&sect_len, section, sizeof(sect_len));

	/*
	 * The section length should be no longer than the section it is within
	 */
	if (sect_len > length)
-
		return (NULL);
+
		return (PKG_ARCH_UNKNOWN);

	MOVE(sizeof(sect_len));

@@ -510,7 +293,7 @@ aeabi_parse_arm_attributes(void *data, size_t length)
		MOVE(1);
	}
	if (length == 0)
-
		return (NULL);
+
		return (PKG_ARCH_UNKNOWN);
	MOVE(1);

	while (length != 0) {
@@ -520,21 +303,21 @@ aeabi_parse_arm_attributes(void *data, size_t length)
		case 1: /* Tag_File */
			MOVE(1);
			if (length < sizeof(tag_length))
-
				return (NULL);
+
				return (PKG_ARCH_UNKNOWN);
			memcpy(&tag_length, section, sizeof(tag_length));
			break;
		case 2: /* Tag_Section */
		case 3: /* Tag_Symbol */
		default:
-
			return (NULL);
+
			return (PKG_ARCH_UNKNOWN);
		}
		/* At least space for the tag and size */
		if (tag_length <= 5)
-
			return (NULL);
+
			return (PKG_ARCH_UNKNOWN);
		tag_length--;
		/* Check the tag fits */
		if (tag_length > length)
-
			return (NULL);
+
			return (PKG_ARCH_UNKNOWN);

#define	MOVE_TAG(len) do {		\
	assert(tag_length >= (len));	\
@@ -568,21 +351,21 @@ aeabi_parse_arm_attributes(void *data, size_t length)
				 * more than one byte.
				 */
				if (val & (1 << 7))
-
					return (NULL);
+
					return (PKG_ARCH_UNKNOWN);

				/* We have an ARMv4 or ARMv5 */
				if (val <= 5)
-
					return ("arm");
+
					return (PKG_ARCH_UNKNOWN);
				else if (val == 6) /* We have an ARMv6 */
-
					return ("armv6");
+
					return (PKG_ARCH_ARMV6);
				else /* We have an ARMv7+ */
-
					return ("armv7");
+
					return (PKG_ARCH_ARMV7);
			} else if (tag == 4 || tag == 5 || tag == 32 ||
			    tag == 65 || tag == 67) {
				while (*section != '\0' && length != 0)
					MOVE_TAG(1);
				if (tag_length == 0)
-
					return (NULL);
+
					return (PKG_ARCH_UNKNOWN);
				/* Skip the last byte */
				MOVE_TAG(1);
			} else if ((tag >= 7 && tag <= 31) || tag == 34 ||
@@ -592,41 +375,34 @@ aeabi_parse_arm_attributes(void *data, size_t length)
				while (*section & (1 << 7) && length != 0)
					MOVE_TAG(1);
				if (tag_length == 0)
-
					return (NULL);
+
					return (PKG_ARCH_UNKNOWN);
				/* Skip the last byte */
				MOVE_TAG(1);
			} else
-
				return (NULL);
+
				return (PKG_ARCH_UNKNOWN);
#undef MOVE_TAG
		}

		break;
	}
-
	return (NULL);
+
	return (PKG_ARCH_UNKNOWN);
#undef MOVE
}

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

		size_t shstrndx;
@@ -649,38 +425,43 @@ elf_parse_arch(os_type_t ostype, Elf *elf, GElf_Ehdr *ehdr)
		}
		break;
	case EM_PPC:
-
		return ("powerpc");
+
		return (PKG_ARCH_POWERPC);
	case EM_PPC64:
		switch (ehdr->e_ident[EI_DATA]) {
		case ELFDATA2MSB:
-
			return ("powerpc64");
+
			return (PKG_ARCH_POWERPC64);
		case ELFDATA2LSB:
-
			return ("powerpc64le");
+
			return (PKG_ARCH_POWERPC64LE);
		}
		break;
	case EM_RISCV:
		switch (ehdr->e_ident[EI_CLASS]) {
		case ELFCLASS32:
-
			return ("riscv32");
+
			return (PKG_ARCH_RISCV32);
		case ELFCLASS64:
-
			return ("riscv64");
+
			return (PKG_ARCH_RISCV64);
		}
		break;
	}

-
	return (NULL);
+
	return (PKG_ARCH_UNKNOWN);
}

+
/* Returns true if the OS and version were successfully parsed */
static bool
-
elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct os_info *oi)
+
elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct pkg_abi *abi)
{
	Elf_Note note;
	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";
+
	int note_ost[6] = {
+
		PKG_OS_LINUX,
+
		PKG_OS_UNKNOWN, /* GNU Hurd */
+
		PKG_OS_UNKNOWN, /* Solaris */
+
		PKG_OS_FREEBSD,
+
		PKG_OS_NETBSD,
+
		PKG_OS_UNKNOWN, /* Syllable */
+
	};
	uint32_t version = 0;
	int version_style = 1;

@@ -709,7 +490,6 @@ elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct os_info *oi)
	if ((uintptr_t)src >= ((uintptr_t)data->d_buf + data->d_size)) {
		return (false);
	}
-
	free(oi->name);
	if (version_style == 2) {
		/*
		 * NT_GNU_ABI_TAG
@@ -733,24 +513,20 @@ elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct os_info *oi)
			}
		}
		if (gnu_abi_tag[0] < 6) {
-
			oi->name = xstrdup((*pnote_os)[gnu_abi_tag[0]]);
-
			oi->ostype = note_ost[gnu_abi_tag[0]];
+
			abi->os= note_ost[gnu_abi_tag[0]];
		} else {
-
			oi->name = xstrdup(invalid_osname);
-
			oi->ostype = OS_UNKNOWN;
+
			abi->os = PKG_OS_UNKNOWN;
		}
	} else {
		if (note.n_namesz == 0) {
-
			oi->name = xstrdup(invalid_osname);
-
			oi->ostype = OS_UNKNOWN;
+
			abi->os = PKG_OS_UNKNOWN;
		} else {
-
			oi->name = xstrdup(src);
			if (STREQ(src, "FreeBSD"))
-
				oi->ostype = OS_FREEBSD;
+
				abi->os = PKG_OS_FREEBSD;
			else if (STREQ(src, "DragonFly"))
-
				oi->ostype = OS_DRAGONFLY;
+
				abi->os = PKG_OS_DRAGONFLY;
			else if (STREQ(src, "NetBSD"))
-
				oi->ostype = OS_NETBSD;
+
				abi->os = PKG_OS_NETBSD;
		}
		src += roundup2(note.n_namesz, 4);
		if (elfhdr->e_ident[EI_DATA] == ELFDATA2MSB)
@@ -759,28 +535,31 @@ elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct os_info *oi)
			version = le32dec(src);
	}

-
	free(oi->version);
	if (version_style == 2) {
-
		if (oi->ostype == OS_LINUX) {
-
			xasprintf(&oi->version, "%d.%d", gnu_abi_tag[1],
-
			    gnu_abi_tag[2]);
+
		if (abi->os == PKG_OS_LINUX) {
+
			abi->major = gnu_abi_tag[1];
+
			abi->minor = gnu_abi_tag[2];
		} else {
-
			xasprintf(&oi->version, "%d.%d.%d", gnu_abi_tag[1],
-
			    gnu_abi_tag[2], gnu_abi_tag[3]);
+
			abi->major = gnu_abi_tag[1];
+
			abi->minor = gnu_abi_tag[2];
+
			abi->patch = gnu_abi_tag[3];
		}
	} else {
-
		if (oi->osversion == 0) {
-
			oi->osversion = version;
-
			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);
+
		switch (abi->os) {
+
		case PKG_OS_UNKNOWN:
+
			break;
+
		case PKG_OS_FREEBSD:
+
			pkg_abi_set_freebsd_osversion(abi, version);
+
			break;
+
		case PKG_OS_DRAGONFLY:
+
			abi->major = version / 100000;
+
			abi->minor = (((version / 100 % 1000)+1)/2)*2;
+
			break;
+
		case PKG_OS_NETBSD:
+
			abi->major = (version + 1000000) / 100000000;
+
			break;
+
		default:
+
			assert(0);
		}
	}

@@ -788,16 +567,16 @@ elf_note_analyse(Elf_Data *data, GElf_Ehdr *elfhdr, struct os_info *oi)
}

int
-
pkg_get_myarch_elfparse(int fd, struct os_info *oi)
+
pkg_elf_abi_from_fd(int fd, struct pkg_abi *abi)
{
+
	*abi = (struct pkg_abi){0};
+

	Elf *elf = NULL;
	GElf_Ehdr elfhdr;
	GElf_Shdr shdr;
	Elf_Data *data;
	Elf_Scn *scn = NULL;
	int ret = EPKG_OK;
-
	char *dest = oi->abi;
-
	size_t sz = sizeof(oi->abi);

	if (elf_version(EV_CURRENT) == EV_NONE) {
		pkg_emit_error("ELF library initialization failed: %s",
@@ -830,25 +609,22 @@ pkg_get_myarch_elfparse(int fd, struct os_info *oi)
			 * loop over all the note section and override what
			 * should be overridden if any
			 */
-
			elf_note_analyse(data, &elfhdr, oi);
+
			elf_note_analyse(data, &elfhdr, abi);
		}
	}

-
	if (oi->name == NULL) {
+
	if (abi->os == PKG_OS_UNKNOWN) {
		ret = EPKG_FATAL;
-
		pkg_emit_error("failed to get the note section");
+
		pkg_emit_error("failed to determine the operating system");
		goto cleanup;
	}

-
	const char *arch = elf_parse_arch(oi->ostype, elf, &elfhdr);
-
	if (arch == NULL) {
+
	abi->arch = elf_parse_arch(elf, &elfhdr);
+
	if (abi->arch == PKG_ARCH_UNKNOWN) {
		ret = EPKG_FATAL;
		pkg_emit_error("failed to determine the architecture");
		goto cleanup;
	}
-
	oi->arch = xstrdup(arch);
-

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

cleanup:
	if (elf != NULL)
@@ -856,33 +632,24 @@ cleanup:
	return (ret);
}

-
int pkg_analyse_init_elf(const char* stage) {
+
int pkg_analyse_init_elf(__unused const char* stage) {
	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);
-
	}
-

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

-
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);
+
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;
		}
-
		return ret;
+
		analyse_fpath(pkg, fpath);
+
	}
+
	return ret;
}

int pkg_analyse_close_elf() {
-
	shlib_list_free();
	return EPKG_OK;
}
modified libpkg/pkg_jobs.c
@@ -219,6 +219,7 @@ pkg_jobs_free(struct pkg_jobs *j)
		ucl_object_unref(j->triggers.schema);
	pkghash_destroy(j->orphaned);
	pkghash_destroy(j->notorphaned);
+
	pkghash_destroy(j->system_shlibs);
	free(j);
}

@@ -928,6 +929,7 @@ pkg_jobs_find_upgrade(struct pkg_jobs *j, const char *pattern, match_t m)
		} else if (rc == EPKG_OK)
			found = true;

+
		pkg_free(p);
		p = NULL;
	}

@@ -1914,8 +1916,21 @@ pkg_jobs_check_and_solve_conflicts(struct pkg_jobs *j, bool *found_conflicts)
int
pkg_jobs_solve(struct pkg_jobs *j)
{
-
	int ret = pkg_jobs_run_solver(j);
+
	int ret;
+

+
	assert(j->system_shlibs == NULL);
+

+
	/* If /usr/bin/uname is in the pkg database, we are targeting
+
	 * a pkgbase system and should rely on the pkgbase packages to
+
	 * provide system shlibs. */
+
	if (!pkgdb_file_exists(j->db, "/usr/bin/uname")) {
+
		ret = scan_system_shlibs(&j->system_shlibs, ctx.pkg_rootdir);
+
		if (ret != EPKG_OK) {
+
			return (ret);
+
		}
+
	}

+
	ret = pkg_jobs_run_solver(j);
	if (ret != EPKG_OK)
		return (ret);

deleted libpkg/pkg_macho.c
@@ -1,394 +0,0 @@
-
/*-
-
 * Copyright (c) 2014 Landon Fuller <landon@landonf.org>
-
 * 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 <sys/types.h>
-
#include <sys/sysctl.h>
-
#include <sys/utsname.h>
-

-
#include <mach/machine.h>
-
#include <mach-o/arch.h>
-
#include <mach-o/loader.h>
-

-
#include <ctype.h>
-
#include <limits.h>
-

-
#include <libmachista.h>
-
#include <bsd_compat.h>
-

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

-
static const char * const system_dylib_prefixes[] = {
-
	"/System/",
-
	"/usr/lib",
-
	"/lib",
-
	NULL
-
 };
-

-
static int
-
analyse_macho(struct pkg *pkg, const char *fpath,
-
	      cpu_type_t cpu_type, macho_handle_t *macho_handle,
-
	      int (action)(void *, struct pkg *, const char *, const char *, bool),
-
	      void *actdata)
-
{
-
	const macho_t *macho = NULL;
-
	struct stat sb;
-
	int mret;
-

-
	/* We're only interested in the generic CPU type */
-
	cpu_type = cpu_type & ~CPU_ARCH_MASK;
-

-
	if (lstat(fpath, &sb) != 0)
-
		pkg_emit_errno("fstat() failed for", fpath);
-

-
	/* ignore empty files and non regular files */
-
	if (sb.st_size == 0 || !S_ISREG(sb.st_mode))
-
		return EPKG_END; /* Empty file or sym-link: no results */
-

-

-
	/* Try to parse the file */
-
	if ((mret = macho_parse_file(macho_handle, fpath, &macho)) != MACHO_SUCCESS) {
-
		if (mret != MACHO_EMAGIC && mret != MACHO_ERANGE) {
-
			pkg_emit_error("macho_parse_file() for %s failed: %s", fpath, macho_strerror(mret));
-
			return EPKG_FATAL; /* Empty file or sym-link: no results */
-
		}
-

-
		/* Not a Mach-O file; no results */
-
		return EPKG_END;
-
	}
-

-
	for (macho_arch_t *march = macho->mt_archs; march != NULL; march = march->next) {
-
		const NXArchInfo *ai;
-
		bool is_shlib = false;
-

-
		/* Determine the architecture name */
-
		ai = NXGetArchInfoFromCpuType(march->mat_cputype, march->mat_cpusubtype);
-
		if (ai == NULL) {
-
			pkg_emit_notice("Could not determine architecture type for cpu %d subtype %d", march->mat_cputype, march->mat_cpusubtype);
-
			continue;
-
		}
-

-
		/* Register non-relative libraries as provided. */
-
		// MACTODO: How to handle @rpath/@loader_path/etc?
-
		if (march->mat_install_name != NULL && march->mat_install_name[0] != '/') {
-
			// XXX MACTODO: To get things working, we're shoving library metadata into the library name;
-
			// these should instead be added as supported attributes of package shared library declarations.
-
			char *libname;
-
			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) {
-
			/* Skip everything except for non-weak dylib references */
-
			if (cmd->mlt_type != LC_LOAD_DYLIB)
-
				continue;
-

-
			/* Prevent cyclic self-references. A valid dylib shouldn't include a
-
			 * LC_LOAD_DYLIB referencing itself, but there's nothing that would
-
			 * actually prevent it */
-
			if (STREQ(cmd->mlt_install_name, march->mat_install_name))
-
				continue;
-

-
			/* Skip non-resolvable library paths. */
-
			switch (cmd->mlt_install_name[0]) {
-
				case '/':
-
					break;
-
				case '@':
-
					// MACTODO: How to handle @rpath/@loader_path/etc?
-
					continue;
-
				default:
-
					continue;
-
			}
-

-
			// XXX MACTODO: To get things working, we're shoving library metadata into the library name;
-
			// these should instead be added as supported attributes of package shared library declarations.
-
			// XXX: This duplicates (and must be kept identical to) the libname construction above.
-
			char *libname;
-
			xasprintf(&libname, "%s.%s", cmd->mlt_install_name, ai->name);
-

-
			action(actdata, pkg, fpath, libname, is_shlib);
-
		}
-
		}
-
	}
-

-
	return EPKG_OK;
-
}
-

-
static int
-
add_dylibs_to_pkg(__unused void *actdata, struct pkg *pkg, const char *fpath,
-
		  const char *name, bool is_shlib)
-
{
-
	/* Skip references to system libraries */
-
	for (size_t i = 0; i < NELEM(system_dylib_prefixes); i++) {
-
		const char *prefix = system_dylib_prefixes[i];
-
		if (strncmp(name, prefix, strlen(prefix)) == 0)
-
			return EPKG_OK;
-
	}
-

-
	/* Record the library requirement. */
-
	pkg_addshlib_required(pkg, name);
-

-
	return EPKG_OK;
-
}
-

-
/**
-
 * Extract the major release number from an XNU kernel
-
 * version returned by uname().
-
 *
-
 * @param src A major.minor.revision version string, e.g., as returned from uname(3).
-
 * @param release On success, the parsed major version.
-
 */
-
static int
-
parse_major_release(const char *src, long long *release)
-
{
-
	int ret = EPKG_OK;
-
	char *parsed = NULL;
-
	const char *errstr;
-
	char *eos;
-

-
	parsed = xstrdup(src);
-
	eos = strchr(parsed, '.');
-
	if (eos == NULL) {
-
		pkg_emit_error("failed to parse major release version from %s", src);
-
		ret = EPKG_FATAL;
-
		goto cleanup;
-
	}
-

-
	*eos = '\0';
-
	*release = strtonum(parsed, 1, LONG_LONG_MAX, &errstr);
-
	if (errstr != NULL) {
-
		pkg_emit_error("failed to parse major release version from %s: %s", src, errstr);
-
		ret = EPKG_FATAL;
-
		goto cleanup;
-
	}
-

-
cleanup:
-
	free(parsed);
-
	return ret;
-
}
-

-
/**
-
 * Fetch the host's CPU type.
-
 *
-
 * @param result On success, the fetched CPU type.
-
 */
-
static int
-
host_cpu_type(cpu_type_t *result)
-
{
-
	size_t len;
-
	int resint;
-

-
	/* Fetch CPU type */
-
	len = sizeof(resint);
-
	if (sysctlbyname("hw.cputype", &resint, &len, NULL, 0) != 0) {
-
		pkg_emit_errno("sysctlbyname", "hw.cputype");
-
		return EPKG_FATAL;
-
	}
-

-
	*result = resint;
-
	return EPKG_OK;
-
}
-

-
/**
-
 * Fetch the OS name and major version.
-
 *
-
 * @param osname On success, the OS name (e.g. Darwin).
-
 * @param sz The maximum number of bytes to be written to osname.
-
 * @param major_version On success, the major version of the host.
-
 */
-
static int
-
host_os_info(char *osname, size_t sz, long long *major_version)
-
{
-
	struct utsname ut;
-

-
	/* Fetch OS info from uname() */
-
	if (uname(&ut) != 0) {
-
		pkg_emit_errno("uname", "&ut");
-
		return EPKG_FATAL;
-
	}
-

-
	/* Provide the OS name to the caller. */
-
	if (sz < strlen(ut.sysname) + 1) {
-
		pkg_emit_error("provided buffer is too small for os name: %d",
-
				(int)strlen(ut.sysname));
-
		return EPKG_FATAL;
-
	}
-

-
	strlcpy(osname, ut.sysname, sz);
-

-
	/* Parse the major release version */
-
	return parse_major_release(ut.release, major_version);
-
}
-

-
int
-
pkg_analyse_files(struct pkgdb *db, struct pkg *pkg, const char *stage)
-
{
-
	macho_handle_t *macho_handle = NULL;
-
	struct pkg_file *file = NULL;
-
	bool failures = false;
-
	cpu_type_t cpu_type;
-
	char *fpath = NULL;
-
	int ret = EPKG_OK;
-

-
	/* Determine our system's CPU type */
-
	if ((ret = host_cpu_type(&cpu_type)) != EPKG_OK)
-
		return (EPKG_FATAL);
-

-
	/* Create our mach-o handle */
-
	macho_handle = macho_create_handle();
-
	if (macho_handle == NULL) {
-
		pkg_emit_error("macho_create_handle() failed");
-
		return (EPKG_FATAL);
-
	}
-

-
	/* Evaluate all package files */
-
	while ((ret = pkg_files(pkg, &file)) == EPKG_OK) {
-
		if (stage != NULL) {
-
			free(fpath);
-
			xasprintf(&fpath, "%s/%s", stage, file->path);
-
		} else {
-
			if ((fpath = file->path) == NULL) {
-
				pkg_emit_error("pkg_analyse_files(): path allocation failed");
-
				macho_destroy_handle(macho_handle);
-
				return (EPKG_FATAL);
-
			}
-
		}
-

-
		ret = analyse_macho(pkg, fpath, cpu_type, macho_handle, add_dylibs_to_pkg, db);
-
		if (ret != EPKG_OK && ret != EPKG_END) {
-
			failures = true;
-
		}
-
	}
-

-
	macho_destroy_handle(macho_handle);
-

-
	if (stage != NULL)
-
		free(fpath);
-

-
	return (failures ? EPKG_FATAL : ret);
-
}
-

-
int
-
pkg_arch_to_legacy(const char *arch, char *dest, size_t sz)
-
{
-
	int i = 0;
-
	const NXArchInfo *ai;
-
	const char *arch_name;
-
	bool is64;
-

-
	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++] = ':';
-

-
	/* Map the architecture name to its CPU type */
-
	ai = NXGetArchInfoFromName(arch + i);
-
	if (ai == NULL) {
-
		pkg_emit_error("could not find architecture info for %s", arch + i);
-
		return EPKG_FATAL;
-
	}
-

-
	/* Fetch the base architecture name */
-
	arch_name = macho_get_arch_name(ai->cputype & ~CPU_ARCH_ABI64);
-
	if (arch_name == NULL) {
-
		pkg_emit_error("macho_get_arch_name() failed for %x", ai->cputype);
-
		return EPKG_FATAL;
-
	}
-

-
	/* Determine word size */
-
	is64 = (ai->cputype & CPU_ARCH_ABI64) != 0;
-

-
	/* Emit the result */
-
	snprintf(dest + i, sz - (arch + i - dest), "%s:%s", arch_name, is64 ? "64" : "32");
-
	return EPKG_OK;
-
}
-

-
int
-
pkg_get_myarch_legacy(char *dest, size_t sz)
-
{
-
	char current[sz];
-
	int ret;
-

-
	if ((ret = pkg_get_myarch(current, sizeof(current), NULL)) != EPKG_OK)
-
		return ret;
-

-
	return pkg_arch_to_legacy(current, dest, sz);
-
}
-

-
int
-
pkg_get_myarch(char *dest, size_t sz, struct os_info *__unused u)
-
{
-
	cpu_type_t cpu_type;
-
	const char *cpu_name = NULL;
-
	long long major_version;
-
	char os_name[BUFSIZ];
-
	char *spec = NULL;
-
	int ret = EPKG_OK;
-

-
	/* Fetch basic OS info */
-
	if ((ret = host_os_info(os_name, sizeof(os_name), &major_version)) != EPKG_OK)
-
	        return ret;
-

-
	/* Fetch host CPU type */
-
	if ((ret = host_cpu_type(&cpu_type)) != EPKG_OK)
-
	        return ret;
-

-
	/* Fetch the name for the base CPU family */
-
	cpu_name = macho_get_arch_name(cpu_type);
-

-
	/* Produce the result */
-
	xasprintf(&spec, "%s:%lld:%s", os_name, major_version, cpu_name);
-
	strlcpy(dest, spec, sz);
-

-
	free(spec);
-
	return ret;
-
}
modified libpkg/pkg_manifest.c
@@ -799,6 +799,7 @@ pkg_parse_manifest_ucl(struct pkg *pkg, ucl_object_t *obj)
		if (!(sk->valid_type & TYPE_SHIFT(ucl_object_type(cur)))) {
			pkg_emit_error("Bad format in manifest for key:"
				" %s", key);
+
			UCL_FREE (sizeof (*it), it);
			return (EPKG_FATAL);
		}
	}
modified libpkg/pkg_solve.c
@@ -40,6 +40,7 @@
#include <tllist.h>

#include "pkg.h"
+
#include "pkghash.h"
#include "private/event.h"
#include "private/pkg.h"
#include "private/pkgdb.h"
@@ -671,6 +672,10 @@ pkg_solve_process_universe_variable(struct pkg_solve_problem *problem,

		/* Shlibs */
		tll_foreach(pkg->shlibs_required, s) {
+
			if (pkghash_get(j->system_shlibs, s->item) != NULL) {
+
				/* The shlib is provided by the system */
+
				continue;
+
			}
			if (pkg_solve_add_require_rule(problem, cur_var,
			    s->item, cur_var->assumed_reponame) != EPKG_OK) {
				continue;
modified libpkg/pkgdb_iterator.c
@@ -851,24 +851,31 @@ populate_pkg(sqlite3_stmt *stmt, struct pkg *pkg) {

			switch (column->type) {
			case PKG_ATTR_ABI:
+
				free(pkg->abi);
				pkg->abi = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_CKSUM:
+
				free(pkg->sum);
				pkg->sum = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_COMMENT:
+
				free(pkg->comment);
				pkg->comment = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_REPONAME:
+
				free(pkg->reponame);
				pkg->reponame = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_DESC:
+
				free(pkg->desc);
				pkg->desc = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_MAINTAINER:
+
				free(pkg->maintainer);
				pkg->maintainer = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_DIGEST:
+
				free(pkg->digest);
				pkg->digest = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_MESSAGE:
@@ -887,33 +894,43 @@ populate_pkg(sqlite3_stmt *stmt, struct pkg *pkg) {
				}
				break;
			case PKG_ATTR_NAME:
+
				free(pkg->name);
				pkg->name = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_OLD_VERSION:
+
				free(pkg->old_version);
				pkg->old_version = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_ORIGIN:
+
				free(pkg->origin);
				pkg->origin = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_PREFIX:
+
				free(pkg->prefix);
				pkg->prefix = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_REPOPATH:
+
				free(pkg->repopath);
				pkg->repopath = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_REPOURL:
+
				free(pkg->repourl);
				pkg->repourl = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_UNIQUEID:
+
				free(pkg->uid);
				pkg->uid = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_VERSION:
+
				free(pkg->version);
				pkg->version = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_WWW:
+
				free(pkg->www);
				pkg->www = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			case PKG_ATTR_DEP_FORMULA:
+
				free(pkg->dep_formula);
				pkg->dep_formula = xstrdup(sqlite3_column_text(stmt, icol));
				break;
			default:
modified libpkg/pkgvec.h
@@ -25,7 +25,7 @@

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

#define pkgvec_clear_and_free(v, free_func) \
	do {                                          \
-
		for (size_t _i; _i < (v)->len ; _i++) { \
+
		for (size_t _i=0; _i < (v)->len ; _i++) { \
			free_func((v)->d[_i]);          \
			(v)->d[_i] = NULL;   \
		}                                     \
modified libpkg/private/binfmt.h
@@ -8,13 +8,19 @@

#include "private/pkg.h"

-
int pkg_get_myarch_elfparse(int fd, struct os_info *oi);
+
/* In the future this will be extended to include
+
   e.g. PKG_PROVIDE_SHLIB_COMPAT_32 */
+
enum pkg_provide_flags {
+
	PKG_PROVIDE_NONE = 0,
+
	PKG_PROVIDE_SHLIB_NATIVE = 1 << 0,
+
};
+

+
int pkg_elf_abi_from_fd(int fd, struct pkg_abi *abi);
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_macho_abi_from_fd(int fd, struct pkg_abi *abi, enum pkg_arch arch_hint);
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();
-

modified libpkg/private/binfmt_macho.h
@@ -294,6 +294,10 @@ 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);
+
ssize_t read_path(const int fd, const bool swap, const uint32_t loadcmdsize, 
+
    char **dest);
+
ssize_t read_dylib(const int fd, const bool swap, const uint32_t loadcmdsize,
+
    dylib_t **dest);

#define READ(f, var)                              \
	if ((x = read_##f(fd, swap, &var)) < 0) { \
deleted libpkg/private/elf_tables.h
@@ -1,59 +0,0 @@
-
/*-
-
 * 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:
-
 * 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 ELF_TABLES_H_
-
#define ELF_TABLES_H_
-
struct _elf_corres {
-
	int elf_nb;
-
	const char *string;
-
};
-

-
static const struct _elf_corres mach_corres[] = {
-
	{ EM_386, "i386" },
-
	{ EM_X86_64, "x86_64" },
-
	{ EM_AARCH64, "aarch64" },
-
	{ EM_ARM, "arm" },
-
	{ EM_MIPS, "mips" },
-
	{ EM_PPC, "powerpc" },
-
	{ EM_PPC64, "powerpc" },
-
	{ EM_RISCV, "riscv" },
-
	{ EM_SPARCV9, "sparc64" },
-
	{ EM_IA_64, "ia64" },
-
	{ -1, NULL },
-
};
-

-
static const struct _elf_corres wordsize_corres[] = {
-
	{ ELFCLASS32, "32" },
-
	{ ELFCLASS64, "64" },
-
	{ -1, NULL},
-
};
-

-
#define NT_VERSION	1
-
#define NT_ARCH	2
-
#define NT_GNU_ABI_TAG	1
-

-

-

-
#endif /* ELF_TABLES_H_ */
modified libpkg/private/fetch.h
@@ -41,7 +41,6 @@ struct fetcher {
	int (*fetch)(struct pkg_repo *repo, int dest, struct fetch_item *);
};

-
int fetch_open(struct pkg_repo *, struct fetch_item *);
int ssh_open(struct pkg_repo *, struct fetch_item *);
int file_open(struct pkg_repo *, struct fetch_item *);
void fh_close(struct pkg_repo *);
deleted libpkg/private/ldconfig.h
@@ -1,81 +0,0 @@
-
/*-
-
 * Copyright (c) 1998 John D. Polstra
-
 * 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 AUTHOR 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 AUTHOR 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.
-
 *
-
 * $FreeBSD: stable/8/sbin/ldconfig/ldconfig.h 92882 2002-03-21 13:14:21Z imp $
-
 */
-

-
#ifndef LDCONFIG_H
-
#define LDCONFIG_H 1
-

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

-
#include <sys/cdefs.h>
-

-
#ifdef HAVE_ELF_HINTS_H
-
#include <elf-hints.h>
-
#else
-
/*
-
 * Hints file produced by ldconfig.
-
 */
-
struct elfhints_hdr
-
{
-
	u_int32_t magic; /* Magic number */
-
	u_int32_t version; /* File version (1) */
-
	u_int32_t strtab; /* Offset of string table in file */
-
	u_int32_t strsize; /* Size of string table */
-
	u_int32_t dirlist; /* Offset of directory list in
-
	 string table */
-
	u_int32_t dirlistlen; /* strlen(dirlist) */
-
	u_int32_t spare[26]; /* Room for expansion */
-
};
-

-
#define ELFHINTS_MAGIC  0x746e6845
-

-
# ifdef __NetBSD__
-
#define _PATH_ELF_HINTS "/var/run/ld.so.hints"
-
# else
-
#define _PATH_ELF_HINTS "/var/run/ld-elf.so.hints"
-
# endif
-
#endif
-

-
extern int	insecure;	/* -i flag, needed here for elfhints.c */
-

-
__BEGIN_DECLS
-
void		shlib_list_init(void);
-
void		rpath_list_init(void);
-
const char     *shlib_list_find_by_name(const char *);
-
void		shlib_list_free(void);
-
void		rpath_list_free(void);
-
int		shlib_list_from_elf_hints(const char *);
-
int		shlib_list_from_rpath(const char *, const char *);
-
void		shlib_list_from_stage(const char *);
-

-
void		list_elf_hints(const char *);
-
void		update_elf_hints(const char *, int, char **, int);
-
__END_DECLS
-

-
#endif
modified libpkg/private/pkg.h
@@ -23,6 +23,7 @@
#include <ucl.h>

#include "xmalloc.h"
+
#include "private/pkg_abi.h"
#include "private/utils.h"
#include "private/fetch.h"
#include "pkghash.h"
@@ -106,18 +107,6 @@ 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;
};
@@ -136,19 +125,6 @@ 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;
@@ -175,7 +151,7 @@ struct pkg_ctx {
	bool defer_triggers;
	bool repo_accept_legacy_pkg;
	ip_version_t ip;
-
	struct os_info *oi;
+
	struct pkg_abi abi;
	bool ischrooted;
};

@@ -637,8 +613,6 @@ typedef enum {
	PKG_RC_STOP
} pkg_rc_attr;

-
int pkg_get_myarch_with_legacy(struct os_info *);
-

/**
 * Remove and unregister the package.
 * @param pkg An installed package to delete
@@ -873,4 +847,6 @@ int pkg_parse_manifest_ucl(struct pkg *pkg, ucl_object_t *o);
int pkg_get_reposdirfd(void);
char * expand_plist_variables(const char *in, kvlist_t *vars);

+
int scan_system_shlibs(pkghash **system_shlibs, const char *rootdir);
+

#endif
added libpkg/private/pkg_abi.h
@@ -0,0 +1,123 @@
+
/*-
+
 * Copyright (c) 2024 The FreeBSD Foundation
+
 *
+
 * This software was developed by Isaac Freund <ifreund@freebsdfoundation.org>
+
 * under sponsorship from the FreeBSD Foundation.
+
 *
+
 * SPDX-License-Identifier: BSD-2-Clause
+
 */
+

+
#pragma once
+

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

+
/*
+
 * This enum is not intended to contain all operating systems in the universe.
+
 * It is intended to contain only the operating systems for which pkg supports
+
 * ABI detection.
+
 * Adding a new OS to this enum should also add test cases for detection of the
+
 * OS through parsing ELF/Mach-O/etc.
+
 */
+
enum pkg_os {
+
	PKG_OS_UNKNOWN = 0,
+
	PKG_OS_FREEBSD,
+
	PKG_OS_NETBSD,
+
	PKG_OS_DRAGONFLY,
+
	PKG_OS_LINUX,
+
	PKG_OS_DARWIN,
+
};
+

+
/*
+
 * Return the canonical string for the given operating system.
+
 */
+
const char *pkg_os_to_string(enum pkg_os os);
+

+
/*
+
 * This enum is not intended to contain all architectures in the universe.
+
 * It is intended to contain only the architectures for which pkg supports
+
 * ABI detection.
+
 * Adding a new architecture to this enum should also test cases for detection
+
 * of the architecture through parsing ELF/Mach-O/etc.
+
 */
+
enum pkg_arch {
+
	PKG_ARCH_UNKNOWN = 0,
+
	PKG_ARCH_I386,
+
	PKG_ARCH_AMD64,
+
	PKG_ARCH_ARMV6,
+
	PKG_ARCH_ARMV7,
+
	PKG_ARCH_AARCH64,
+
	PKG_ARCH_POWERPC,
+
	PKG_ARCH_POWERPC64,
+
	PKG_ARCH_POWERPC64LE,
+
	PKG_ARCH_RISCV32,
+
	PKG_ARCH_RISCV64,
+
};
+

+
/*
+
 * Return the canonical string for the given architecture.
+
 *
+
 * The string used for the arch depends on the OS in some cases.
+
 * For example, "amd64" is used for FreeBSD while "x86_64" is used for Linux
+
 * operating systems though both refer to the same physical architecture.
+
 */
+
const char *pkg_arch_to_string(enum pkg_os os, enum pkg_arch arch);
+

+
struct pkg_abi {
+
	enum pkg_os os;
+

+
	int major;
+
	int minor;
+
	int patch;
+

+
	enum pkg_arch arch;
+
};
+

+
/*
+
 * Attempts to determine the ABI by parsing /usr/bin/uname or /bin/sh.
+
 * If ABI_FILE is set in the environment, that file path is parsed instead.
+
 */
+
int pkg_abi_from_file(struct pkg_abi *abi);
+

+
/*
+
 * Serializes the ABI to a string with format OS:VERSION:ARCH.
+
 *
+
 * The caller is responsible for freeing the returned string.
+
 */
+
char *pkg_abi_to_string(const struct pkg_abi *abi);
+

+
/*
+
 * Validate and parse a string into a pkg_abi struct.
+
 * Returns false if the string is not a complete and valid ABI string
+
 * in the format OS:VERSION:ARCH
+
 */
+
bool pkg_abi_from_string(struct pkg_abi *abi, const char *string);
+

+
/*
+
 * Return true if the canonical ABI string format for the given OS uses only
+
 * the major version rather than both the the major and minor version.
+
 */
+
bool pkg_abi_string_only_major_version(enum pkg_os os);
+

+
/*
+
 * Set the version fields of the provided pkg_abi struct from the
+
 * FreeBSD-specific osversion value.
+
 *
+
 * Asserts that abi->os == PKG_OS_FREEBSD.
+
 *
+
 * See __FreeBSD_version in /usr/include/sys/param.h for a description
+
 * of the format.
+
 */
+
void pkg_abi_set_freebsd_osversion(struct pkg_abi *abi, int osversion);
+

+
/*
+
 * Returns the FreeBSD-specific osversion value derived from the
+
 * major/minor/patch fields of the provided pkg_abi struct.
+
 *
+
 * Asserts that abi->os == PKG_OS_FREEBSD.
+
 *
+
 * See __FreeBSD_version in /usr/include/sys/param.h for a description
+
 * of the format.
+
 */
+
int pkg_abi_get_freebsd_osversion(struct pkg_abi *abi);
modified libpkg/private/pkg_jobs.h
@@ -142,6 +142,7 @@ struct pkg_jobs {
	struct triggers triggers;
	struct pkghash *orphaned;
	struct pkghash *notorphaned;
+
	struct pkghash *system_shlibs;
};

#define PKG_PATTERN_FLAG_FILE (1 << 0)
modified libpkg/private/pkgdb.h
@@ -161,10 +161,7 @@ int pkgdb_check_access(unsigned mode, const char *dbname);
 */
void pkgdb_regex(sqlite3_context *ctx, int argc, sqlite3_value **argv);
void pkgdb_regex_delete(void *p);
-
void pkgdb_split_uid(sqlite3_context *ctx, int argc, sqlite3_value **argv);
-
void pkgdb_split_version(sqlite3_context *ctx, int argc, sqlite3_value **argv);
void pkgdb_now(sqlite3_context *ctx, int argc, __unused sqlite3_value **argv);
-
void pkgdb_myarch(sqlite3_context *ctx, int argc, sqlite3_value **argv);
int pkgdb_sqlcmd_init(sqlite3 *db, const char **err, const void *noused);
int pkgdb_update_config_file_content(struct pkg *pkg, sqlite3 *s);
void pkgdb_syscall_overload(void);
modified libpkg/ssh.c
@@ -79,8 +79,10 @@ pkg_sshserve(int fd)
		if (line[linelen - 1] == '\n')
			line[linelen - 1] = '\0';

-
		if (STREQ(line, "quit"))
+
		if (STREQ(line, "quit")) {
+
			free(line);
			return (EPKG_OK);
+
		}

		if (strncmp(line, "get ", 4) != 0) {
			printf("ko: unknown command '%s'\n", line);
added libpkg/system_shlibs.c
@@ -0,0 +1,92 @@
+
/*-
+
 * Copyright (c) 1998 John D. Polstra
+
 * Copyright (c) 2012 Matthew Seaman <matthew@FreeBSD.org>
+
 * Copyright (c) 2024 The FreeBSD Foundation
+
 *
+
 * This software was developed in part by Isaac Freund <ifreund@freebsdfoundation.org>
+
 * under sponsorship from the FreeBSD Foundation.
+
 *
+
 * SPDX-License-Identifier: BSD-2-Clause
+
 */
+

+
#include <assert.h>
+
#include <ctype.h>
+
#include <dirent.h>
+
#include <errno.h>
+
#include <string.h>
+

+
#include "pkg.h"
+
#include "pkghash.h"
+
#include "private/event.h"
+
#include "xmalloc.h"
+

+
static int
+
scan_dir_for_shlibs(pkghash **shlib_list, const char *dir)
+
{
+
	DIR *dirp= opendir(dir);
+
	if (dirp == NULL) {
+
		if (errno == ENOENT) {
+
			return (EPKG_OK);
+
		}
+
		pkg_errno("Failed to open '%s' to scan for shared libraries", dir);
+
		return (EPKG_FATAL);
+
	}
+

+
	struct dirent *dp;
+
	while ((dp = readdir(dirp)) != NULL) {
+
		/* Only regular files and sym-links. On some
+
		   filesystems d_type is not set, on these the d_type
+
		   field will be DT_UNKNOWN. */
+
		if (dp->d_type != DT_REG && dp->d_type != DT_LNK &&
+
		    dp->d_type != DT_UNKNOWN)
+
			continue;
+

+
		int len = strlen(dp->d_name);
+
		/* Name can't be shorter than "libx.so" */
+
		if (len < 7 || strncmp(dp->d_name, "lib", 3) != 0)
+
			continue;
+

+
		const char *vers = dp->d_name + len;
+
		while (vers > dp->d_name &&
+
		       (isdigit(*(vers-1)) || *(vers-1) == '.'))
+
			vers--;
+
		if (vers == dp->d_name + len) {
+
			if (strncmp(vers - 3, ".so", 3) != 0)
+
				continue;
+
		} else if (vers < dp->d_name + 3 ||
+
		    strncmp(vers - 3, ".so.", 4) != 0)
+
			continue;
+

+
		/* We have a valid shared library name. */
+
		pkghash_safe_add(*shlib_list, dp->d_name, NULL, NULL);
+
	}
+

+
	closedir(dirp);
+

+
	return (EPKG_OK);
+
}
+

+
static const char *system_shlib_dirs[] = {
+
	"/lib",
+
	"/usr/lib",
+
};
+

+
int
+
scan_system_shlibs(pkghash **system_shlibs, const char *rootdir)
+
{
+
	for (int i = 0; i < NELEM(system_shlib_dirs); i++) {
+
		char *dir;
+
		if (rootdir != NULL) {
+
			xasprintf(&dir, "%s%s", rootdir, system_shlib_dirs[i]);
+
		} else {
+
			dir = xstrdup(system_shlib_dirs[i]);
+
		}
+
		int ret = scan_dir_for_shlibs(system_shlibs, dir);
+
		free(dir);
+
		if (ret != EPKG_OK) {
+
			return (ret);
+
		}
+
	}
+

+
	return (EPKG_OK);
+
}
modified libpkg/triggers.c
@@ -351,17 +351,18 @@ triggers_load(bool cleanup_only)
void
trigger_free(struct trigger *t)
{
-
	if (t == NULL)
+
	if (!t)
		return;
	free(t->name);
-
	if (t->path != NULL)
+
	if (t->path)
		ucl_object_unref(t->path);
-
	if (t->path != NULL)
+
	if (t->path_glob)
		ucl_object_unref(t->path_glob);
-
	if (t->path != NULL)
+
	if (t->path_regex)
		ucl_object_unref(t->path_regex);
	free(t->cleanup.script);
	free(t->script.script);
+
	free(t);
}

static char *
@@ -695,5 +696,6 @@ pkg_execute_deferred_triggers(void)
		}
		exec_deferred(trigfd, e->d_name);
	}
+
	closedir(d);
	return (EPKG_OK);
}
modified libpkg/utils.c
@@ -55,6 +55,7 @@
#include "pkg.h"
#include "pkgvec.h"
#include "private/event.h"
+
#include "private/pkg_abi.h"
#include "private/utils.h"
#include "private/pkg.h"
#include "xmalloc.h"
@@ -351,7 +352,7 @@ check_for_hardlink(hardlinks_t *hl, struct stat *st)
bool
is_valid_abi(const char *testabi, bool emit_error)
{
-
	const char *abi = ctx.oi->abi;
+
	const char *abi = pkg_object_string(pkg_config_get("ABI"));

	if (strncasecmp(testabi, abi, strlen(testabi)) != 0 &&
	    fnmatch(testabi, abi, FNM_CASEFOLD) == FNM_NOMATCH) {
@@ -367,11 +368,10 @@ is_valid_abi(const char *testabi, bool emit_error)
bool
is_valid_os_version(struct pkg *pkg)
{
-
	if (ctx.oi->ostype != OS_FREEBSD)
+
	if (ctx.abi.os != PKG_OS_FREEBSD)
		return (true);
	const char *fbsd_version;
	const char *errstr = NULL;
-
	int fbsdver;
	char query_buf[512];
	/* -1: not checked, 0: not allowed, 1: allowed */
	static int osver_mismatch_allowed = -1;
@@ -380,14 +380,15 @@ is_valid_os_version(struct pkg *pkg)
	if (pkg_object_bool(pkg_config_get("IGNORE_OSVERSION")))
		return (true);
	if ((fbsd_version = pkg_kv_get(&pkg->annotations, "FreeBSD_version")) != NULL) {
-
		fbsdver = strtonum(fbsd_version, 1, INT_MAX, &errstr);
+
		int pkg_osversion = strtonum(fbsd_version, 1, INT_MAX, &errstr);
		if (errstr != NULL) {
			pkg_emit_error("Invalid FreeBSD version %s for package %s",
			    fbsd_version, pkg->name);
			return (false);
		}
-
		if (fbsdver > ctx.oi->osversion) {
-
			if (fbsdver - ctx.oi->osversion < 100000) {
+
		int abi_osversion = pkg_abi_get_freebsd_osversion(&ctx.abi);
+
		if (pkg_osversion > abi_osversion) {
+
			if (pkg_osversion - abi_osversion < 100000) {
				/* Negligible difference, ask user to enforce */
				if (osver_mismatch_allowed == -1) {
					snprintf(query_buf, sizeof(query_buf),
@@ -396,7 +397,7 @@ is_valid_os_version(struct pkg *pkg)
							"- package: %d\n"
							"- running userland: %d\n"
							"Ignore the mismatch and continue? ", pkg->name,
-
							fbsdver, ctx.oi->osversion);
+
							pkg_osversion, abi_osversion);
					ret = pkg_emit_query_yesno(false, query_buf);
					osver_mismatch_allowed = ret;
				}
@@ -409,7 +410,7 @@ is_valid_os_version(struct pkg *pkg)
					"- package: %d\n"
					"- running kernel: %d\n",
					pkg->name,
-
					fbsdver, ctx.oi->osversion);
+
					pkg_osversion, abi_osversion);
				return (false);
			}
		}
modified libpkg/xmalloc.h
@@ -3,6 +3,7 @@

#include <stdarg.h>
#include <stdio.h>
+
#include <stdlib.h>
#include <string.h>

static inline void *xmalloc(size_t size)
modified scripts/completion/_pkg.in
@@ -108,8 +108,6 @@ _pkg_config_opts() {
	_values 'configuration option' \
		'ABI[ABI of package you want to install]:string' \
		'ALIAS[define local aliases for various pkg(8) standard command lines]:key/value list' \
-
		'ALLOW_BASE_SHLIBS[enable base libraries analysis]:boolean:(yes no)' \
-
		'ALTABI[override the automatically detected old-form ABI]:string' \
		'AUTOCLEAN[cleanout content of cache directory after upgrades or installations]:boolean:(yes no)' \
		'AUTOMERGE[automatically merge configuration files]:boolean:(yes no)' \
		'DEFAULT_ALWAYS_YES[default to "yes" for all questions requiring user confirmation]:boolean:(yes no)' \
modified src/clean.c
@@ -159,7 +159,8 @@ populate_sums(struct pkgdb *db)
		pkghash_safe_add(suml, cksum, NULL, NULL);
		free(cksum);
	}
-

+
	pkgdb_it_free(it);
+
	
	return (suml);
}

modified src/main.c
@@ -446,6 +446,7 @@ expand_aliases(int argc, char ***argv)
	while ((alias = pkg_object_iterate(all_aliases, &it))) {
		if (STREQ(oldargv[0], pkg_object_key(alias))) {
			matched = true;
+
			free(it);
			break;
		}
	}
modified src/query.c
@@ -954,12 +954,14 @@ exec_query(int argc, char **argv)
	if ((match == MATCH_ALL || pkgname != NULL)
	    && argc > 1) {
		usage_query();
-
		return (EXIT_FAILURE);
+
		retcode = EXIT_FAILURE;
+
		goto cleanup;
	}

	if (argc == 0) {
		usage_query();
-
		return (EXIT_FAILURE);
+
		retcode = EXIT_FAILURE;
+
		goto cleanup;
	}

	/* Default to all packages if no pkg provided */
@@ -968,12 +970,15 @@ exec_query(int argc, char **argv)
	} else if (((argc == 1) ^ (match == MATCH_ALL)) && pkgname == NULL
			&& condition == NULL) {
		usage_query();
-
		return (EXIT_FAILURE);
+
		retcode = EXIT_FAILURE;
+
		goto cleanup;
	}

	if (analyse_query_string(argv[0], accepted_query_flags, q_flags_len,
-
			&query_flags, &multiline) != EPKG_OK)
-
		return (EXIT_FAILURE);
+
			&query_flags, &multiline) != EPKG_OK) {
+
		retcode = EXIT_FAILURE;
+
		goto cleanup;
+
	}

	if (pkgname != NULL) {
		/* Use a manifest or compact manifest if possible. */
@@ -995,42 +1000,49 @@ exec_query(int argc, char **argv)
			open_flags = PKG_OPEN_MANIFEST_ONLY;
		}
		if (pkg_open(&pkg, pkgname, open_flags) != EPKG_OK) {
-
			return (EXIT_FAILURE);
+
			retcode = EXIT_FAILURE;
+
			goto cleanup;
		}

		print_query(pkg, argv[0], multiline);
-
		pkg_free(pkg);
-
		return (EXIT_SUCCESS);
+
		retcode = EXIT_SUCCESS;
+
		goto cleanup;
	}

	if (condition != NULL) {
		sqlcond = xstring_new();
		if (format_sql_condition(condition, sqlcond, false) != EPKG_OK) {
-
			xstring_free(sqlcond);
-
			return (EXIT_FAILURE);
+
			retcode = EXIT_FAILURE;
+
			goto cleanup;
		}
	}

	ret = pkgdb_access(PKGDB_MODE_READ, PKGDB_DB_LOCAL);
	if (ret == EPKG_ENOACCESS) {
		warnx("Insufficient privileges to query the package database");
-
		return (EXIT_FAILURE);
+
		retcode = EXIT_FAILURE;
+
		goto cleanup;
	} else if (ret == EPKG_ENODB) {
		if (!quiet)
			warnx("No packages installed");
-
		return (EXIT_SUCCESS);
-
	} else if (ret != EPKG_OK)
-
		return (EXIT_FAILURE);
+
		retcode = EXIT_SUCCESS;
+
		goto cleanup;
+
	} else if (ret != EPKG_OK) {
+
		retcode = EXIT_FAILURE;
+
		goto cleanup;
+
	}

	ret = pkgdb_open(&db, PKGDB_DEFAULT);
-
	if (ret != EPKG_OK)
-
		return (EXIT_FAILURE);
+
	if (ret != EPKG_OK) {
+
		retcode = EXIT_FAILURE;
+
		goto cleanup;
+
	}

	pkg_drop_privileges();
	if (pkgdb_obtain_lock(db, PKGDB_LOCK_READONLY) != EPKG_OK) {
-
		pkgdb_close(db);
		warnx("Cannot get a read lock on a database, it is locked by another process");
-
		return (EXIT_FAILURE);
+
		retcode = EXIT_FAILURE;
+
		goto cleanup;
	}

	if (sqlcond) {
@@ -1067,6 +1079,9 @@ exec_query(int argc, char **argv)
		retcode = EXIT_FAILURE;
	}

+
cleanup:
+
	xstring_free(sqlcond);
+

	pkg_free(pkg);

	pkgdb_release_lock(db, PKGDB_LOCK_READONLY);
modified src/updating.c
@@ -71,6 +71,7 @@ regex_cache_free(struct regex_cache *p)
{
	if (!p)
		return;
+
	regfree(&p->reg);
	free(p->pattern);
	free(p);
}
modified tests/Makefile.autosetup
@@ -28,6 +28,7 @@ TESTS_SH= \
	frontend/conflicts.sh \
	frontend/conflicts-multirepo.sh \
	frontend/create.sh \
+
	frontend/create-parsebin.sh \
	frontend/delete.sh \
	frontend/extract.sh \
	frontend/fetch.sh \
@@ -91,6 +92,7 @@ TESTS_SHELL_BINS= \
	frontend/macos106.bin \
	frontend/macos150.bin \
	frontend/macosfat.bin \
+
	frontend/macosfatlib.bin \
	frontend/libtestfbsd.so.1 \
	frontend/libtest2fbsd.so.1 \
	frontend/libfoo.so.1
modified tests/frontend/abi.sh
@@ -20,8 +20,8 @@ native_body() {
			;;
		Darwin)
			# without a hint, the first arch is selected, which happens to be consistently x86_64
-
			thisarch="amd64"
-
			thisabi="x86:64"
+
			thisarch="x86_64"
+
			thisabi="x86_64"
			version=$(uname -r | cut -d. -f1)
			;;
		FreeBSD)
@@ -49,192 +49,57 @@ override_body() {
	atf_check \
		-o inline:"${_expected}" \
		-e ignore \
-
		pkg -o ABI=FreeBSD:12:powerpc config abi
+
		pkg -o ABI=FreeBSD:12:powerpc -o OSVERSION=1201000 config abi

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

elfparse_body() {
	# ELF parsing now works across platforms

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

-
	_expected="dragonfly:5.10:x86:64\n"
-
	atf_check \
-
		-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
+
	for bin in \
+
		freebsd-aarch64.bin freebsd-amd64.bin freebsd-armv6.bin freebsd-armv7.bin \
+
		freebsd-i386.bin freebsd-powerpc.bin freebsd-powerpc64.bin freebsd-powerpc64le.bin \
+
		freebsd-riscv64.bin dfly.bin linux.bin
+
	do
+
		bin_meta ${bin}
+

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

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

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
+
	for bin in \
+
		macos.bin macos106.bin macos150.bin \
+
		macosfat.bin "macosfat.bin#x86_64" "macosfat.bin#aarch64" \
+
		macosfatlib.bin "macosfatlib.bin#x86_64" "macosfatlib.bin#aarch64"
+
	do
+
		bin_meta ${bin}

-
	_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="${XABI}\n"
+
		atf_check \
+
			-o inline:"${_expected}" \
+
			pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/${bin} config abi

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

-
	# macosfat.bin has amd64 as its first entry
-
	_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
-

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

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

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

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

	# explicitely select a fat entry that is not in the ABI_FILE
	_expected="Scanned 2 entries, found none matching selector i386\n"
@@ -251,17 +116,17 @@ machoparse_body() {
		pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macosfat.bin#i386 config altabi

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

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

	# if the binary is not universal, selecting the first entry is not commentable
@@ -277,27 +142,27 @@ machoparse_body() {
		-e not-match:"picking first" \
		pkg -d -o IGNORE_OSMAJOR=1 -o ABI_FILE=$(atf_get_srcdir)/macos.bin config altabi

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

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

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

-
	_expected="darwin:24:x86:64\n"
+
	_expected="darwin:17:x86_64\n"
	atf_check \
		-o inline:"${_expected}" \
		-e match:"picking first" \
added tests/frontend/create-parsebin.sh
@@ -0,0 +1,126 @@
+
#! /usr/bin/env atf-sh
+

+
. $(atf_get_srcdir)/test_environment.sh
+

+
tests_init \
+
	create_from_bin
+

+
genmanifest() {
+
    local PKG_NAME="$1"
+
    shift
+
    local PKG_FLATSIZE=0
+
    local PKG_FILES=""
+
    local PKG_SHA256=""
+
    local NL="
+
"
+

+
    bin_meta "$1"
+
    while [ -n "$1" ]; do
+
        local file1="${1%#*}"
+
        local file1_base=$(basename ${file1})
+
        local file1_size=$(wc -c < ${file1})
+
        local file1_sha=$(openssl dgst -sha256 -hex ${file1} | sed -nE 's/.*=[[:space:]]*([[:xdigit:]]+)/\1/p')
+
        cp -a ${file1} ${TMPDIR}/${file1_base}
+

+
        PKG_FILES="${PKG_FILES}/${file1_base}: {perm: 0644}${NL}"
+
        PKG_SHA256="${PKG_SHA256}${NL}    /${file1_base} = \"1\$${file1_sha}\";"
+

+
        PKG_FLATSIZE=$((${PKG_FLATSIZE}+${file1_size}))
+
        shift
+
    done
+

+
	cat << EOF > ${PKG_NAME}.manifest
+
name: ${PKG_NAME}
+
origin: ${PKG_NAME}
+
version: 1
+
maintainer: test
+
categories: [test]
+
comment: a test
+
www: http://test
+
prefix: /
+
desc: <<EOD
+
Yet another test
+
EOD
+
files: {
+
    ${PKG_FILES}
+
}
+
EOF
+

+
	cat << EOF > ${PKG_NAME}.expected
+
name = "${PKG_NAME}";
+
origin = "${PKG_NAME}";
+
version = "1";
+
comment = "a test";
+
maintainer = "test";
+
www = "http://test";
+
abi = "${XABI}";
+
arch = "${XALTABI}";
+
prefix = "/";
+
flatsize = ${PKG_FLATSIZE};
+
desc = "Yet another test";
+
categories [
+
    "test",
+
]
+
EOF
+
    if [ -n "${Xshlibs_required}" ]; then
+
        echo "shlibs_required [" >> ${PKG_NAME}.expected
+
        for i in ${Xshlibs_required}; do
+
            echo ${NL}"    "\"$i\", >> ${PKG_NAME}.expected
+
        done
+
        echo "]" >> ${PKG_NAME}.expected
+
    fi
+
    if [ -n "${Xshlibs_provided}" ]; then
+
        echo "shlibs_provided [" >> ${PKG_NAME}.expected
+
        for i in ${Xshlibs_provided}; do
+
            echo ${NL}"    "\"$i\", >> ${PKG_NAME}.expected
+
        done
+
        echo "]" >> ${PKG_NAME}.expected
+
    fi
+

+
    if [ -n "${XFreeBSD_version}" ]; then
+
    	cat << EOF >> ${PKG_NAME}.expected
+
annotations {
+
    FreeBSD_version = "${XFreeBSD_version}";
+
}
+
EOF
+
    fi
+

+
	cat << EOF >> ${PKG_NAME}.expected
+
files {${PKG_SHA256}
+
}
+
EOF
+
}
+

+
do_check() {
+
    local PKG_NAME=$1
+
    local file1=$(atf_get_srcdir)/$2
+

+
    genmanifest ${PKG_NAME} ${file1}
+

+
    # cat ${PKG_NAME}.manifest
+
    atf_check \
+
        -o empty \
+
        -e empty \
+
        -s exit:0 \
+
        pkg -o IGNORE_OSMAJOR=1 -o ABI_FILE=${file1} create -M ./${PKG_NAME}.manifest -r ${TMPDIR}
+

+
    # cat ${PKG_NAME}.expected
+
    atf_check \
+
        -o file:${PKG_NAME}.expected \
+
        -e empty \
+
        -s exit:0 \
+
        pkg info -R --raw-format=ucl -F ${PKG_NAME}-1.pkg
+
}
+

+
create_from_bin_body() {
+
    for bin in \
+
        freebsd-aarch64.bin freebsd-amd64.bin freebsd-armv6.bin freebsd-armv7.bin \
+
		freebsd-i386.bin freebsd-powerpc.bin freebsd-powerpc64.bin freebsd-powerpc64le.bin \
+
		freebsd-riscv64.bin dfly.bin linux.bin \
+
        macos.bin macos106.bin macos150.bin \
+
        macosfat.bin "macosfat.bin#x86_64" "macosfat.bin#aarch64" \
+
        macosfatlib.bin "macosfatlib.bin#x86_64" "macosfatlib.bin#aarch64"
+
    do
+
        do_check testbin $bin
+
    done
+
}
modified tests/frontend/macosfat.binin
added tests/frontend/macosfatlib.binin
modified tests/frontend/pkg.sh
@@ -21,15 +21,6 @@ pkg_no_database_body() {

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

	atf_check \
	    -o match:'^ *PKG_DBDIR = "/var/db/pkg";$' \
	    -o match:'^ *PKG_CACHEDIR = "/var/cache/pkg";$' \
@@ -39,7 +30,7 @@ pkg_config_defaults_body()
	    -o match:'^ *ASSUME_ALWAYS_YES = false;$' \
	    -o match:'^ *PLIST_KEYWORDS_DIR = "";$' \
	    -o match:'^ *SYSLOG = true;$' \
-
	    -o match:"${MATCH_ABI}" \
+
	    -o match:'^ *ABI = "[a-zA-Z0-9]+:[a-z\.A-Z0-9]+:[a-zA-Z0-9_]+";$'\
	    -o match:'^ *DEVELOPER_MODE = false;$' \
	    -o match:'^ *VULNXML_SITE = "https://vuxml.freebsd.org/freebsd/vuln.xml.xz";$' \
	    -o match:'^ *FETCH_RETRY = 3;$' \
modified tests/frontend/test_environment.sh.in
@@ -47,3 +47,134 @@ atf_require() {
		atf_skip "$@"
	fi
}
+

+

+
# helper function to obtain expected values for binaries used by the test cases
+

+
bin_meta() {
+
	local file="$1"
+
	XABI=""
+
	XALTABI=""
+
	XFreeBSD_version=""
+
	Xshlibs_provided=""
+
	Xshlibs_required=""
+
	case "${file}" in
+
		*freebsd-aarch64.bin)
+
			XABI=FreeBSD:14:aarch64
+
			XALTABI=freebsd:14:aarch64:64
+
			XFreeBSD_version=1401000
+
			Xshlibs_required="libc.so.7"
+
			;;
+
		*freebsd-amd64.bin)
+
			XABI=FreeBSD:14:amd64
+
			XALTABI=freebsd:14:x86:64
+
			XFreeBSD_version=1401000
+
			Xshlibs_required="libc.so.7"
+
			;;
+
		*freebsd-armv6.bin)
+
			XABI=FreeBSD:13:armv6
+
			XALTABI=freebsd:13:armv6:32:el:eabi:hardfp
+
			XFreeBSD_version=1304000
+
			Xshlibs_required="libgcc_s.so.1 libc.so.7"
+
			;;
+
		*freebsd-armv7.bin)
+
			XABI=FreeBSD:14:armv7
+
			XALTABI=freebsd:14:armv7:32:el:eabi:hardfp
+
			XFreeBSD_version=1401000
+
			Xshlibs_required="libgcc_s.so.1 libc.so.7"
+
			;;
+
		*freebsd-i386.bin)
+
			XABI=FreeBSD:14:i386
+
			XALTABI=freebsd:14:x86:32
+
			XFreeBSD_version=1401000
+
			Xshlibs_required="libc.so.7"
+
			;;
+
		*freebsd-powerpc.bin)
+
			XABI=FreeBSD:14:powerpc
+
			XALTABI=freebsd:14:powerpc:32:eb
+
			XFreeBSD_version=1401000
+
			Xshlibs_required="libc.so.7"
+
			;;
+
		*freebsd-powerpc64.bin)
+
			XABI=FreeBSD:14:powerpc64
+
			XALTABI=freebsd:14:powerpc:64:eb
+
			XFreeBSD_version=1401000
+
			Xshlibs_required="libc.so.7"
+
			;;
+
		*freebsd-powerpc64le.bin)
+
			XABI=FreeBSD:14:powerpc64le
+
			XALTABI=freebsd:14:powerpc:64:el
+
			XFreeBSD_version=1401000
+
			Xshlibs_required="libc.so.7"
+
			;;
+
		*freebsd-riscv64.bin)
+
			XABI=FreeBSD:14:riscv64
+
			XALTABI=freebsd:14:riscv:64:hf
+
			XFreeBSD_version=1401000
+
# This riscv64 binary does not have the OS set to FreeBSD in its ELF header
+
# TODO: handle this in pkg_elf.c
+
#			Xshlibs_required="libc.so.7"
+
			;;
+
		*dfly.bin)
+
			XABI=dragonfly:5.10:x86:64
+
			XALTABI=dragonfly:5.10:x86:64
+
			Xshlibs_required="libc.so.8"
+
			;;
+
		*linux.bin)
+
			XABI=Linux:3.2:x86_64
+
			XALTABI=linux:3.2:x86_64
+
			Xshlibs_required="libc.so.6"
+
			;;
+

+
		*macos.bin)
+
			XABI=Darwin:24:aarch64
+
			XALTABI=darwin:24:aarch64:64
+
			Xshlibs_required="libSystem.B.dylib-1351.0"
+
			;;
+
		*macos106.bin)
+
			XABI=Darwin:10:x86_64
+
			XALTABI=darwin:10:x86_64
+
			Xshlibs_required="libSystem.B.dylib-125.2.11"
+
			;;
+
		*macos150.bin)
+
			XABI=Darwin:24:x86_64
+
			XALTABI=darwin:24:x86_64
+
			Xshlibs_required="libSystem.B.dylib-1351.0"
+
			;;
+

+
		# macosfat.bin has x86_64 as its first entry
+
		*macosfat.bin|*macosfat.bin#x86_64)
+
			XABI=Darwin:17:x86_64
+
			XALTABI=darwin:17:x86_64
+
			Xshlibs_required="libAnswer.A.dylib-1.2 libSystem.B.dylib-1319.0"
+
			;;
+

+
		# macosfat also has an aarch64 entry
+
		*macosfat.bin#aarch64)
+
			XABI=Darwin:20:aarch64
+
			XALTABI=darwin:20:aarch64:64
+
			Xshlibs_required="libAnswer.A.dylib-1.1 libSystem.B.dylib-1319.0"
+
			;;
+

+
		# macosfatlib.bin has x86_64 as its first entry
+
		*macosfatlib.bin|*macosfatlib.bin#x86_64)
+
			XABI=Darwin:17:x86_64
+
			XALTABI=darwin:17:x86_64
+
			Xshlibs_provided="libAnswer.A.dylib-1.2"
+
			Xshlibs_required="libSystem.B.dylib-1319.0"
+
			;;
+

+
		*macosfatlib.bin#aarch64)
+
			XABI=Darwin:20:aarch64
+
			XALTABI=darwin:20:aarch64:64
+
			Xshlibs_provided="libAnswer.A.dylib-1.1"
+
			Xshlibs_required="libSystem.B.dylib-1319.0"
+
			;;
+

+
		*)
+
			echo Unknown binary $1
+
			return 1
+
			;;
+
	esac
+
	return 0
+
}
modified tests/lib/checksum.c
@@ -79,7 +79,7 @@ ATF_TC_BODY(check_types, tc)

ATF_TC_BODY(check_symlinks, tc)
{
-
	unsigned char *sum;
+
	char *sum;

	ATF_REQUIRE_EQ(symlink("foo", "bar"), 0);

@@ -115,7 +115,7 @@ ATF_TC_HEAD(check_files, tc)
ATF_TC_BODY(check_files, tc)
{
	FILE *f;
-
	unsigned char *sum;
+
	char *sum;

	f = fopen("foo", "w");
	fprintf(f, "bar\n");
@@ -123,9 +123,9 @@ ATF_TC_BODY(check_files, tc)

	sum = pkg_checksum_file("foo", PKG_HASH_TYPE_SHA256_HEX);
	ATF_REQUIRE_STREQ(sum, "7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730");
+
	free(sum);

	ATF_CHECK(pkg_checksum_validate_file("foo", "7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730") == 0);
-
	free(sum);

	sum=pkg_checksum_generate_file("foo", PKG_HASH_TYPE_SHA256_HEX);
	ATF_REQUIRE_STREQ(sum, "1$7d865e959b2466918c9863afca942d0fb89d7c9ac0c99bafc3749504ded97730");
@@ -140,7 +140,10 @@ ATF_TC_BODY(check_files, tc)
	ATF_REQUIRE_EQ(pkg_checksum_symlinkat(AT_FDCWD, "nonexistent", PKG_HASH_TYPE_BLAKE2_BASE32), NULL);
	ATF_REQUIRE_EQ(pkg_checksum_file("nonexistent", 42), NULL);
	ATF_REQUIRE_EQ(pkg_checksum_data("a", 1, 42), NULL);
-
	ATF_REQUIRE_STREQ(pkg_checksum_data("a", 0, PKG_HASH_TYPE_BLAKE2_BASE32), "u3xsc8fhkf9ntjikcz3hcsg1h5n59yqmz8s483emc8gessm4qnpk7ikhgqcmmz98ci391sdx565bazeffh1djkzkep7j1qqgeawsc6y");
+

+
	sum = pkg_checksum_data("a", 0, PKG_HASH_TYPE_BLAKE2_BASE32);
+
	ATF_REQUIRE_STREQ(sum, "u3xsc8fhkf9ntjikcz3hcsg1h5n59yqmz8s483emc8gessm4qnpk7ikhgqcmmz98ci391sdx565bazeffh1djkzkep7j1qqgeawsc6y");
+
	free(sum);

	sum = pkg_checksum_file("foo", PKG_HASH_TYPE_BLAKE2_BASE32);
	ATF_REQUIRE_STREQ(sum, "gf8mcrnmm6p6hg6wa9xkfb98zo8g6nxu8z4q7s93boz8hzf5ogrsr4qgpsb7utd6speio3op18ocyrsa9ms8jj15byttiq7ofbih8gn");
@@ -180,6 +183,8 @@ ATF_TC_BODY(check_pkg, tc)
	ATF_REQUIRE_STREQ(sum, "2$5$9819ezi7ytn58y3mwhcxaqbkiaik7ui9o3obewhqmuyx99kmb95y");
	ATF_REQUIRE_EQ(pkg_checksum_get_type(sum, -1), PKG_HASH_TYPE_BLAKE2S_BASE32);
	free(sum);
+

+
	pkg_free(p);
}

ATF_TP_ADD_TCS(tp)
modified tests/lib/lua.c
@@ -44,7 +44,9 @@ ATF_TC_WITHOUT_HEAD(prefix_path);

ATF_TC_BODY(readdir, tc)
{
-
	int rootfd = open(getcwd(NULL, 0), O_DIRECTORY);
+
	char *cwd = getcwd(NULL, 0);
+
	int rootfd = open(cwd, O_DIRECTORY);
+
	free(cwd);
	lua_State *L = luaL_newstate();
	static const luaL_Reg test_lib[] = {
		{ "readdir", lua_readdir },
@@ -123,7 +125,9 @@ ATF_TC_BODY(readdir, tc)

ATF_TC_BODY(stat, tc)
{
-
	int rootfd = open(getcwd(NULL, 0), O_DIRECTORY);
+
	char *cwd = getcwd(NULL, 0);
+
	int rootfd = open(cwd, O_DIRECTORY);
+
	free(cwd);
	lua_State *L = luaL_newstate();
	static const luaL_Reg test_lib[] = {
		{ "stat", lua_stat },
@@ -319,7 +323,9 @@ ATF_TC_BODY(override, tc)
	}
	atf_utils_wait(p, 0, "[string \"os.exit(1)\"]:1: os.exit not available\n", "");

-
	int rootfd = open(getcwd(NULL, 0), O_DIRECTORY);
+
	char *cwd = getcwd(NULL, 0);
+
	int rootfd = open(cwd, O_DIRECTORY);
+
	free(cwd);
	lua_pushinteger(L, rootfd);
	lua_setglobal(L, "rootfd");
	p = atf_utils_fork();
@@ -355,7 +361,9 @@ ATF_TC_BODY(override, tc)
ATF_TC_BODY(fileops, tc)
{
	char b[1024];
-
	int rootfd = open(getcwd(NULL, 0), O_DIRECTORY);
+
	char *cwd = getcwd(NULL, 0);
+
	int rootfd = open(cwd, O_DIRECTORY);
+
	free(cwd);
	lua_State *L = luaL_newstate();
	luaL_openlibs(L);
	lua_pushinteger(L, rootfd);
modified tests/lib/packing.c
@@ -101,6 +101,7 @@ ATF_TC_BODY(packing_set_format, tc)
	ATF_REQUIRE_STREQ(packing_set_format(a, TGZ, INT_MAX, -1), "tgz");
	ATF_REQUIRE_STREQ(packing_set_format(a, TAR, INT_MAX, -1), "tar");
	ATF_REQUIRE_EQ(packing_set_format(a, 28, INT_MAX, -1), NULL);
+
	archive_write_free(a);
}

ATF_TP_ADD_TCS(tp)
modified tests/lib/pkg_elf.c
@@ -10,6 +10,7 @@

#include <atf-c.h>
#include <private/pkg.h>
+
#include <private/pkg_abi.h>
#include <private/binfmt.h>
#include <xstring.h>
#include <tllist.h>
@@ -48,6 +49,8 @@ ATF_TC_BODY(analyse_elf, tc)
	struct pkg *p = NULL;
	char *binpath = NULL;

+
	ctx.abi.arch = PKG_ARCH_AMD64;
+

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

	ATF_REQUIRE_EQ(EPKG_OK, pkg_new(&p, PKG_INSTALLED));
@@ -58,22 +61,26 @@ ATF_TC_BODY(analyse_elf, tc)
	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");
+
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 1);
+
	ATF_REQUIRE_STREQ(tll_front(p->shlibs_required), "libc.so.7");
	free(binpath);

	xasprintf(&binpath, "%s/Makefile", atf_tc_get_config_var(tc, "srcdir"));
	ATF_REQUIRE_EQ(pkg_analyse_elf(false, p, binpath), EPKG_END);
	ATF_REQUIRE_EQ(tll_length(p->shlibs_provided), 1);
+
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 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");
+
	ATF_REQUIRE_EQ(tll_length(p->shlibs_required), 2);
+
	ATF_REQUIRE_STREQ(tll_front(p->shlibs_required), "libc.so.7");
+
	ATF_REQUIRE_STREQ(tll_back(p->shlibs_required), "libfoo.so.1");
	free(binpath);

+
	pkg_free(p);
}

ATF_TP_ADD_TCS(tp)
modified tests/lib/plist.c
@@ -318,6 +318,8 @@ ATF_TC_BODY(expand_plist_variables, tc)
	plop = expand_plist_variables("%%this%% %F is %%kof a %%new%% line %", &kv);
	ATF_REQUIRE_STREQ(plop, "@comment  %F is %%kof a var line %");
	free(plop);
+

+
	tll_free_and_free(kv, pkg_kv_free);
}

ATF_TP_ADD_TCS(tp)
modified tests/lib/ssh.c
@@ -43,7 +43,9 @@ ATF_TC_BODY(badcommand, tc)
	char strout[] =
		"ok: pkg " PKGVERSION "\n"
		"ko: unknown command 'plop'\n";
-
	int rootfd = open(getcwd(NULL, 0), O_DIRECTORY);
+
	char *cwd = getcwd(NULL, 0);
+
	int rootfd = open(cwd, O_DIRECTORY);
+
	free(cwd);
	int stdin_pipe[2];
	ATF_REQUIRE(pipe(stdin_pipe) >= 0);
	pid_t p = atf_utils_fork();
@@ -74,7 +76,9 @@ ATF_TC_BODY(getfile, tc)
		"ko: file not found\n"
		"ko: not a file\n"
		"ko: file not found\n";
-
	int rootfd = open(getcwd(NULL, 0), O_DIRECTORY);
+
	char * cwd = getcwd(NULL, 0);
+
	int rootfd = open(cwd, O_DIRECTORY);
+
	free(cwd);
	int stdin_pipe[2];
	ATF_REQUIRE(pipe(stdin_pipe) >= 0);
	FILE *f = fopen("testfile", "w+");
@@ -88,8 +92,10 @@ ATF_TC_BODY(getfile, tc)
		dup2(stdin_pipe[0], STDIN_FILENO);
		close(stdin_pipe[1]);
		config = ucl_object_typed_new(UCL_OBJECT);
-
		ucl_object_insert_key(config, ucl_object_fromstring_common(getcwd(NULL, 0), 0, UCL_STRING_TRIM),
+
		char *cwd = getcwd(NULL, 0);
+
		ucl_object_insert_key(config, ucl_object_fromstring_common(cwd, 0, UCL_STRING_TRIM),
			"SSH_RESTRICT_DIR", 16, false);
+
		free(cwd);
		exit(pkg_sshserve(rootfd));
	}
	close(stdin_pipe[0]);
@@ -115,7 +121,9 @@ ATF_TC_BODY(badrestrict, tc)
	char strout[] =
		"ok: pkg " PKGVERSION "\n"
		"ko: chdir failed (/nonexistent)\n";
-
	int rootfd = open(getcwd(NULL, 0), O_DIRECTORY);
+
	char *cwd = getcwd(NULL, 0);
+
	int rootfd = open(cwd, O_DIRECTORY);
+
	free(cwd);
	int stdin_pipe[2];
	ATF_REQUIRE(pipe(stdin_pipe) >= 0);
	pid_t p = atf_utils_fork();
@@ -185,11 +193,15 @@ ATF_TC_BODY(restricted, tc)
		dup2(stdin_pipe[0], STDIN_FILENO);
		close(stdin_pipe[1]);
		config = ucl_object_typed_new(UCL_OBJECT);
-
		char *restriteddir;
-
		xasprintf(&restriteddir, "%s/test", getcwd(NULL, 0));
+
		char *restriteddir = 0;
+
		char *cwd = getcwd(NULL, 0);
+
		xasprintf(&restriteddir, "%s/test", cwd);
+
		free(cwd);
		ucl_object_insert_key(config, ucl_object_fromstring_common(restriteddir, 0, UCL_STRING_TRIM),
			"SSH_RESTRICT_DIR", 16, false);
-
		exit(pkg_sshserve(rootfd));
+
		int ret = pkg_sshserve(rootfd);
+
		free(restriteddir);
+
		exit(ret);
	}
	close(stdin_pipe[0]);
	dprintf(stdin_pipe[1], "get ../testfile 0\n");
modified tests/lib/utils.c
@@ -69,6 +69,7 @@ ATF_TC_BODY(random_suffix, tc) {
ATF_TC_BODY(json_escape, tc) {
	char *m = json_escape("entry1\"\"\\ ");
	ATF_REQUIRE_STREQ_MSG(m, "entry1\\\"\\\"\\\\ ", "Invalid escaping");
+
	free(m);
}

ATF_TC_BODY(open_tempdir, tc) {
modified tests/lib/vec.c
@@ -116,6 +116,8 @@ ATF_TC_BODY(c_charv_contains, tc)
	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");
+

+
	pkgvec_free(&list);
}

ATF_TP_ADD_TCS(tp)