aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile9
-rw-r--r--lib/atf/Makefile.inc3
-rw-r--r--lib/atf/libatf-c++/Makefile3
-rw-r--r--lib/atf/libatf-c/Makefile2
-rw-r--r--lib/clang/libclang/Makefile89
-rw-r--r--lib/clang/liblldb/Makefile23
-rw-r--r--lib/clang/libllvm/Makefile153
-rw-r--r--lib/clang/llvm.build.mk2
-rw-r--r--lib/csu/common/crtbegin.c33
-rw-r--r--lib/csu/common/crtend.c4
-rw-r--r--lib/csu/tests/Makefile1
-rw-r--r--lib/csu/tests/dso/Makefile2
-rw-r--r--lib/csu/tests/errno/Makefile18
-rw-r--r--lib/csu/tests/errno/errno_test.c23
-rw-r--r--lib/csu/tests/init_test.c30
-rw-r--r--lib/geom/eli/geli.82
-rw-r--r--lib/geom/raid/graid.82
-rw-r--r--lib/lib80211/regdomain.xml298
-rw-r--r--lib/libarchive/Makefile3
-rw-r--r--lib/libarchive/tests/Makefile34
-rw-r--r--lib/libbe/be.c25
-rw-r--r--lib/libbe/be.h25
-rw-r--r--lib/libbe/be_access.c67
-rw-r--r--lib/libbe/be_error.c25
-rw-r--r--lib/libbe/be_impl.h25
-rw-r--r--lib/libbe/be_info.c25
-rw-r--r--lib/libbe/libbe.313
-rw-r--r--lib/libc/amd64/static_tls.h44
-rw-r--r--lib/libc/arm/aeabi/Symbol.map44
-rw-r--r--lib/libc/arm/aeabi/aeabi_int_div.S2
-rw-r--r--lib/libc/arm/aeabi/aeabi_vfp.h4
-rw-r--r--lib/libc/arm/static_tls.h45
-rw-r--r--lib/libc/csu/libc_start1.c9
-rw-r--r--lib/libc/gen/Makefile.inc22
-rw-r--r--lib/libc/gen/Symbol.map14
-rw-r--r--lib/libc/gen/_pthread_stubs.c1
-rw-r--r--lib/libc/gen/alarm.32
-rw-r--r--lib/libc/gen/dlfcn.c2
-rw-r--r--lib/libc/gen/dup3.315
-rw-r--r--lib/libc/gen/dup3.c9
-rw-r--r--lib/libc/gen/elf_utils.c27
-rw-r--r--lib/libc/gen/err.c51
-rw-r--r--lib/libc/gen/exec.c6
-rw-r--r--lib/libc/gen/fdopendir.c7
-rw-r--r--lib/libc/gen/fnmatch.38
-rw-r--r--lib/libc/gen/fnmatch.c227
-rw-r--r--lib/libc/gen/fts.386
-rw-r--r--lib/libc/gen/fts.c242
-rw-r--r--lib/libc/gen/gen-private.h4
-rw-r--r--lib/libc/gen/glob.366
-rw-r--r--lib/libc/gen/glob.c75
-rw-r--r--lib/libc/gen/inotify.c48
-rw-r--r--lib/libc/gen/libc_interposing_table.c2
-rw-r--r--lib/libc/gen/opendir.c7
-rw-r--r--lib/libc/gen/opendir2.c31
-rw-r--r--lib/libc/gen/posix_spawn.c2
-rw-r--r--lib/libc/gen/psignal.376
-rw-r--r--lib/libc/gen/psignal.c6
-rw-r--r--lib/libc/gen/readdir.c11
-rw-r--r--lib/libc/gen/rtld_get_var.32
-rw-r--r--lib/libc/gen/scandir.3127
-rw-r--r--lib/libc/gen/scandir.c129
-rw-r--r--lib/libc/gen/sig2str.c113
-rw-r--r--lib/libc/gen/sysconf.c7
-rw-r--r--lib/libc/gen/sysctl.316
-rw-r--r--lib/libc/gen/telldir.c4
-rw-r--r--lib/libc/gen/telldir.h6
-rw-r--r--lib/libc/gen/tls.c98
-rw-r--r--lib/libc/gen/ualarm.32
-rw-r--r--lib/libc/gen/uexterr_format.c35
-rw-r--r--lib/libc/gen/uexterr_gettext.c43
-rw-r--r--lib/libc/gen/wordexp.c10
-rw-r--r--lib/libc/i386/static_tls.h44
-rw-r--r--lib/libc/include/block_abi.h2
-rw-r--r--lib/libc/include/libc_private.h10
-rw-r--r--lib/libc/locale/collate.c259
-rw-r--r--lib/libc/locale/collate.h11
-rw-r--r--lib/libc/locale/euc.c2
-rw-r--r--lib/libc/net/Makefile.inc15
-rw-r--r--lib/libc/net/Symbol.map4
-rw-r--r--lib/libc/net/getaddrinfo.c58
-rw-r--r--lib/libc/net/linkaddr.377
-rw-r--r--lib/libc/net/linkaddr.c306
-rw-r--r--lib/libc/powerpc/static_tls.h44
-rw-r--r--lib/libc/powerpc64/static_tls.h44
-rw-r--r--lib/libc/riscv/static_tls.h44
-rw-r--r--lib/libc/rpc/rpc_secure.33
-rw-r--r--lib/libc/rpc/svc_nl.c3
-rw-r--r--lib/libc/stdio/mktemp.37
-rw-r--r--lib/libc/stdio/mktemp.c2
-rw-r--r--lib/libc/stdlib/Makefile.inc2
-rw-r--r--lib/libc/stdlib/Symbol.map4
-rw-r--r--lib/libc/stdlib/alloca.385
-rw-r--r--lib/libc/stdlib/atexit.c61
-rw-r--r--lib/libc/stdlib/getenv.340
-rw-r--r--lib/libc/stdlib/getenv.c36
-rw-r--r--lib/libc/stdlib/getopt_long.34
-rw-r--r--lib/libc/stdtime/strftime.c2
-rw-r--r--lib/libc/string/memccpy.32
-rw-r--r--lib/libc/string/memset.32
-rw-r--r--lib/libc/sys/closefrom.c10
-rw-r--r--lib/libc/tests/gen/Makefile28
-rw-r--r--lib/libc/tests/gen/fnmatch_test.c81
-rw-r--r--lib/libc/tests/gen/fts_blocks_test.c68
-rw-r--r--lib/libc/tests/gen/fts_misc_test.c78
-rw-r--r--lib/libc/tests/gen/fts_options_test.c394
-rw-r--r--lib/libc/tests/gen/fts_test.h81
-rw-r--r--lib/libc/tests/gen/glob2_test.c75
-rw-r--r--lib/libc/tests/gen/glob_blocks_test.c62
-rw-r--r--lib/libc/tests/gen/opendir_test.c145
-rw-r--r--lib/libc/tests/gen/scandir_blocks_test.c118
-rw-r--r--lib/libc/tests/gen/scandir_test.c195
-rw-r--r--lib/libc/tests/gen/sig2str_test.c213
-rw-r--r--lib/libc/tests/gen/wordexp_test.c26
-rw-r--r--lib/libc/tests/locale/wctomb_test.c13
-rw-r--r--lib/libc/tests/net/Makefile6
-rw-r--r--lib/libc/tests/net/getaddrinfo/Makefile41
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/basics_v4.exp42
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/basics_v4_only.exp50
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/basics_v4v6.exp50
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/basics_v4v6_prefer_v4.exp50
-rwxr-xr-xlib/libc/tests/net/getaddrinfo/data/generate_testdata.sh45
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/no_host_v4.exp44
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/no_host_v4_only.exp68
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/no_host_v4v6.exp68
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/no_host_v4v6_prefer_v4.exp68
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/no_serv_v4.exp17
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/no_serv_v4_only.exp20
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6.exp20
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6_prefer_v4.exp20
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/scoped.exp5
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/scoped_v4_only.exp5
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/scoped_v4v6_prefer_v4.exp5
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/sock_raw_v4.exp13
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/sock_raw_v4_only.exp15
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6.exp15
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6_prefer_v4.exp15
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/spec_fam_v4.exp7
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/spec_fam_v4_only.exp10
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6.exp10
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6_prefer_v4.exp10
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/unsup_fam.exp2
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4_only.exp2
-rw-r--r--lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4v6_prefer_v4.exp2
-rw-r--r--lib/libc/tests/net/getaddrinfo/getaddrinfo.c271
-rwxr-xr-xlib/libc/tests/net/getaddrinfo/getaddrinfo_test.sh443
-rw-r--r--lib/libc/tests/net/link_addr_test.cc532
-rw-r--r--lib/libc/tests/secure/Makefile1
-rw-r--r--lib/libc/tests/secure/fortify_signal_test.c316
-rw-r--r--lib/libc/tests/secure/fortify_stdlib_test.c147
-rwxr-xr-xlib/libc/tests/secure/generate-fortify-tests.lua21
-rw-r--r--lib/libc/tests/stdio/scanfloat_test.c136
-rw-r--r--lib/libc/tests/stdlib/Makefile9
-rw-r--r--lib/libc/tests/stdlib/cxa_atexit_test.c132
-rw-r--r--lib/libc/tests/stdlib/getenv_r_test.c69
-rw-r--r--lib/libc/tests/stdlib/libatexit/Makefile11
-rw-r--r--lib/libc/tests/stdlib/libatexit/libatexit.cc67
-rw-r--r--lib/libcam/Makefile5
-rw-r--r--lib/libcasper/services/cap_dns/tests/dns_test.c37
-rw-r--r--lib/libcasper/services/cap_net/cap_net.c55
-rw-r--r--lib/libcasper/services/cap_net/cap_net.h22
-rw-r--r--lib/libcom_err/Makefile2
-rw-r--r--lib/libcompiler_rt/Makefile.inc18
-rw-r--r--lib/libcxxrt/Makefile1
-rw-r--r--lib/libedit/Makefile1
-rw-r--r--lib/libefivar/efivar-dp-format.c1
-rw-r--r--lib/libefivar/efivar-dp-parse.c1
-rw-r--r--lib/libefivar/efivar.c71
-rw-r--r--lib/libefivar/efivar.h17
-rw-r--r--lib/libefivar/uefi-dplib.h8
-rw-r--r--lib/libefivar/uefi-dputil.c1
-rw-r--r--lib/libexpat/expat_config.h6
-rw-r--r--lib/libexpat/libbsdxml.34
-rw-r--r--lib/libgcc_eh/Makefile.inc1
-rw-r--r--lib/libgcc_s/arm/Symbol.map68
-rw-r--r--lib/libifconfig/libifconfig.h2
-rw-r--r--lib/libifconfig/libifconfig_bridge.c54
-rw-r--r--lib/libifconfig/libifconfig_sfp.c2
-rw-r--r--lib/libiscsiutil/libiscsiutil.h4
-rw-r--r--lib/libjail/jail.c84
-rw-r--r--lib/libjail/jail.h1
-rw-r--r--lib/libkvm/kvm_amd64.c46
-rw-r--r--lib/libkvm/kvm_open.315
-rw-r--r--lib/liblutok/Makefile4
-rw-r--r--lib/liblzma/Makefile9
-rw-r--r--lib/liblzma/Symbol.map9
-rw-r--r--lib/liblzma/Versions.def5
-rw-r--r--lib/liblzma/config.h18
-rw-r--r--lib/libmd/Makefile9
-rw-r--r--lib/libmd/aarch64/sha1block.S490
-rw-r--r--lib/libmd/aarch64/sha1dispatch.c24
-rw-r--r--lib/libmd/amd64/sha1block.S1851
-rw-r--r--lib/libmd/amd64/sha1dispatch.c77
-rw-r--r--lib/libmd/i386/sha.S1951
-rw-r--r--lib/libmd/sha1c.c654
-rw-r--r--lib/libnvmf/libnvmf.h6
-rw-r--r--lib/libnvmf/nvmf_host.c21
-rw-r--r--lib/libopenbsd/Makefile3
-rw-r--r--lib/libopenbsd/recallocarray.c82
-rw-r--r--lib/libpam/libpam/Makefile1
-rw-r--r--lib/libpam/modules/pam_krb5/Makefile55
-rw-r--r--lib/libpam/modules/pam_krb5/config.h412
-rw-r--r--lib/libpam/modules/pam_krb5/pam-krb5.81025
-rw-r--r--lib/libpam/modules/pam_krb5/pam_krb5.c4
-rw-r--r--lib/libpam/modules/pam_ksu/Makefile11
-rw-r--r--lib/libpam/modules/pam_ksu/pam_ksu.c62
-rw-r--r--lib/libpam/modules/pam_xdg/pam_xdg.819
-rw-r--r--lib/libpam/pam.d/Makefile11
-rw-r--r--lib/libpam/pam.d/ftp13
-rw-r--r--lib/libpfctl/libpfctl.c132
-rw-r--r--lib/libpfctl/libpfctl.h20
-rw-r--r--lib/libpmcstat/libpmcstat_image.c8
-rw-r--r--lib/libproc/libproc.h2
-rw-r--r--lib/libproc/proc_util.c7
-rw-r--r--lib/libprocstat/Makefile23
-rw-r--r--lib/libprocstat/cd9660.c3
-rw-r--r--lib/libprocstat/libprocstat.c5
-rw-r--r--lib/libprocstat/libprocstat.h1
-rw-r--r--lib/libprocstat/msdosfs.c15
-rw-r--r--lib/libprocstat/smbfs.c3
-rw-r--r--lib/libprocstat/udf.c2
-rw-r--r--lib/libprocstat/zfs.c52
-rw-r--r--lib/libprocstat/zfs/Makefile30
-rw-r--r--lib/libprocstat/zfs/Makefile.depend11
-rw-r--r--lib/libprocstat/zfs_defs.c81
-rw-r--r--lib/libprocstat/zfs_defs.h36
-rw-r--r--lib/libsecureboot/local.trust.mk2
-rw-r--r--lib/libsys/Makefile.sys6
-rw-r--r--lib/libsys/Symbol.sys.map3
-rw-r--r--lib/libsys/_libsys.h6
-rw-r--r--lib/libsys/_umtx_op.22
-rw-r--r--lib/libsys/accept.214
-rw-r--r--lib/libsys/aio_read.26
-rw-r--r--lib/libsys/aio_waitcomplete.26
-rw-r--r--lib/libsys/aio_write.26
-rw-r--r--lib/libsys/amd64/Makefile.sys1
-rw-r--r--lib/libsys/amd64/Symbol.sys.map4
-rw-r--r--lib/libsys/amd64/amd64_set_tlsbase.c (renamed from lib/libc/aarch64/static_tls.h)33
-rw-r--r--lib/libsys/auxv.38
-rw-r--r--lib/libsys/auxv.c28
-rw-r--r--lib/libsys/clock_gettime.218
-rw-r--r--lib/libsys/closefrom.29
-rw-r--r--lib/libsys/execve.27
-rw-r--r--lib/libsys/fcntl.2102
-rw-r--r--lib/libsys/fhopen.219
-rw-r--r--lib/libsys/fork.212
-rw-r--r--lib/libsys/getdirentries.210
-rw-r--r--lib/libsys/getsockopt.22
-rw-r--r--lib/libsys/inotify.2379
-rw-r--r--lib/libsys/nanosleep.254
-rw-r--r--lib/libsys/open.283
-rw-r--r--lib/libsys/pathconf.215
-rw-r--r--lib/libsys/pipe.29
-rw-r--r--lib/libsys/procctl.218
-rw-r--r--lib/libsys/ptrace.212
-rw-r--r--lib/libsys/recv.23
-rw-r--r--lib/libsys/sendfile.28
-rw-r--r--lib/libsys/setcred.22
-rw-r--r--lib/libsys/socket.213
-rw-r--r--lib/libsys/socketpair.25
-rw-r--r--lib/libsys/statfs.28
-rw-r--r--lib/libsys/symlink.26
-rw-r--r--lib/libsys/syscalls.map6
-rw-r--r--lib/libsys/thr_new.29
-rw-r--r--lib/libsys/timer_create.23
-rw-r--r--lib/libsys/wait.28
-rw-r--r--lib/libsys/write.210
-rw-r--r--lib/libsysdecode/Makefile1
-rw-r--r--lib/libsysdecode/flags.c22
-rw-r--r--lib/libsysdecode/mktables3
-rw-r--r--lib/libsysdecode/sysdecode.h1
-rw-r--r--lib/libsysdecode/sysdecode_fcntl_arg.33
-rw-r--r--lib/libtelnet/Makefile3
-rw-r--r--lib/libthr/Makefile1
-rw-r--r--lib/libthr/arch/aarch64/include/pthread_md.h2
-rw-r--r--lib/libthr/arch/aarch64/include/pthread_tls.h44
-rw-r--r--lib/libthr/arch/amd64/Makefile.inc2
-rw-r--r--lib/libthr/arch/amd64/amd64/thr_machdep.c48
-rw-r--r--lib/libthr/arch/amd64/include/pthread_md.h2
-rw-r--r--lib/libthr/arch/amd64/include/pthread_tls.h44
-rw-r--r--lib/libthr/arch/arm/include/pthread_md.h2
-rw-r--r--lib/libthr/arch/arm/include/pthread_tls.h44
-rw-r--r--lib/libthr/arch/i386/include/pthread_md.h2
-rw-r--r--lib/libthr/arch/i386/include/pthread_tls.h44
-rw-r--r--lib/libthr/arch/powerpc/include/pthread_md.h2
-rw-r--r--lib/libthr/arch/powerpc/include/pthread_tls.h44
-rw-r--r--lib/libthr/arch/riscv/include/pthread_md.h2
-rw-r--r--lib/libthr/arch/riscv/include/pthread_tls.h44
-rw-r--r--lib/libthr/pthread.map3
-rw-r--r--lib/libthr/tests/dlopen/dso/Makefile1
-rw-r--r--lib/libthr/thread/thr_condattr.c1
-rw-r--r--lib/libthr/thread/thr_create.c12
-rw-r--r--lib/libthr/thread/thr_init.c8
-rw-r--r--lib/libthr/thread/thr_list.c39
-rw-r--r--lib/libthr/thread/thr_malloc.c13
-rw-r--r--lib/libthr/thread/thr_private.h8
-rw-r--r--lib/libthr/thread/thr_rtld.c26
-rw-r--r--lib/libthr/thread/thr_sig.c19
-rw-r--r--lib/libthr/thread/thr_switch_np.c5
-rw-r--r--lib/libthr/thread/thr_syscalls.c14
-rw-r--r--lib/libufs/Makefile2
-rw-r--r--lib/libunbound/config.h6
-rw-r--r--lib/libusb/libusb.322
-rw-r--r--lib/libusb/libusb.h21
-rw-r--r--lib/libusb/libusb01.c2
-rw-r--r--lib/libusb/libusb10.c232
-rw-r--r--lib/libusb/libusb10.h33
-rw-r--r--lib/libusb/libusb10_desc.c11
-rw-r--r--lib/libusb/libusb10_hotplug.c5
-rw-r--r--lib/libusb/libusb10_io.c24
-rw-r--r--lib/libusb/libusb20.31
-rw-r--r--lib/libusb/libusb20.h1
-rw-r--r--lib/libusb/libusb20_desc.h6
-rw-r--r--lib/libutil/Makefile14
-rw-r--r--lib/libutil/kinfo_getfile.c4
-rw-r--r--lib/libutil/mntopts.3377
-rw-r--r--lib/libutil/mntopts.c300
-rw-r--r--lib/libutil/mntopts.h114
-rw-r--r--lib/libyaml/Makefile29
-rw-r--r--lib/msun/aarch64/fenv.h1
-rw-r--r--lib/msun/arm/fenv.h1
-rw-r--r--lib/msun/riscv/fenv.h1
-rw-r--r--lib/msun/src/math.h1
-rw-r--r--lib/msun/src/s_cbrt.c4
-rw-r--r--lib/msun/src/s_cbrtf.c4
-rw-r--r--lib/msun/src/s_cbrtl.c2
-rw-r--r--lib/ncurses/ncurses/Makefile2
-rw-r--r--lib/ncurses/tinfo/Makefile2
-rw-r--r--lib/ofed/libibnetdisc/Makefile1
329 files changed, 14126 insertions, 4711 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 1f69b4208738..3417e7b30cb4 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -109,6 +109,7 @@ SUBDIR= ${SUBDIR_BOOTSTRAP} \
libwrap \
libxo \
liby \
+ libyaml \
libz \
libzstd \
ncurses \
@@ -175,18 +176,24 @@ SUBDIR.${MK_FILE}+= libmagic
SUBDIR.${MK_GPIO}+= libgpio
SUBDIR.${MK_GSSAPI}+= libgssapi librpcsec_gss
SUBDIR.${MK_ICONV}+= libiconv_modules
+.if ${MK_MITKRB5} == "no"
SUBDIR.${MK_KERBEROS_SUPPORT}+= libcom_err
+.endif
SUBDIR.${MK_LDNS}+= libldns
SUBDIR.${MK_STATS}+= libstats
# The libraries under libclang_rt can only be built by clang.
-.if ${COMPILER_TYPE} == "clang" && ${MK_CLANG} != "no"
+.if (${COMPILER_TYPE} == "clang" || make(clean) || make(cleandir)) && \
+ ${MK_CLANG} != "no"
_libclang_rt= libclang_rt
.elif (${MK_ASAN} != "no" || ${MK_UBSAN} != "no") && make(all)
.error Requested build with sanitizers but cannot build runtime libraries!
.endif
+# This construct disables libefivar for 32-bit build.
+.if ${MACHINE_CPUARCH} != "i386"
SUBDIR.${MK_EFI}+= libefivar
+.endif
SUBDIR.${MK_GOOGLETEST}+= googletest
SUBDIR.${MK_NETGRAPH}+= libnetgraph
SUBDIR.${MK_NIS}+= libypclnt
diff --git a/lib/atf/Makefile.inc b/lib/atf/Makefile.inc
index c776c2f8f84e..f8f329842eb4 100644
--- a/lib/atf/Makefile.inc
+++ b/lib/atf/Makefile.inc
@@ -27,6 +27,3 @@
CFLAGS+= -DHAVE_CONFIG_H
WARNS?= 3
-
-# Permit use of auto_ptr for compilers defaulting to C++17 or later
-CXXSTD= c++11
diff --git a/lib/atf/libatf-c++/Makefile b/lib/atf/libatf-c++/Makefile
index 221a16657c2a..985a79b7dc03 100644
--- a/lib/atf/libatf-c++/Makefile
+++ b/lib/atf/libatf-c++/Makefile
@@ -48,9 +48,6 @@ CFLAGS+= -I.
CFLAGS+= -DHAVE_CONFIG_H
-# Silence warnings about usage of deprecated std::auto_ptr
-CXXWARNFLAGS+= -Wno-deprecated-declarations
-
SRCS= application.cpp \
build.cpp \
check.cpp \
diff --git a/lib/atf/libatf-c/Makefile b/lib/atf/libatf-c/Makefile
index 9fd36dc913f3..4cfee2ed824f 100644
--- a/lib/atf/libatf-c/Makefile
+++ b/lib/atf/libatf-c/Makefile
@@ -119,6 +119,8 @@ MLINKS+= atf-c.3 ATF_CHECK.3 \
atf-c.3 atf_tc_fail.3 \
atf-c.3 atf_tc_fail_nonfatal.3 \
atf-c.3 atf_tc_pass.3 \
+ atf-c.3 atf_tc_require_kmod.3 \
+ atf-c.3 atf_tc_require_prog.3 \
atf-c.3 atf_tc_skip.3 \
atf-c.3 atf_utils_cat_file.3 \
atf-c.3 atf_utils_compare_file.3 \
diff --git a/lib/clang/libclang/Makefile b/lib/clang/libclang/Makefile
index d7e1532d2a8c..7eb2c99b25c8 100644
--- a/lib/clang/libclang/Makefile
+++ b/lib/clang/libclang/Makefile
@@ -1,7 +1,22 @@
.include <bsd.init.mk>
.include "../clang.pre.mk"
+.if defined(TOOLS_PREFIX)
+# Build static library during cross-tools stage
LIB= clang
+INTERNALLIB=
+.else
+PACKAGE= clang
+SHLIB_CXX= clang
+SHLIB_MAJOR= 19
+PRIVATELIB=
+.if ${MACHINE} == "powerpc"
+# Work around "relocation R_PPC_GOT16 out of range" errors
+PICFLAG= -fPIC
+.endif
+.endif
+
+SHARED_CXXFLAGS+= -UPIC # To avoid compile errors
CFLAGS+= -I${.OBJDIR}
CFLAGS+= -I${OBJTOP}/lib/clang/libllvm
@@ -70,7 +85,7 @@ SRCS_MIN+= AST/CommentParser.cpp
SRCS_MIN+= AST/CommentSema.cpp
SRCS_MIN+= AST/ComparisonCategories.cpp
SRCS_MIN+= AST/ComputeDependence.cpp
-SRCS_FUL+= AST/DataCollection.cpp
+SRCS_MIN+= AST/DataCollection.cpp
SRCS_MIN+= AST/Decl.cpp
SRCS_MIN+= AST/DeclBase.cpp
SRCS_MIN+= AST/DeclCXX.cpp
@@ -158,7 +173,9 @@ SRCS_MIN+= AST/VTableBuilder.cpp
SRCS_MIN+= ASTMatchers/ASTMatchFinder.cpp
SRCS_MIN+= ASTMatchers/ASTMatchersInternal.cpp
SRCS_MIN+= ASTMatchers/Dynamic/Diagnostics.cpp
+SRCS_MIN+= ASTMatchers/Dynamic/Marshallers.cpp
SRCS_MIN+= ASTMatchers/Dynamic/Registry.cpp
+SRCS_MIN+= ASTMatchers/Dynamic/VariantValue.cpp
SRCS_MIN+= Analysis/AnalysisDeclContext.cpp
SRCS_MIN+= Analysis/BodyFarm.cpp
SRCS_MIN+= Analysis/CFG.cpp
@@ -424,27 +441,27 @@ SRCS_MIN+= ExtractAPI/DeclarationFragments.cpp
SRCS_MIN+= ExtractAPI/ExtractAPIConsumer.cpp
SRCS_MIN+= ExtractAPI/Serialization/SymbolGraphSerializer.cpp
SRCS_MIN+= ExtractAPI/TypedefUnderlyingTypeResolver.cpp
-SRCS_EXT+= Format/AffectedRangeManager.cpp
-SRCS_EXT+= Format/BreakableToken.cpp
-SRCS_EXT+= Format/ContinuationIndenter.cpp
-SRCS_EXT+= Format/DefinitionBlockSeparator.cpp
-SRCS_EXT+= Format/Format.cpp
-SRCS_EXT+= Format/FormatToken.cpp
-SRCS_EXT+= Format/FormatTokenLexer.cpp
-SRCS_EXT+= Format/IntegerLiteralSeparatorFixer.cpp
-SRCS_EXT+= Format/MacroCallReconstructor.cpp
-SRCS_EXT+= Format/MacroExpander.cpp
+SRCS_MIN+= Format/AffectedRangeManager.cpp
+SRCS_MIN+= Format/BreakableToken.cpp
+SRCS_MIN+= Format/ContinuationIndenter.cpp
+SRCS_MIN+= Format/DefinitionBlockSeparator.cpp
+SRCS_MIN+= Format/Format.cpp
+SRCS_MIN+= Format/FormatToken.cpp
+SRCS_MIN+= Format/FormatTokenLexer.cpp
+SRCS_MIN+= Format/IntegerLiteralSeparatorFixer.cpp
+SRCS_MIN+= Format/MacroCallReconstructor.cpp
+SRCS_MIN+= Format/MacroExpander.cpp
SRCS_EXT+= Format/MatchFilePath.cpp
-SRCS_EXT+= Format/NamespaceEndCommentsFixer.cpp
-SRCS_EXT+= Format/ObjCPropertyAttributeOrderFixer.cpp
-SRCS_EXT+= Format/QualifierAlignmentFixer.cpp
-SRCS_EXT+= Format/SortJavaScriptImports.cpp
-SRCS_EXT+= Format/TokenAnalyzer.cpp
-SRCS_EXT+= Format/TokenAnnotator.cpp
-SRCS_EXT+= Format/UnwrappedLineFormatter.cpp
-SRCS_EXT+= Format/UnwrappedLineParser.cpp
-SRCS_EXT+= Format/UsingDeclarationsSorter.cpp
-SRCS_EXT+= Format/WhitespaceManager.cpp
+SRCS_MIN+= Format/NamespaceEndCommentsFixer.cpp
+SRCS_MIN+= Format/ObjCPropertyAttributeOrderFixer.cpp
+SRCS_MIN+= Format/QualifierAlignmentFixer.cpp
+SRCS_MIN+= Format/SortJavaScriptImports.cpp
+SRCS_MIN+= Format/TokenAnalyzer.cpp
+SRCS_MIN+= Format/TokenAnnotator.cpp
+SRCS_MIN+= Format/UnwrappedLineFormatter.cpp
+SRCS_MIN+= Format/UnwrappedLineParser.cpp
+SRCS_MIN+= Format/UsingDeclarationsSorter.cpp
+SRCS_MIN+= Format/WhitespaceManager.cpp
SRCS_MIN+= Frontend/ASTConsumers.cpp
SRCS_MIN+= Frontend/ASTMerge.cpp
SRCS_MIN+= Frontend/ASTUnit.cpp
@@ -824,10 +841,19 @@ SRCS_MIN+= Tooling/ArgumentsAdjusters.cpp
SRCS_MIN+= Tooling/CommonOptionsParser.cpp
SRCS_MIN+= Tooling/CompilationDatabase.cpp
SRCS_MIN+= Tooling/Core/Replacement.cpp
+SRCS_MIN+= Tooling/DependencyScanning/DependencyScanningFilesystem.cpp
+SRCS_MIN+= Tooling/DependencyScanning/DependencyScanningService.cpp
+SRCS_MIN+= Tooling/DependencyScanning/DependencyScanningTool.cpp
+SRCS_MIN+= Tooling/DependencyScanning/DependencyScanningWorker.cpp
+SRCS_MIN+= Tooling/DependencyScanning/ModuleDepCollector.cpp
+SRCS_MIN+= Tooling/ExpandResponseFilesCompilationDatabase.cpp
SRCS_MIN+= Tooling/FileMatchTrie.cpp
-SRCS_EXT+= Tooling/Inclusions/HeaderIncludes.cpp
-SRCS_EXT+= Tooling/Inclusions/IncludeStyle.cpp
+SRCS_MIN+= Tooling/GuessTargetAndModeCompilationDatabase.cpp
+SRCS_MIN+= Tooling/Inclusions/HeaderIncludes.cpp
+SRCS_MIN+= Tooling/Inclusions/IncludeStyle.cpp
+SRCS_MIN+= Tooling/InterpolatingCompilationDatabase.cpp
SRCS_MIN+= Tooling/JSONCompilationDatabase.cpp
+SRCS_MIN+= Tooling/LocateToolCompilationDatabase.cpp
SRCS_MIN+= Tooling/Refactoring.cpp
SRCS_MIN+= Tooling/RefactoringCallbacks.cpp
SRCS_MIN+= Tooling/Tooling.cpp
@@ -844,6 +870,21 @@ SRCS_ALL+= ${SRCS_LDB}
.endif
SRCS+= ${SRCS_ALL:O}
+LIBDEPS+= llvm
+
+.if defined(TOOLS_PREFIX)
+LIBPRIV=
+LIBEXT= a
+.else
+LIBPRIV= private
+LIBEXT= so
+.endif
+
+.for lib in ${LIBDEPS}
+DPADD+= ${OBJTOP}/lib/clang/lib${lib}/lib${LIBPRIV}${lib}.${LIBEXT}
+LDADD+= ${OBJTOP}/lib/clang/lib${lib}/lib${LIBPRIV}${lib}.${LIBEXT}
+.endfor
+
clang/AST/AbstractBasicReader.inc: \
${CLANG_SRCS}/include/clang/AST/PropertiesBase.td
${CLANG_TBLGEN} -gen-clang-basic-reader \
@@ -1299,6 +1340,4 @@ CLEANFILES+= ${TGHDRS} ${TGHDRS:C/$/.d/}
.include "../clang.build.mk"
-INTERNALLIB=
-
.include <bsd.lib.mk>
diff --git a/lib/clang/liblldb/Makefile b/lib/clang/liblldb/Makefile
index 26edeb966992..a3ff8e367864 100644
--- a/lib/clang/liblldb/Makefile
+++ b/lib/clang/liblldb/Makefile
@@ -1,7 +1,13 @@
.include <bsd.init.mk>
.include "../lldb.pre.mk"
-LIB= lldb
+PACKAGE= lldb
+SHLIB_CXX= lldb
+SHLIB_MAJOR= 19
+PRIVATELIB=
+
+SHARED_CXXFLAGS+= -UPIC # To avoid compile errors
+
SRCDIR= lldb/source
CFLAGS+= -I${LLDB_SRCS}/include
@@ -744,6 +750,19 @@ SRCS+= Utility/VMRange.cpp
SRCS+= Utility/XcodeSDK.cpp
SRCS+= Version/Version.cpp
+LIBDEPS+= clang
+LIBDEPS+= llvm
+
+LIBPRIV= private
+LIBEXT= so
+
+.for lib in ${LIBDEPS}
+DPADD+= ${OBJTOP}/lib/clang/lib${lib}/lib${LIBPRIV}${lib}.${LIBEXT}
+LDADD+= ${OBJTOP}/lib/clang/lib${lib}/lib${LIBPRIV}${lib}.${LIBEXT}
+.endfor
+
+LIBADD+= kvm
+
LLDB_TBLGEN?= lldb-tblgen
CommandOptions.inc: ${LLDB_SRCS}/source/Commands/Options.td
@@ -779,8 +798,6 @@ CLEANFILES+= ${TGHDRS} ${TGHDRS:C/$/.d/}
.include "../clang.build.mk"
-INTERNALLIB=
-
# Building lldb's bindings requires swig, but we do not want to include it in
# the FreeBSD base system (as a build tool) because it has non-trivial
# dependencies. As a workaround we commit the generated file. Requires the
diff --git a/lib/clang/libllvm/Makefile b/lib/clang/libllvm/Makefile
index 455d32b6f329..e634a72b4f90 100644
--- a/lib/clang/libllvm/Makefile
+++ b/lib/clang/libllvm/Makefile
@@ -1,8 +1,22 @@
.include <bsd.init.mk>
.include "../llvm.pre.mk"
+.if defined(TOOLS_PREFIX)
+# Build static library during cross-tools stage
LIB= llvm
INTERNALLIB=
+.else
+PACKAGE= clang
+SHLIB_CXX= llvm
+SHLIB_MAJOR= 19
+PRIVATELIB=
+.if ${MACHINE} == "powerpc"
+# Work around "relocation R_PPC_GOT16 out of range" errors
+PICFLAG= -fPIC
+.endif
+.endif
+
+SHARED_CXXFLAGS+= -UPIC # To avoid compile errors
CFLAGS+= -I${.OBJDIR}
CFLAGS+= -I${SRCTOP}/sys/contrib/zstd/lib
@@ -139,7 +153,6 @@ SRCS_MIN+= Analysis/RegionPass.cpp
SRCS_MIN+= Analysis/RegionPrinter.cpp
SRCS_MIN+= Analysis/ReplayInlineAdvisor.cpp
SRCS_MIN+= Analysis/ScalarEvolution.cpp
-SRCS_MIN+= Analysis/ScalarEvolution.cpp
SRCS_MIN+= Analysis/ScalarEvolutionAliasAnalysis.cpp
SRCS_MIN+= Analysis/ScalarEvolutionDivision.cpp
SRCS_MIN+= Analysis/ScalarEvolutionNormalization.cpp
@@ -509,24 +522,24 @@ SRCS_EXT+= DWP/DWP.cpp
SRCS_EXT+= DWP/DWPError.cpp
SRCS_MIW+= DebugInfo/BTF/BTFContext.cpp
SRCS_MIW+= DebugInfo/BTF/BTFParser.cpp
-SRCS_EXT+= DebugInfo/CodeView/AppendingTypeTableBuilder.cpp
+SRCS_MIN+= DebugInfo/CodeView/AppendingTypeTableBuilder.cpp
SRCS_MIN+= DebugInfo/CodeView/CVSymbolVisitor.cpp
SRCS_MIN+= DebugInfo/CodeView/CVTypeVisitor.cpp
SRCS_MIN+= DebugInfo/CodeView/CodeViewError.cpp
SRCS_MIN+= DebugInfo/CodeView/CodeViewRecordIO.cpp
SRCS_MIN+= DebugInfo/CodeView/ContinuationRecordBuilder.cpp
SRCS_MIN+= DebugInfo/CodeView/DebugChecksumsSubsection.cpp
-SRCS_EXT+= DebugInfo/CodeView/DebugCrossExSubsection.cpp
-SRCS_EXT+= DebugInfo/CodeView/DebugCrossImpSubsection.cpp
+SRCS_MIN+= DebugInfo/CodeView/DebugCrossExSubsection.cpp
+SRCS_MIN+= DebugInfo/CodeView/DebugCrossImpSubsection.cpp
SRCS_MIN+= DebugInfo/CodeView/DebugFrameDataSubsection.cpp
SRCS_MIN+= DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp
SRCS_MIN+= DebugInfo/CodeView/DebugLinesSubsection.cpp
SRCS_MIN+= DebugInfo/CodeView/DebugStringTableSubsection.cpp
-SRCS_MIW+= DebugInfo/CodeView/DebugSubsection.cpp
-SRCS_EXT+= DebugInfo/CodeView/DebugSubsectionRecord.cpp
-SRCS_EXT+= DebugInfo/CodeView/DebugSubsectionVisitor.cpp
-SRCS_EXT+= DebugInfo/CodeView/DebugSymbolRVASubsection.cpp
-SRCS_EXT+= DebugInfo/CodeView/DebugSymbolsSubsection.cpp
+SRCS_MIN+= DebugInfo/CodeView/DebugSubsection.cpp
+SRCS_MIN+= DebugInfo/CodeView/DebugSubsectionRecord.cpp
+SRCS_MIN+= DebugInfo/CodeView/DebugSubsectionVisitor.cpp
+SRCS_MIN+= DebugInfo/CodeView/DebugSymbolRVASubsection.cpp
+SRCS_MIN+= DebugInfo/CodeView/DebugSymbolsSubsection.cpp
SRCS_MIN+= DebugInfo/CodeView/EnumTables.cpp
SRCS_MIN+= DebugInfo/CodeView/Formatters.cpp
SRCS_MIN+= DebugInfo/CodeView/GlobalTypeTableBuilder.cpp
@@ -540,7 +553,7 @@ SRCS_EXT+= DebugInfo/CodeView/StringsAndChecksums.cpp
SRCS_MIN+= DebugInfo/CodeView/SymbolDumper.cpp
SRCS_MIN+= DebugInfo/CodeView/SymbolRecordHelpers.cpp
SRCS_MIN+= DebugInfo/CodeView/SymbolRecordMapping.cpp
-SRCS_EXT+= DebugInfo/CodeView/SymbolSerializer.cpp
+SRCS_MIN+= DebugInfo/CodeView/SymbolSerializer.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeDumpVisitor.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeHashing.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeIndex.cpp
@@ -549,37 +562,37 @@ SRCS_EXT+= DebugInfo/CodeView/TypeRecordHelpers.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeRecordMapping.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeStreamMerger.cpp
SRCS_MIN+= DebugInfo/CodeView/TypeTableCollection.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFAcceleratorTable.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFAddressRange.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFCompileUnit.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFContext.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDataExtractor.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugAbbrev.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugAddr.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugArangeSet.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugAranges.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugFrame.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugLine.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugLoc.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugMacro.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugPubTable.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugRangeList.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDebugRnglists.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFDie.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFAcceleratorTable.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFAddressRange.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFCompileUnit.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFContext.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDataExtractor.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugAbbrev.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugAddr.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugArangeSet.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugAranges.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugFrame.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugLine.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugLoc.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugMacro.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugPubTable.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugRangeList.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDebugRnglists.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFDie.cpp
SRCS_MIN+= DebugInfo/DWARF/DWARFExpression.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFFormValue.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFGdbIndex.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFListTable.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFTypePrinter.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFTypeUnit.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFUnit.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFUnitIndex.cpp
-SRCS_MIW+= DebugInfo/DWARF/DWARFVerifier.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFFormValue.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFGdbIndex.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFListTable.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFTypePrinter.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFTypeUnit.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFUnit.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFUnitIndex.cpp
+SRCS_MIN+= DebugInfo/DWARF/DWARFVerifier.cpp
SRCS_MIN+= DebugInfo/MSF/MSFBuilder.cpp
SRCS_MIN+= DebugInfo/MSF/MSFCommon.cpp
-SRCS_EXT+= DebugInfo/MSF/MSFError.cpp
+SRCS_MIN+= DebugInfo/MSF/MSFError.cpp
SRCS_MIN+= DebugInfo/MSF/MappedBlockStream.cpp
SRCS_EXT+= DebugInfo/PDB/GenericError.cpp
SRCS_EXT+= DebugInfo/PDB/IPDBSourceFile.cpp
@@ -867,7 +880,7 @@ SRCS_MIN+= LTO/LTO.cpp
SRCS_MIN+= LTO/LTOBackend.cpp
SRCS_EXL+= LTO/LTOCodeGenerator.cpp
SRCS_EXL+= LTO/LTOModule.cpp
-SRCS_EXL+= LTO/SummaryBasedOptimizations.cpp
+SRCS_MIN+= LTO/SummaryBasedOptimizations.cpp
SRCS_EXL+= LTO/ThinLTOCodeGenerator.cpp
SRCS_MIN+= LTO/UpdateCompilerUsed.cpp
SRCS_MIN+= Linker/IRMover.cpp
@@ -892,7 +905,7 @@ SRCS_MIN+= MC/MCContext.cpp
SRCS_MIN+= MC/MCDXContainerStreamer.cpp
SRCS_MIN+= MC/MCDXContainerWriter.cpp
SRCS_XDL+= MC/MCDisassembler/Disassembler.cpp
-SRCS_XDW+= MC/MCDisassembler/MCDisassembler.cpp
+SRCS_MIN+= MC/MCDisassembler/MCDisassembler.cpp
SRCS_XDW+= MC/MCDisassembler/MCExternalSymbolizer.cpp
SRCS_MIN+= MC/MCDisassembler/MCRelocationInfo.cpp
SRCS_XDW+= MC/MCDisassembler/MCSymbolizer.cpp
@@ -1006,9 +1019,9 @@ SRCS_MIW+= ObjCopy/wasm/WasmWriter.cpp
SRCS_MIN+= Object/Archive.cpp
SRCS_MIN+= Object/ArchiveWriter.cpp
SRCS_MIN+= Object/Binary.cpp
-SRCS_MIW+= Object/BuildID.cpp
+SRCS_MIN+= Object/BuildID.cpp
SRCS_MIN+= Object/COFFImportFile.cpp
-SRCS_MIW+= Object/COFFModuleDefinition.cpp
+SRCS_MIN+= Object/COFFModuleDefinition.cpp
SRCS_MIN+= Object/COFFObjectFile.cpp
SRCS_MIN+= Object/Decompressor.cpp
SRCS_MIN+= Object/ELF.cpp
@@ -1018,31 +1031,34 @@ SRCS_MIW+= Object/FaultMapParser.cpp
SRCS_MIN+= Object/IRObjectFile.cpp
SRCS_MIN+= Object/IRSymtab.cpp
SRCS_MIN+= Object/MachOObjectFile.cpp
-SRCS_MIW+= Object/MachOUniversal.cpp
+SRCS_MIN+= Object/MachOUniversal.cpp
SRCS_MIW+= Object/MachOUniversalWriter.cpp
-SRCS_MIW+= Object/Minidump.cpp
+SRCS_MIN+= Object/Minidump.cpp
SRCS_MIN+= Object/ModuleSymbolTable.cpp
SRCS_EXT+= Object/Object.cpp
SRCS_MIN+= Object/ObjectFile.cpp
-SRCS_MIW+= Object/OffloadBinary.cpp
+SRCS_MIN+= Object/OffloadBinary.cpp
SRCS_MIN+= Object/RecordStreamer.cpp
-SRCS_MIW+= Object/RelocationResolver.cpp
+SRCS_MIN+= Object/RelocationResolver.cpp
SRCS_MIW+= Object/SymbolSize.cpp
SRCS_MIN+= Object/SymbolicFile.cpp
-SRCS_MIW+= Object/TapiFile.cpp
-SRCS_MIW+= Object/TapiUniversal.cpp
+SRCS_MIN+= Object/TapiFile.cpp
+SRCS_MIN+= Object/TapiUniversal.cpp
SRCS_MIN+= Object/WasmObjectFile.cpp
SRCS_MIW+= Object/WindowsMachineFlag.cpp
SRCS_MIN+= Object/WindowsResource.cpp
SRCS_MIN+= Object/XCOFFObjectFile.cpp
SRCS_MIN+= ObjectYAML/COFFYAML.cpp
-SRCS_EXT+= ObjectYAML/CodeViewYAMLDebugSections.cpp
-SRCS_EXT+= ObjectYAML/CodeViewYAMLSymbols.cpp
-SRCS_EXT+= ObjectYAML/CodeViewYAMLTypes.cpp
+SRCS_MIN+= ObjectYAML/CodeViewYAMLDebugSections.cpp
+SRCS_MIN+= ObjectYAML/CodeViewYAMLSymbols.cpp
+SRCS_MIN+= ObjectYAML/CodeViewYAMLTypeHashing.cpp
+SRCS_MIN+= ObjectYAML/CodeViewYAMLTypes.cpp
+SRCS_MIN+= ObjectYAML/DWARFEmitter.cpp
SRCS_MIN+= ObjectYAML/DWARFYAML.cpp
+SRCS_MIN+= ObjectYAML/ELFEmitter.cpp
SRCS_MIN+= ObjectYAML/ELFYAML.cpp
SRCS_MIN+= ObjectYAML/MachOYAML.cpp
-SRCS_EXT+= ObjectYAML/YAML.cpp
+SRCS_MIN+= ObjectYAML/YAML.cpp
SRCS_MIN+= Option/Arg.cpp
SRCS_MIN+= Option/ArgList.cpp
SRCS_MIN+= Option/OptTable.cpp
@@ -1135,7 +1151,7 @@ SRCS_MIN+= Support/ErrorHandling.cpp
SRCS_MIN+= Support/ExponentialBackoff.cpp
SRCS_MIN+= Support/ExtensibleRTTI.cpp
SRCS_MIN+= Support/FileCollector.cpp
-SRCS_MIW+= Support/FileOutputBuffer.cpp
+SRCS_MIN+= Support/FileOutputBuffer.cpp
SRCS_MIN+= Support/FileUtilities.cpp
SRCS_MIN+= Support/FloatingPointMode.cpp
SRCS_MIN+= Support/FoldingSet.cpp
@@ -1161,7 +1177,7 @@ SRCS_MIW+= Support/MSP430Attributes.cpp
SRCS_MIN+= Support/ManagedStatic.cpp
SRCS_MIN+= Support/MathExtras.cpp
SRCS_MIN+= Support/MemAlloc.cpp
-SRCS_MIW+= Support/Memory.cpp
+SRCS_MIN+= Support/Memory.cpp
SRCS_MIN+= Support/MemoryBuffer.cpp
SRCS_MIN+= Support/MemoryBufferRef.cpp
SRCS_MIN+= Support/NativeFormatting.cpp
@@ -1200,7 +1216,7 @@ SRCS_MIN+= Support/SuffixTree.cpp
SRCS_MIN+= Support/SuffixTreeNode.cpp
SRCS_EXT+= Support/SystemUtils.cpp
SRCS_LLD+= Support/TarWriter.cpp
-SRCS_MIW+= Support/ThreadPool.cpp
+SRCS_MIN+= Support/ThreadPool.cpp
SRCS_MIN+= Support/Threading.cpp
SRCS_MIN+= Support/TimeProfiler.cpp
SRCS_MIN+= Support/Timer.cpp
@@ -1695,21 +1711,22 @@ SRCS_MIN+= TargetParser/SubtargetFeature.cpp
SRCS_MIN+= TargetParser/TargetParser.cpp
SRCS_MIN+= TargetParser/Triple.cpp
SRCS_MIN+= TargetParser/X86TargetParser.cpp
-SRCS_MIW+= TextAPI/Architecture.cpp
-SRCS_MIW+= TextAPI/ArchitectureSet.cpp
+SRCS_MIN+= TextAPI/Architecture.cpp
+SRCS_MIN+= TextAPI/ArchitectureSet.cpp
SRCS_MIW+= TextAPI/BinaryReader/DylibReader.cpp
-SRCS_MIW+= TextAPI/InterfaceFile.cpp
-SRCS_MIW+= TextAPI/PackedVersion.cpp
-SRCS_MIW+= TextAPI/Platform.cpp
+SRCS_MIN+= TextAPI/InterfaceFile.cpp
+SRCS_MIN+= TextAPI/PackedVersion.cpp
+SRCS_MIN+= TextAPI/Platform.cpp
SRCS_MIW+= TextAPI/RecordVisitor.cpp
-SRCS_MIW+= TextAPI/Symbol.cpp
-SRCS_MIW+= TextAPI/SymbolSet.cpp
-SRCS_MIW+= TextAPI/Target.cpp
-SRCS_MIW+= TextAPI/TextAPIError.cpp
-SRCS_MIW+= TextAPI/TextStub.cpp
-SRCS_MIW+= TextAPI/TextStubCommon.cpp
-SRCS_MIW+= TextAPI/TextStubV5.cpp
-SRCS_MIW+= TextAPI/Utils.cpp
+SRCS_MIW+= TextAPI/RecordsSlice.cpp
+SRCS_MIN+= TextAPI/Symbol.cpp
+SRCS_MIN+= TextAPI/SymbolSet.cpp
+SRCS_MIN+= TextAPI/Target.cpp
+SRCS_MIN+= TextAPI/TextAPIError.cpp
+SRCS_MIN+= TextAPI/TextStub.cpp
+SRCS_MIN+= TextAPI/TextStubCommon.cpp
+SRCS_MIN+= TextAPI/TextStubV5.cpp
+SRCS_MIN+= TextAPI/Utils.cpp
SRCS_MIN+= ToolDrivers/llvm-dlltool/DlltoolDriver.cpp
SRCS_MIW+= ToolDrivers/llvm-lib/LibDriver.cpp
SRCS_MIN+= Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp
diff --git a/lib/clang/llvm.build.mk b/lib/clang/llvm.build.mk
index 2520637e2d06..e88b2ff1033e 100644
--- a/lib/clang/llvm.build.mk
+++ b/lib/clang/llvm.build.mk
@@ -119,7 +119,7 @@ LDFLAGS+= -Wl,-m,elf64lriscv_fbsd
.endif
.endif
-CXXSTD?= c++17
+CXXSTD= c++17
CXXFLAGS+= -fno-exceptions
CXXFLAGS+= -fno-rtti
.if ${.MAKE.OS} == "FreeBSD" || !defined(BOOTSTRAPPING)
diff --git a/lib/csu/common/crtbegin.c b/lib/csu/common/crtbegin.c
index 06fe990052f7..8ef9b8923c21 100644
--- a/lib/csu/common/crtbegin.c
+++ b/lib/csu/common/crtbegin.c
@@ -98,36 +98,3 @@ asm (
".popsection \n"
);
#endif
-
-/*
- * Handler for gcj. These provide a _Jv_RegisterClasses function and fill
- * out the .jcr section. We just need to call this function with a pointer
- * to the appropriate section.
- */
-extern void _Jv_RegisterClasses(void *) __weak_symbol;
-static void register_classes(void) __used;
-
-static crt_func __JCR_LIST__[] __section(".jcr") __used = { };
-
-#ifndef CTORS_CONSTRUCTORS
-__attribute__((constructor))
-#endif
-static void
-register_classes(void)
-{
-
- if (_Jv_RegisterClasses != NULL && __JCR_LIST__[0] != 0)
- _Jv_RegisterClasses(__JCR_LIST__);
-}
-
-/*
- * We can't use constructors when they use the .ctors section as they may be
- * placed before __CTOR_LIST__.
- */
-#ifdef CTORS_CONSTRUCTORS
-asm (
- ".pushsection .init \n"
- "\t" INIT_CALL_SEQ(register_classes) "\n"
- ".popsection \n"
-);
-#endif
diff --git a/lib/csu/common/crtend.c b/lib/csu/common/crtend.c
index bf25c1d836a9..9eb75de2ef60 100644
--- a/lib/csu/common/crtend.c
+++ b/lib/csu/common/crtend.c
@@ -26,10 +26,6 @@
typedef void (*crt_func)(void);
-static crt_func __JCR_END__[] __section(".jcr") __used = {
- (crt_func)0
-};
-
#ifdef HAVE_CTORS
/*
diff --git a/lib/csu/tests/Makefile b/lib/csu/tests/Makefile
index c9a0e6eff5da..b76ef590c88f 100644
--- a/lib/csu/tests/Makefile
+++ b/lib/csu/tests/Makefile
@@ -4,6 +4,7 @@ SUBDIR= dso
TESTS_SUBDIRS= dynamic
TESTS_SUBDIRS+= dynamiclib
TESTS_SUBDIRS+= dynamicpie
+TESTS_SUBDIRS+= errno
TESTS_SUBDIRS+= static
SUBDIR_DEPEND_dynamiclib=dso
diff --git a/lib/csu/tests/dso/Makefile b/lib/csu/tests/dso/Makefile
index 6c1d00e9fb58..431168de0328 100644
--- a/lib/csu/tests/dso/Makefile
+++ b/lib/csu/tests/dso/Makefile
@@ -1,4 +1,6 @@
.PATH: ${.CURDIR:H}
+
+PACKAGE= tests
SHLIB= h_csu
SHLIB_NAME= libh_csu.so
SHLIB_MAJOR= 1
diff --git a/lib/csu/tests/errno/Makefile b/lib/csu/tests/errno/Makefile
new file mode 100644
index 000000000000..eae54a936294
--- /dev/null
+++ b/lib/csu/tests/errno/Makefile
@@ -0,0 +1,18 @@
+PLAIN_TESTS_C= errno_test \
+ errno_static_test \
+ errno_thr_test \
+ errno_thr_static_test
+
+SRCS.errno_static_test= errno_test.c
+LDFLAGS.errno_static_test= -static
+
+SRCS.errno_thr_test= errno_test.c
+LIBADD.errno_thr_test= pthread
+
+SRCS.errno_thr_static_test= errno_test.c
+LDFLAGS.errno_thr_static_test= -static
+LIBADD.errno_thr_static_test= pthread
+
+MK_PIE:= no
+
+.include <bsd.test.mk>
diff --git a/lib/csu/tests/errno/errno_test.c b/lib/csu/tests/errno/errno_test.c
new file mode 100644
index 000000000000..d190c7fd2959
--- /dev/null
+++ b/lib/csu/tests/errno/errno_test.c
@@ -0,0 +1,23 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Mark Johnston <markj@FreeBSD.org>
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+
+static void __attribute__((constructor))
+f(void)
+{
+ errno = 42;
+}
+
+int
+main(void)
+{
+ /* errno must be zero upon program startup. */
+ if (errno != 0)
+ exit(1);
+ exit(0);
+}
diff --git a/lib/csu/tests/init_test.c b/lib/csu/tests/init_test.c
index 47bd9b7e64d7..2d4484735f76 100644
--- a/lib/csu/tests/init_test.c
+++ b/lib/csu/tests/init_test.c
@@ -38,9 +38,6 @@
typedef void (*func_ptr)(void);
-extern volatile int jcr_run;
-extern const func_ptr *jcr_ptr;
-extern const void *jcr_func_ptr;
extern volatile int ctors_run;
extern volatile int preinit_array_run;
extern volatile int preinit_array_state;
@@ -48,37 +45,11 @@ extern volatile int init_array_run;
extern volatile int init_array_state;
#ifndef DSO_BASE
-volatile int jcr_run;
-const func_ptr *jcr_ptr;
volatile int ctors_run;
volatile int preinit_array_run;
volatile int preinit_array_state = -1;
volatile int init_array_run;
volatile int init_array_state = -1;
-
-void _Jv_RegisterClasses(const func_ptr *);
-
-__section(".jcr") __used static func_ptr jcr_func = (func_ptr)1;
-const void *jcr_func_ptr = &jcr_func;
-
-void
-_Jv_RegisterClasses(const func_ptr *jcr)
-{
-
- jcr_run = 1;
- jcr_ptr = jcr;
-}
-#endif
-
-#ifndef DSO_LIB
-ATF_TC_WITHOUT_HEAD(jcr_test);
-ATF_TC_BODY(jcr_test, tc)
-{
-
- ATF_REQUIRE_MSG(jcr_run == 1, ".jcr not run");
- ATF_REQUIRE_MSG(jcr_ptr == jcr_func_ptr,
- "Incorrect pointer passed to _Jv_RegisterClasses");
-}
#endif
#ifndef DSO_BASE
@@ -160,7 +131,6 @@ ATF_TC_BODY(init_array_test, tc)
ATF_TP_ADD_TCS(tp)
{
- ATF_TP_ADD_TC(tp, jcr_test);
ATF_TP_ADD_TC(tp, ctors_test);
ATF_TP_ADD_TC(tp, preinit_array_test);
ATF_TP_ADD_TC(tp, init_array_test);
diff --git a/lib/geom/eli/geli.8 b/lib/geom/eli/geli.8
index d34e15dc4ad8..876caf67ab40 100644
--- a/lib/geom/eli/geli.8
+++ b/lib/geom/eli/geli.8
@@ -857,7 +857,7 @@ must allocate a buffer for every write operation, used when performing
encryption.
This sysctl reports the maximum size in bytes for which geli will perform the
allocation using
-.Xr UMA 9 ,
+.Xr uma 9 ,
as opposed to
.Xr malloc 9 .
.It Va kern.geom.eli.visible_passphrase : No 0
diff --git a/lib/geom/raid/graid.8 b/lib/geom/raid/graid.8
index f722fd5c17bd..4ef0cd22e703 100644
--- a/lib/geom/raid/graid.8
+++ b/lib/geom/raid/graid.8
@@ -275,7 +275,7 @@ NVIDIA metadata format does not support volumes above 2TiB.
.Sh SYSCTL VARIABLES
The following
.Xr sysctl 8
-variable can be used to control the behavior of the
+variables can be used to control the behavior of the
.Nm RAID
GEOM class.
.Bl -tag -width indent
diff --git a/lib/lib80211/regdomain.xml b/lib/lib80211/regdomain.xml
index 557af0349cb0..16b74445f429 100644
--- a/lib/lib80211/regdomain.xml
+++ b/lib/lib80211/regdomain.xml
@@ -494,6 +494,10 @@
<flags>IEEE80211_CHAN_PASSIVE</flags>
<flags>IEEE80211_CHAN_DFS</flags>
</band>
+ <band>
+ <freqband ref="A20_5745_5865"/>
+ <maxpower>13</maxpower>
+ </band>
</netband>
<netband mode="11ng">
<band>
@@ -548,6 +552,14 @@
<flags>IEEE80211_CHAN_PASSIVE</flags>
<flags>IEEE80211_CHAN_DFS</flags>
</band>
+ <band>
+ <freqband ref="NA20_5745_5865"/>
+ <maxpower>13</maxpower>
+ </band>
+ <band>
+ <freqband ref="NA40_5745_5845"/>
+ <maxpower>13</maxpower>
+ </band>
</netband>
<netband mode="11ac">
<!-- 5150-5250/80, 200 mW, indoor -->
@@ -645,7 +657,7 @@
<flags>IEEE80211_CHAN_DFS</flags>
</band>
<band>
- <freqband ref="AC2_5745_5805_40"/>
+ <freqband ref="AC2_5745_5845_40"/>
<maxpower>13</maxpower>
<flags>IEEE80211_CHAN_HT40</flags>
<flags>IEEE80211_CHAN_VHT40</flags>
@@ -658,13 +670,6 @@
<flags>IEEE80211_CHAN_VHT80</flags>
<flags>IEEE80211_CHAN_DFS</flags>
</band>
- <band>
- <freqband ref="AC2_5745_5885_160"/>
- <maxpower>13</maxpower>
- <flags>IEEE80211_CHAN_HT40</flags>
- <flags>IEEE80211_CHAN_VHT160</flags>
- <flags>IEEE80211_CHAN_DFS</flags>
- </band>
</netband>
</rd>
@@ -1187,6 +1192,202 @@
</netband>
</rd>
+<rd id="taiwan">
+ <name>TAIWAN</name>
+ <netband mode="11b">
+ <band>
+ <freqband ref="F1_2412_2472"/>
+ <maxpower>30</maxpower>
+ <flags>IEEE80211_CHAN_B</flags>
+ </band>
+ </netband>
+
+ <netband mode="11g">
+ <band>
+ <freqband ref="F1_2412_2472"/>
+ <maxpower>30</maxpower>
+ <flags>IEEE80211_CHAN_G</flags>
+ </band>
+ </netband>
+
+ <netband mode="11ng">
+ <band>
+ <freqband ref="F1_2412_2472"/>
+ <maxpower>30</maxpower>
+ <flags>IEEE80211_CHAN_G</flags>
+ <flags>IEEE80211_CHAN_HT20</flags>
+ </band>
+ <band>
+ <freqband ref="H4_2412_2472"/>
+ <maxpower>30</maxpower>
+ <flags>IEEE80211_CHAN_G</flags>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ </band>
+ </netband>
+
+ <netband mode="11a">
+ <band>
+ <freqband ref="F1_5160_5240"/>
+ <maxpower>23</maxpower>
+ </band>
+ <band>
+ <freqband ref="F1_5260_5340"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+ <band>
+ <freqband ref="F1_5480_5720"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+ <band>
+ <freqband ref="F1_5745_5845"/>
+ <maxpower>30</maxpower>
+ </band>
+ </netband>
+
+ <netband mode="11na">
+ <band>
+ <freqband ref="F1_5160_5240"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT20</flags>
+ </band>
+ <band>
+ <freqband ref="H4_5180_5240"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ </band>
+
+ <band>
+ <freqband ref="F1_5260_5340"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT20</flags>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+ <band>
+ <freqband ref="H4_5260_5320"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+
+ <band>
+ <freqband ref="F1_5480_5720"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT20</flags>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+ <band>
+ <freqband ref="H4_5500_5720"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+
+ <band>
+ <freqband ref="F1_5745_5845"/>
+ <maxpower>30</maxpower>
+ <flags>IEEE80211_CHAN_HT20</flags>
+ </band>
+ <band>
+ <freqband ref="H4_5745_5845"/>
+ <maxpower>30</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ </band>
+ </netband>
+
+ <netband mode="11ac">
+ <band>
+ <freqband ref="AC2_5160_5240_20"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT20</flags>
+ <flags>IEEE80211_CHAN_VHT20</flags>
+ </band>
+ <band>
+ <freqband ref="AC2_5180_5240_40"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ <flags>IEEE80211_CHAN_VHT40</flags>
+ </band>
+ <band>
+ <freqband ref="AC2_5180_5240_80"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ <flags>IEEE80211_CHAN_VHT80</flags>
+ </band>
+
+ <band>
+ <freqband ref="AC2_5260_5340_20"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT20</flags>
+ <flags>IEEE80211_CHAN_VHT20</flags>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+ <band>
+ <freqband ref="AC2_5260_5320_40"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ <flags>IEEE80211_CHAN_VHT40</flags>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+ <band>
+ <freqband ref="AC2_5260_5320_80"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ <flags>IEEE80211_CHAN_VHT80</flags>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+
+ <band>
+ <freqband ref="AC2_5480_5700_20"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT20</flags>
+ <flags>IEEE80211_CHAN_VHT20</flags>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+ <band>
+ <freqband ref="AC2_5500_5720_40"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ <flags>IEEE80211_CHAN_VHT40</flags>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+ <band>
+ <freqband ref="AC2_5500_5720_80"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ <flags>IEEE80211_CHAN_VHT80</flags>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+ <band>
+ <freqband ref="AC2_5500_5640_160"/>
+ <maxpower>23</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ <flags>IEEE80211_CHAN_VHT160</flags>
+ <flags>IEEE80211_CHAN_DFS</flags>
+ </band>
+
+ <band>
+ <freqband ref="AC2_5745_5845_20"/>
+ <maxpower>30</maxpower>
+ <flags>IEEE80211_CHAN_HT20</flags>
+ <flags>IEEE80211_CHAN_VHT20</flags>
+ </band>
+ <band>
+ <freqband ref="AC2_5745_5845_40"/>
+ <maxpower>30</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ <flags>IEEE80211_CHAN_VHT40</flags>
+ </band>
+ <band>
+ <freqband ref="AC2_5745_5805_80"/>
+ <maxpower>30</maxpower>
+ <flags>IEEE80211_CHAN_HT40</flags>
+ <flags>IEEE80211_CHAN_VHT80</flags>
+ </band>
+ </netband>
+</rd>
+
<!-- Rest Of World -->
<rd id="row">
@@ -1781,7 +1982,7 @@
<isocc>760</isocc> <name>Syria</name> <rd ref="none"/>
</country>
<country id="TW">
- <isocc>158</isocc> <name>Taiwan</name> <rd ref="row"/>
+ <isocc>158</isocc> <name>Taiwan</name> <rd ref="taiwan"/>
</country>
<country id="TH">
<isocc>764</isocc> <name>Thailand</name> <rd ref="none"/>
@@ -1904,6 +2105,11 @@
<flags>IEEE80211_CHAN_A</flags>
</freqband>
<!-- 5150-5250/80 -->
+<freqband id="F1_5160_5240">
+ <freqstart>5120</freqstart> <freqend>5240</freqend>
+ <chanwidth>20</chanwidth> <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
<freqband id="AC2_5160_5240_20">
<freqstart>5160</freqstart> <freqend>5240</freqend>
<chanwidth>20</chanwidth> <chansep>20</chansep>
@@ -1925,6 +2131,11 @@
<flags>IEEE80211_CHAN_A</flags>
</freqband>
<!-- 5250-5350/80 -->
+<freqband id="F1_5260_5340">
+ <freqstart>5260</freqstart> <freqend>5340</freqend>
+ <chanwidth>20</chanwidth> <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
<freqband id="AC2_5260_5340_20">
<freqstart>5260</freqstart> <freqend>5340</freqend>
<chanwidth>20</chanwidth> <chansep>20</chansep>
@@ -1941,6 +2152,11 @@
<flags>IEEE80211_CHAN_A</flags>
</freqband>
<!-- 5470-5725/160 -->
+<freqband id="F1_5480_5720">
+ <freqstart>5480</freqstart> <freqend>5720</freqend>
+ <chanwidth>20</chanwidth> <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
<freqband id="AC2_5480_5700_20">
<freqstart>5480</freqstart> <freqend>5700</freqend>
<chanwidth>20</chanwidth> <chansep>20</chansep>
@@ -1961,7 +2177,38 @@
<chanwidth>160</chanwidth> <chansep>20</chansep>
<flags>IEEE80211_CHAN_A</flags>
</freqband>
+<!-- 5500-5720/80 -->
+<freqband id="AC2_5500_5720_40">
+ <freqstart>5500</freqstart> <freqend>5720</freqend>
+ <chanwidth>40</chanwidth> <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="AC2_5500_5720_80">
+ <freqstart>5500</freqstart> <freqend>5720</freqend>
+ <chanwidth>80</chanwidth> <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
<!-- 5725-5875/80 short range -->
+<freqband id="F1_5745_5825">
+ <freqstart>5745</freqstart> <freqend>5825</freqend>
+ <chanwidth>20</chanwidth> <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="F1_5745_5845">
+ <freqstart>5745</freqstart> <freqend>5845</freqend>
+ <chanwidth>20</chanwidth> <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="H4_5745_5845">
+ <freqstart>5745</freqstart> <freqend>5845</freqend>
+ <chanwidth>40</chanwidth> <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="AC2_5745_5845_20">
+ <freqstart>5745</freqstart> <freqend>5845</freqend>
+ <chanwidth>20</chanwidth> <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
<freqband id="AC2_5745_5865_20">
<freqstart>5745</freqstart> <freqend>5865</freqend>
<chanwidth>20</chanwidth> <chansep>20</chansep>
@@ -1972,6 +2219,11 @@
<chanwidth>40</chanwidth> <chansep>20</chansep>
<flags>IEEE80211_CHAN_A</flags>
</freqband>
+<freqband id="AC2_5745_5845_40">
+ <freqstart>5745</freqstart> <freqend>5845</freqend>
+ <chanwidth>40</chanwidth> <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
<freqband id="AC2_5745_5805_80">
<freqstart>5745</freqstart> <freqend>5805</freqend>
<chanwidth>80</chanwidth> <chansep>20</chansep>
@@ -2027,6 +2279,11 @@
<chanwidth>20</chanwidth> <chansep>20</chansep>
<flags>IEEE80211_CHAN_A</flags>
</freqband>
+<freqband id="H4_5500_5720">
+ <freqstart>5500</freqstart> <freqend>5720</freqend>
+ <chanwidth>40</chanwidth> <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
<freqband id="H4_5500_5580">
<freqstart>5500</freqstart> <freqend>5580</freqend>
<chanwidth>40</chanwidth> <chansep>20</chansep>
@@ -2052,6 +2309,29 @@
<chanwidth>20</chanwidth> <chansep>20</chansep>
<flags>IEEE80211_CHAN_A</flags>
</freqband>
+<freqband id="A20_5745_5865">
+ <freqstart>5745</freqstart>
+ <freqend>5865</freqend>
+ <chanwidth>20</chanwidth>
+ <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+</freqband>
+<freqband id="NA20_5745_5865">
+ <freqstart>5745</freqstart>
+ <freqend>5865</freqend>
+ <chanwidth>20</chanwidth>
+ <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+ <flags>IEEE80211_CHAN_HT20</flags>
+</freqband>
+<freqband id="NA40_5745_5845">
+ <freqstart>5745</freqstart>
+ <freqend>5845</freqend>
+ <chanwidth>40</chanwidth>
+ <chansep>20</chansep>
+ <flags>IEEE80211_CHAN_A</flags>
+ <flags>IEEE80211_CHAN_HT40</flags>
+</freqband>
<freqband id="F1_5660_5700">
<freqstart>5660</freqstart> <freqend>5700</freqend>
<chanwidth>20</chanwidth> <chansep>20</chansep>
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile
index a68b938ca978..fed73c388318 100644
--- a/lib/libarchive/Makefile
+++ b/lib/libarchive/Makefile
@@ -42,11 +42,11 @@ SRCS= archive_acl.c \
archive_entry_stat.c \
archive_entry_strmode.c \
archive_entry_xattr.c \
- archive_getdate.c \
archive_hmac.c \
archive_match.c \
archive_options.c \
archive_pack_dev.c \
+ archive_parse_date.c \
archive_pathmatch.c \
archive_ppmd7.c \
archive_ppmd8.c \
@@ -101,6 +101,7 @@ SRCS= archive_acl.c \
archive_read_support_format_zip.c \
archive_string.c \
archive_string_sprintf.c \
+ archive_time.c \
archive_util.c \
archive_version_details.c \
archive_virtual.c \
diff --git a/lib/libarchive/tests/Makefile b/lib/libarchive/tests/Makefile
index 0562197e6936..07c5fe24dd30 100644
--- a/lib/libarchive/tests/Makefile
+++ b/lib/libarchive/tests/Makefile
@@ -17,6 +17,7 @@ PROGS+= libarchive_test
CFLAGS+= -I${.CURDIR} -I${.CURDIR:H} -I${.OBJDIR}
CFLAGS+= -I${_LIBARCHIVEDIR}/libarchive -I${_LIBARCHIVEDIR}/libarchive/test
CFLAGS+= -I${_LIBARCHIVEDIR}/test_utils
+CFLAGS+= -I${SRCTOP}/sys/contrib/zstd/lib
CFLAGS.test_utils.c+= -Wno-cast-align
@@ -38,11 +39,11 @@ TESTS_SRCS= \
test_archive_clear_error.c \
test_archive_cmdline.c \
test_archive_digest.c \
- test_archive_getdate.c \
test_archive_match_time.c \
test_archive_match_owner.c \
test_archive_match_path.c \
test_archive_pathmatch.c \
+ test_archive_parse_date.c \
test_archive_read.c \
test_archive_read_add_passphrase.c \
test_archive_read_close_twice.c \
@@ -72,6 +73,7 @@ TESTS_SRCS= \
test_compat_bzip2.c \
test_compat_cpio.c \
test_compat_gtar.c \
+ test_compat_gtar_large.c \
test_compat_gzip.c \
test_compat_lz4.c \
test_compat_lzip.c \
@@ -148,7 +150,9 @@ TESTS_SRCS= \
test_read_format_gtar_filename.c \
test_read_format_gtar_gz.c \
test_read_format_gtar_lzma.c \
+ test_read_format_gtar_redundant_L.c \
test_read_format_gtar_sparse.c \
+ test_read_format_gtar_sparse_length.c \
test_read_format_gtar_sparse_skip_entry.c \
test_read_format_huge_rpm.c \
test_read_format_iso_Z.c \
@@ -178,6 +182,7 @@ TESTS_SRCS= \
test_read_format_rar_encryption_partially.c \
test_read_format_rar_filter.c \
test_read_format_rar_invalid1.c \
+ test_read_format_rar_overflow.c \
test_read_format_raw.c \
test_read_format_tar.c \
test_read_format_tar_concatenated.c \
@@ -186,7 +191,10 @@ TESTS_SRCS= \
test_read_format_tar_empty_with_gnulabel.c \
test_read_format_tar_filename.c \
test_read_format_tar_invalid_pax_size.c \
+ test_read_format_tar_mac_metadata.c \
+ test_read_format_tar_pax_g_large.c \
test_read_format_tar_pax_large_attr.c \
+ test_read_format_tar_pax_negative_time.c \
test_read_format_tbz.c \
test_read_format_tgz.c \
test_read_format_tlz.c \
@@ -219,6 +227,7 @@ TESTS_SRCS= \
test_read_format_zip_with_invalid_traditional_eocd.c \
test_read_format_zip_zip64.c \
test_read_large.c \
+ test_read_pax_empty_val_no_nl.c \
test_read_pax_xattr_rht_security_selinux.c \
test_read_pax_xattr_schily.c \
test_read_pax_truncated.c \
@@ -287,6 +296,7 @@ TESTS_SRCS= \
test_write_format_mtree_classic_indent.c \
test_write_format_mtree_fflags.c \
test_write_format_mtree_no_separator.c \
+ test_write_format_mtree_preset_digests.c \
test_write_format_mtree_quoted_filename.c \
test_write_format_pax.c \
test_write_format_raw.c \
@@ -303,6 +313,9 @@ TESTS_SRCS= \
test_write_format_xar_empty.c \
test_write_format_zip.c \
test_write_format_zip_compression_store.c \
+ test_write_format_zip_compression_zstd.c \
+ test_write_format_zip_compression_bzip2.c \
+ test_write_format_zip_compression_lzmaxz.c \
test_write_format_zip_empty.c \
test_write_format_zip_empty_zip64.c \
test_write_format_zip_entry_size_unset.c \
@@ -447,6 +460,7 @@ ${PACKAGE}FILES+= test_read_format_7zip_bcj2_copy_2.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_bcj2_copy_lzma.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_bcj2_deflate.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_deflate_arm64.7z.uu
+${PACKAGE}FILES+= test_read_format_7zip_deflate_powerpc.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_bcj2_lzma1_1.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_bcj2_lzma1_2.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_bcj2_lzma2_1.7z.uu
@@ -476,16 +490,23 @@ ${PACKAGE}FILES+= test_read_format_7zip_lzma1_lzma2.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_lzma2.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_lzma2_arm.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_lzma2_arm64.7z.uu
+${PACKAGE}FILES+= test_read_format_7zip_lzma2_powerpc.7z.uu
+${PACKAGE}FILES+= test_read_format_7zip_lzma2_riscv.7z.uu
+${PACKAGE}FILES+= test_read_format_7zip_lzma2_sparc.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_malformed.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_malformed2.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_packinfo_digests.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_ppmd.7z.uu
+${PACKAGE}FILES+= test_read_format_7zip_sfx_elf.elf.uu
+${PACKAGE}FILES+= test_read_format_7zip_sfx_modified_pe.exe.uu
+${PACKAGE}FILES+= test_read_format_7zip_sfx_pe.exe.uu
${PACKAGE}FILES+= test_read_format_7zip_solid_zstd.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_symbolic_name.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_zstd.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_zstd_arm.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_zstd_bcj.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_zstd_nobcj.7z.uu
+${PACKAGE}FILES+= test_read_format_7zip_zstd_sparc.7z.uu
${PACKAGE}FILES+= test_read_format_7zip_win_attrib.7z.uu
${PACKAGE}FILES+= test_read_format_ar.ar.uu
${PACKAGE}FILES+= test_read_format_cab_1.cab.uu
@@ -504,12 +525,14 @@ ${PACKAGE}FILES+= test_read_format_cpio_svr4_gzip_rpm.rpm.uu
${PACKAGE}FILES+= test_read_format_gtar_filename_cp866.tar.Z.uu
${PACKAGE}FILES+= test_read_format_gtar_filename_eucjp.tar.Z.uu
${PACKAGE}FILES+= test_read_format_gtar_filename_koi8r.tar.Z.uu
+${PACKAGE}FILES+= test_read_format_gtar_redundant_L.tar.Z.uu
${PACKAGE}FILES+= test_read_format_gtar_sparse_1_13.tar.uu
${PACKAGE}FILES+= test_read_format_gtar_sparse_1_17.tar.uu
${PACKAGE}FILES+= test_read_format_gtar_sparse_1_17_posix00.tar.uu
${PACKAGE}FILES+= test_read_format_gtar_sparse_1_17_posix01.tar.uu
${PACKAGE}FILES+= test_read_format_gtar_sparse_1_17_posix10.tar.uu
${PACKAGE}FILES+= test_read_format_gtar_sparse_1_17_posix10_modified.tar.uu
+${PACKAGE}FILES+= test_read_format_gtar_sparse_length.tar.Z.uu
${PACKAGE}FILES+= test_read_format_gtar_sparse_skip_entry.tar.Z.uu
${PACKAGE}FILES+= test_read_format_huge_rpm.rpm.uu
${PACKAGE}FILES+= test_read_format_iso.iso.Z.uu
@@ -550,6 +573,7 @@ ${PACKAGE}FILES+= test_read_format_rar_compress_normal.rar.uu
${PACKAGE}FILES+= test_read_format_rar_encryption_data.rar.uu
${PACKAGE}FILES+= test_read_format_rar_encryption_header.rar.uu
${PACKAGE}FILES+= test_read_format_rar_encryption_partially.rar.uu
+${PACKAGE}FILES+= test_read_format_rar_endarc_huge.rar.uu
${PACKAGE}FILES+= test_read_format_rar_filter.rar.uu
${PACKAGE}FILES+= test_read_format_rar_invalid1.rar.uu
${PACKAGE}FILES+= test_read_format_rar_multi_lzss_blocks.rar.uu
@@ -557,12 +581,15 @@ ${PACKAGE}FILES+= test_read_format_rar_multivolume.part0001.rar.uu
${PACKAGE}FILES+= test_read_format_rar_multivolume.part0002.rar.uu
${PACKAGE}FILES+= test_read_format_rar_multivolume.part0003.rar.uu
${PACKAGE}FILES+= test_read_format_rar_multivolume.part0004.rar.uu
+${PACKAGE}FILES+= test_read_format_rar_newsub_huge.rar.uu
${PACKAGE}FILES+= test_read_format_rar_noeof.rar.uu
+${PACKAGE}FILES+= test_read_format_rar_overflow.rar.uu
${PACKAGE}FILES+= test_read_format_rar_ppmd_lzss_conversion.rar.uu
${PACKAGE}FILES+= test_read_format_rar_ppmd_use_after_free.rar.uu
${PACKAGE}FILES+= test_read_format_rar_ppmd_use_after_free2.rar.uu
${PACKAGE}FILES+= test_read_format_rar_sfx.exe.uu
${PACKAGE}FILES+= test_read_format_rar_subblock.rar.uu
+${PACKAGE}FILES+= test_read_format_rar_symlink_huge.rar.uu
${PACKAGE}FILES+= test_read_format_rar_unicode.rar.uu
${PACKAGE}FILES+= test_read_format_rar_windows.rar.uu
${PACKAGE}FILES+= test_read_format_rar4_encrypted.rar.uu
@@ -627,11 +654,15 @@ ${PACKAGE}FILES+= test_read_format_tar_empty_with_gnulabel.tar.uu
${PACKAGE}FILES+= test_read_format_tar_empty_pax.tar.Z.uu
${PACKAGE}FILES+= test_read_format_tar_filename_koi8r.tar.Z.uu
${PACKAGE}FILES+= test_read_format_tar_invalid_pax_size.tar.uu
+${PACKAGE}FILES+= test_read_format_tar_mac_metadata_1.tar.uu
+${PACKAGE}FILES+= test_read_format_tar_pax_g_large.tar.uu
${PACKAGE}FILES+= test_read_format_tar_pax_large_attr.tar.Z.uu
+${PACKAGE}FILES+= test_read_format_tar_pax_negative_time.tar.uu
${PACKAGE}FILES+= test_read_format_ustar_filename_cp866.tar.Z.uu
${PACKAGE}FILES+= test_read_format_ustar_filename_eucjp.tar.Z.uu
${PACKAGE}FILES+= test_read_format_ustar_filename_koi8r.tar.Z.uu
${PACKAGE}FILES+= test_read_format_warc.warc.uu
+${PACKAGE}FILES+= test_read_format_warc_incomplete.warc.uu
${PACKAGE}FILES+= test_read_format_xar_doublelink.xar.uu
${PACKAGE}FILES+= test_read_format_xar_duplicate_filename_node.xar.uu
${PACKAGE}FILES+= test_read_format_zip.zip.uu
@@ -691,6 +722,7 @@ ${PACKAGE}FILES+= test_read_large_splitted_rar_ab.uu
${PACKAGE}FILES+= test_read_large_splitted_rar_ac.uu
${PACKAGE}FILES+= test_read_large_splitted_rar_ad.uu
${PACKAGE}FILES+= test_read_large_splitted_rar_ae.uu
+${PACKAGE}FILES+= test_read_pax_empty_val_no_nl.tar.uu
${PACKAGE}FILES+= test_read_pax_xattr_rht_security_selinux.tar.uu
${PACKAGE}FILES+= test_read_pax_xattr_schily.tar.uu
${PACKAGE}FILES+= test_read_splitted_rar_aa.uu
diff --git a/lib/libbe/be.c b/lib/libbe/be.c
index e0ced1c5bcfc..613235d5e908 100644
--- a/lib/libbe/be.c
+++ b/lib/libbe/be.c
@@ -1,28 +1,7 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
+/*
* Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in>
*
- * 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 REGENTS 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 REGENTS 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.
+ * SPDX-License-Identifier: BSD-2-Clause
*/
#include <sys/param.h>
diff --git a/lib/libbe/be.h b/lib/libbe/be.h
index 0e4486fbb6d2..01ee94fd03ca 100644
--- a/lib/libbe/be.h
+++ b/lib/libbe/be.h
@@ -1,28 +1,7 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
+/*
* Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in>
*
- * 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 REGENTS 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 REGENTS 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.
+ * SPDX-License-Identifier: BSD-2-Clause
*/
#ifndef _LIBBE_H
diff --git a/lib/libbe/be_access.c b/lib/libbe/be_access.c
index 67b30d3fb4fb..a7eb6b703cda 100644
--- a/lib/libbe/be_access.c
+++ b/lib/libbe/be_access.c
@@ -1,30 +1,9 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
+/*
* Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in>
* Copyright (c) 2018 Kyle Evans <kevans@FreeBSD.org>
* Copyright (c) 2019 Wes Maag <wes@jwmaag.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.
- * 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 REGENTS 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 REGENTS 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.
+ * SPDX-License-Identifier: BSD-2-Clause
*/
#include <sys/cdefs.h>
@@ -33,6 +12,8 @@
#include "be.h"
#include "be_impl.h"
+#define LIBBE_MOUNT_PREFIX "be_mount."
+
struct be_mountcheck_info {
const char *path;
char *name;
@@ -164,7 +145,11 @@ be_umount_iter(zfs_handle_t *zfs_hdl, void *data)
if (!zfs_is_mounted(zfs_hdl, &mountpoint)) {
return (0);
}
- free(mountpoint);
+
+ if (info->depth == 0 && info->mountpoint == NULL)
+ info->mountpoint = mountpoint;
+ else
+ free(mountpoint);
if (zfs_unmount(zfs_hdl, NULL, info->mntflags) != 0) {
switch (errno) {
@@ -255,7 +240,17 @@ be_mount(libbe_handle_t *lbh, const char *bootenv, const char *mountpoint,
/* Create mountpoint if it is not specified */
if (mountpoint == NULL) {
- strlcpy(mnt_temp, "/tmp/be_mount.XXXX", sizeof(mnt_temp));
+ const char *tmpdir;
+
+ tmpdir = getenv("TMPDIR");
+ if (tmpdir == NULL)
+ tmpdir = _PATH_TMP;
+
+ if (snprintf(mnt_temp, sizeof(mnt_temp), "%s%s%sXXXX", tmpdir,
+ tmpdir[strlen(tmpdir) - 1] == '/' ? "" : "/",
+ LIBBE_MOUNT_PREFIX) >= (int)sizeof(mnt_temp))
+ return (set_error(lbh, BE_ERR_PATHLEN));
+
if (mkdtemp(mnt_temp) == NULL)
return (set_error(lbh, BE_ERR_IO));
}
@@ -307,10 +302,32 @@ be_unmount(libbe_handle_t *lbh, const char *bootenv, int flags)
info.depth = 0;
if ((err = be_umount_iter(root_hdl, &info)) != 0) {
+ free(__DECONST(char *, info.mountpoint));
zfs_close(root_hdl);
return (err);
}
+ /*
+ * We'll attempt to remove the directory if we created it on a
+ * best-effort basis. rmdir(2) failure will not be reported.
+ */
+ if (info.mountpoint != NULL) {
+ const char *mdir;
+
+ mdir = strrchr(info.mountpoint, '/');
+ if (mdir == NULL)
+ mdir = info.mountpoint;
+ else
+ mdir++;
+
+ if (strncmp(mdir, LIBBE_MOUNT_PREFIX,
+ sizeof(LIBBE_MOUNT_PREFIX) - 1) == 0) {
+ (void)rmdir(info.mountpoint);
+ }
+ }
+
+ free(__DECONST(char *, info.mountpoint));
+
zfs_close(root_hdl);
return (BE_ERR_SUCCESS);
}
diff --git a/lib/libbe/be_error.c b/lib/libbe/be_error.c
index f515fe136f12..bb1e1ed88c5d 100644
--- a/lib/libbe/be_error.c
+++ b/lib/libbe/be_error.c
@@ -1,28 +1,7 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
+/*
* Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in>
*
- * 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 REGENTS 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 REGENTS 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.
+ * SPDX-License-Identifier: BSD-2-Clause
*/
#include <sys/cdefs.h>
diff --git a/lib/libbe/be_impl.h b/lib/libbe/be_impl.h
index 0327f8abaa0a..11d1e0ddca28 100644
--- a/lib/libbe/be_impl.h
+++ b/lib/libbe/be_impl.h
@@ -1,28 +1,7 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
+/*
* Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in>
*
- * 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 REGENTS 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 REGENTS 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.
+ * SPDX-License-Identifier: BSD-2-Clause
*/
#ifndef _LIBBE_IMPL_H
diff --git a/lib/libbe/be_info.c b/lib/libbe/be_info.c
index 509b56cb8cf5..4b0f611ce421 100644
--- a/lib/libbe/be_info.c
+++ b/lib/libbe/be_info.c
@@ -1,29 +1,8 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
+/*
* Copyright (c) 2017 Kyle J. Kneitinger <kyle@kneit.in>
* Copyright (c) 2018 Kyle Evans <kevans@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.
- * 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 REGENTS 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 REGENTS 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.
+ * SPDX-License-Identifier: BSD-2-Clause
*/
#include <sys/cdefs.h>
diff --git a/lib/libbe/libbe.3 b/lib/libbe/libbe.3
index 4d9439206b7b..3b10711dd0f9 100644
--- a/lib/libbe/libbe.3
+++ b/lib/libbe/libbe.3
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 9, 2024
+.Dd April 20, 2025
.Dt LIBBE 3
.Os
.Sh NAME
@@ -358,6 +358,10 @@ If
is
.Dv NULL ,
a mount point will be generated in
+.Ev TMPDIR
+or, if
+.Ev TMPDIR
+is not set,
.Pa /tmp
using
.Xr mkdtemp 3 .
@@ -392,6 +396,13 @@ This list of properties matches the properties collected by
The
.Fn be_unmount
function will unmount the given boot environment.
+If the mount point looks like it was created by
+.Fn be_mount ,
+then
+.Fn be_unmount
+will attempt to
+.Xr rmdir 2
+the mountpoint after a successful unmount.
Setting the
.Dv BE_MNT_FORCE
flag will pass
diff --git a/lib/libc/amd64/static_tls.h b/lib/libc/amd64/static_tls.h
deleted file mode 100644
index 1ee738b231c7..000000000000
--- a/lib/libc/amd64/static_tls.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _LIBC_AMD64_STATIC_TLS_H
-#define _LIBC_AMD64_STATIC_TLS_H
-
-static __inline uintptr_t
-_libc_get_static_tls_base(size_t offset)
-{
- uintptr_t tlsbase;
-
- __asm __volatile("movq %%fs:0, %0" : "=r" (tlsbase));
- tlsbase -= offset;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libc/arm/aeabi/Symbol.map b/lib/libc/arm/aeabi/Symbol.map
index 175884c82881..515794004ba7 100644
--- a/lib/libc/arm/aeabi/Symbol.map
+++ b/lib/libc/arm/aeabi/Symbol.map
@@ -6,50 +6,6 @@
FBSDprivate_1.0 {
__aeabi_atexit;
- __aeabi_dcmpeq;
- __aeabi_dcmplt;
- __aeabi_dcmple;
- __aeabi_dcmpge;
- __aeabi_dcmpgt;
- __aeabi_dcmpun;
-
- __aeabi_cdcmpeq;
- __aeabi_cdcmple;
- __aeabi_cdrcmple;
-
- __aeabi_d2iz;
- __aeabi_d2f;
-
- __aeabi_dadd;
- __aeabi_ddiv;
- __aeabi_dmul;
- __aeabi_dsub;
-
-
- __aeabi_fcmpeq;
- __aeabi_fcmplt;
- __aeabi_fcmple;
- __aeabi_fcmpge;
- __aeabi_fcmpgt;
- __aeabi_fcmpun;
-
- __aeabi_cfcmpeq;
- __aeabi_cfcmple;
- __aeabi_cfrcmple;
-
- __aeabi_f2iz;
- __aeabi_f2d;
-
- __aeabi_fadd;
- __aeabi_fdiv;
- __aeabi_fmul;
- __aeabi_fsub;
-
-
- __aeabi_i2d;
- __aeabi_i2f;
-
-
__aeabi_memclr;
__aeabi_memclr4;
__aeabi_memclr8;
diff --git a/lib/libc/arm/aeabi/aeabi_int_div.S b/lib/libc/arm/aeabi/aeabi_int_div.S
index 708b478b3881..bb002c2716f7 100644
--- a/lib/libc/arm/aeabi/aeabi_int_div.S
+++ b/lib/libc/arm/aeabi/aeabi_int_div.S
@@ -37,11 +37,13 @@
*/
ENTRY(__aeabi_uidiv_compat)
+ .hidden __aeabi_uidiv_compat
.symver __aeabi_uidiv_compat, __aeabi_uidiv@
b __udivsi3
END(__aeabi_uidiv_compat)
ENTRY(__aeabi_idiv_compat)
+ .hidden __aeabi_idiv_compat
.symver __aeabi_idiv_compat, __aeabi_idiv@
b __divsi3
END(__aeabi_idiv_compat)
diff --git a/lib/libc/arm/aeabi/aeabi_vfp.h b/lib/libc/arm/aeabi/aeabi_vfp.h
index 3b70fe06fab3..4f3bb2ef969b 100644
--- a/lib/libc/arm/aeabi/aeabi_vfp.h
+++ b/lib/libc/arm/aeabi/aeabi_vfp.h
@@ -40,7 +40,9 @@
#define AEABI_ENTRY(x) ENTRY(__aeabi_ ## x ## _vfp)
#define AEABI_END(x) END(__aeabi_ ## x ## _vfp)
#else
-#define AEABI_ENTRY(x) ENTRY(__aeabi_ ## x)
+#define AEABI_ENTRY(x) \
+ ENTRY(__aeabi_ ## x) \
+ .symver __aeabi_##x, __aeabi_##x##@FBSDprivate_1.0;
#define AEABI_END(x) END(__aeabi_ ## x)
#endif
diff --git a/lib/libc/arm/static_tls.h b/lib/libc/arm/static_tls.h
deleted file mode 100644
index 557748d75347..000000000000
--- a/lib/libc/arm/static_tls.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _LIBC_ARM_STATIC_TLS_H
-#define _LIBC_ARM_STATIC_TLS_H
-
-static __inline uintptr_t
-_libc_get_static_tls_base(size_t offset)
-{
- uintptr_t tlsbase;
-
- __asm __volatile("mrc p15, 0, %0, c13, c0, 3" : "=r" (tlsbase));
-
- tlsbase += offset;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libc/csu/libc_start1.c b/lib/libc/csu/libc_start1.c
index 045ea1e68141..5b08ba03ba8c 100644
--- a/lib/libc/csu/libc_start1.c
+++ b/lib/libc/csu/libc_start1.c
@@ -28,6 +28,7 @@
#include <sys/param.h>
#include <sys/elf.h>
#include <sys/elf_common.h>
+#include <errno.h>
#include <stdlib.h>
#include "libc_private.h"
@@ -169,6 +170,13 @@ __libc_start1(int argc, char *argv[], char *env[], void (*cleanup)(void),
}
handle_static_init(argc, argv, env);
+
+ /*
+ * C17 4.3 paragraph 3:
+ * The value of errno in the initial thread is zero at program
+ * startup.
+ */
+ errno = 0;
exit(mainX(argc, argv, env));
}
@@ -194,5 +202,6 @@ __libc_start1_gcrt(int argc, char *argv[], char *env[],
monstartup(eprolp, etextp);
handle_static_init(argc, argv, env);
+ errno = 0;
exit(mainX(argc, argv, env));
}
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index 9b92e52cdfad..4d064d18d36e 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -89,6 +89,7 @@ SRCS+= \
glob.c \
glob-compat11.c \
initgroups.c \
+ inotify.c \
isatty.c \
isinf.c \
isnan.c \
@@ -134,6 +135,7 @@ SRCS+= \
setmode.c \
setproctitle.c \
setprogname.c \
+ sig2str.c \
siginterrupt.c \
siglist.c \
signal.c \
@@ -159,6 +161,8 @@ SRCS+= \
ttyname.c \
ttyslot.c \
ualarm.c \
+ uexterr_format.c \
+ uexterr_gettext.c \
ulimit.c \
uname.c \
unvis-compat.c \
@@ -168,6 +172,11 @@ SRCS+= \
valloc.c \
wordexp.c
+.if ${COMPILER_FEATURES:Mblocks}
+CFLAGS.fts.c= -fblocks
+CFLAGS.glob.c= -fblocks
+.endif
+
CFLAGS.arc4random.c= -I${SRCTOP}/sys -I${SRCTOP}/sys/crypto/chacha20
CFLAGS.sysconf.c= -I${SRCTOP}/contrib/tzcode
@@ -362,7 +371,8 @@ MLINKS+=exec.3 execl.3 \
exec.3 exect.3 \
exec.3 execv.3 \
exec.3 execvP.3 \
- exec.3 execvp.3
+ exec.3 execvp.3 \
+ exec.3 execvpe.3
MLINKS+=fpclassify.3 finite.3 \
fpclassify.3 finitef.3 \
fpclassify.3 isfinite.3 \
@@ -465,7 +475,10 @@ MLINKS+=posix_spawn.3 posix_spawnp.3 \
posix_spawnattr_getsigdefault.3 posix_spawnattr_setsigdefault.3 \
posix_spawnattr_getsigmask.3 posix_spawnattr_setsigmask.3 \
posix_spawnattr_init.3 posix_spawnattr_destroy.3
-MLINKS+=psignal.3 strsignal.3 \
+MLINKS+=psignal.3 psiginfo.3 \
+ psignal.3 sig2str.3 \
+ psignal.3 str2sig.3 \
+ psignal.3 strsignal.3 \
psignal.3 sys_siglist.3 \
psignal.3 sys_signame.3
MLINKS+=pwcache.3 gid_from_group.3 \
@@ -487,8 +500,11 @@ MLINKS+=rand48.3 _rand48.3 \
MLINKS+=rtld_get_var.3 \
rtld_set_var.3
MLINKS+=scandir.3 alphasort.3 \
- scandir.3 scandirat.3 \
+ scandir.3 fdscandir.3 \
+ scandir.3 fdscandir_b.3 \
scandir.3 scandir_b.3 \
+ scandir.3 scandirat.3 \
+ scandir.3 scandirat_b.3 \
scandir.3 versionsort.3
MLINKS+=sem_open.3 sem_close.3 \
sem_open.3 sem_unlink.3
diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map
index ca3974e6b747..26f638568efc 100644
--- a/lib/libc/gen/Symbol.map
+++ b/lib/libc/gen/Symbol.map
@@ -458,8 +458,20 @@ FBSD_1.8 {
aio_read2;
aio_write2;
execvpe;
+ fdscandir;
+ fdscandir_b;
+ fts_open_b;
+ glob_b;
+ inotify_add_watch;
+ inotify_init;
+ inotify_init1;
+ psiginfo;
rtld_get_var;
rtld_set_var;
+ scandirat_b;
+ uexterr_gettext;
+ sig2str;
+ str2sig;
};
FBSDprivate_1.0 {
@@ -584,10 +596,10 @@ FBSDprivate_1.0 {
__libc_tcdrain;
- __pthread_distribute_static_tls;
__pthread_map_stacks_exec;
__fillcontextx;
__fillcontextx2;
__getcontextx_size;
__makecontext;
+ __uexterr_format;
};
diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c
index 2a0cebadd5fd..d867ee4db51e 100644
--- a/lib/libc/gen/_pthread_stubs.c
+++ b/lib/libc/gen/_pthread_stubs.c
@@ -63,6 +63,7 @@ static int stub_getname_np(pthread_t, char *, size_t);
#define PJT_DUAL_ENTRY(entry) \
(pthread_func_t)entry, (pthread_func_t)entry
+__attribute__((visibility("protected")))
pthread_func_entry_t __thr_jtable[PJT_MAX] = {
[PJT_ATFORK] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_DESTROY] = {PJT_DUAL_ENTRY(stub_zero)},
diff --git a/lib/libc/gen/alarm.3 b/lib/libc/gen/alarm.3
index 8aeda29481eb..4a24cc6d7216 100644
--- a/lib/libc/gen/alarm.3
+++ b/lib/libc/gen/alarm.3
@@ -63,7 +63,7 @@ Due to
.Xr setitimer 2
restriction the maximum number of
.Fa seconds
-allowed is 100000000.
+allowed is 100,000,000.
.Sh RETURN VALUES
The return value of
.Fn alarm
diff --git a/lib/libc/gen/dlfcn.c b/lib/libc/gen/dlfcn.c
index bffee3952e0d..ae1c8d83df19 100644
--- a/lib/libc/gen/dlfcn.c
+++ b/lib/libc/gen/dlfcn.c
@@ -229,7 +229,7 @@ _dl_iterate_phdr_locked(
return (1);
_once(&dl_phdr_info_once, dl_init_phdr_info);
ti.ti_module = 1;
- ti.ti_offset = 0;
+ ti.ti_offset = -TLS_DTV_OFFSET;
phdr_info.dlpi_tls_data = __tls_get_addr(&ti);
ret = callback(&phdr_info, sizeof(phdr_info), data);
return (ret);
diff --git a/lib/libc/gen/dup3.3 b/lib/libc/gen/dup3.3
index f2798930797b..338a9ae74c64 100644
--- a/lib/libc/gen/dup3.3
+++ b/lib/libc/gen/dup3.3
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 16, 2013
+.Dd May 17, 2025
.Dt DUP3 3
.Os
.Sh NAME
@@ -47,6 +47,11 @@ The close-on-exec flag on the new file descriptor is determined by the
bit in
.Fa flags .
.Pp
+The close-on-fork flag on the new file descriptor is determined by the
+.Dv O_CLOFORK
+bit in
+.Fa flags .
+.Pp
If
.Fa oldd
\*(Ne
@@ -91,7 +96,9 @@ argument.
The
.Fa flags
argument has bits set other than
-.Dv O_CLOEXEC .
+.Dv O_CLOEXEC
+or
+.Dv O_CLOFORK .
.El
.Sh SEE ALSO
.Xr accept 2 ,
@@ -112,3 +119,7 @@ The
.Fn dup3
function appeared in
.Fx 10.0 .
+The
+.Dv O_CLOFORK
+flag appeared in
+.Fx 15.0 .
diff --git a/lib/libc/gen/dup3.c b/lib/libc/gen/dup3.c
index fca1e99fb47b..1401c1f5b607 100644
--- a/lib/libc/gen/dup3.c
+++ b/lib/libc/gen/dup3.c
@@ -39,21 +39,22 @@ int __dup3(int, int, int);
int
__dup3(int oldfd, int newfd, int flags)
{
- int how;
+ int fdflags;
if (oldfd == newfd) {
errno = EINVAL;
return (-1);
}
- if (flags & ~O_CLOEXEC) {
+ if ((flags & ~(O_CLOEXEC | O_CLOFORK)) != 0) {
errno = EINVAL;
return (-1);
}
- how = (flags & O_CLOEXEC) ? F_DUP2FD_CLOEXEC : F_DUP2FD;
+ fdflags = ((flags & O_CLOEXEC) != 0 ? FD_CLOEXEC : 0) |
+ ((flags & O_CLOFORK) != 0 ? FD_CLOFORK : 0);
- return (_fcntl(oldfd, how, newfd));
+ return (_fcntl(oldfd, F_DUP3FD | (fdflags << F_DUP3FD_SHIFT), newfd));
}
__weak_reference(__dup3, dup3);
diff --git a/lib/libc/gen/elf_utils.c b/lib/libc/gen/elf_utils.c
index 5b87e012d0eb..3714a0dc42b5 100644
--- a/lib/libc/gen/elf_utils.c
+++ b/lib/libc/gen/elf_utils.c
@@ -31,14 +31,16 @@
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/sysctl.h>
+
+#include <machine/tls.h>
+
#include <link.h>
#include <stddef.h>
#include <string.h>
+
#include "libc_private.h"
-#include "static_tls.h"
void __pthread_map_stacks_exec(void);
-void __pthread_distribute_static_tls(size_t, void *, size_t, size_t);
int
__elf_phdr_match_addr(struct dl_phdr_info *phdr_info, void *addr)
@@ -102,24 +104,3 @@ __pthread_map_stacks_exec(void)
((void (*)(void))__libc_interposing[INTERPOS_map_stacks_exec])();
}
-
-void
-__libc_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
- uintptr_t tlsbase;
-
- tlsbase = _libc_get_static_tls_base(offset);
- memcpy((void *)tlsbase, src, len);
- memset((char *)tlsbase + len, 0, total_len - len);
-}
-
-#pragma weak __pthread_distribute_static_tls
-void
-__pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
-
- ((void (*)(size_t, void *, size_t, size_t))__libc_interposing[
- INTERPOS_distribute_static_tls])(offset, src, len, total_len);
-}
diff --git a/lib/libc/gen/err.c b/lib/libc/gen/err.c
index 24ea242560b8..16cbe27693e7 100644
--- a/lib/libc/gen/err.c
+++ b/lib/libc/gen/err.c
@@ -30,9 +30,12 @@
*/
#include "namespace.h"
+#include <sys/exterrvar.h>
#include <err.h>
#include <errno.h>
+#include <exterr.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -43,6 +46,11 @@
static FILE *err_file; /* file to use for error output */
static void (*err_exit)(int);
+static void verrci(bool doexterr, int eval, int code, const char *fmt,
+ va_list ap) __printf0like(4, 0) __dead2;
+static void vwarnci(bool doexterr, int code, const char *fmt, va_list ap)
+ __printf0like(3, 0);
+
/*
* This is declared to take a `void *' so that the caller is not required
* to include <stdio.h> first. However, it is really a `FILE *', and the
@@ -70,14 +78,14 @@ _err(int eval, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- verrc(eval, errno, fmt, ap);
+ verrci(true, eval, errno, fmt, ap);
va_end(ap);
}
void
verr(int eval, const char *fmt, va_list ap)
{
- verrc(eval, errno, fmt, ap);
+ verrci(true, eval, errno, fmt, ap);
}
void
@@ -85,13 +93,24 @@ errc(int eval, int code, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
- verrc(eval, code, fmt, ap);
+ verrci(false, eval, code, fmt, ap);
va_end(ap);
}
void
verrc(int eval, int code, const char *fmt, va_list ap)
{
+ verrci(false, eval, code, fmt, ap);
+}
+
+static void
+vexterr(bool doexterr, int code, const char *fmt, va_list ap)
+{
+ char exterr[UEXTERROR_MAXLEN]; /* libc knows the buffer size */
+ int extstatus;
+
+ if (doexterr)
+ extstatus = uexterr_gettext(exterr, sizeof(exterr));
if (err_file == NULL)
err_set_file(NULL);
fprintf(err_file, "%s: ", _getprogname());
@@ -99,7 +118,16 @@ verrc(int eval, int code, const char *fmt, va_list ap)
vfprintf(err_file, fmt, ap);
fprintf(err_file, ": ");
}
- fprintf(err_file, "%s\n", strerror(code));
+ fprintf(err_file, "%s", strerror(code));
+ if (doexterr && extstatus == 0 && exterr[0] != '\0')
+ fprintf(err_file, " (extended error %s)", exterr);
+ fprintf(err_file, "\n");
+}
+
+static void
+verrci(bool doexterr, int eval, int code, const char *fmt, va_list ap)
+{
+ vexterr(doexterr, code, fmt, ap);
if (err_exit)
err_exit(eval);
exit(eval);
@@ -157,17 +185,16 @@ warnc(int code, const char *fmt, ...)
void
vwarnc(int code, const char *fmt, va_list ap)
{
+ vwarnci(false, code, fmt, ap);
+}
+
+static void
+vwarnci(bool doexterr, int code, const char *fmt, va_list ap)
+{
int saved_errno;
saved_errno = errno;
- if (err_file == NULL)
- err_set_file(NULL);
- fprintf(err_file, "%s: ", _getprogname());
- if (fmt != NULL) {
- vfprintf(err_file, fmt, ap);
- fprintf(err_file, ": ");
- }
- fprintf(err_file, "%s\n", strerror(code));
+ vexterr(doexterr, code, fmt, ap);
errno = saved_errno;
}
diff --git a/lib/libc/gen/exec.c b/lib/libc/gen/exec.c
index d9285733e965..926c50d64852 100644
--- a/lib/libc/gen/exec.c
+++ b/lib/libc/gen/exec.c
@@ -136,7 +136,7 @@ execv(const char *name, char * const *argv)
int
execvp(const char *name, char * const *argv)
{
- return (execvpe(name, argv, environ));
+ return (__libc_execvpe(name, argv, environ));
}
static int
@@ -288,7 +288,7 @@ execvP(const char *name, const char *path, char * const argv[])
}
int
-execvpe(const char *name, char * const argv[], char * const envp[])
+__libc_execvpe(const char *name, char * const argv[], char * const envp[])
{
const char *path;
@@ -298,3 +298,5 @@ execvpe(const char *name, char * const argv[], char * const envp[])
return (execvPe(name, path, argv, envp));
}
+
+__weak_reference(__libc_execvpe, execvpe);
diff --git a/lib/libc/gen/fdopendir.c b/lib/libc/gen/fdopendir.c
index 67c0766b6d83..df6709fbcb85 100644
--- a/lib/libc/gen/fdopendir.c
+++ b/lib/libc/gen/fdopendir.c
@@ -30,14 +30,13 @@
*/
#include "namespace.h"
-#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
+#include <stdbool.h>
#include "un-namespace.h"
#include "gen-private.h"
diff --git a/lib/libc/gen/fnmatch.3 b/lib/libc/gen/fnmatch.3
index 804bc968c1ce..7f020fec58e3 100644
--- a/lib/libc/gen/fnmatch.3
+++ b/lib/libc/gen/fnmatch.3
@@ -27,7 +27,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 2, 2022
+.Dd April 7, 2025
.Dt FNMATCH 3
.Os
.Sh NAME
@@ -129,12 +129,8 @@ otherwise, it returns the value
.Sh STANDARDS
The current implementation of the
.Fn fnmatch
-function
-.Em does not
-conform to
+function is expected to conform to
.St -p1003.2 .
-Collating symbol expressions, equivalence class expressions and
-character class expressions are not supported.
.Sh HISTORY
A predecessor to
.Fn fnmatch ,
diff --git a/lib/libc/gen/fnmatch.c b/lib/libc/gen/fnmatch.c
index fb1829e69502..1c583a9d23e2 100644
--- a/lib/libc/gen/fnmatch.c
+++ b/lib/libc/gen/fnmatch.c
@@ -67,7 +67,8 @@
#define RANGE_NOMATCH 0
#define RANGE_ERROR (-1)
-static int rangematch(const char *, wchar_t, int, char **, mbstate_t *);
+static int rangematch(const char *, wchar_t, const char *, int, char **,
+ char **, mbstate_t *, mbstate_t *);
static int fnmatch1(const char *, const char *, const char *, int, mbstate_t,
mbstate_t);
@@ -85,7 +86,7 @@ fnmatch1(const char *pattern, const char *string, const char *stringstart,
{
const char *bt_pattern, *bt_string;
mbstate_t bt_patmbs, bt_strmbs;
- char *newp;
+ char *newp, *news;
char c;
wchar_t pc, sc;
size_t pclen, sclen;
@@ -151,8 +152,10 @@ fnmatch1(const char *pattern, const char *string, const char *stringstart,
* there is no way having it match more characters
* can help us, given that we are already here.
*/
- bt_pattern = pattern, bt_patmbs = patmbs;
- bt_string = string, bt_strmbs = strmbs;
+ bt_pattern = pattern;
+ bt_patmbs = patmbs;
+ bt_string = string;
+ bt_strmbs = strmbs;
break;
case '[':
if (sc == EOS)
@@ -164,17 +167,17 @@ fnmatch1(const char *pattern, const char *string, const char *stringstart,
((flags & FNM_PATHNAME) && *(string - 1) == '/')))
goto backtrack;
- switch (rangematch(pattern, sc, flags, &newp,
- &patmbs)) {
+ switch (rangematch(pattern, sc, string + sclen, flags,
+ &newp, &news, &patmbs, &strmbs)) {
case RANGE_ERROR:
goto norm;
case RANGE_MATCH:
pattern = newp;
+ string = news;
break;
case RANGE_NOMATCH:
goto backtrack;
}
- string += sclen;
break;
case '\\':
if (!(flags & FNM_NOESCAPE)) {
@@ -218,8 +221,10 @@ fnmatch1(const char *pattern, const char *string, const char *stringstart,
if (sc == '/' && flags & FNM_PATHNAME)
return (FNM_NOMATCH);
bt_string += sclen;
- pattern = bt_pattern, patmbs = bt_patmbs;
- string = bt_string, strmbs = bt_strmbs;
+ pattern = bt_pattern;
+ patmbs = bt_patmbs;
+ string = bt_string;
+ strmbs = bt_strmbs;
}
break;
}
@@ -228,15 +233,20 @@ fnmatch1(const char *pattern, const char *string, const char *stringstart,
}
static int
-rangematch(const char *pattern, wchar_t test, int flags, char **newp,
- mbstate_t *patmbs)
+rangematch(const char *pattern, wchar_t test, const char *string, int flags,
+ char **newp, char **news, mbstate_t *patmbs, mbstate_t *strmbs)
{
int negate, ok;
wchar_t c, c2;
size_t pclen;
const char *origpat;
struct xlocale_collate *table =
- (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
+ (struct xlocale_collate *)__get_locale()->components[XLC_COLLATE];
+ wchar_t buf[COLLATE_STR_LEN]; /* STR_LEN defined in collate.h */
+ const char *cp, *savestring;
+ int special;
+ mbstate_t save;
+ size_t sclen, len;
/*
* A bracket expression starting with an unquoted circumflex
@@ -259,20 +269,132 @@ rangematch(const char *pattern, wchar_t test, int flags, char **newp,
ok = 0;
origpat = pattern;
for (;;) {
+ c = 0;
if (*pattern == ']' && pattern > origpat) {
- pattern++;
break;
} else if (*pattern == '\0') {
return (RANGE_ERROR);
} else if (*pattern == '/' && (flags & FNM_PATHNAME)) {
return (RANGE_NOMATCH);
- } else if (*pattern == '\\' && !(flags & FNM_NOESCAPE))
+ } else if (*pattern == '\\' && !(flags & FNM_NOESCAPE)) {
pattern++;
- pclen = mbrtowc(&c, pattern, MB_LEN_MAX, patmbs);
- if (pclen == (size_t)-1 || pclen == (size_t)-2)
- return (RANGE_NOMATCH);
- pattern += pclen;
+ } else if (*pattern == '[' &&
+ ((special = *(pattern + 1)) == '.' ||
+ special == '=' || special == ':')) {
+ cp = (pattern += 2);
+ while ((cp = strchr(cp, special))) {
+ if (*(cp + 1) == ']')
+ break;
+ cp++;
+ }
+ if (!cp)
+ return (RANGE_ERROR);
+ if (special == '.') {
+treat_like_collating_symbol:
+ len = __collate_collating_symbol(buf,
+ COLLATE_STR_LEN, pattern,
+ cp - pattern, patmbs);
+ if (len == (size_t)-1 || len == 0)
+ return (RANGE_ERROR);
+ pattern = cp + 2;
+ if (len > 1) {
+ wchar_t *wp, sc;
+ /*
+ * No multi-character collation
+ * symbols as start of range.
+ */
+ if (*(cp + 2) == '-' &&
+ *(cp + 3) != EOS &&
+ *(cp + 3) != ']')
+ return (RANGE_ERROR);
+ wp = buf;
+ if (test != *wp++)
+ continue;
+ if (len == 1) {
+ ok = 1;
+ break;
+ }
+ memcpy(&save, strmbs, sizeof(save));
+ savestring = string;
+ while (--len > 0) {
+ sclen = mbrtowc(&sc, string,
+ MB_LEN_MAX, strmbs);
+ if (sclen == (size_t)-1 ||
+ sclen == (size_t)-2) {
+ sc = (unsigned char)*string;
+ sclen = 1;
+ memset(&strmbs, 0,
+ sizeof(strmbs));
+ }
+ if (sc != *wp++) {
+ memcpy(strmbs, &save,
+ sizeof(save));
+ string = savestring;
+ break;
+ }
+ string += sclen;
+ }
+ if (len == 0) {
+ ok = 1;
+ break;
+ }
+ continue; /* no match */
+ }
+ c = *buf;
+ } else if (special == '=') {
+ int ec;
+ memcpy(&save, patmbs, sizeof(save));
+ ec = __collate_equiv_class(pattern,
+ cp - pattern, patmbs);
+ if (ec < 0)
+ return (RANGE_ERROR);
+ if (ec == 0) {
+ memcpy(patmbs, &save, sizeof(save));
+ goto treat_like_collating_symbol;
+ }
+ pattern = cp + 2;
+ /* no equivalence classes as start of range */
+ if (*(cp + 2) == '-' && *(cp + 3) != EOS &&
+ *(cp + 3) != ']')
+ return (RANGE_ERROR);
+ len = __collate_equiv_match(ec, NULL, 0, test,
+ string, strlen(string), strmbs, &sclen);
+ if (len < 0)
+ return (RANGE_ERROR);
+ if (len > 0) {
+ ok = 1;
+ string += sclen;
+ break;
+ }
+ continue;
+ } else { /* special == ':' */
+ wctype_t charclass;
+ char name[CHARCLASS_NAME_MAX + 1];
+ /* no character classes as start of range */
+ if (*(cp + 2) == '-' && *(cp + 3) != EOS &&
+ *(cp + 3) != ']')
+ return (RANGE_ERROR);
+ /* assume character class names are ascii */
+ if (cp - pattern > CHARCLASS_NAME_MAX)
+ return (RANGE_ERROR);
+ strlcpy(name, pattern, cp - pattern + 1);
+ pattern = cp + 2;
+ if ((charclass = wctype(name)) == 0)
+ return (RANGE_ERROR);
+ if (iswctype(test, charclass)) {
+ ok = 1;
+ break;
+ }
+ continue;
+ }
+ }
+ if (!c) {
+ pclen = mbrtowc(&c, pattern, MB_LEN_MAX, patmbs);
+ if (pclen == (size_t)-1 || pclen == (size_t)-2)
+ return (RANGE_NOMATCH);
+ pattern += pclen;
+ }
if (flags & FNM_CASEFOLD)
c = towlower(c);
@@ -288,6 +410,37 @@ rangematch(const char *pattern, wchar_t test, int flags, char **newp,
if (c2 == EOS)
return (RANGE_ERROR);
+ if ((c2 == '[' && (special = *pattern) == '.') ||
+ special == '=' || special == ':') {
+
+ /*
+ * No equivalence classes or character
+ * classes as end of range.
+ */
+ if (special == '=' || special == ':')
+ return (RANGE_ERROR);
+ cp = ++pattern;
+ while ((cp = strchr(cp, special))) {
+ if (*(cp + 1) == ']')
+ break;
+ cp++;
+ }
+ if (!cp)
+ return (RANGE_ERROR);
+ len = __collate_collating_symbol(buf,
+ COLLATE_STR_LEN, pattern,
+ cp - pattern, patmbs);
+
+ /*
+ * No multi-character collation symbols
+ * as end of range.
+ */
+ if (len != 1)
+ return (RANGE_ERROR);
+ pattern = cp + 2;
+ c2 = *buf;
+ }
+
if (flags & FNM_CASEFOLD)
c2 = towlower(c2);
@@ -295,12 +448,44 @@ rangematch(const char *pattern, wchar_t test, int flags, char **newp,
c <= test && test <= c2 :
__wcollate_range_cmp(c, test) <= 0
&& __wcollate_range_cmp(test, c2) <= 0
- )
+ ) {
ok = 1;
- } else if (c == test)
+ break;
+ }
+ } else if (c == test) {
ok = 1;
+ break;
+ }
}
- *newp = (char *)pattern;
+ /* go to end of bracket expression */
+ special = 0;
+ while (*pattern != ']') {
+ if (*pattern == 0)
+ return (RANGE_ERROR);
+ if (*pattern == special) {
+ if (*++pattern == ']') {
+ special = 0;
+ pattern++;
+ }
+ continue;
+ }
+ if (!special && *pattern == '[') {
+ special = *++pattern;
+ if (special != '.' && special != '=' && special != ':')
+ special = 0;
+ else
+ pattern++;
+ continue;
+ }
+ pclen = mbrtowc(&c, pattern, MB_LEN_MAX, patmbs);
+ if (pclen == (size_t)-1 || pclen == (size_t)-2)
+ return (RANGE_NOMATCH);
+ pattern += pclen;
+ }
+
+ *newp = (char *)++pattern;
+ *news = (char *)string;
+
return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH);
}
diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3
index 468b14115ec6..ee558b892c8c 100644
--- a/lib/libc/gen/fts.3
+++ b/lib/libc/gen/fts.3
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 12, 2014
+.Dd June 30, 2025
.Dt FTS 3
.Os
.Sh NAME
@@ -37,6 +37,8 @@
.In fts.h
.Ft FTS *
.Fn fts_open "char * const *path_argv" "int options" "int (*compar)(const FTSENT * const *, const FTSENT * const *)"
+.Ft FTS *
+.Fn fts_open_b "char * const *path_argv" "int options" "int (^compar)(const FTSENT * const *, const FTSENT * const *)"
.Ft FTSENT *
.Fn fts_read "FTS *ftsp"
.Ft FTSENT *
@@ -59,7 +61,9 @@ functions are provided for traversing
file hierarchies.
A simple overview is that the
.Fn fts_open
-function returns a
+and
+.Fn fts_open_b
+functions return a
.Dq handle
on a file hierarchy, which is then supplied to
the other
@@ -176,6 +180,12 @@ by one of the other
values.
.It Dv FTS_DNR
A directory which cannot be read.
+This immediately follows
+.Dv FTS_D ,
+in place of
+.Dv FTS_DP ,
+when the directory could not be entered, or could be entered but not
+read.
This is an error return, and the
.Fa fts_errno
field will be set to indicate what caused the error.
@@ -186,6 +196,8 @@ or
.Ql ..\&
which was not specified as a file name to
.Fn fts_open
+or
+.Fn fts_open_b
(see
.Dv FTS_SEEDOT ) .
.It Dv FTS_DP
@@ -234,6 +246,8 @@ A path for accessing the file from the current directory.
The path for the file relative to the root of the traversal.
This path contains the path specified to
.Fn fts_open
+or
+.Fn fts_open_b
as a prefix.
.It Fa fts_pathlen
The length of the string referenced by
@@ -380,12 +394,16 @@ must be specified.
The options are selected by
.Em or Ns 'ing
the following values:
-.Bl -tag -width "FTS_PHYSICAL"
+.Bl -tag -width "FTS_COMFOLLOWDIR"
.It Dv FTS_COMFOLLOW
This option causes any symbolic link specified as a root path to be
followed immediately whether or not
.Dv FTS_LOGICAL
is also specified.
+.It Dv FTS_COMFOLLOWDIR
+This option is similar to
+.Dv FTS_COMFOLLOW ,
+but only follows symbolic links to directories.
.It Dv FTS_LOGICAL
This option causes the
.Nm
@@ -441,6 +459,15 @@ field to
and leave the contents of the
.Fa statp
field undefined.
+.It Dv FTS_NOSTAT_TYPE
+This option is similar to
+.Dv FTS_NOSTAT ,
+but attempts to populate
+.Fa fts_info
+based on information from the
+.Fa d_type
+field of
+.Vt struct dirent .
.It Dv FTS_PHYSICAL
This option causes the
.Nm
@@ -518,6 +545,15 @@ the directory traversal order is in the order listed in
.Fa path_argv
for the root paths, and in the order listed in the directory for
everything else.
+.Sh FTS_OPEN_B
+The
+.Fn fts_open_b
+function is identical to
+.Fn fts_open
+except that it takes a block pointer instead of a function pointer.
+The block is copied before
+.Fn fts_open_b
+returns, so the original can safely go out of scope or be released.
.Sh FTS_READ
The
.Fn fts_read
@@ -593,9 +629,13 @@ As a special case, if
has not yet been called for a hierarchy,
.Fn fts_children
will return a pointer to the files in the logical directory specified to
-.Fn fts_open ,
+.Fn fts_open
+or
+.Fn fts_open_b ,
i.e., the arguments specified to
-.Fn fts_open .
+.Fn fts_open
+or
+.Fn fts_open_b .
Otherwise, if the
.Vt FTSENT
structure most recently returned by
@@ -716,6 +756,8 @@ function closes a file hierarchy stream
.Fa ftsp
and restores the current directory to the directory from which
.Fn fts_open
+or
+.Fn fts_open_b
was called to open
.Fa ftsp .
The
@@ -723,29 +765,38 @@ The
function
returns 0 on success, and \-1 if an error occurs.
.Sh ERRORS
-The function
+The
.Fn fts_open
-may fail and set
+and
+.Fn fts_open_b
+functions may fail and set
.Va errno
for any of the errors specified for the library functions
.Xr open 2
and
.Xr malloc 3 .
+The
+.Fn fts_open_b
+function may also fail and set
+.Va errno
+to
+.Dv ENOSYS
+if the blocks runtime is missing.
.Pp
-The function
+The
.Fn fts_close
-may fail and set
+function may fail and set
.Va errno
for any of the errors specified for the library functions
.Xr chdir 2
and
.Xr close 2 .
.Pp
-The functions
+The
.Fn fts_read
and
.Fn fts_children
-may fail and set
+functions may fail and set
.Va errno
for any of the errors specified for the library functions
.Xr chdir 2 ,
@@ -755,12 +806,12 @@ for any of the errors specified for the library functions
and
.Xr stat 2 .
.Pp
-In addition,
+In addition, the
.Fn fts_children ,
-.Fn fts_open
+.Fn fts_open ,
and
.Fn fts_set
-may fail and set
+functions may fail and set
.Va errno
as follows:
.Bl -tag -width Er
@@ -788,6 +839,13 @@ functions were introduced in
principally to provide for alternative interfaces to the
.Nm
functionality using different data structures.
+Blocks support and the
+.Dv FTS_COMFOLLOWDIR
+and
+.Dv FTS_NOSTAT
+options were added in
+.Fx 15.0
+based on similar functionality in macOS.
.Sh BUGS
The
.Fn fts_open
diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c
index 80f98a993123..cce959ba836a 100644
--- a/lib/libc/gen/fts.c
+++ b/lib/libc/gen/fts.c
@@ -48,6 +48,19 @@
#include "gen-private.h"
+#ifdef __BLOCKS__
+#include <Block.h>
+#else
+#include "block_abi.h"
+typedef DECLARE_BLOCK(int, fts_block,
+ const FTSENT * const *, const FTSENT * const *);
+void qsort_b(void *, size_t, size_t, fts_block);
+#endif /* __BLOCKS__ */
+/* only present if linked with blocks runtime */
+void *_Block_copy(const void *) __weak_symbol;
+void _Block_release(const void *) __weak_symbol;
+extern void *_NSConcreteGlobalBlock[] __weak_symbol;
+
static FTSENT *fts_alloc(FTS *, char *, size_t);
static FTSENT *fts_build(FTS *, int);
static void fts_lfree(FTSENT *);
@@ -102,39 +115,21 @@ static const char *ufslike_filesystems[] = {
0
};
-FTS *
-fts_open(char * const *argv, int options,
- int (*compar)(const FTSENT * const *, const FTSENT * const *))
+static FTS *
+__fts_open(FTS *sp, char * const *argv)
{
- struct _fts_private *priv;
- FTS *sp;
FTSENT *p, *root;
FTSENT *parent, *tmp;
size_t len, nitems;
- /* Options check. */
- if (options & ~FTS_OPTIONMASK) {
- errno = EINVAL;
- return (NULL);
- }
-
- /* fts_open() requires at least one path */
- if (*argv == NULL) {
- errno = EINVAL;
- return (NULL);
- }
-
- /* Allocate/initialize the stream. */
- if ((priv = calloc(1, sizeof(*priv))) == NULL)
- return (NULL);
- sp = &priv->ftsp_fts;
- sp->fts_compar = compar;
- sp->fts_options = options;
-
/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
if (ISSET(FTS_LOGICAL))
SET(FTS_NOCHDIR);
+ /* NOSTAT_TYPE implies NOSTAT */
+ if (ISSET(FTS_NOSTAT_TYPE))
+ SET(FTS_NOSTAT);
+
/*
* Start out with 1K of path space, and enough, in any case,
* to hold the user's paths.
@@ -158,7 +153,9 @@ fts_open(char * const *argv, int options,
p->fts_level = FTS_ROOTLEVEL;
p->fts_parent = parent;
p->fts_accpath = p->fts_name;
- p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1);
+ p->fts_info = fts_stat(sp, p,
+ ISSET(FTS_COMFOLLOWDIR) ? -1 : ISSET(FTS_COMFOLLOW),
+ -1);
/* Command-line "." and ".." are real directories. */
if (p->fts_info == FTS_DOT)
@@ -168,7 +165,7 @@ fts_open(char * const *argv, int options,
* If comparison routine supplied, traverse in sorted
* order; otherwise traverse in the order specified.
*/
- if (compar) {
+ if (sp->fts_compar) {
p->fts_link = root;
root = p;
} else {
@@ -181,7 +178,7 @@ fts_open(char * const *argv, int options,
}
}
}
- if (compar && nitems > 1)
+ if (sp->fts_compar && nitems > 1)
root = fts_sort(sp, root, nitems);
/*
@@ -214,6 +211,97 @@ mem1: free(sp);
return (NULL);
}
+FTS *
+fts_open(char * const *argv, int options,
+ int (*compar)(const FTSENT * const *, const FTSENT * const *))
+{
+ struct _fts_private *priv;
+ FTS *sp;
+
+ /* Options check. */
+ if (options & ~FTS_OPTIONMASK) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* fts_open() requires at least one path */
+ if (*argv == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Allocate/initialize the stream. */
+ if ((priv = calloc(1, sizeof(*priv))) == NULL)
+ return (NULL);
+ sp = &priv->ftsp_fts;
+ sp->fts_compar = compar;
+ sp->fts_options = options;
+
+ return (__fts_open(sp, argv));
+}
+
+#ifdef __BLOCKS__
+FTS *
+fts_open_b(char * const *argv, int options,
+ int (^compar)(const FTSENT * const *, const FTSENT * const *))
+#else
+FTS *
+fts_open_b(char * const *argv, int options, fts_block compar)
+#endif /* __BLOCKS__ */
+{
+ struct _fts_private *priv;
+ FTS *sp;
+
+ /* No blocks, no problems. */
+ if (compar == NULL)
+ return (fts_open(argv, options, NULL));
+
+ /* Avoid segfault if blocks runtime is missing. */
+ if (_Block_copy == NULL) {
+ errno = ENOSYS;
+ return (NULL);
+ }
+
+ /* Options check. */
+ if (options & ~FTS_OPTIONMASK) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* fts_open() requires at least one path */
+ if (*argv == NULL) {
+ errno = EINVAL;
+ return (NULL);
+ }
+
+ /* Allocate/initialize the stream. */
+ if ((priv = calloc(1, sizeof(*priv))) == NULL)
+ return (NULL);
+ sp = &priv->ftsp_fts;
+#ifdef __BLOCKS__
+ compar = Block_copy(compar);
+#else
+ if (compar->isa != &_NSConcreteGlobalBlock)
+ compar = _Block_copy(compar);
+#endif /* __BLOCKS__ */
+ if (compar == NULL) {
+ free(priv);
+ return (NULL);
+ }
+ sp->fts_compar_b = compar;
+ sp->fts_options = options | FTS_COMPAR_B;
+
+ if ((sp = __fts_open(sp, argv)) == NULL) {
+#ifdef __BLOCKS__
+ Block_release(compar);
+#else
+ if (compar->isa != &_NSConcreteGlobalBlock)
+ _Block_release(compar);
+#endif /* __BLOCKS__ */
+ }
+ return (sp);
+}
+
static void
fts_load(FTS *sp, FTSENT *p)
{
@@ -265,6 +353,17 @@ fts_close(FTS *sp)
free(sp->fts_array);
free(sp->fts_path);
+ /* Free up any block pointer. */
+ if (ISSET(FTS_COMPAR_B) && sp->fts_compar_b != NULL) {
+#ifdef __BLOCKS__
+ Block_release(sp->fts_compar_b);
+#else
+ if (((fts_block)(sp->fts_compar_b))->isa !=
+ &_NSConcreteGlobalBlock)
+ _Block_release(sp->fts_compar_b);
+#endif /* __BLOCKS__ */
+ }
+
/* Return to original directory, save errno if necessary. */
if (!ISSET(FTS_NOCHDIR)) {
saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
@@ -650,14 +749,10 @@ fts_build(FTS *sp, int type)
* Open the directory for reading. If this fails, we're done.
* If being called from fts_read, set the fts_info field.
*/
-#ifdef FTS_WHITEOUT
if (ISSET(FTS_WHITEOUT))
oflag = DTF_NODUP;
else
oflag = DTF_HIDEW | DTF_NODUP;
-#else
-#define __opendir2(path, flag) opendir(path)
-#endif
if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
if (type == BREAD) {
cur->fts_info = FTS_DNR;
@@ -784,10 +879,8 @@ mem1: saved_errno = errno;
p->fts_parent = sp->fts_cur;
p->fts_pathlen = len + dnamlen;
-#ifdef FTS_WHITEOUT
if (dp->d_type == DT_WHT)
p->fts_flags |= FTS_ISW;
-#endif
if (cderrno) {
if (nlinks) {
@@ -796,12 +889,8 @@ mem1: saved_errno = errno;
} else
p->fts_info = FTS_NSOK;
p->fts_accpath = cur->fts_accpath;
- } else if (nlinks == 0
-#ifdef DT_DIR
- || (nostat &&
- dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
-#endif
- ) {
+ } else if (nlinks == 0 || (nostat &&
+ dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)) {
p->fts_accpath =
ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
p->fts_info = FTS_NSOK;
@@ -821,6 +910,25 @@ mem1: saved_errno = errno;
p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
--nlinks;
}
+ if (p->fts_info == FTS_NSOK && ISSET(FTS_NOSTAT_TYPE)) {
+ switch (dp->d_type) {
+ case DT_FIFO:
+ case DT_CHR:
+ case DT_BLK:
+ case DT_SOCK:
+ p->fts_info = FTS_DEFAULT;
+ break;
+ case DT_REG:
+ p->fts_info = FTS_F;
+ break;
+ case DT_LNK:
+ p->fts_info = FTS_SL;
+ break;
+ case DT_WHT:
+ p->fts_info = FTS_W;
+ break;
+ }
+ }
/* We walk in directory order so "ls -f" doesn't get upset. */
p->fts_link = NULL;
@@ -897,18 +1005,19 @@ fts_stat(FTS *sp, FTSENT *p, int follow, int dfd)
dev_t dev;
ino_t ino;
struct stat *sbp, sb;
- int saved_errno;
+ int ret, saved_errno;
const char *path;
- if (dfd == -1)
- path = p->fts_accpath, dfd = AT_FDCWD;
- else
+ if (dfd == -1) {
+ path = p->fts_accpath;
+ dfd = AT_FDCWD;
+ } else {
path = p->fts_name;
+ }
/* If user needs stat info, stat buffer already allocated. */
sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
-#ifdef FTS_WHITEOUT
/* Check for whiteout. */
if (p->fts_flags & FTS_ISW) {
if (sbp != &sb) {
@@ -917,22 +1026,27 @@ fts_stat(FTS *sp, FTSENT *p, int follow, int dfd)
}
return (FTS_W);
}
-#endif
/*
- * If doing a logical walk, or application requested FTS_FOLLOW, do
- * a stat(2). If that fails, check for a non-existent symlink. If
- * fail, set the errno from the stat call.
+ * If doing a logical walk, or caller requested FTS_COMFOLLOW, do
+ * a full stat(2). If that fails, do an lstat(2) to check for a
+ * non-existent symlink. If that fails, set the errno from the
+ * stat(2) call.
+ *
+ * As a special case, if stat(2) succeeded but the target is not a
+ * directory and follow is negative (indicating FTS_COMFOLLOWDIR
+ * rather than FTS_COMFOLLOW), we also revert to lstat(2).
*/
if (ISSET(FTS_LOGICAL) || follow) {
- if (fstatat(dfd, path, sbp, 0)) {
+ if ((ret = fstatat(dfd, path, sbp, 0)) != 0 ||
+ (follow < 0 && !S_ISDIR(sbp->st_mode))) {
saved_errno = errno;
if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
p->fts_errno = saved_errno;
goto err;
}
errno = 0;
- if (S_ISLNK(sbp->st_mode))
+ if (ret != 0 && S_ISLNK(sbp->st_mode))
return (FTS_SLNONE);
}
} else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
@@ -977,21 +1091,6 @@ err: memset(sbp, 0, sizeof(struct stat));
return (FTS_DEFAULT);
}
-/*
- * The comparison function takes pointers to pointers to FTSENT structures.
- * Qsort wants a comparison function that takes pointers to void.
- * (Both with appropriate levels of const-poisoning, of course!)
- * Use a trampoline function to deal with the difference.
- */
-static int
-fts_compar(const void *a, const void *b)
-{
- FTS *parent;
-
- parent = (*(const FTSENT * const *)a)->fts_fts;
- return (*parent->fts_compar)(a, b);
-}
-
static FTSENT *
fts_sort(FTS *sp, FTSENT *head, size_t nitems)
{
@@ -1014,7 +1113,18 @@ fts_sort(FTS *sp, FTSENT *head, size_t nitems)
}
for (ap = sp->fts_array, p = head; p; p = p->fts_link)
*ap++ = p;
- qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar);
+ if (ISSET(FTS_COMPAR_B)) {
+#ifdef __BLOCKS__
+ qsort_b(sp->fts_array, nitems, sizeof(FTSENT *),
+ (int (^)(const void *, const void *))sp->fts_compar_b);
+#else
+ qsort_b(sp->fts_array, nitems, sizeof(FTSENT *),
+ sp->fts_compar_b);
+#endif /* __BLOCKS__ */
+ } else {
+ qsort(sp->fts_array, nitems, sizeof(FTSENT *),
+ (int (*)(const void *, const void *))sp->fts_compar);
+ }
for (head = *(ap = sp->fts_array); --nitems; ++ap)
ap[0]->fts_link = ap[1];
ap[0]->fts_link = NULL;
diff --git a/lib/libc/gen/gen-private.h b/lib/libc/gen/gen-private.h
index 3792a61ff942..b6749b3435cd 100644
--- a/lib/libc/gen/gen-private.h
+++ b/lib/libc/gen/gen-private.h
@@ -43,8 +43,8 @@ struct pthread_mutex;
*/
struct _dirdesc {
int dd_fd; /* file descriptor associated with directory */
- long dd_loc; /* offset in current buffer */
- long dd_size; /* amount of data returned by getdirentries */
+ size_t dd_loc; /* offset in current buffer */
+ size_t dd_size; /* amount of data returned by getdirentries */
char *dd_buf; /* data buffer */
int dd_len; /* size of data buffer */
off_t dd_seek; /* magic cookie returned by getdirentries */
diff --git a/lib/libc/gen/glob.3 b/lib/libc/gen/glob.3
index 006e8decb3db..839d98ce02b5 100644
--- a/lib/libc/gen/glob.3
+++ b/lib/libc/gen/glob.3
@@ -27,11 +27,12 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 20, 2011
+.Dd June 23, 2025
.Dt GLOB 3
.Os
.Sh NAME
.Nm glob ,
+.Nm glob_b ,
.Nm globfree
.Nd generate pathnames matching a pattern
.Sh LIBRARY
@@ -39,7 +40,9 @@
.Sh SYNOPSIS
.In glob.h
.Ft int
-.Fn glob "const char * restrict pattern" "int flags" "int (*errfunc)(const char *, int)" "glob_t * restrict pglob"
+.Fn glob "const char * restrict pattern" "int flags" "int (*errfunc)(const char *epath, int errno)" "glob_t * restrict pglob"
+.Ft int
+.Fn glob_b "const char * restrict pattern" "int flags" "int (^errblk)(const char *epath, int errno)" "glob_t * restrict pglob"
.Ft void
.Fn globfree "glob_t *pglob"
.Sh DESCRIPTION
@@ -272,10 +275,24 @@ is
.Pf non- Dv NULL ,
.Fn glob
calls
-.Fa \*(lp*errfunc\*(rp Ns ( Fa path , errno ) ,
+.Fa \*(lp*errfunc\*(rp Ns ( Fa path , errno ) .
+This may be unintuitive: a pattern like
+.Ql */Makefile
+will try to
+.Xr stat 2
+.Ql foo/Makefile
+even if
+.Ql foo
+is not a directory, resulting in a
+call to
+.Fa errfunc .
+The error routine can suppress this action by testing for
+.Er ENOENT
+and
+.Er ENOTDIR ;
however, the
.Dv GLOB_ERR
-flag will cause an immediate
+flag will still cause an immediate
return when this happens.
.Pp
If
@@ -307,16 +324,27 @@ or
returns zero, the error is ignored.
.Pp
The
+.Fn glob_b
+function is like
+.Fn glob
+except that the error callback is a block pointer instead of a function
+pointer.
+.Pp
+The
.Fn globfree
function frees any space associated with
.Fa pglob
from a previous call(s) to
-.Fn glob .
+.Fn glob
+or
+.Fn glob_b .
.Sh RETURN VALUES
On successful completion,
.Fn glob
-returns zero.
-In addition the fields of
+and
+.Fn glob_b
+return zero.
+In addition, the fields of
.Fa pglob
contain the values described below:
.Bl -tag -width GLOB_NOCHECK
@@ -324,12 +352,16 @@ contain the values described below:
contains the total number of matched pathnames so far.
This includes other matches from previous invocations of
.Fn glob
+or
+.Fn glob_b
if
.Dv GLOB_APPEND
was specified.
.It Fa gl_matchc
contains the number of matched pathnames in the current invocation of
-.Fn glob .
+.Fn glob
+or
+.Fn glob_b .
.It Fa gl_flags
contains a copy of the
.Fa flags
@@ -352,6 +384,8 @@ are undefined.
.Pp
If
.Fn glob
+or
+.Fn glob_b
terminates due to an error, it sets errno and returns one of the
following non-zero constants, which are defined in the include
file
@@ -397,6 +431,14 @@ g.gl_pathv[0] = "ls";
g.gl_pathv[1] = "-l";
execvp("ls", g.gl_pathv);
.Ed
+.Sh CAVEATS
+The
+.Fn glob
+and
+.Fn glob_b
+functions
+will not match filenames that begin with a period
+unless this is specifically requested (e.g., by ".*").
.Sh SEE ALSO
.Xr sh 1 ,
.Xr fnmatch 3 ,
@@ -435,6 +477,10 @@ and
.Fn globfree
functions first appeared in
.Bx 4.4 .
+The
+.Fn glob_b
+function first appeared in
+.Fx 15.0 .
.Sh BUGS
Patterns longer than
.Dv MAXPATHLEN
@@ -442,7 +488,9 @@ may cause unchecked errors.
.Pp
The
.Fn glob
-argument
+and
+.Fn glob_b
+functions
may fail and set errno for any of the errors specified for the
library routines
.Xr stat 2 ,
diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c
index 7a988196549a..f7da5f0cda09 100644
--- a/lib/libc/gen/glob.c
+++ b/lib/libc/gen/glob.c
@@ -88,8 +88,11 @@
#include <unistd.h>
#include <wchar.h>
+#include "block_abi.h"
#include "collate.h"
+typedef DECLARE_BLOCK(int, glob_b_block, const char*, int);
+
/*
* glob(3) expansion limits. Stop the expansion if any of these limits
* is reached. This caps the runtime in the face of DoS attacks. See
@@ -104,8 +107,8 @@
struct glob_limit {
size_t l_brace_cnt;
size_t l_path_lim;
- size_t l_readdir_cnt;
- size_t l_stat_cnt;
+ size_t l_readdir_cnt;
+ size_t l_stat_cnt;
size_t l_string_cnt;
};
@@ -179,9 +182,8 @@ static int err_aborted(glob_t *, int, char *);
static void qprintf(const char *, Char *);
#endif
-int
-glob(const char * __restrict pattern, int flags,
- int (*errfunc)(const char *, int), glob_t * __restrict pglob)
+static int
+__glob(const char *pattern, glob_t *pglob)
{
struct glob_limit limit = { 0, 0, 0, 0, 0 };
const char *patnext;
@@ -192,25 +194,23 @@ glob(const char * __restrict pattern, int flags,
int too_long;
patnext = pattern;
- if (!(flags & GLOB_APPEND)) {
+ if (!(pglob->gl_flags & GLOB_APPEND)) {
pglob->gl_pathc = 0;
pglob->gl_pathv = NULL;
- if (!(flags & GLOB_DOOFFS))
+ if (!(pglob->gl_flags & GLOB_DOOFFS))
pglob->gl_offs = 0;
}
- if (flags & GLOB_LIMIT) {
+ if (pglob->gl_flags & GLOB_LIMIT) {
limit.l_path_lim = pglob->gl_matchc;
if (limit.l_path_lim == 0)
limit.l_path_lim = GLOB_LIMIT_PATH;
}
- pglob->gl_flags = flags & ~GLOB_MAGCHAR;
- pglob->gl_errfunc = errfunc;
pglob->gl_matchc = 0;
bufnext = patbuf;
bufend = bufnext + MAXPATHLEN - 1;
too_long = 1;
- if (flags & GLOB_NOESCAPE) {
+ if (pglob->gl_flags & GLOB_NOESCAPE) {
memset(&mbs, 0, sizeof(mbs));
while (bufnext <= bufend) {
clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
@@ -250,15 +250,45 @@ glob(const char * __restrict pattern, int flags,
return (err_nomatch(pglob, &limit, pattern));
*bufnext = EOS;
- if (flags & GLOB_BRACE)
+ if (pglob->gl_flags & GLOB_BRACE)
return (globexp0(patbuf, pglob, &limit, pattern));
else
return (glob0(patbuf, pglob, &limit, pattern));
}
+int
+glob(const char * __restrict pattern, int flags,
+ int (*errfunc)(const char *, int), glob_t * __restrict pglob)
+{
+ int rv;
+
+ pglob->gl_flags = flags & ~(GLOB_MAGCHAR | _GLOB_ERR_BLOCK);
+ pglob->gl_errfunc = errfunc;
+ rv = __glob(pattern, pglob);
+ pglob->gl_errfunc = NULL;
+
+ return (rv);
+}
+
+int
+glob_b(const char * __restrict pattern, int flags,
+ glob_b_block block, glob_t * __restrict pglob)
+{
+ int rv;
+
+ pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+ pglob->gl_flags |= _GLOB_ERR_BLOCK;
+ pglob->gl_errblk = block;
+ rv = __glob(pattern, pglob);
+ pglob->gl_errblk = NULL;
+
+ return (rv);
+}
+
static int
globexp0(const Char *pattern, glob_t *pglob, struct glob_limit *limit,
- const char *origpat) {
+ const char *origpat)
+{
int rv;
size_t oldpathc;
@@ -724,7 +754,7 @@ glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
return (GLOB_NOSPACE);
}
*pathend = EOS;
- if (pglob->gl_errfunc != NULL &&
+ if ((pglob->gl_errfunc != NULL || pglob->gl_errblk != NULL) &&
g_Ctoc(pathbuf, buf, sizeof(buf))) {
errno = E2BIG;
return (GLOB_NOSPACE);
@@ -1085,10 +1115,21 @@ err_nomatch(glob_t *pglob, struct glob_limit *limit, const char *origpat) {
}
static int
-err_aborted(glob_t *pglob, int err, char *buf) {
- if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) ||
- (pglob->gl_flags & GLOB_ERR))
+err_aborted(glob_t *pglob, int err, char *buf)
+{
+ int rv = 0;
+
+ if ((pglob->gl_flags & _GLOB_ERR_BLOCK) != 0) {
+ if (pglob->gl_errblk != NULL)
+ rv = CALL_BLOCK((glob_b_block)pglob->gl_errblk, buf,
+ errno);
+ } else if (pglob->gl_errfunc != NULL) {
+ rv = pglob->gl_errfunc(buf, errno);
+ }
+ /* GLOB_ERR is allowed to override the error callback function. */
+ if (rv != 0 || pglob->gl_flags & GLOB_ERR) {
return (GLOB_ABORTED);
+ }
return (0);
}
diff --git a/lib/libc/gen/inotify.c b/lib/libc/gen/inotify.c
new file mode 100644
index 000000000000..7ce53aaccd58
--- /dev/null
+++ b/lib/libc/gen/inotify.c
@@ -0,0 +1,48 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Klara, Inc.
+ */
+
+#include "namespace.h"
+#include <sys/fcntl.h>
+#include <sys/inotify.h>
+#include <sys/specialfd.h>
+#include "un-namespace.h"
+#include "libc_private.h"
+
+/*
+ * Provide compatibility with libinotify, which uses different values for these
+ * flags.
+ */
+#define IN_NONBLOCK_OLD 0x80000
+#define IN_CLOEXEC_OLD 0x00800
+
+int
+inotify_add_watch(int fd, const char *pathname, uint32_t mask)
+{
+ return (inotify_add_watch_at(fd, AT_FDCWD, pathname, mask));
+}
+
+int
+inotify_init1(int flags)
+{
+ struct specialfd_inotify args;
+
+ if ((flags & IN_NONBLOCK_OLD) != 0) {
+ flags &= ~IN_NONBLOCK_OLD;
+ flags |= IN_NONBLOCK;
+ }
+ if ((flags & IN_CLOEXEC_OLD) != 0) {
+ flags &= ~IN_CLOEXEC_OLD;
+ flags |= IN_CLOEXEC;
+ }
+ args.flags = flags;
+ return (__sys___specialfd(SPECIALFD_INOTIFY, &args, sizeof(args)));
+}
+
+int
+inotify_init(void)
+{
+ return (inotify_init1(0));
+}
diff --git a/lib/libc/gen/libc_interposing_table.c b/lib/libc/gen/libc_interposing_table.c
index d15d32711910..025a67ac3eac 100644
--- a/lib/libc/gen/libc_interposing_table.c
+++ b/lib/libc/gen/libc_interposing_table.c
@@ -42,7 +42,7 @@ interpos_func_t __libc_interposing[INTERPOS_MAX] = {
SLOT(spinlock, __libc_spinlock_stub),
SLOT(spinunlock, __libc_spinunlock_stub),
SLOT(map_stacks_exec, __libc_map_stacks_exec),
- SLOT(distribute_static_tls, __libc_distribute_static_tls),
+ SLOT(uexterr_gettext, __libc_uexterr_gettext),
};
#undef SLOT
diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c
index 956c92c321e8..08d9eb10eaa2 100644
--- a/lib/libc/gen/opendir.c
+++ b/lib/libc/gen/opendir.c
@@ -30,14 +30,7 @@
*/
#include "namespace.h"
-#include <sys/param.h>
-
#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
#include "un-namespace.h"
#include "gen-private.h"
diff --git a/lib/libc/gen/opendir2.c b/lib/libc/gen/opendir2.c
index 30a9030693e4..c5c2e662efd8 100644
--- a/lib/libc/gen/opendir2.c
+++ b/lib/libc/gen/opendir2.c
@@ -30,11 +30,12 @@
*/
#include "namespace.h"
-#include <sys/param.h>
+#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -52,8 +53,7 @@ __opendir2(const char *name, int flags)
if ((flags & (__DTF_READALL | __DTF_SKIPREAD)) != 0)
return (NULL);
- if ((fd = _open(name,
- O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC)) == -1)
+ if ((fd = _open(name, O_DIRECTORY | O_RDONLY | O_CLOEXEC)) == -1)
return (NULL);
dir = __opendir_common(fd, flags, false);
@@ -243,20 +243,18 @@ _filldir(DIR *dirp, bool use_current_pos)
return (true);
}
+/*
+ * Return true if the file descriptor is associated with a file from a
+ * union file system or from a file system mounted with the union flag.
+ */
static bool
is_unionstack(int fd)
{
- int unionstack;
-
- unionstack = _fcntl(fd, F_ISUNIONSTACK, 0);
- if (unionstack != -1)
- return (unionstack);
-
/*
- * Should not happen unless running on a kernel without the op,
- * but no use rendering the system useless in such a case.
+ * This call shouldn't fail, but if it does, just assume that the
+ * answer is no.
*/
- return (0);
+ return (_fcntl(fd, F_ISUNIONSTACK, 0) > 0);
}
/*
@@ -266,6 +264,7 @@ DIR *
__opendir_common(int fd, int flags, bool use_current_pos)
{
DIR *dirp;
+ ssize_t ret;
int incr;
int saved_errno;
bool unionstack;
@@ -315,13 +314,11 @@ __opendir_common(int fd, int flags, bool use_current_pos)
* to prime dd_seek. This also checks if the
* fd passed to fdopendir() is a directory.
*/
- dirp->dd_size = _getdirentries(dirp->dd_fd,
+ ret = _getdirentries(dirp->dd_fd,
dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
- if (dirp->dd_size < 0) {
- if (errno == EINVAL)
- errno = ENOTDIR;
+ if (ret < 0)
goto fail;
- }
+ dirp->dd_size = (size_t)ret;
dirp->dd_flags |= __DTF_SKIPREAD;
} else {
dirp->dd_size = 0;
diff --git a/lib/libc/gen/posix_spawn.c b/lib/libc/gen/posix_spawn.c
index ee2ce05ff317..a5b732696b8c 100644
--- a/lib/libc/gen/posix_spawn.c
+++ b/lib/libc/gen/posix_spawn.c
@@ -261,7 +261,7 @@ _posix_spawn_thr(void *data)
}
envp = psa->envp != NULL ? psa->envp : environ;
if (psa->use_env_path)
- execvpe(psa->path, psa->argv, envp);
+ __libc_execvpe(psa->path, psa->argv, envp);
else
_execve(psa->path, psa->argv, envp);
psa->error = errno;
diff --git a/lib/libc/gen/psignal.3 b/lib/libc/gen/psignal.3
index cd3cef0b44a9..098b7b02a9b9 100644
--- a/lib/libc/gen/psignal.3
+++ b/lib/libc/gen/psignal.3
@@ -25,14 +25,17 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 30, 2016
+.Dd May 10, 2025
.Dt PSIGNAL 3
.Os
.Sh NAME
.Nm psignal ,
+.Nm psiginfo ,
.Nm strsignal ,
.Nm sys_siglist ,
-.Nm sys_signame
+.Nm sys_signame ,
+.Nm sig2str ,
+.Nm str2sig
.Nd system signal messages
.Sh LIBRARY
.Lb libc
@@ -40,11 +43,17 @@
.In signal.h
.Ft void
.Fn psignal "int sig" "const char *s"
+.Ft void
+.Fn psiginfo "const siginfo_t *si" "const char *s"
.Vt extern const char * const sys_siglist[] ;
.Vt extern const char * const sys_signame[] ;
.In string.h
.Ft "char *"
.Fn strsignal "int sig"
+.Ft int
+.Fn sig2str "int signum" "char *str"
+.Ft int
+.Fn str2sig "char *str" "int *pnum"
.Sh DESCRIPTION
The
.Fn psignal
@@ -79,6 +88,16 @@ the string
.Dq "Unknown signal"
is produced.
.Pp
+The
+.Fn psiginfo
+function is similar to
+.Fn psignal ,
+except that the signal number information is taken from the
+.Fa si
+argument which is a
+.Vt siginfo_t
+structure.
+.Pp
The message strings can be accessed directly
through the external array
.Va sys_siglist ,
@@ -95,12 +114,65 @@ contains a count of the strings in
.Va sys_siglist
and
.Va sys_signame .
+.Pp
+The
+.Fn sig2str
+function translates the signal number
+.Fa signum
+to the signal name, without the
+.Dq SIG
+prefix, and stores it at the location specified by
+.Fa str ,
+which should be large enough to hold the name and the terminating
+.Dv NUL
+byte.
+The symbol
+.Dv SIG2STR_MAX
+gives the maximum size in bytes required.
+.Pp
+The
+.Fn str2sig
+function translates the signal name
+.Fa str
+to a signal number and stores it in the location referenced by
+.Fa pnum .
+The name in
+.Fa str
+can be either the name of the signal, with or without the
+.Dq SIG
+prefix, or a decimal number.
.Sh SEE ALSO
.Xr sigaction 2 ,
.Xr perror 3 ,
.Xr strerror 3
+.Sh STANDARDS
+The
+.Fn psignal
+and
+.Fn psiginfo
+functions are defined by
+.St -p1003.1-2008
+, while the
+.Fn sig2str
+and
+.Fn str2sig
+functions are defined by
+.St -p1003.1-2024 .
.Sh HISTORY
The
.Fn psignal
function appeared in
.Bx 4.2 .
+The
+.Fn psiginfo
+function appeared in
+.Fx 14.3 ,
+.Nx 6.0 ,
+and
+.Dx 4.1 .
+The
+.Fn sig2str
+and
+.Fn str2sig
+functions appeared in
+.Fx 15.0 .
diff --git a/lib/libc/gen/psignal.c b/lib/libc/gen/psignal.c
index ab044f683d86..291a6a9337a0 100644
--- a/lib/libc/gen/psignal.c
+++ b/lib/libc/gen/psignal.c
@@ -55,3 +55,9 @@ psignal(int sig, const char *s)
(void)_write(STDERR_FILENO, c, strlen(c));
(void)_write(STDERR_FILENO, "\n", 1);
}
+
+void
+psiginfo(const siginfo_t *si, const char *s)
+{
+ psignal(si->si_signo, s);
+}
diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c
index 2a2fa999b7ce..b70102954df1 100644
--- a/lib/libc/gen/readdir.c
+++ b/lib/libc/gen/readdir.c
@@ -48,8 +48,9 @@ struct dirent *
_readdir_unlocked(DIR *dirp, int flags)
{
struct dirent *dp;
- long initial_seek;
- long initial_loc = 0;
+ off_t initial_seek;
+ size_t initial_loc = 0;
+ ssize_t ret;
for (;;) {
if (dirp->dd_loc >= dirp->dd_size) {
@@ -61,11 +62,13 @@ _readdir_unlocked(DIR *dirp, int flags)
}
if (dirp->dd_loc == 0 &&
!(dirp->dd_flags & (__DTF_READALL | __DTF_SKIPREAD))) {
+ dirp->dd_size = 0;
initial_seek = dirp->dd_seek;
- dirp->dd_size = _getdirentries(dirp->dd_fd,
+ ret = _getdirentries(dirp->dd_fd,
dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
- if (dirp->dd_size <= 0)
+ if (ret <= 0)
return (NULL);
+ dirp->dd_size = (size_t)ret;
_fixtelldir(dirp, initial_seek, initial_loc);
}
dirp->dd_flags &= ~__DTF_SKIPREAD;
diff --git a/lib/libc/gen/rtld_get_var.3 b/lib/libc/gen/rtld_get_var.3
index e211d78345e3..092114e86d78 100644
--- a/lib/libc/gen/rtld_get_var.3
+++ b/lib/libc/gen/rtld_get_var.3
@@ -103,4 +103,4 @@ is unknown.
The
.Nm
function first appeared in
-.Fx 15.0 .
+.Fx 14.3 .
diff --git a/lib/libc/gen/scandir.3 b/lib/libc/gen/scandir.3
index 6656842c251f..3da4500cefb9 100644
--- a/lib/libc/gen/scandir.3
+++ b/lib/libc/gen/scandir.3
@@ -25,13 +25,16 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 31, 2023
+.Dd June 25, 2025
.Dt SCANDIR 3
.Os
.Sh NAME
.Nm scandir ,
+.Nm fdscandir ,
.Nm scandirat ,
.Nm scandir_b ,
+.Nm fdscandir_b ,
+.Nm fdscandirat_b ,
.Nm alphasort ,
.Nm versionsort
.Nd scan a directory
@@ -47,6 +50,13 @@
.Fa "int \*(lp*compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
.Fc
.Ft int
+.Fo fdscandir
+.Fa "int dirfd"
+.Fa "struct dirent ***namelist"
+.Fa "int \*(lp*select\*(rp\*(lpconst struct dirent *\*(rp"
+.Fa "int \*(lp*compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
+.Fc
+.Ft int
.Fo scandirat
.Fa "int dirfd"
.Fa "const char *dirname"
@@ -62,6 +72,21 @@
.Fa "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
.Fc
.Ft int
+.Fo fdscandir_b
+.Fa "int dirfd"
+.Fa "struct dirent ***namelist"
+.Fa "int \*(lp^select\*(rp\*(lpconst struct dirent *\*(rp"
+.Fa "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
+.Fc
+.Ft int
+.Fo scandirat_b
+.Fa "int dirfd"
+.Fa "const char *dirname"
+.Fa "struct dirent ***namelist"
+.Fa "int \*(lp^select\*(rp\*(lpconst struct dirent *\*(rp"
+.Fa "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp"
+.Fc
+.Ft int
.Fn alphasort "const struct dirent **d1" "const struct dirent **d2"
.Ft int
.Fn versionsort "const struct dirent **d1" "const struct dirent **d2"
@@ -77,7 +102,8 @@ entries using
It returns the number of entries in the array.
A pointer to the array of directory entries is stored in the location
referenced by
-.Fa namelist .
+.Fa namelist
+(even if no entries were selected).
.Pp
The
.Fa select
@@ -118,6 +144,13 @@ The memory allocated for the array can be deallocated with
by freeing each pointer in the array and then the array itself.
.Pp
The
+.Fn fdscandir
+function is similar to
+.Fn scandir ,
+but takes a file descriptor referencing a directory instead of a path.
+The file descriptor is left open on return, regardless of outcome.
+.Pp
+The
.Fn scandirat
function is similar to
.Fn scandir ,
@@ -151,17 +184,67 @@ See
for additional details.
.Pp
The
-.Fn scandir_b
-function behaves in the same way as
+.Fn scandir_b ,
+.Fn fdscandir_b ,
+and
+.Fn scandirat_b
+functions behave in the same way as
.Fn scandir ,
-but takes blocks as arguments instead of function pointers and calls
+.Fn fdscandir ,
+and
+.Fn scandirat ,
+respectively,
+but take blocks as arguments instead of function pointers and call
.Fn qsort_b
rather than
.Fn qsort .
.Sh DIAGNOSTICS
-Returns \-1 if the directory cannot be opened for reading or if
+The
+.Fn scandir ,
+.Fn fdscandir ,
+.Fn scandirat ,
+.Fn scandir_b ,
+.Fn fdscandir_b ,
+and
+.Fn scandirat_b
+functions return the number of directory entries found on succes.
+If the directory cannot be opened for reading, an error occurs
+while reading the directory, or
.Xr malloc 3
-cannot allocate enough memory to hold all the data structures.
+cannot allocate enough memory to hold all the directory entries,
+they return \-1 and set
+.Va errno
+to an appropriate value.
+.Sh ERRORS
+The
+.Fn scandir ,
+.Fn scandirat ,
+.Fn scandir_b ,
+and
+.Fn scandirat_b
+functions may fail and set
+.Va errno
+for any of the errors specified for the
+.Xr opendir 3 ,
+.Xr malloc 3 ,
+.Xr readdir 3 ,
+and
+.Xr closedir 3
+functions.
+.Pp
+The
+.Fn fdscandir
+and
+.Fn fdscandir_b
+functions may fail and set
+.Va errno
+for any of the errors specified for the
+.Xr fdopendir 3 ,
+.Xr malloc 3 ,
+.Xr readdir 3 ,
+and
+.Xr closedir 3
+functions.
.Sh SEE ALSO
.Xr openat 2 ,
.Xr directory 3 ,
@@ -172,8 +255,25 @@ cannot allocate enough memory to hold all the data structures.
.Xr dir 5
.Sh STANDARDS
The
+.Fn alphasort
+and
+.Fn scandir
+functions are expected to conform to
+.St -p1003.1-2008 .
+The
+.Fn scandirat
+and
.Fn versionsort
-function is a GNU extension and conforms to no standard.
+functions are GNU extensions and conform to no standard.
+The
+.Fn fdscandir ,
+.Fn scandir_b ,
+.Fn fdscandir_b ,
+and
+.Fn scandirat_b
+functions are
+.Fx
+extensions.
.Sh HISTORY
The
.Fn scandir
@@ -182,8 +282,19 @@ and
functions appeared in
.Bx 4.2 .
The
+.Fn scandir_b
+function was added in
+.Fx 11.0 .
+The
.Fn scandirat
and
.Fn versionsort
functions were added in
.Fx 13.2 .
+The
+.Fn fdscandir ,
+.Fn fdscandir_b ,
+and
+.Fn scandirat_b
+functions were added in
+.Fx 15.0 .
diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c
index f59f57047278..fb589f4b36b6 100644
--- a/lib/libc/gen/scandir.c
+++ b/lib/libc/gen/scandir.c
@@ -38,6 +38,7 @@
#include "namespace.h"
#include <dirent.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
@@ -64,71 +65,76 @@ static int scandir_thunk_cmp(const void *p1, const void *p2, void *thunk);
static int
#ifdef I_AM_SCANDIR_B
-scandir_b_dirp(DIR *dirp, struct dirent ***namelist, select_block select,
+scandir_dirp_b(DIR *dirp, struct dirent ***namelist, select_block select,
dcomp_block dcomp)
#else
scandir_dirp(DIR *dirp, struct dirent ***namelist,
- int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **,
- const struct dirent **))
+ int (*select)(const struct dirent *),
+ int (*dcomp)(const struct dirent **, const struct dirent **))
#endif
{
- struct dirent *d, *p, **names = NULL;
- size_t arraysz, numitems;
+ struct dirent *d, *p = NULL, **names = NULL, **names2;
+ size_t arraysz = 32, numitems = 0;
+ int serrno;
- numitems = 0;
- arraysz = 32; /* initial estimate of the array size */
- names = (struct dirent **)malloc(arraysz * sizeof(struct dirent *));
+ names = malloc(arraysz * sizeof(*names));
if (names == NULL)
- goto fail;
+ return (-1);
- while ((d = readdir(dirp)) != NULL) {
+ while (errno = 0, (d = readdir(dirp)) != NULL) {
if (select != NULL && !SELECT(d))
continue; /* just selected names */
/*
* Make a minimum size copy of the data
*/
- p = (struct dirent *)malloc(_GENERIC_DIRSIZ(d));
+ p = malloc(_GENERIC_DIRSIZ(d));
if (p == NULL)
goto fail;
p->d_fileno = d->d_fileno;
p->d_type = d->d_type;
p->d_reclen = d->d_reclen;
p->d_namlen = d->d_namlen;
- bcopy(d->d_name, p->d_name, p->d_namlen + 1);
+ memcpy(p->d_name, d->d_name, p->d_namlen + 1);
/*
* Check to make sure the array has space left and
* realloc the maximum size.
*/
if (numitems >= arraysz) {
- struct dirent **names2;
-
- names2 = reallocarray(names, arraysz,
- 2 * sizeof(struct dirent *));
- if (names2 == NULL) {
- free(p);
+ arraysz = arraysz * 2;
+ names2 = reallocarray(names, arraysz, sizeof(*names));
+ if (names2 == NULL)
goto fail;
- }
names = names2;
- arraysz *= 2;
}
names[numitems++] = p;
}
- closedir(dirp);
- if (numitems && dcomp != NULL)
+ /*
+ * Since we can't simultaneously return both -1 and a count, we
+ * must either suppress the error or discard the partial result.
+ * The latter seems the lesser of two evils.
+ */
+ if (errno != 0)
+ goto fail;
+ if (numitems > 0 && dcomp != NULL) {
#ifdef I_AM_SCANDIR_B
- qsort_b(names, numitems, sizeof(struct dirent *), (void*)dcomp);
+ qsort_b(names, numitems, sizeof(struct dirent *),
+ (void *)dcomp);
#else
qsort_r(names, numitems, sizeof(struct dirent *),
scandir_thunk_cmp, &dcomp);
#endif
+ }
*namelist = names;
return (numitems);
fail:
+ serrno = errno;
+ if (numitems == 0 || names[numitems - 1] != p)
+ free(p);
while (numitems > 0)
free(names[--numitems]);
free(names);
- closedir(dirp);
+ errno = serrno;
return (-1);
}
@@ -138,44 +144,87 @@ scandir_b(const char *dirname, struct dirent ***namelist, select_block select,
dcomp_block dcomp)
#else
scandir(const char *dirname, struct dirent ***namelist,
- int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **,
- const struct dirent **))
+ int (*select)(const struct dirent *),
+ int (*dcomp)(const struct dirent **, const struct dirent **))
#endif
{
DIR *dirp;
+ int ret, serrno;
dirp = opendir(dirname);
if (dirp == NULL)
return (-1);
- return (
+ ret =
#ifdef I_AM_SCANDIR_B
- scandir_b_dirp
+ scandir_dirp_b
#else
scandir_dirp
#endif
- (dirp, namelist, select, dcomp));
+ (dirp, namelist, select, dcomp);
+ serrno = errno;
+ closedir(dirp);
+ errno = serrno;
+ return (ret);
}
-#ifndef I_AM_SCANDIR_B
int
-scandirat(int dirfd, const char *dirname, struct dirent ***namelist,
- int (*select)(const struct dirent *), int (*dcomp)(const struct dirent **,
- const struct dirent **))
+#ifdef I_AM_SCANDIR_B
+fdscandir_b(int dirfd, struct dirent ***namelist, select_block select,
+ dcomp_block dcomp)
+#else
+fdscandir(int dirfd, struct dirent ***namelist,
+ int (*select)(const struct dirent *),
+ int (*dcomp)(const struct dirent **, const struct dirent **))
+#endif
{
DIR *dirp;
- int fd;
+ int ret, serrno;
+
+ dirp = fdopendir(dirfd);
+ if (dirp == NULL)
+ return (-1);
+ ret =
+#ifdef I_AM_SCANDIR_B
+ scandir_dirp_b
+#else
+ scandir_dirp
+#endif
+ (dirp, namelist, select, dcomp);
+ serrno = errno;
+ fdclosedir(dirp);
+ errno = serrno;
+ return (ret);
+}
+
+int
+#ifdef I_AM_SCANDIR_B
+scandirat_b(int dirfd, const char *dirname, struct dirent ***namelist,
+ select_block select, dcomp_block dcomp)
+#else
+scandirat(int dirfd, const char *dirname, struct dirent ***namelist,
+ int (*select)(const struct dirent *),
+ int (*dcomp)(const struct dirent **, const struct dirent **))
+#endif
+{
+ int fd, ret, serrno;
fd = _openat(dirfd, dirname, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
if (fd == -1)
return (-1);
- dirp = fdopendir(fd);
- if (dirp == NULL) {
- _close(fd);
- return (-1);
- }
- return (scandir_dirp(dirp, namelist, select, dcomp));
+ ret =
+#ifdef I_AM_SCANDIR_B
+ fdscandir_b
+#else
+ fdscandir
+#endif
+ (fd, namelist, select, dcomp);
+ serrno = errno;
+ _close(fd);
+ errno = serrno;
+ return (ret);
}
+#ifndef I_AM_SCANDIR_B
/*
* Alphabetic order comparison routine for those who want it.
* POSIX 2008 requires that alphasort() uses strcoll().
diff --git a/lib/libc/gen/sig2str.c b/lib/libc/gen/sig2str.c
new file mode 100644
index 000000000000..869a09ab9db4
--- /dev/null
+++ b/lib/libc/gen/sig2str.c
@@ -0,0 +1,113 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Ricardo Branco <rbranco@suse.de>.
+ *
+ * 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.
+ */
+
+/*
+ * Translate between signal names and numbers
+ */
+#include "namespace.h"
+#include <ctype.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ssp/ssp.h>
+#include "un-namespace.h"
+
+static const char rtmin_str[] = "RTMIN";
+static const char rtmax_str[] = "RTMAX";
+
+int
+__ssp_real(sig2str)(int signum, char *str)
+{
+ if (signum <= 0 || signum > SIGRTMAX)
+ return (-1);
+
+ if (signum < sys_nsig)
+ (void)strlcpy(str, sys_signame[signum], SIG2STR_MAX);
+ else if (signum < SIGRTMIN)
+ (void)snprintf(str, SIG2STR_MAX, "%d", signum);
+ else if (signum == SIGRTMIN)
+ (void)strlcpy(str, rtmin_str, SIG2STR_MAX);
+ else if (signum == SIGRTMAX)
+ (void)strlcpy(str, rtmax_str, SIG2STR_MAX);
+ else if (signum <= (SIGRTMIN + SIGRTMAX) / 2)
+ (void)snprintf(str, SIG2STR_MAX, "%s+%d",
+ rtmin_str, signum - SIGRTMIN);
+ else
+ (void)snprintf(str, SIG2STR_MAX, "%s-%d",
+ rtmax_str, SIGRTMAX - signum);
+
+ return (0);
+}
+
+int
+str2sig(const char * restrict str, int * restrict pnum)
+{
+ const char *errstr;
+ long long n;
+ int sig;
+ int rtend = sizeof(rtmin_str) - 1;
+
+ if (strncasecmp(str, "SIG", 3) == 0)
+ str += 3;
+
+ if (strncasecmp(str, rtmin_str, sizeof(rtmin_str) - 1) == 0 ||
+ strncasecmp(str, rtmax_str, sizeof(rtmax_str) - 1) == 0) {
+ sig = (toupper(str[4]) == 'X') ? SIGRTMAX : SIGRTMIN;
+ n = 0;
+ if (str[rtend] == '+' || str[rtend] == '-') {
+ n = strtonum(str + rtend, INT_MIN, INT_MAX, &errstr);
+ if (n == 0 || errstr != NULL)
+ return (-1);
+ } else if (str[rtend] != '\0') {
+ return (-1);
+ }
+ sig += (int)n;
+ if (sig < SIGRTMIN || sig > SIGRTMAX)
+ return (-1);
+ *pnum = sig;
+ return (0);
+ }
+
+ if (isdigit((unsigned char)str[0])) {
+ n = strtonum(str, 1, SIGRTMAX, &errstr);
+ if (errstr == NULL) {
+ *pnum = (int)n;
+ return (0);
+ }
+ }
+
+ for (sig = 1; sig < sys_nsig; sig++) {
+ if (strcasecmp(sys_signame[sig], str) == 0) {
+ *pnum = sig;
+ return (0);
+ }
+ }
+
+ return (-1);
+}
diff --git a/lib/libc/gen/sysconf.c b/lib/libc/gen/sysconf.c
index be42dd238b56..66562d0e29f0 100644
--- a/lib/libc/gen/sysconf.c
+++ b/lib/libc/gen/sysconf.c
@@ -34,6 +34,7 @@
#include "namespace.h"
#include <sys/param.h>
+#include <sys/exterrvar.h>
#include <sys/time.h>
#include <sys/sysctl.h>
#include <sys/resource.h>
@@ -286,6 +287,8 @@ do_NAME_MAX:
mib[0] = CTL_P1003_1B;
mib[1] = CTL_P1003_1B_MQ_OPEN_MAX;
goto yesno;
+ case _SC_NSIG:
+ return (_SIG_MAXSIG);
case _SC_PAGESIZE:
return (getpagesize());
case _SC_RTSIG_MAX:
@@ -567,7 +570,7 @@ yesno:
case _SC_IPV6:
#if _POSIX_IPV6 == 0
sverrno = errno;
- value = _socket(PF_INET6, SOCK_DGRAM, 0);
+ value = _socket(PF_INET6, SOCK_CLOEXEC | SOCK_DGRAM, 0);
errno = sverrno;
if (value >= 0) {
_close(value);
@@ -602,6 +605,8 @@ yesno:
return (-1);
return ((long)value);
#endif
+ case _SC_UEXTERR_MAXLEN:
+ return (UEXTERROR_MAXLEN);
default:
errno = EINVAL;
diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3
index fb68ddd60edc..95e33dc802be 100644
--- a/lib/libc/gen/sysctl.3
+++ b/lib/libc/gen/sysctl.3
@@ -502,7 +502,6 @@ specifies the current process.
.It Dv KERN_PROC_ENV Ta "Set of strings"
.It Dv KERN_PROC_AUXV Ta "Elf_Auxinfo []"
.It Dv KERN_PROC_RLIMIT Ta "Integer"
-.It Dv KERN_PROC_RLIMIT_USAGE Ta "rlim_t []"
.It Dv KERN_PROC_PS_STRINGS Ta "Integer"
.It Dv KERN_PROC_UMASK Ta "Integer/short"
.It Dv KERN_PROC_OSREL Ta "Integer"
@@ -511,6 +510,7 @@ specifies the current process.
.It Dv KERN_PROC_NFDS Ta "Integer"
.It Dv KERN_PROC_SIGFASTBLK Ta "Integer"
.It Dv KERN_PROC_VM_LAYOUT Ta "struct kinfo_vm_layout"
+.It Dv KERN_PROC_RLIMIT_USAGE Ta "rlim_t []"
.It Dv KERN_PROC_KQUEUE Ta "struct kinfo_knote []"
.El
.Pp
@@ -549,13 +549,6 @@ Additinal OID name element must be supplied, specifiing the resource name
as in
.Xr getrlimit 2 .
The call returns the given resource limit for the process.
-.It Dv KERN_PROC_RLIMIT_USAGE
-Like
-.Dv KERN_PROC_RLIMIT ,
-but instead of the limit, returns the accounted resource usage.
-For resources which do not have a meaningful current value,
-.Li \-1
-is returned.
.It Dv KERN_PROC_PS_STRINGS
Returns the location of the
.Vt ps_strings
@@ -585,6 +578,13 @@ Returns the address of the
location, if active.
.It Dv KERN_PROC_VM_LAYOUT
Fills a structure describing process virtual address space layout.
+.It Dv KERN_PROC_RLIMIT_USAGE
+Like
+.Dv KERN_PROC_RLIMIT ,
+but instead of the limit, returns the accounted resource usage.
+For resources which do not have a meaningful current value,
+.Li \-1
+is returned.
.It Dv KERN_PROC_KQUEUE
Fills an array of structures describing events registered with
the specified kqueue.
diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c
index b751fafd975f..1731cc4d7a2c 100644
--- a/lib/libc/gen/telldir.c
+++ b/lib/libc/gen/telldir.c
@@ -118,7 +118,7 @@ _seekdir(DIR *dirp, long loc)
struct dirent *dp;
union ddloc_packed ddloc;
off_t loc_seek;
- long loc_loc;
+ size_t loc_loc;
ddloc.l = loc;
@@ -171,7 +171,7 @@ _seekdir(DIR *dirp, long loc)
* fetching a new block to fix any such telldir locations.
*/
void
-_fixtelldir(DIR *dirp, long oldseek, long oldloc)
+_fixtelldir(DIR *dirp, off_t oldseek, size_t oldloc)
{
struct ddloc_mem *lp;
diff --git a/lib/libc/gen/telldir.h b/lib/libc/gen/telldir.h
index 6d113491e819..02fd52af9060 100644
--- a/lib/libc/gen/telldir.h
+++ b/lib/libc/gen/telldir.h
@@ -46,9 +46,9 @@
*/
struct ddloc_mem {
LIST_ENTRY(ddloc_mem) loc_lqe; /* entry in list */
- long loc_index; /* key associated with structure */
+ size_t loc_index; /* key associated with structure */
off_t loc_seek; /* magic cookie returned by getdirentries */
- long loc_loc; /* offset of entry in buffer */
+ size_t loc_loc; /* offset of entry in buffer */
};
#ifdef __LP64__
@@ -102,7 +102,7 @@ bool _filldir(DIR *, bool);
struct dirent *_readdir_unlocked(DIR *, int);
void _reclaim_telldir(DIR *);
void _seekdir(DIR *, long);
-void _fixtelldir(DIR *dirp, long oldseek, long oldloc);
+void _fixtelldir(DIR *dirp, off_t oldseek, size_t oldloc);
DIR *__opendir_common(int, int, bool);
#define RDU_SKIP 0x0001
diff --git a/lib/libc/gen/tls.c b/lib/libc/gen/tls.c
index 30b4fc583c98..b26b13d45589 100644
--- a/lib/libc/gen/tls.c
+++ b/lib/libc/gen/tls.c
@@ -80,13 +80,13 @@ static void *libc_tls_init;
void *
__libc_tls_get_addr(void *vti)
{
- uintptr_t *dtv;
+ struct dtv *dtv;
tls_index *ti;
dtv = _tcb_get()->tcb_dtv;
ti = vti;
- return ((char *)(dtv[ti->ti_module + 1] + ti->ti_offset) +
- TLS_DTV_OFFSET);
+ return (dtv->dtv_slots[ti->ti_module - 1].dtvs_tls +
+ (ti->ti_offset + TLS_DTV_OFFSET));
}
#ifdef __i386__
@@ -151,7 +151,8 @@ libc_free_aligned(void *ptr)
* where TP points (with bias) to TLS and TCB immediately precedes TLS without
* any alignment gap[4]. Only TLS should be aligned. The TCB[0] points to DTV
* vector and DTV values are biased by constant value (TLS_DTV_OFFSET) from
- * real addresses[5].
+ * real addresses. However, like RTLD, we don't actually bias the DTV values,
+ * instead we compensate in __tls_get_addr for ti_offset's bias.
*
* [1] Ulrich Drepper: ELF Handling for Thread-Local Storage
* www.akkadia.org/drepper/tls.pdf
@@ -167,8 +168,6 @@ libc_free_aligned(void *ptr)
* but we must follow this rule due to suboptimal _tcb_set()
* (aka <ARCH>_SET_TP) implementation. This function doesn't expect TP but
* TCB as argument.
- *
- * [5] I'm not able to validate "values are biased" assertions.
*/
/*
@@ -201,11 +200,9 @@ get_tls_block_ptr(void *tcb, size_t tcbsize)
void
__libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused)
{
- Elf_Addr *dtv;
- Elf_Addr **tls;
+ struct dtv *dtv;
- tls = (Elf_Addr **)tcb;
- dtv = tls[0];
+ dtv = ((struct tcb *)tcb)->tcb_dtv;
__je_bootstrap_free(dtv);
libc_free_aligned(get_tls_block_ptr(tcb, tcbsize));
}
@@ -233,7 +230,8 @@ __libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused)
void *
__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign)
{
- Elf_Addr *dtv, **tcb;
+ struct dtv *dtv;
+ struct tcb *tcb;
char *tls_block, *tls;
size_t extra_size, maxalign, post_size, pre_size, tls_block_size;
@@ -262,7 +260,7 @@ __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign)
abort();
}
memset(tls_block, 0, tls_block_size);
- tcb = (Elf_Addr **)(tls_block + pre_size + extra_size);
+ tcb = (struct tcb *)(tls_block + pre_size + extra_size);
tls = (char *)tcb + TLS_TCB_SIZE + post_size;
if (oldtcb != NULL) {
@@ -271,19 +269,20 @@ __libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign)
libc_free_aligned(oldtcb);
/* Adjust the DTV. */
- dtv = tcb[0];
- dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET);
+ dtv = tcb->tcb_dtv;
+ dtv->dtv_slots[0].dtvs_tls = tls;
} else {
- dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr));
+ dtv = __je_bootstrap_malloc(sizeof(struct dtv) +
+ sizeof(struct dtv_slot));
if (dtv == NULL) {
tls_msg("__libc_allocate_tls: Out of memory.\n");
abort();
}
/* Build the DTV. */
- tcb[0] = dtv;
- dtv[0] = 1; /* Generation. */
- dtv[1] = 1; /* Segments count. */
- dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET);
+ tcb->tcb_dtv = dtv;
+ dtv->dtv_gen = 1; /* Generation. */
+ dtv->dtv_size = 1; /* Segments count. */
+ dtv->dtv_slots[0].dtvs_tls = tls;
if (libc_tls_init_size > 0)
memcpy(tls, libc_tls_init, libc_tls_init_size);
@@ -303,8 +302,8 @@ void
__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign)
{
size_t size;
- Elf_Addr* dtv;
- Elf_Addr tlsstart, tlsend;
+ struct dtv *dtv;
+ uintptr_t tlsstart, tlsend;
/*
* Figure out the size of the initial TLS block so that we can
@@ -313,8 +312,8 @@ __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign)
tcbalign = MAX(tcbalign, libc_tls_init_align);
size = roundup2(libc_tls_static_space, tcbalign);
- dtv = ((Elf_Addr**)tcb)[1];
- tlsend = (Elf_Addr) tcb;
+ dtv = ((struct tcb *)tcb)->tcb_dtv;
+ tlsend = (uintptr_t)tcb;
tlsstart = tlsend - size;
libc_free_aligned((void*)tlsstart);
__je_bootstrap_free(dtv);
@@ -324,61 +323,60 @@ __libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign)
* Allocate Static TLS using the Variant II method.
*/
void *
-__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
+__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign)
{
size_t size;
- char *tls;
- Elf_Addr *dtv;
- Elf_Addr segbase, oldsegbase;
+ char *tls_block, *tls;
+ struct dtv *dtv;
+ struct tcb *tcb;
tcbalign = MAX(tcbalign, libc_tls_init_align);
size = roundup2(libc_tls_static_space, tcbalign);
- if (tcbsize < 2 * sizeof(Elf_Addr))
- tcbsize = 2 * sizeof(Elf_Addr);
- tls = libc_malloc_aligned(size + tcbsize, tcbalign);
- if (tls == NULL) {
+ if (tcbsize < 2 * sizeof(uintptr_t))
+ tcbsize = 2 * sizeof(uintptr_t);
+ tls_block = libc_malloc_aligned(size + tcbsize, tcbalign);
+ if (tls_block == NULL) {
tls_msg("__libc_allocate_tls: Out of memory.\n");
abort();
}
- memset(tls, 0, size + tcbsize);
- dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr));
+ memset(tls_block, 0, size + tcbsize);
+ dtv = __je_bootstrap_malloc(sizeof(struct dtv) +
+ sizeof(struct dtv_slot));
if (dtv == NULL) {
tls_msg("__libc_allocate_tls: Out of memory.\n");
abort();
}
- segbase = (Elf_Addr)(tls + size);
- ((Elf_Addr*)segbase)[0] = segbase;
- ((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv;
+ tcb = (struct tcb *)(tls_block + size);
+ tls = (char *)tcb - libc_tls_static_space;
+ tcb->tcb_self = tcb;
+ tcb->tcb_dtv = dtv;
- dtv[0] = 1;
- dtv[1] = 1;
- dtv[2] = segbase - libc_tls_static_space;
+ dtv->dtv_gen = 1;
+ dtv->dtv_size = 1;
+ dtv->dtv_slots[0].dtvs_tls = tls;
- if (oldtls) {
+ if (oldtcb != NULL) {
/*
* Copy the static TLS block over whole.
*/
- oldsegbase = (Elf_Addr) oldtls;
- memcpy((void *)(segbase - libc_tls_static_space),
- (const void *)(oldsegbase - libc_tls_static_space),
+ memcpy(tls, (const char *)oldtcb - libc_tls_static_space,
libc_tls_static_space);
/*
* We assume that this block was the one we created with
* allocate_initial_tls().
*/
- _rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr));
+ _rtld_free_tls(oldtcb, 2 * sizeof(uintptr_t),
+ sizeof(uintptr_t));
} else {
- memcpy((void *)(segbase - libc_tls_static_space),
- libc_tls_init, libc_tls_init_size);
- memset((void *)(segbase - libc_tls_static_space +
- libc_tls_init_size), 0,
+ memcpy(tls, libc_tls_init, libc_tls_init_size);
+ memset(tls + libc_tls_init_size, 0,
libc_tls_static_space - libc_tls_init_size);
}
- return (void*) segbase;
+ return (tcb);
}
#endif /* TLS_VARIANT_II */
@@ -386,7 +384,7 @@ __libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
#else
void *
-__libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused,
+__libc_allocate_tls(void *oldtcb __unused, size_t tcbsize __unused,
size_t tcbalign __unused)
{
return (0);
diff --git a/lib/libc/gen/ualarm.3 b/lib/libc/gen/ualarm.3
index f4e0973b133a..dfd9ddd5f434 100644
--- a/lib/libc/gen/ualarm.3
+++ b/lib/libc/gen/ualarm.3
@@ -70,7 +70,7 @@ restriction the maximum number of
.Fa microseconds
and
.Fa interval
-is limited to 100000000000000
+is limited to 100,000,000,000,000
(in case this value fits in the unsigned integer).
.Sh RETURN VALUES
When the signal has successfully been caught,
diff --git a/lib/libc/gen/uexterr_format.c b/lib/libc/gen/uexterr_format.c
new file mode 100644
index 000000000000..e8ddfbd578e3
--- /dev/null
+++ b/lib/libc/gen/uexterr_format.c
@@ -0,0 +1,35 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software were developed by Konstantin Belousov <kib@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ */
+
+#include <sys/types.h>
+#include <sys/exterrvar.h>
+#include <exterr.h>
+#include <stdio.h>
+#include <string.h>
+
+int
+__uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz)
+{
+ if (bufsz > UEXTERROR_MAXLEN)
+ bufsz = UEXTERROR_MAXLEN;
+ if (ue->error == 0) {
+ strlcpy(buf, "", bufsz);
+ return (0);
+ }
+ if (ue->msg[0] == '\0') {
+ snprintf(buf, bufsz,
+ "errno %d category %u (src line %u) p1 %#jx p2 %#jx",
+ ue->error, ue->cat, ue->src_line,
+ (uintmax_t)ue->p1, (uintmax_t)ue->p2);
+ } else {
+ strlcpy(buf, ue->msg, bufsz);
+ }
+ return (0);
+}
diff --git a/lib/libc/gen/uexterr_gettext.c b/lib/libc/gen/uexterr_gettext.c
new file mode 100644
index 000000000000..5b8a5cd17a48
--- /dev/null
+++ b/lib/libc/gen/uexterr_gettext.c
@@ -0,0 +1,43 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software were developed by Konstantin Belousov <kib@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ */
+
+#define _WANT_P_OSREL
+#include <sys/param.h>
+#include <sys/exterrvar.h>
+#include <exterr.h>
+#include <string.h>
+#include "libc_private.h"
+
+static struct uexterror uexterr = {
+ .ver = UEXTERROR_VER,
+};
+
+int __getosreldate(void);
+
+static void uexterr_ctr(void) __attribute__((constructor));
+static void
+uexterr_ctr(void)
+{
+ if (__getosreldate() >= P_OSREL_EXTERRCTL)
+ exterrctl(EXTERRCTL_ENABLE, 0, &uexterr);
+}
+
+int
+__libc_uexterr_gettext(char *buf, size_t bufsz)
+{
+ return (__uexterr_format(&uexterr, buf, bufsz));
+}
+
+int
+uexterr_gettext(char *buf, size_t bufsz)
+{
+ return (((int (*)(char *, size_t))
+ __libc_interposing[INTERPOS_uexterr_gettext])(buf, bufsz));
+}
diff --git a/lib/libc/gen/wordexp.c b/lib/libc/gen/wordexp.c
index f1437e30bbe2..f8080c20d121 100644
--- a/lib/libc/gen/wordexp.c
+++ b/lib/libc/gen/wordexp.c
@@ -265,7 +265,15 @@ cleanup:
errno = serrno;
return (error);
}
- if (wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
+ /*
+ * Check process exit status, but ignore ECHILD as the child may have
+ * been automatically reaped if the process had set SIG_IGN or
+ * SA_NOCLDWAIT for SIGCHLD, and our reason for waitpid was just to
+ * reap our own child on behalf of the calling process.
+ */
+ if (wpid < 0 && errno != ECHILD)
+ return (WRDE_NOSPACE); /* abort for unknown reason */
+ if (wpid >= 0 && (!WIFEXITED(status) || WEXITSTATUS(status) != 0))
return (WRDE_NOSPACE); /* abort for unknown reason */
/*
diff --git a/lib/libc/i386/static_tls.h b/lib/libc/i386/static_tls.h
deleted file mode 100644
index baf9dfc59a5a..000000000000
--- a/lib/libc/i386/static_tls.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _LIBC_I386_STATIC_TLS_H
-#define _LIBC_I386_STATIC_TLS_H
-
-static __inline uintptr_t
-_libc_get_static_tls_base(size_t offset)
-{
- uintptr_t tlsbase;
-
- __asm __volatile("movl %%gs:0, %0" : "=r" (tlsbase));
- tlsbase -= offset;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libc/include/block_abi.h b/lib/libc/include/block_abi.h
index e04998d6148d..cf670c6c079e 100644
--- a/lib/libc/include/block_abi.h
+++ b/lib/libc/include/block_abi.h
@@ -37,7 +37,7 @@
* compilers that support blocks and exposing the ABI in the source for other
* compilers.
*/
-#define CALL_BLOCK(name, ...) name(__VA_ARGS__)
+#define CALL_BLOCK(name, ...) (name)(__VA_ARGS__)
#else // !__BLOCKS__
#define DECLARE_BLOCK(retTy, name, argTys, ...)\
struct {\
diff --git a/lib/libc/include/libc_private.h b/lib/libc/include/libc_private.h
index 4c244f962b2b..db4cbc32be35 100644
--- a/lib/libc/include/libc_private.h
+++ b/lib/libc/include/libc_private.h
@@ -249,8 +249,9 @@ enum {
INTERPOS_map_stacks_exec,
INTERPOS_fdatasync,
INTERPOS_clock_nanosleep,
- INTERPOS_distribute_static_tls,
+ INTERPOS__reserved0, /* was distribute_static_tls */
INTERPOS_pdfork,
+ INTERPOS_uexterr_gettext,
INTERPOS_MAX
};
@@ -345,6 +346,7 @@ struct __ucontext;
struct __wrusage;
enum idtype;
+int __libc_execvpe(const char *, char * const *, char * const *);
int __libc_sigaction(int, const struct sigaction *,
struct sigaction *) __hidden;
int __libc_sigprocmask(int, const __sigset_t *, __sigset_t *)
@@ -359,8 +361,6 @@ struct dl_phdr_info;
int __elf_phdr_match_addr(struct dl_phdr_info *, void *);
void __init_elf_aux_vector(void);
void __libc_map_stacks_exec(void);
-void __libc_distribute_static_tls(__size_t, void *, __size_t, __size_t);
-__uintptr_t __libc_static_tls_base(__size_t);
void _pthread_cancel_enter(int);
void _pthread_cancel_leave(int);
@@ -379,4 +379,8 @@ struct __nl_cat_d *__catopen_l(const char *name, int type,
int __strerror_rl(int errnum, char *strerrbuf, size_t buflen,
struct _xlocale *locale);
+struct uexterror;
+int __uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz);
+int __libc_uexterr_gettext(char *buf, size_t bufsz);
+
#endif /* _LIBC_PRIVATE_H_ */
diff --git a/lib/libc/locale/collate.c b/lib/libc/locale/collate.c
index 8e3635485f10..c0fc4c91481d 100644
--- a/lib/libc/locale/collate.c
+++ b/lib/libc/locale/collate.c
@@ -43,6 +43,7 @@
#include <sys/mman.h>
#include <assert.h>
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -732,3 +733,261 @@ __collate_equiv_value(locale_t locale, const wchar_t *str, size_t len)
}
return (0);
}
+
+/*
+ * __collate_collating_symbol takes the multibyte string specified by
+ * src and slen, and using ps, converts that to a wide character. Then
+ * it is checked to verify it is a collating symbol, and then copies
+ * it to the wide character string specified by dst and dlen (the
+ * results are not null terminated). The length of the wide characters
+ * copied to dst is returned if successful. Zero is returned if no such
+ * collating symbol exists. (size_t)-1 is returned if there are wide-character
+ * conversion errors, if the length of the converted string is greater that
+ * COLLATE_STR_LEN or if dlen is too small. It is up to the calling routine to
+ * preserve the mbstate_t structure as needed.
+ */
+size_t
+__collate_collating_symbol(wchar_t *dst, size_t dlen, const char *src,
+ size_t slen, mbstate_t *ps)
+{
+ wchar_t wname[COLLATE_STR_LEN];
+ wchar_t w, *wp;
+ struct xlocale_collate *table;
+ size_t len, l;
+
+ table =
+ (struct xlocale_collate *)__get_locale()->components[XLC_COLLATE];
+ /* POSIX locale */
+ if (table->__collate_load_error) {
+ if (dlen < 1)
+ return ((size_t)-1);
+ if (slen != 1 || !isascii(*src))
+ return (0);
+ *dst = *src;
+ return (1);
+ }
+ for (wp = wname, len = 0; slen > 0; len++) {
+ l = mbrtowc(&w, src, slen, ps);
+ if (l == (size_t)-1 || l == (size_t)-2)
+ return ((size_t)-1);
+ if (l == 0)
+ break;
+ if (len >= COLLATE_STR_LEN)
+ return ((size_t)-1);
+ *wp++ = w;
+ src += l;
+ slen -= l;
+ }
+ if (len == 0 || len > dlen)
+ return ((size_t)-1);
+ if (len == 1) {
+ if (*wname <= UCHAR_MAX) {
+ if (table->char_pri_table[*wname].pri[0] >= 0) {
+ if (dlen > 0)
+ *dst = *wname;
+ return (1);
+ }
+ return (0);
+ } else if (table->info->large_count > 0) {
+ collate_large_t *match;
+ match = largesearch(table, *wname);
+ if (match && match->pri.pri[0] >= 0) {
+ if (dlen > 0)
+ *dst = *wname;
+ return (1);
+ }
+ }
+ return (0);
+ }
+ *wp = 0;
+ if (table->info->chain_count > 0) {
+ collate_chain_t *match;
+ int ll;
+ match = chainsearch(table, wname, &ll);
+ if (match) {
+ if (ll < dlen)
+ dlen = ll;
+ wcsncpy(dst, wname, dlen);
+ return (dlen);
+ }
+ }
+ return (0);
+}
+
+/*
+ * __collate_equiv_class returns the equivalence class number for the symbol
+ * specified by src and slen, using ps to convert from multi-byte to wide
+ * character. Zero is returned if the symbol is not in an equivalence
+ * class. -1 is returned if there are wide character conversion errors,
+ * if there are any greater-than-8-bit characters or if a multi-byte symbol
+ * is greater or equal to COLLATE_STR_LEN in length. It is up to the calling
+ * routine to preserve the mbstate_t structure as needed.
+ */
+int
+__collate_equiv_class(const char *src, size_t slen, mbstate_t *ps)
+{
+ wchar_t wname[COLLATE_STR_LEN];
+ wchar_t w, *wp;
+ struct xlocale_collate *table;
+ size_t len, l;
+ int e;
+
+ table =
+ (struct xlocale_collate *)__get_locale()->components[XLC_COLLATE];
+ /* POSIX locale */
+ if (table->__collate_load_error)
+ return (0);
+ for (wp = wname, len = 0; slen > 0; len++) {
+ l = mbrtowc(&w, src, slen, ps);
+ if (l == (size_t)-1 || l == (size_t)-2)
+ return (-1);
+ if (l == 0)
+ break;
+ if (len >= COLLATE_STR_LEN)
+ return (-1);
+ *wp++ = w;
+ src += l;
+ slen -= l;
+ }
+ if (len == 0)
+ return (-1);
+ if (len == 1) {
+ e = -1;
+ if (*wname <= UCHAR_MAX)
+ e = table->char_pri_table[*wname].pri[0];
+ else if (table->info->large_count > 0) {
+ collate_large_t *match;
+ match = largesearch(table, *wname);
+ if (match)
+ e = match->pri.pri[0];
+ }
+ if (e == 0)
+ return (IGNORE_EQUIV_CLASS);
+ return (e > 0 ? e : 0);
+ }
+ *wp = 0;
+ if (table->info->chain_count > 0) {
+ collate_chain_t *match;
+ int ll;
+ match = chainsearch(table, wname, &ll);
+ if (match) {
+ e = match->pri[0];
+ if (e == 0)
+ return (IGNORE_EQUIV_CLASS);
+ return (e < 0 ? -e : e);
+ }
+ }
+ return (0);
+}
+
+
+/*
+ * __collate_equiv_match tries to match any single or multi-character symbol
+ * in equivalence class equiv_class in the multi-byte string specified by src
+ * and slen. If start is non-zero, it is taken to be the first (pre-converted)
+ * wide character. Subsequence wide characters, if needed, will use ps in
+ * the conversion. On a successful match, the length of the matched string
+ * is returned (including the start character). If dst is non-NULL, the
+ * matched wide-character string is copied to dst, a wide character array of
+ * length dlen (the results are not zero-terminated). If rlen is non-NULL,
+ * the number of character in src actually used is returned. Zero is
+ * returned by __collate_equiv_match if there is no match. (size_t)-1 is
+ * returned on error: if there were conversion errors or if dlen is too small
+ * to accept the results. On no match or error, ps is restored to its incoming
+ * state.
+ */
+size_t
+__collate_equiv_match(int equiv_class, wchar_t *dst, size_t dlen, wchar_t start,
+ const char *src, size_t slen, mbstate_t *ps, size_t *rlen)
+{
+ wchar_t w;
+ size_t len, l, clen;
+ int i;
+ wchar_t buf[COLLATE_STR_LEN], *wp;
+ mbstate_t save;
+ const char *s = src;
+ struct xlocale_collate *table;
+ size_t sl = slen;
+ collate_chain_t *ch = NULL;
+
+ table =
+ (struct xlocale_collate *)__get_locale()->components[XLC_COLLATE];
+ /* POSIX locale */
+ if (table->__collate_load_error)
+ return ((size_t)-1);
+ if (equiv_class == IGNORE_EQUIV_CLASS)
+ equiv_class = 0;
+ if (ps)
+ save = *ps;
+ wp = buf;
+ len = clen = 0;
+ if (start) {
+ *wp++ = start;
+ len = 1;
+ }
+ /* convert up to the max chain length */
+ while (sl > 0 && len < table->info->chain_max_len) {
+ l = mbrtowc(&w, s, sl, ps);
+ if (l == (size_t)-1 || l == (size_t)-2 || l == 0)
+ break;
+ *wp++ = w;
+ s += l;
+ clen += l;
+ sl -= l;
+ len++;
+ }
+ *wp = 0;
+ if (len > 1 && (ch = chainsearch(table, buf, &i)) != NULL) {
+ int e = ch->pri[0];
+ if (e < 0)
+ e = -e;
+ if (e == equiv_class)
+ goto found;
+ }
+ /* try single character */
+ i = 1;
+ if (*buf <= UCHAR_MAX) {
+ if (equiv_class == table->char_pri_table[*buf].pri[0])
+ goto found;
+ } else if (table->info->large_count > 0) {
+ collate_large_t *match;
+ match = largesearch(table, *buf);
+ if (match && equiv_class == match->pri.pri[0])
+ goto found;
+ }
+ /* no match */
+ if (ps)
+ *ps = save;
+ return (0);
+found:
+ /*
+ * If we converted more than we used, restore to initial
+ * and reconvert up to what did match.
+ */
+ if (i < len) {
+ len = i;
+ if (ps)
+ *ps = save;
+ if (start)
+ i--;
+ clen = 0;
+ while (i-- > 0) {
+ l = mbrtowc(&w, src, slen, ps);
+ src += l;
+ clen += l;
+ slen -= l;
+ }
+ }
+ if (dst) {
+ if (dlen < len) {
+ if (ps)
+ *ps = save;
+ return ((size_t)-1);
+ }
+ for (wp = buf; len > 0; len--)
+ *dst++ = *wp++;
+ }
+ if (rlen)
+ *rlen = clen;
+ return (len);
+}
diff --git a/lib/libc/locale/collate.h b/lib/libc/locale/collate.h
index f157d8651899..64e0e6f2337d 100644
--- a/lib/libc/locale/collate.h
+++ b/lib/libc/locale/collate.h
@@ -38,6 +38,7 @@
#include <sys/types.h>
#include <limits.h>
+#include <wchar.h>
#include "xlocale_private.h"
/*
@@ -65,6 +66,8 @@
#define DIRECTIVE_DIRECTION_MASK (DIRECTIVE_FORWARD | DIRECTIVE_BACKWARD)
+#define IGNORE_EQUIV_CLASS 1
+
/*
* The collate file format is as follows:
*
@@ -85,6 +88,7 @@
typedef struct collate_info {
uint8_t directive_count;
uint8_t directive[COLL_WEIGHTS_MAX];
+ uint8_t chain_max_len; /* In padding */
int32_t pri_count[COLL_WEIGHTS_MAX];
int32_t flags;
int32_t chain_count;
@@ -126,8 +130,13 @@ struct xlocale_collate {
};
__BEGIN_DECLS
-int __collate_load_tables(const char *);
+size_t __collate_collating_symbol(wchar_t *, size_t, const char *, size_t,
+ mbstate_t *);
+int __collate_equiv_class(const char *, size_t, mbstate_t *);
int __collate_equiv_value(locale_t, const wchar_t *, size_t);
+size_t __collate_equiv_match(int, wchar_t *, size_t, wchar_t, const char *,
+ size_t, mbstate_t *, size_t *);
+int __collate_load_tables(const char *);
void _collate_lookup(struct xlocale_collate *,const wchar_t *, int *, int *,
int, const int **);
int __collate_range_cmp(char, char);
diff --git a/lib/libc/locale/euc.c b/lib/libc/locale/euc.c
index c54a6ceceff2..c110fc61b375 100644
--- a/lib/libc/locale/euc.c
+++ b/lib/libc/locale/euc.c
@@ -426,7 +426,7 @@ _EUC_wcrtomb_impl(char * __restrict s, wchar_t wc,
/* This first check excludes CS1, which is implicitly valid. */
if ((wc < 0xa100) || (wc > 0xffff)) {
/* Check for valid CS2 or CS3 */
- nm = (wc >> ((len - 1) * 8));
+ nm = (wc >> ((len - 1) * 8)) & 0xff;
if (nm == cs2) {
if (len != cs2width) {
errno = EILSEQ;
diff --git a/lib/libc/net/Makefile.inc b/lib/libc/net/Makefile.inc
index 558cf7be5771..7e9e5295c78c 100644
--- a/lib/libc/net/Makefile.inc
+++ b/lib/libc/net/Makefile.inc
@@ -1,7 +1,7 @@
# machine-independent net sources
.PATH: ${LIBC_SRCTOP}/net
-CONFS+= net/hosts net/hosts.equiv net/networks net/nsswitch.conf net/protocols
+CONFS+= net/hosts net/hosts.equiv net/networks ${.OBJDIR}/nsswitch.conf net/protocols
SRCS+= base64.c ether_addr.c eui64.c \
gai_strerror.c getaddrinfo.c \
gethostbydns.c gethostbyht.c gethostbynis.c gethostnamadr.c \
@@ -141,7 +141,8 @@ MLINKS+=inet6_opt_init.3 inet6_opt_append.3 \
inet6_rthdr_space.3 inet6_rthdr_reverse.3 \
inet6_rthdr_space.3 inet6_rthdr_segments.3
MLINKS+=linkaddr.3 link_addr.3 \
- linkaddr.3 link_ntoa.3
+ linkaddr.3 link_ntoa.3 \
+ linkaddr.3 link_ntoa_r.3
MLINKS+=rcmd.3 iruserok.3 \
rcmd.3 iruserok_sa.3 \
rcmd.3 rcmd_af.3 \
@@ -176,9 +177,13 @@ MLINKS+=hesiod.3 hesiod_init.3 \
hesiod.3 hesiod_end.3
.endif
-afterinstallconfig: modify-nsswitch-conf
-modify-nsswitch-conf: .PHONY
+all: ${.OBJDIR}/nsswitch.conf
+
+# Manually stage nsswitch.conf in the object directory so that we can edit it
+# before installing.
+${.OBJDIR}/nsswitch.conf: ${LIBC_SRCTOP}/net/nsswitch.conf
+ cp -f ${LIBC_SRCTOP}/net/nsswitch.conf ${.TARGET}
.if ${MK_NIS} == "no"
sed -i "" -e 's/.*_compat:/# &/' -e 's/compat$$/files/' \
- ${DESTDIR}/etc/nsswitch.conf
+ ${.TARGET}
.endif
diff --git a/lib/libc/net/Symbol.map b/lib/libc/net/Symbol.map
index ebc3a56b549f..25e79b4e5807 100644
--- a/lib/libc/net/Symbol.map
+++ b/lib/libc/net/Symbol.map
@@ -138,6 +138,10 @@ FBSD_1.3 {
sctp_sendv;
};
+FBSD_1.8 {
+ link_ntoa_r;
+};
+
FBSDprivate_1.0 {
_nsdispatch;
_nsyyerror; /* generated from nslexer.l */
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
index 2b9499d5099b..b8af23ebe8da 100644
--- a/lib/libc/net/getaddrinfo.c
+++ b/lib/libc/net/getaddrinfo.c
@@ -2341,9 +2341,14 @@ _dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
if (res_searchN(hostname, &q, res) < 0) {
free(buf);
free(buf2);
- if (res->res_h_errno == NO_DATA)
+ switch (res->res_h_errno) {
+ case NO_DATA:
return (NS_ADDRFAMILY);
- return (NS_NOTFOUND);
+ case TRY_AGAIN:
+ return (NS_TRYAGAIN);
+ default:
+ return (NS_NOTFOUND);
+ }
}
/* prefer IPv6 */
if (q.next) {
@@ -2705,9 +2710,18 @@ res_queryN(const char *name, struct res_target *target, res_state res)
int n;
u_int oflags;
struct res_target *t;
- int rcode;
+ u_int rcode;
int ancount;
+ /*
+ * Extend rcode values in the scope of this function. The DNS header
+ * rcode we use in this function (hp->rcode) is limited by 4 bits, so
+ * anything starting from 16 is safe wrt aliasing. However, nameser.h
+ * already has extended enum __ns_rcode, so for future safety let's use
+ * even larger values.
+ */
+#define RCODE_UNREACH 32
+#define RCODE_TIMEDOUT 33
rcode = NOERROR;
ancount = 0;
@@ -2768,7 +2782,29 @@ again:
printf(";; res_nquery: retry without EDNS0\n");
goto again;
}
- rcode = hp->rcode; /* record most recent error */
+ /*
+ * Historically if a DNS server replied with ICMP port
+ * unreach res_nsend() would signal that with
+ * ECONNREFUSED and the upper layers would convert that
+ * into TRY_AGAIN. See 3a0b3b673936b and deeper.
+ * Also, res_nsend() may set errno to ECONNREFUSED due
+ * to internal failures. This may not be intentional,
+ * but we also treat that as soft failures.
+ *
+ * A more practical case is when a DNS server(s) were
+ * queried and didn't respond anything, which usually
+ * indicates a soft network failure.
+ */
+ switch (errno) {
+ case ECONNREFUSED:
+ rcode = RCODE_UNREACH;
+ break;
+ case ETIMEDOUT:
+ rcode = RCODE_TIMEDOUT;
+ break;
+ default:
+ rcode = hp->rcode;
+ }
#ifdef DEBUG
if (res->options & RES_DEBUG)
printf(";; res_query: send error\n");
@@ -2800,6 +2836,8 @@ again:
case NXDOMAIN:
RES_SET_H_ERRNO(res, HOST_NOT_FOUND);
break;
+ case RCODE_UNREACH:
+ case RCODE_TIMEDOUT:
case SERVFAIL:
RES_SET_H_ERRNO(res, TRY_AGAIN);
break;
@@ -2862,10 +2900,6 @@ res_searchN(const char *name, struct res_target *target, res_state res)
ret = res_querydomainN(name, NULL, target, res);
if (ret > 0 || trailing_dot)
return (ret);
- if (errno == ECONNREFUSED) {
- RES_SET_H_ERRNO(res, TRY_AGAIN);
- return (-1);
- }
switch (res->res_h_errno) {
case NO_DATA:
case HOST_NOT_FOUND:
@@ -2906,7 +2940,6 @@ res_searchN(const char *name, struct res_target *target, res_state res)
ret = res_querydomainN(name, *domain, target, res);
if (ret > 0)
return (ret);
-
/*
* If no server present, give up.
* If name isn't found in this domain,
@@ -2920,11 +2953,6 @@ res_searchN(const char *name, struct res_target *target, res_state res)
* but try the input name below in case it's
* fully-qualified.
*/
- if (errno == ECONNREFUSED) {
- RES_SET_H_ERRNO(res, TRY_AGAIN);
- return (-1);
- }
-
switch (res->res_h_errno) {
case NO_DATA:
got_nodata++;
@@ -2933,8 +2961,8 @@ res_searchN(const char *name, struct res_target *target, res_state res)
/* keep trying */
break;
case TRY_AGAIN:
- got_servfail++;
if (hp->rcode == SERVFAIL) {
+ got_servfail++;
/* try next search element, if any */
break;
}
diff --git a/lib/libc/net/linkaddr.3 b/lib/libc/net/linkaddr.3
index ee3ea3056c71..38ee6a0aedea 100644
--- a/lib/libc/net/linkaddr.3
+++ b/lib/libc/net/linkaddr.3
@@ -28,12 +28,13 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 28, 2007
+.Dd May 9, 2025
.Dt LINK_ADDR 3
.Os
.Sh NAME
.Nm link_addr ,
-.Nm link_ntoa
+.Nm link_ntoa ,
+.Nm link_ntoa_r
.Nd elementary address specification routines for link level access
.Sh LIBRARY
.Lb libc
@@ -41,16 +42,29 @@
.In sys/types.h
.In sys/socket.h
.In net/if_dl.h
-.Ft void
+.Ft int
.Fn link_addr "const char *addr" "struct sockaddr_dl *sdl"
.Ft char *
.Fn link_ntoa "const struct sockaddr_dl *sdl"
+.Ft int
+.Fn link_ntoa_r "const struct sockaddr_dl *sdl" "char *obuf" "size_t *buflen"
.Sh DESCRIPTION
The routine
.Fn link_addr
-interprets character strings representing
-link-level addresses, returning binary information suitable
-for use in system calls.
+parses a character string
+.Fa addr
+representing a link-level address,
+and stores the resulting address in the structure pointed to by
+.Fa sdl .
+A link-level address consists of an optional interface name, followed by
+a colon (which is required in all cases), followed by an address
+consisting of either a string of hexadecimal digits, or a series of
+hexadecimal octets separated by one of the characters
+.Sq "." ,
+.Sq ":" ,
+or
+.Sq - .
+.Pp
The routine
.Fn link_ntoa
takes
@@ -60,9 +74,34 @@ address and returns an
string representing some of the information present,
including the link level address itself, and the interface name
or number, if present.
+The returned string is stored in a static buffer.
This facility is experimental and is
still subject to change.
.Pp
+The routine
+.Fn link_ntoa_r
+behaves like
+.Fn link_ntoa ,
+except the string is placed in the provided buffer instead of a static
+buffer.
+The caller should initialize
+.Fa buflen
+to the number of bytes available in
+.Fa obuf .
+On return,
+.Fa buflen
+is set to the actual number of bytes required for the output buffer,
+including the NUL terminator.
+If
+.Fa obuf
+is NULL, then
+.Fa buflen
+is set as described, but nothing is written.
+This may be used to determine the required length of the buffer before
+calling
+.Fn link_ntoa_r
+a second time.
+.Pp
For
.Fn link_addr ,
the string
@@ -94,12 +133,21 @@ The
.Fn link_ntoa
function
always returns a null terminated string.
+.Pp
+The
+.Fn link_ntoa_r
+function returns 0 on success, or -1 if the provided buffer was not
+large enough; in the latter case, the contents of the buffer are
+indeterminate, but a trailing NUL will always be written if the buffer
+was at least one byte in size.
+.Pp
The
.Fn link_addr
-function
-has no return value.
-(See
-.Sx BUGS . )
+function returns 0 on success.
+If the address did not appear to be a valid link-level address, -1 is
+returned and
+.Va errno
+is set to indicate the error.
.Sh SEE ALSO
.Xr getnameinfo 3
.Sh HISTORY
@@ -109,15 +157,14 @@ and
.Fn link_ntoa
functions appeared in
.Bx 4.3 Reno .
+The
+.Fn link_ntoa_r
+function appeared in
+.Fx 15.0 .
.Sh BUGS
The returned values for link_ntoa
reside in a static memory area.
.Pp
-The function
-.Fn link_addr
-should diagnose improperly formed input, and there should be an unambiguous
-way to recognize this.
-.Pp
If the
.Va sdl_len
field of the link socket address
diff --git a/lib/libc/net/linkaddr.c b/lib/libc/net/linkaddr.c
index dedc910b9474..5be4c0a7a43e 100644
--- a/lib/libc/net/linkaddr.c
+++ b/lib/libc/net/linkaddr.c
@@ -31,135 +31,261 @@
#include <sys/types.h>
#include <sys/socket.h>
+
#include <net/if.h>
#include <net/if_dl.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdint.h>
#include <string.h>
-/* States*/
-#define NAMING 0
-#define GOTONE 1
-#define GOTTWO 2
-#define RESET 3
-/* Inputs */
-#define DIGIT (4*0)
-#define END (4*1)
-#define DELIM (4*2)
-#define LETTER (4*3)
-
-void
+int
link_addr(const char *addr, struct sockaddr_dl *sdl)
{
char *cp = sdl->sdl_data;
char *cplim = sdl->sdl_len + (char *)sdl;
- int byte = 0, state = NAMING, new;
+ const char *nptr;
+ size_t newsize;
+ int error = 0;
+ char delim = 0;
+ /* Initialise the sdl to zero, except for sdl_len. */
bzero((char *)&sdl->sdl_family, sdl->sdl_len - 1);
sdl->sdl_family = AF_LINK;
- do {
- state &= ~LETTER;
- if ((*addr >= '0') && (*addr <= '9')) {
- new = *addr - '0';
- } else if ((*addr >= 'a') && (*addr <= 'f')) {
- new = *addr - 'a' + 10;
- } else if ((*addr >= 'A') && (*addr <= 'F')) {
- new = *addr - 'A' + 10;
- } else if (*addr == 0) {
- state |= END;
- } else if (state == NAMING &&
- (((*addr >= 'A') && (*addr <= 'Z')) ||
- ((*addr >= 'a') && (*addr <= 'z'))))
- state |= LETTER;
- else
- state |= DELIM;
- addr++;
- switch (state /* | INPUT */) {
- case NAMING | DIGIT:
- case NAMING | LETTER:
- *cp++ = addr[-1];
- continue;
- case NAMING | DELIM:
- state = RESET;
- sdl->sdl_nlen = cp - sdl->sdl_data;
- continue;
- case GOTTWO | DIGIT:
- *cp++ = byte;
- /* FALLTHROUGH */
- case RESET | DIGIT:
- state = GOTONE;
- byte = new;
- continue;
- case GOTONE | DIGIT:
- state = GOTTWO;
- byte = new + (byte << 4);
- continue;
- default: /* | DELIM */
- state = RESET;
- *cp++ = byte;
- byte = 0;
- continue;
- case GOTONE | END:
- case GOTTWO | END:
- *cp++ = byte;
- /* FALLTHROUGH */
- case RESET | END:
+
+ /*
+ * Everything up to the first ':' is the interface name. Usually the
+ * ':' should always be present even if there's no interface name, but
+ * since this interface was poorly specified in the past, accept a
+ * missing colon as meaning no interface name.
+ */
+ if ((nptr = strchr(addr, ':')) != NULL) {
+ size_t namelen = nptr - addr;
+
+ /* Ensure the sdl is large enough to store the name. */
+ if (namelen > cplim - cp) {
+ errno = ENOSPC;
+ return (-1);
+ }
+
+ memcpy(cp, addr, namelen);
+ cp += namelen;
+ sdl->sdl_nlen = namelen;
+ /* Skip the interface name and the colon. */
+ addr += namelen + 1;
+ }
+
+ /*
+ * The remainder of the string should be hex digits representing the
+ * address, with optional delimiters. Each two hex digits form one
+ * octet, but octet output can be forced using a delimiter, so we accept
+ * a long string of hex digits, or a mix of delimited and undelimited
+ * digits like "1122.3344.5566", or delimited one- or two-digit octets
+ * like "1.22.3".
+ *
+ * If anything fails at this point, exit the loop so we set sdl_alen and
+ * sdl_len based on whatever we did manage to parse. This preserves
+ * compatibility with the 4.3BSD version of link_addr, which had no way
+ * to indicate an error and would just return.
+ */
+#define DIGIT(c) \
+ (((c) >= '0' && (c) <= '9') ? ((c) - '0') \
+ : ((c) >= 'a' && (c) <= 'f') ? ((c) - 'a' + 10) \
+ : ((c) >= 'A' && (c) <= 'F') ? ((c) - 'A' + 10) \
+ : (-1))
+#define ISDELIM(c) (((c) == '.' || (c) == ':' || (c) == '-') && \
+ (delim == 0 || delim == (c)))
+
+ for (;;) {
+ int digit, digit2;
+
+ /*
+ * Treat any leading delimiters as empty bytes. This supports
+ * the (somewhat obsolete) form of Ethernet addresses with empty
+ * octets, e.g. "1::3:4:5:6".
+ */
+ while (ISDELIM(*addr) && cp < cplim) {
+ delim = *addr++;
+ *cp++ = 0;
+ }
+
+ /* Did we reach the end of the string? */
+ if (*addr == '\0')
+ break;
+
+ /*
+ * If not, the next character must be a digit, so make sure we
+ * have room for at least one more octet.
+ */
+
+ if (cp >= cplim) {
+ error = ENOSPC;
+ break;
+ }
+
+ if ((digit = DIGIT(*addr)) == -1) {
+ error = EINVAL;
break;
}
- break;
- } while (cp < cplim);
+
+ ++addr;
+
+ /* If the next character is another digit, consume it. */
+ if ((digit2 = DIGIT(*addr)) != -1) {
+ digit = (digit << 4) | digit2;
+ ++addr;
+ }
+
+ if (ISDELIM(*addr)) {
+ /*
+ * If the digit is followed by a delimiter, write it
+ * and consume the delimiter.
+ */
+ delim = *addr++;
+ *cp++ = digit;
+ } else if (DIGIT(*addr) != -1) {
+ /*
+ * If two digits are followed by a third digit, treat
+ * the two digits we have as a single octet and
+ * continue.
+ */
+ *cp++ = digit;
+ } else if (*addr == '\0') {
+ /* If the digit is followed by EOS, we're done. */
+ *cp++ = digit;
+ break;
+ } else {
+ /* Otherwise, the input was invalid. */
+ error = EINVAL;
+ break;
+ }
+ }
+#undef DIGIT
+#undef ISDELIM
+
+ /* How many bytes did we write to the address? */
sdl->sdl_alen = cp - LLADDR(sdl);
- new = cp - (char *)sdl;
- if (new > sizeof(*sdl))
- sdl->sdl_len = new;
- return;
+
+ /*
+ * The user might have given us an sdl which is larger than sizeof(sdl);
+ * in that case, record the actual size of the new sdl.
+ */
+ newsize = cp - (char *)sdl;
+ if (newsize > sizeof(*sdl))
+ sdl->sdl_len = (u_char)newsize;
+
+ if (error == 0)
+ return (0);
+
+ errno = error;
+ return (-1);
}
-static const char hexlist[] = "0123456789abcdef";
char *
link_ntoa(const struct sockaddr_dl *sdl)
{
static char obuf[64];
+ size_t buflen;
_Static_assert(sizeof(obuf) >= IFNAMSIZ + 20, "obuf is too small");
+
+ /*
+ * Ignoring the return value of link_ntoa_r() is safe here because it
+ * always writes the terminating NUL. This preserves the traditional
+ * behaviour of link_ntoa().
+ */
+ buflen = sizeof(obuf);
+ (void)link_ntoa_r(sdl, obuf, &buflen);
+ return obuf;
+}
+
+int
+link_ntoa_r(const struct sockaddr_dl *sdl, char *obuf, size_t *buflen)
+{
+ static const char hexlist[] = "0123456789abcdef";
char *out;
const u_char *in, *inlim;
int namelen, i, rem;
+ size_t needed;
- namelen = (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ;
+ assert(sdl);
+ assert(buflen);
+ /* obuf may be null */
+ needed = 1; /* 1 for the NUL */
out = obuf;
- rem = sizeof(obuf);
+ if (obuf)
+ rem = *buflen;
+ else
+ rem = 0;
+
+/*
+ * Check if at least n bytes are available in the output buffer, plus 1 for the
+ * trailing NUL. If not, set rem = 0 so we stop writing.
+ * Either way, increment needed by the amount we would have written.
+ */
+#define CHECK(n) do { \
+ if ((SIZE_MAX - (n)) >= needed) \
+ needed += (n); \
+ if (rem >= ((n) + 1)) \
+ rem -= (n); \
+ else \
+ rem = 0; \
+ } while (0)
+
+/*
+ * Write the char c to the output buffer, unless the buffer is full.
+ * Note that if obuf is NULL, rem is always zero.
+ */
+#define OUT(c) do { \
+ if (rem > 0) \
+ *out++ = (c); \
+ } while (0)
+
+ namelen = (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ;
if (namelen > 0) {
- bcopy(sdl->sdl_data, out, namelen);
- out += namelen;
- rem -= namelen;
+ CHECK(namelen);
+ if (rem > 0) {
+ bcopy(sdl->sdl_data, out, namelen);
+ out += namelen;
+ }
+
if (sdl->sdl_alen > 0) {
- *out++ = ':';
- rem--;
+ CHECK(1);
+ OUT(':');
}
}
- in = (const u_char *)sdl->sdl_data + sdl->sdl_nlen;
+ in = (const u_char *)LLADDR(sdl);
inlim = in + sdl->sdl_alen;
- while (in < inlim && rem > 1) {
- if (in != (const u_char *)sdl->sdl_data + sdl->sdl_nlen) {
- *out++ = '.';
- rem--;
+ while (in < inlim) {
+ if (in != (const u_char *)LLADDR(sdl)) {
+ CHECK(1);
+ OUT('.');
}
i = *in++;
if (i > 0xf) {
- if (rem < 3)
- break;
- *out++ = hexlist[i >> 4];
- *out++ = hexlist[i & 0xf];
- rem -= 2;
+ CHECK(2);
+ OUT(hexlist[i >> 4]);
+ OUT(hexlist[i & 0xf]);
} else {
- if (rem < 2)
- break;
- *out++ = hexlist[i];
- rem--;
+ CHECK(1);
+ OUT(hexlist[i]);
}
}
- *out = 0;
- return (obuf);
+
+#undef CHECK
+#undef OUT
+
+ /*
+ * We always leave enough room for the NUL if possible, but the user
+ * might have passed a NULL or zero-length buffer.
+ */
+ if (out && *buflen)
+ *out = '\0';
+
+ *buflen = needed;
+ return ((rem > 0) ? 0 : -1);
}
diff --git a/lib/libc/powerpc/static_tls.h b/lib/libc/powerpc/static_tls.h
deleted file mode 100644
index 9ae38c71a515..000000000000
--- a/lib/libc/powerpc/static_tls.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _LIBC_POWERPC_STATIC_TLS_H
-#define _LIBC_POWERPC_STATIC_TLS_H
-
-static __inline uintptr_t
-_libc_get_static_tls_base(size_t offset)
-{
- uintptr_t tlsbase;
-
- __asm __volatile("mr %0,2" : "=r"(tlsbase));
- tlsbase += offset - 0x7008;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libc/powerpc64/static_tls.h b/lib/libc/powerpc64/static_tls.h
deleted file mode 100644
index 014b8a931453..000000000000
--- a/lib/libc/powerpc64/static_tls.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _LIBC_POWERPC64_STATIC_TLS_H
-#define _LIBC_POWERPC64_STATIC_TLS_H
-
-static __inline uintptr_t
-_libc_get_static_tls_base(size_t offset)
-{
- uintptr_t tlsbase;
-
- __asm __volatile("mr %0,13" : "=r"(tlsbase));
- tlsbase += offset - 0x7010;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libc/riscv/static_tls.h b/lib/libc/riscv/static_tls.h
deleted file mode 100644
index ce9fa23338a6..000000000000
--- a/lib/libc/riscv/static_tls.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _LIBC_RISCV_STATIC_TLS_H
-#define _LIBC_RISCV_STATIC_TLS_H
-
-static __inline uintptr_t
-_libc_get_static_tls_base(size_t offset)
-{
- uintptr_t tlsbase;
-
- __asm __volatile("mv %0, tp" : "=r"(tlsbase));
- tlsbase += offset;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libc/rpc/rpc_secure.3 b/lib/libc/rpc/rpc_secure.3
index 11b871b5c99d..ce59bba7115f 100644
--- a/lib/libc/rpc/rpc_secure.3
+++ b/lib/libc/rpc/rpc_secure.3
@@ -266,8 +266,7 @@ Inverse of
.Fn netname2user .
.Sh SEE ALSO
.Xr rpc 3 ,
-.Xr xdr 3 ,
-.Xr keyserv 8
+.Xr xdr 3
.Pp
The following manuals:
.Rs
diff --git a/lib/libc/rpc/svc_nl.c b/lib/libc/rpc/svc_nl.c
index 5cce44d9d98f..cff364063c5c 100644
--- a/lib/libc/rpc/svc_nl.c
+++ b/lib/libc/rpc/svc_nl.c
@@ -92,7 +92,7 @@ svc_nl_create(const char *service)
.nl_family = PF_NETLINK,
};
struct nl_softc *sc;
- SVCXPRT *xprt;
+ SVCXPRT *xprt = NULL;
void *buf = NULL;
uint16_t family;
ssize_t len = 1024;
@@ -133,6 +133,7 @@ svc_nl_create(const char *service)
return (xprt);
fail:
+ free(xprt);
free(buf);
snl_free(&sc->snl);
free(sc);
diff --git a/lib/libc/stdio/mktemp.3 b/lib/libc/stdio/mktemp.3
index 2b8b2d6c9e44..8d38dd2cd57e 100644
--- a/lib/libc/stdio/mktemp.3
+++ b/lib/libc/stdio/mktemp.3
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 29, 2019
+.Dd July 07, 2025
.Dt MKTEMP 3
.Os
.Sh NAME
@@ -101,9 +101,10 @@ The permitted flags are
.Dv O_DIRECT ,
.Dv O_SHLOCK ,
.Dv O_EXLOCK ,
-.Dv O_SYNC
+.Dv O_SYNC ,
+.Dv O_CLOEXEC
and
-.Dv O_CLOEXEC .
+.Dv O_CLOFORK .
.Pp
The
.Fn mkstemps
diff --git a/lib/libc/stdio/mktemp.c b/lib/libc/stdio/mktemp.c
index 8aff226acf14..a2f80ee7b0dd 100644
--- a/lib/libc/stdio/mktemp.c
+++ b/lib/libc/stdio/mktemp.c
@@ -121,7 +121,7 @@ _gettemp(int dfd, char *path, int *doopen, int domkdir, int slen, int oflags)
if ((doopen != NULL && domkdir) || slen < 0 ||
(oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC |
- O_CLOEXEC)) != 0) {
+ O_CLOEXEC | O_CLOFORK)) != 0) {
errno = EINVAL;
return (0);
}
diff --git a/lib/libc/stdlib/Makefile.inc b/lib/libc/stdlib/Makefile.inc
index bea82445304d..ca199a669be1 100644
--- a/lib/libc/stdlib/Makefile.inc
+++ b/lib/libc/stdlib/Makefile.inc
@@ -31,7 +31,7 @@ SYM_MAPS+= ${LIBC_SRCTOP}/stdlib/Symbol.map
# machine-dependent stdlib sources
.sinclude "${LIBC_SRCTOP}/${LIBC_ARCH}/stdlib/Makefile.inc"
-MAN+= a64l.3 abort.3 abs.3 alloca.3 atexit.3 atof.3 \
+MAN+= a64l.3 abort.3 abs.3 atexit.3 atof.3 \
atoi.3 atol.3 at_quick_exit.3 bsearch.3 \
div.3 exit.3 getenv.3 getopt.3 getopt_long.3 getsubopt.3 \
hcreate.3 imaxabs.3 imaxdiv.3 insque.3 labs.3 ldiv.3 llabs.3 lldiv.3 \
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
index d74df869cf54..2b79ca2ece8b 100644
--- a/lib/libc/stdlib/Symbol.map
+++ b/lib/libc/stdlib/Symbol.map
@@ -127,6 +127,10 @@ FBSD_1.7 {
secure_getenv;
};
+FBSD_1.8 {
+ getenv_r;
+};
+
FBSDprivate_1.0 {
__system;
_system;
diff --git a/lib/libc/stdlib/alloca.3 b/lib/libc/stdlib/alloca.3
deleted file mode 100644
index d2111872ae0b..000000000000
--- a/lib/libc/stdlib/alloca.3
+++ /dev/null
@@ -1,85 +0,0 @@
-.\" Copyright (c) 1980, 1991, 1993
-.\" The Regents of the University of California. All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. Neither the name of the University nor the names of its contributors
-.\" may be used to endorse or promote products derived from this software
-.\" without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
-.\"
-.Dd September 5, 2006
-.Dt ALLOCA 3
-.Os
-.Sh NAME
-.Nm alloca
-.Nd memory allocator
-.Sh LIBRARY
-.Lb libc
-.Sh SYNOPSIS
-.In stdlib.h
-.Ft void *
-.Fn alloca "size_t size"
-.Sh DESCRIPTION
-The
-.Fn alloca
-function
-allocates
-.Fa size
-bytes of space in the stack frame of the caller.
-This temporary space is automatically freed on
-return.
-.Sh RETURN VALUES
-The
-.Fn alloca
-function returns a pointer to the beginning of the allocated space.
-.Sh SEE ALSO
-.Xr brk 2 ,
-.Xr calloc 3 ,
-.Xr getpagesize 3 ,
-.Xr malloc 3 ,
-.Xr realloc 3
-.Sh HISTORY
-The
-.Fn alloca
-function appeared in
-.At 32v .
-.\" .Bx ?? .
-.\" The function appeared in 32v, pwb and pwb.2 and in 3bsd 4bsd
-.\" The first man page (or link to a man page that I can find at the
-.\" moment is 4.3...
-.Sh BUGS
-The
-.Fn alloca
-function
-is machine and compiler dependent;
-its use is discouraged.
-.Pp
-The
-.Fn alloca
-function is slightly unsafe because it cannot ensure that the pointer
-returned points to a valid and usable block of memory.
-The allocation made may exceed the bounds of the stack, or even go
-further into other objects in memory, and
-.Fn alloca
-cannot determine such an error.
-Avoid
-.Fn alloca
-with large unbounded allocations.
diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c
index e5aa66c51f38..6e4a12f9e530 100644
--- a/lib/libc/stdlib/atexit.c
+++ b/lib/libc/stdlib/atexit.c
@@ -35,6 +35,7 @@
#include "namespace.h"
#include <errno.h>
#include <link.h>
+#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
@@ -56,6 +57,8 @@ _Block_copy(void*);
#define ATEXIT_FN_CXA 2
static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
+static void *current_finalize_dso = NULL;
+static bool call_finalize_again = false;
#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
@@ -115,6 +118,9 @@ atexit_register(struct atexit_fn *fptr)
__atexit = p;
}
p->fns[p->ind++] = *fptr;
+ if (current_finalize_dso != NULL &&
+ current_finalize_dso == fptr->fn_dso)
+ call_finalize_again = true;
_MUTEX_UNLOCK(&atexit_mutex);
return 0;
}
@@ -208,33 +214,38 @@ __cxa_finalize(void *dso)
}
_MUTEX_LOCK(&atexit_mutex);
- for (p = __atexit; p; p = p->next) {
- for (n = p->ind; --n >= 0;) {
- if (p->fns[n].fn_type == ATEXIT_FN_EMPTY)
- continue; /* already been called */
- fn = p->fns[n];
- if (dso != NULL && dso != fn.fn_dso) {
- /* wrong DSO ? */
- if (!has_phdr || global_exit ||
- !__elf_phdr_match_addr(&phdr_info,
- fn.fn_ptr.cxa_func))
- continue;
+ current_finalize_dso = dso;
+ do {
+ call_finalize_again = false;
+ for (p = __atexit; p; p = p->next) {
+ for (n = p->ind; --n >= 0;) {
+ if (p->fns[n].fn_type == ATEXIT_FN_EMPTY)
+ continue; /* already been called */
+ fn = p->fns[n];
+ if (dso != NULL && dso != fn.fn_dso) {
+ /* wrong DSO ? */
+ if (!has_phdr || global_exit ||
+ !__elf_phdr_match_addr(&phdr_info,
+ fn.fn_ptr.cxa_func))
+ continue;
+ }
+ /*
+ Mark entry to indicate that this particular
+ handler has already been called.
+ */
+ p->fns[n].fn_type = ATEXIT_FN_EMPTY;
+ _MUTEX_UNLOCK(&atexit_mutex);
+
+ /* Call the function of correct type. */
+ if (fn.fn_type == ATEXIT_FN_CXA)
+ fn.fn_ptr.cxa_func(fn.fn_arg);
+ else if (fn.fn_type == ATEXIT_FN_STD)
+ fn.fn_ptr.std_func();
+ _MUTEX_LOCK(&atexit_mutex);
}
- /*
- Mark entry to indicate that this particular handler
- has already been called.
- */
- p->fns[n].fn_type = ATEXIT_FN_EMPTY;
- _MUTEX_UNLOCK(&atexit_mutex);
-
- /* Call the function of correct type. */
- if (fn.fn_type == ATEXIT_FN_CXA)
- fn.fn_ptr.cxa_func(fn.fn_arg);
- else if (fn.fn_type == ATEXIT_FN_STD)
- fn.fn_ptr.std_func();
- _MUTEX_LOCK(&atexit_mutex);
}
- }
+ } while (call_finalize_again);
+ current_finalize_dso = NULL;
_MUTEX_UNLOCK(&atexit_mutex);
if (dso == NULL)
_MUTEX_DESTROY(&atexit_mutex);
diff --git a/lib/libc/stdlib/getenv.3 b/lib/libc/stdlib/getenv.3
index 1337ec867237..045a1831dfdc 100644
--- a/lib/libc/stdlib/getenv.3
+++ b/lib/libc/stdlib/getenv.3
@@ -29,12 +29,13 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 14, 2023
+.Dd April 22, 2025
.Dt GETENV 3
.Os
.Sh NAME
.Nm clearenv ,
.Nm getenv ,
+.Nm getenv_r ,
.Nm putenv ,
.Nm secure_getenv ,
.Nm setenv ,
@@ -48,6 +49,8 @@
.Fn clearenv "void"
.Ft char *
.Fn getenv "const char *name"
+.Ft int
+.Fn getenv_r "const char *name" "char *buf" "size_t len"
.Ft char *
.Fn secure_getenv "const char *name"
.Ft int
@@ -71,7 +74,8 @@ and
.Pp
The
.Fn getenv
-function obtains the current value of the environment variable,
+function obtains the current value of the environment variable
+designated by
.Fa name .
The application should not modify the string pointed
to by the
@@ -79,13 +83,23 @@ to by the
function.
.Pp
The
+.Fn getenv_r
+function obtains the current value of the environment variable
+designated by
+.Fa name
+and copies it into the buffer
+.Fa buf
+of length
+.Fa len .
+.Pp
+The
.Fn secure_getenv
returns
.Va NULL
when the environment cannot be trusted, otherwise it acts like
.Fn getenv .
The environment currently is not trusted when
-.Xr issetugid 3
+.Xr issetugid 2
returns a non-zero value, but other conditions may be added
in the future.
.Pp
@@ -157,12 +171,13 @@ function returns
if the process is in "secure execution," otherwise it will call
.Fn getenv .
.Pp
-.Rv -std clearenv setenv putenv unsetenv
+.Rv -std clearenv getenv_r setenv putenv unsetenv
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EINVAL
The function
.Fn getenv ,
+.Fn getenv_r ,
.Fn setenv
or
.Fn unsetenv
@@ -191,6 +206,11 @@ is the first character in
This does not follow the
.Tn POSIX
specification.
+.It Bq Er ENOENT
+The function
+.Fn getenv_r
+failed because the requested variable was not found in the
+environment.
.It Bq Er ENOMEM
The function
.Fn setenv ,
@@ -198,6 +218,11 @@ The function
or
.Fn putenv
failed because they were unable to allocate memory for the environment.
+.It Bq Er ERANGE
+The function
+.Fn getenv_r
+failed because the value of the requested variable was too long to fit
+in the provided buffer.
.El
.Sh SEE ALSO
.Xr csh 1 ,
@@ -251,6 +276,13 @@ and
.Fn secure_getenv
functions were added in
.Fx 14 .
+.Pp
+The
+.Fn getenv_r
+function first appeared in
+.Nx 4.0
+and was added in
+.Fx 15 .
.Sh BUGS
Successive calls to
.Fn setenv
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
index f8f59526421a..c1d0b7a559d5 100644
--- a/lib/libc/stdlib/getenv.c
+++ b/lib/libc/stdlib/getenv.c
@@ -28,6 +28,7 @@
#include "namespace.h"
#include <sys/types.h>
+#include <ssp/ssp.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
@@ -444,6 +445,41 @@ getenv(const char *name)
/*
+ * Like getenv(), but copies the value into the provided buffer.
+ */
+int
+__ssp_real(getenv_r)(const char *name, char *buf, size_t len)
+{
+ const char *val;
+ size_t nameLen;
+ int envNdx;
+
+ if (name == NULL || (nameLen = __strleneq(name)) == 0) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (environ == NULL || environ[0] == NULL) {
+ val = NULL;
+ } else if (envVars == NULL || environ != intEnviron) {
+ val = __findenv_environ(name, nameLen);
+ } else {
+ envNdx = envVarsTotal - 1;
+ val = __findenv(name, nameLen, &envNdx, true);
+ }
+ if (val == NULL) {
+ errno = ENOENT;
+ return (-1);
+ }
+ if (strlcpy(buf, val, len) >= len) {
+ errno = ERANGE;
+ return (-1);
+ }
+ return (0);
+}
+
+
+/*
* Runs getenv() unless the current process is tainted by uid or gid changes, in
* which case it will return NULL.
*/
diff --git a/lib/libc/stdlib/getopt_long.3 b/lib/libc/stdlib/getopt_long.3
index f8bb1f1b6b11..d6998d13822a 100644
--- a/lib/libc/stdlib/getopt_long.3
+++ b/lib/libc/stdlib/getopt_long.3
@@ -217,7 +217,7 @@ an error and return
Specifying
.Ql \&:
in
-.Fa optstr
+.Fa optstring
will cause the error message to be suppressed and
.Ql \&:
to be returned instead.
@@ -229,7 +229,7 @@ a leading
or
.Ql \&-
in
-.Fa optstr
+.Fa optstring
also has special meaning.
If either of these are specified, they must appear before
.Ql \&: .
diff --git a/lib/libc/stdtime/strftime.c b/lib/libc/stdtime/strftime.c
index 5943e6387174..89c9e4cf88ff 100644
--- a/lib/libc/stdtime/strftime.c
+++ b/lib/libc/stdtime/strftime.c
@@ -1,4 +1,6 @@
/*
+ * SPDX-License-Identifier: BSD-4.3TAHOE
+ *
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
diff --git a/lib/libc/string/memccpy.3 b/lib/libc/string/memccpy.3
index 2de981449119..0d35a68fce67 100644
--- a/lib/libc/string/memccpy.3
+++ b/lib/libc/string/memccpy.3
@@ -80,7 +80,7 @@ The
function conforms to
.St -p1003.1-2004
and
-.St -isoC-2024 .
+.St -isoC-2023 .
.Sh HISTORY
The
.Fn memccpy
diff --git a/lib/libc/string/memset.3 b/lib/libc/string/memset.3
index f2dba3ec5a48..f6ab9dacb516 100644
--- a/lib/libc/string/memset.3
+++ b/lib/libc/string/memset.3
@@ -141,4 +141,4 @@ conforms to
K.3.7.4.1.
.Fn memset_explicit
conforms to
-.St -isoC-2024 .
+.St -isoC-2023 .
diff --git a/lib/libc/sys/closefrom.c b/lib/libc/sys/closefrom.c
index 292702fad38c..76ed4e744397 100644
--- a/lib/libc/sys/closefrom.c
+++ b/lib/libc/sys/closefrom.c
@@ -26,20 +26,12 @@
*/
#include <sys/param.h>
-#include <sys/syscall.h>
#include <unistd.h>
#include "libc_private.h"
-#define CLOSE_RANGE_OSREL 1300091
-
void
closefrom(int lowfd)
{
-
- if (__getosreldate() >= CLOSE_RANGE_OSREL)
- __sys_close_range(MAX(0, lowfd), ~0U, 0);
- else
- /* Fallback to closefrom(2) on older kernels. */
- syscall(SYS_freebsd12_closefrom, lowfd);
+ __sys_close_range(MAX(0, lowfd), ~0U, 0);
}
diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile
index 87f2b8320d25..8c2151105209 100644
--- a/lib/libc/tests/gen/Makefile
+++ b/lib/libc/tests/gen/Makefile
@@ -7,14 +7,28 @@ ATF_TESTS_C+= fmtcheck2_test
ATF_TESTS_C+= fmtmsg_test
ATF_TESTS_C+= fnmatch2_test
ATF_TESTS_C+= fpclassify2_test
+.if ${COMPILER_FEATURES:Mblocks}
+ATF_TESTS_C+= fts_blocks_test
+.endif
+ATF_TESTS_C+= fts_misc_test
+ATF_TESTS_C+= fts_options_test
ATF_TESTS_C+= ftw_test
ATF_TESTS_C+= getentropy_test
ATF_TESTS_C+= getmntinfo_test
ATF_TESTS_C+= glob2_test
+.if ${COMPILER_FEATURES:Mblocks}
+ATF_TESTS_C+= glob_blocks_test
+.endif
ATF_TESTS_C+= makecontext_test
+ATF_TESTS_C+= opendir_test
ATF_TESTS_C+= popen_test
ATF_TESTS_C+= posix_spawn_test
ATF_TESTS_C+= realpath2_test
+ATF_TESTS_C+= scandir_test
+.if ${COMPILER_FEATURES:Mblocks}
+ATF_TESTS_C+= scandir_blocks_test
+.endif
+ATF_TESTS_C+= sig2str_test
ATF_TESTS_C+= sigsetops_test
ATF_TESTS_C+= wordexp_test
@@ -92,6 +106,20 @@ TEST_METADATA.setdomainname_test+= is_exclusive=true
TESTS_SUBDIRS= execve
TESTS_SUBDIRS+= posix_spawn
+# Tests that require address sanitizer
+.if ${COMPILER_FEATURES:Masan}
+.for t in scandir_test realpath2_test
+CFLAGS.${t}.c+= -fsanitize=address
+LDFLAGS.${t}+= -fsanitize=address
+.endfor
+.endif
+
+# Tests that require blocks support
+.for t in fts_blocks_test glob_blocks_test scandir_blocks_test
+CFLAGS.${t}.c+= -fblocks
+LIBADD.${t}+= BlocksRuntime
+.endfor
+
# The old testcase name
TEST_FNMATCH= test-fnmatch
CLEANFILES+= ${GEN_SH_CASE_TESTCASES}
diff --git a/lib/libc/tests/gen/fnmatch_test.c b/lib/libc/tests/gen/fnmatch_test.c
index 6cdf5f2a05fa..0ff7400a4a4f 100644
--- a/lib/libc/tests/gen/fnmatch_test.c
+++ b/lib/libc/tests/gen/fnmatch_test.c
@@ -26,6 +26,7 @@
#include <sys/param.h>
#include <errno.h>
+#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -176,10 +177,90 @@ ATF_TC_BODY(fnmatch_test, tc)
}
+ATF_TC(fnmatch_characterclass);
+ATF_TC_HEAD(fnmatch_characterclass, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test fnmatch with character classes");
+}
+
+ATF_TC_BODY(fnmatch_characterclass, tc)
+{
+ ATF_CHECK(fnmatch("[[:alnum:]]", "a", 0) == 0);
+ ATF_CHECK(fnmatch("[[:cntrl:]]", "\a", 0) == 0);
+ ATF_CHECK(fnmatch("[[:lower:]]", "a", 0) == 0);
+ ATF_CHECK(fnmatch("[[:space:]]", " ", 0) == 0);
+ ATF_CHECK(fnmatch("[[:alpha:]]", "a", 0) == 0);
+ ATF_CHECK(fnmatch("[[:digit:]]", "0", 0) == 0);
+ ATF_CHECK(fnmatch("[[:print:]]", "a", 0) == 0);
+ ATF_CHECK(fnmatch("[[:upper:]]", "A", 0) == 0);
+ ATF_CHECK(fnmatch("[[:blank:]]", " ", 0) == 0);
+ ATF_CHECK(fnmatch("[[:graph:]]", "a", 0) == 0);
+ ATF_CHECK(fnmatch("[[:punct:]]", ".", 0) == 0);
+ ATF_CHECK(fnmatch("[[:xdigit:]]", "f", 0) == 0);
+
+ /*
+ * POSIX.1, section 9.3.5. states that '[:' and ':]'
+ * should be interpreted as character classes symbol only
+ * when part of a bracket expression.
+ */
+ ATF_CHECK(fnmatch("[:alnum:]", "a", 0) == 0);
+ ATF_CHECK(fnmatch("[:alnum:]", ":", 0) == 0);
+ ATF_CHECK(fnmatch("[:alnum:]", "1", 0) != 0);
+}
+
+ATF_TC(fnmatch_collsym);
+ATF_TC_HEAD(fnmatch_collsym, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test fnmatch with collating symbols");
+}
+
+ATF_TC_BODY(fnmatch_collsym, tc)
+{
+ setlocale(LC_ALL, "cs_CZ.UTF-8");
+ ATF_CHECK(fnmatch("[ch]", "ch", 0) != 0);
+ ATF_CHECK(fnmatch("[[.ch.]]", "ch", 0) == 0);
+ ATF_CHECK(fnmatch("[[.ch.]]h", "chh", 0) == 0);
+
+ /*
+ * POSIX.1, section 9.3.5. states that '[.' and '.]'
+ * should be interpreted as a collating symbol only
+ * when part of a bracket expression.
+ */
+ ATF_CHECK(fnmatch("[.ch.]", "c", 0) == 0);
+ ATF_CHECK(fnmatch("[.ch.]", "h", 0) == 0);
+ ATF_CHECK(fnmatch("[.ch.]", ".", 0) == 0);
+}
+
+ATF_TC(fnmatch_equivclass);
+ATF_TC_HEAD(fnmatch_equivclass, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test fnmatch with equivalence classes");
+}
+
+ATF_TC_BODY(fnmatch_equivclass, tc)
+{
+ setlocale(LC_ALL, "en_US.UTF-8");
+ ATF_CHECK(fnmatch("[[=a=]]b", "ab", 0) == 0);
+ ATF_CHECK(fnmatch("[[=a=]]b", "Ab", 0) == 0);
+ ATF_CHECK(fnmatch("[[=à=]]b", "ab", 0) == 0);
+ ATF_CHECK(fnmatch("[[=a=]]b", "àb", 0) == 0);
+
+ /*
+ * POSIX.1, section 9.3.5. states that '[=' and '=]'
+ * should be interpreted as an equivalence class only
+ * when part of a bracket expression.
+ */
+ ATF_CHECK(fnmatch("[=a=]b", "=b", 0) == 0);
+ ATF_CHECK(fnmatch("[=a=]b", "ab", 0) == 0);
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, fnmatch_test);
+ ATF_TP_ADD_TC(tp, fnmatch_collsym);
+ ATF_TP_ADD_TC(tp, fnmatch_characterclass);
+ ATF_TP_ADD_TC(tp, fnmatch_equivclass);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/fts_blocks_test.c b/lib/libc/tests/gen/fts_blocks_test.c
new file mode 100644
index 000000000000..f020dd8dea45
--- /dev/null
+++ b/lib/libc/tests/gen/fts_blocks_test.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <fts.h>
+
+#include <atf-c.h>
+
+/*
+ * Create two directories with three files each in lexicographical order,
+ * then call FTS with a sort block that sorts in reverse lexicographical
+ * order. This has the least chance of getting a false positive due to
+ * differing file system semantics. UFS will return the files in the
+ * order they were created while ZFS will sort them lexicographically; in
+ * both cases, the order we expect is the reverse.
+ */
+ATF_TC(fts_blocks_test);
+ATF_TC_HEAD(fts_blocks_test, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test FTS with a block in lieu of a comparison function");
+}
+ATF_TC_BODY(fts_blocks_test, tc)
+{
+ char *args[] = {
+ "bar", "foo", NULL
+ };
+ char *paths[] = {
+ "foo", "z", "y", "x", "foo",
+ "bar", "c", "b", "a", "bar",
+ NULL
+ };
+ char **expect = paths;
+ FTS *fts;
+ FTSENT *ftse;
+
+ ATF_REQUIRE_EQ(0, mkdir("bar", 0755));
+ ATF_REQUIRE_EQ(0, close(creat("bar/a", 0644)));
+ ATF_REQUIRE_EQ(0, close(creat("bar/b", 0644)));
+ ATF_REQUIRE_EQ(0, close(creat("bar/c", 0644)));
+ ATF_REQUIRE_EQ(0, mkdir("foo", 0755));
+ ATF_REQUIRE_EQ(0, close(creat("foo/x", 0644)));
+ ATF_REQUIRE_EQ(0, close(creat("foo/y", 0644)));
+ ATF_REQUIRE_EQ(0, close(creat("foo/z", 0644)));
+ fts = fts_open_b(args, 0,
+ ^(const FTSENT * const *a, const FTSENT * const *b) {
+ return (strcmp((*b)->fts_name, (*a)->fts_name));
+ });
+ ATF_REQUIRE_MSG(fts != NULL, "fts_open_b(): %m");
+ while ((ftse = fts_read(fts)) != NULL && *expect != NULL) {
+ ATF_CHECK_STREQ(*expect, ftse->fts_name);
+ expect++;
+ }
+ ATF_CHECK_EQ(NULL, ftse);
+ ATF_CHECK_EQ(NULL, *expect);
+ ATF_REQUIRE_EQ_MSG(0, fts_close(fts), "fts_close(): %m");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, fts_blocks_test);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/fts_misc_test.c b/lib/libc/tests/gen/fts_misc_test.c
new file mode 100644
index 000000000000..91640078f63c
--- /dev/null
+++ b/lib/libc/tests/gen/fts_misc_test.c
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <fts.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "fts_test.h"
+
+ATF_TC(fts_unrdir);
+ATF_TC_HEAD(fts_unrdir, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "unreadable directories");
+ atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+ATF_TC_BODY(fts_unrdir, tc)
+{
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("dir/unr", 0100));
+ ATF_REQUIRE_EQ(0, mkdir("dir/unx", 0400));
+ fts_test(tc, &(struct fts_testcase){
+ (char *[]){ "dir", NULL },
+ FTS_PHYSICAL,
+ (struct fts_expect[]){
+ { FTS_D, "dir", "dir" },
+ { FTS_D, "unr", "unr" },
+ { FTS_DNR, "unr", "unr" },
+ { FTS_D, "unx", "unx" },
+ { FTS_DP, "unx", "unx" },
+ { FTS_DP, "dir", "dir" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TC(fts_unrdir_nochdir);
+ATF_TC_HEAD(fts_unrdir_nochdir, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "unreadable directories (nochdir)");
+ atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+ATF_TC_BODY(fts_unrdir_nochdir, tc)
+{
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("dir/unr", 0100));
+ ATF_REQUIRE_EQ(0, mkdir("dir/unx", 0400));
+ fts_test(tc, &(struct fts_testcase){
+ (char *[]){ "dir", NULL },
+ FTS_PHYSICAL | FTS_NOCHDIR,
+ (struct fts_expect[]){
+ { FTS_D, "dir", "dir" },
+ { FTS_D, "unr", "dir/unr" },
+ { FTS_DNR, "unr", "dir/unr" },
+ { FTS_D, "unx", "dir/unx" },
+ { FTS_DP, "unx", "dir/unx" },
+ { FTS_DP, "dir", "dir" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ fts_check_debug();
+ ATF_TP_ADD_TC(tp, fts_unrdir);
+ ATF_TP_ADD_TC(tp, fts_unrdir_nochdir);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/fts_options_test.c b/lib/libc/tests/gen/fts_options_test.c
new file mode 100644
index 000000000000..fc3015138a49
--- /dev/null
+++ b/lib/libc/tests/gen/fts_options_test.c
@@ -0,0 +1,394 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+
+#include <fcntl.h>
+#include <fts.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+#include "fts_test.h"
+
+static char *all_paths[] = {
+ "dir",
+ "dirl",
+ "file",
+ "filel",
+ "dead",
+ "noent",
+ NULL
+};
+
+/*
+ * Prepare the files and directories we will be inspecting.
+ */
+static void
+fts_options_prepare(const struct atf_tc *tc)
+{
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE_EQ(0, close(creat("file", 0644)));
+ ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644)));
+ ATF_REQUIRE_EQ(0, symlink("..", "dir/up"));
+ ATF_REQUIRE_EQ(0, symlink("dir", "dirl"));
+ ATF_REQUIRE_EQ(0, symlink("file", "filel"));
+ ATF_REQUIRE_EQ(0, symlink("noent", "dead"));
+}
+
+ATF_TC(fts_options_logical);
+ATF_TC_HEAD(fts_options_logical, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "FTS_LOGICAL");
+}
+ATF_TC_BODY(fts_options_logical, tc)
+{
+ fts_options_prepare(tc);
+ fts_test(tc, &(struct fts_testcase){
+ all_paths,
+ FTS_LOGICAL,
+ (struct fts_expect[]){
+ { FTS_DL, "dead", "dead" },
+ { FTS_D, "dir", "dir" },
+ { FTS_F, "file", "dir/file" },
+ { FTS_D, "up", "dir/up" },
+ { FTS_DL, "dead", "dir/up/dead" },
+ { FTS_DC, "dir", "dir/up/dir" },
+ { FTS_DC, "dirl", "dir/up/dirl" },
+ { FTS_F, "file", "dir/up/file" },
+ { FTS_F, "filel", "dir/up/filel" },
+ { FTS_DP, "up", "dir/up" },
+ { FTS_DP, "dir", "dir" },
+ { FTS_D, "dirl", "dirl" },
+ { FTS_F, "file", "dirl/file" },
+ { FTS_D, "up", "dirl/up" },
+ { FTS_DL, "dead", "dirl/up/dead" },
+ { FTS_DC, "dir", "dirl/up/dir" },
+ { FTS_DC, "dirl", "dirl/up/dirl" },
+ { FTS_F, "file", "dirl/up/file" },
+ { FTS_F, "filel", "dirl/up/filel" },
+ { FTS_DP, "up", "dirl/up" },
+ { FTS_DP, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_F, "filel", "filel" },
+ { FTS_NS, "noent", "noent" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TC(fts_options_logical_nostat);
+ATF_TC_HEAD(fts_options_logical_nostat, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "FTS_LOGICAL | FTS_NOSTAT");
+}
+ATF_TC_BODY(fts_options_logical_nostat, tc)
+{
+ /*
+ * While FTS_LOGICAL is not documented as being incompatible with
+ * FTS_NOSTAT, and FTS does not clear FTS_NOSTAT if FTS_LOGICAL is
+ * set, FTS_LOGICAL effectively nullifies FTS_NOSTAT by overriding
+ * the follow check in fts_stat(). In theory, FTS could easily be
+ * changed to only stat links (to check what they point to) in the
+ * FTS_LOGICAL | FTS_NOSTAT case, which would produce a different
+ * result here, so keep the test around in case that ever happens.
+ */
+ atf_tc_expect_fail("FTS_LOGICAL nullifies FTS_NOSTAT");
+ fts_options_prepare(tc);
+ fts_test(tc, &(struct fts_testcase){
+ all_paths,
+ FTS_LOGICAL | FTS_NOSTAT,
+ (struct fts_expect[]){
+ { FTS_DL, "dead", "dead" },
+ { FTS_D, "dir", "dir" },
+ { FTS_NSOK, "file", "dir/file" },
+ { FTS_D, "up", "dir/up" },
+ { FTS_DL, "dead", "dir/up/dead" },
+ { FTS_DC, "dir", "dir/up/dir" },
+ { FTS_DC, "dirl", "dir/up/dirl" },
+ { FTS_NSOK, "file", "dir/up/file" },
+ { FTS_NSOK, "filel", "dir/up/filel" },
+ { FTS_DP, "up", "dir/up" },
+ { FTS_DP, "dir", "dir" },
+ { FTS_D, "dirl", "dirl" },
+ { FTS_NSOK, "file", "dirl/file" },
+ { FTS_D, "up", "dirl/up" },
+ { FTS_DL, "dead", "dirl/up/dead" },
+ { FTS_DC, "dir", "dirl/up/dir" },
+ { FTS_DC, "dirl", "dirl/up/dirl" },
+ { FTS_NSOK, "file", "dirl/up/file" },
+ { FTS_NSOK, "filel", "dirl/up/filel" },
+ { FTS_DP, "up", "dirl/up" },
+ { FTS_DP, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_F, "filel", "filel" },
+ { FTS_NS, "noent", "noent" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TC(fts_options_logical_seedot);
+ATF_TC_HEAD(fts_options_logical_seedot, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "FTS_LOGICAL | FTS_SEEDOT");
+}
+ATF_TC_BODY(fts_options_logical_seedot, tc)
+{
+ fts_options_prepare(tc);
+ fts_test(tc, &(struct fts_testcase){
+ all_paths,
+ FTS_LOGICAL | FTS_SEEDOT,
+ (struct fts_expect[]){
+ { FTS_DL, "dead", "dead" },
+ { FTS_D, "dir", "dir" },
+ { FTS_DOT, ".", "dir/." },
+ { FTS_DOT, "..", "dir/.." },
+ { FTS_F, "file", "dir/file" },
+ { FTS_D, "up", "dir/up" },
+ { FTS_DOT, ".", "dir/up/." },
+ { FTS_DOT, "..", "dir/up/.." },
+ { FTS_DL, "dead", "dir/up/dead" },
+ { FTS_DC, "dir", "dir/up/dir" },
+ { FTS_DC, "dirl", "dir/up/dirl" },
+ { FTS_F, "file", "dir/up/file" },
+ { FTS_F, "filel", "dir/up/filel" },
+ { FTS_DP, "up", "dir/up" },
+ { FTS_DP, "dir", "dir" },
+ { FTS_D, "dirl", "dirl" },
+ { FTS_DOT, ".", "dirl/." },
+ { FTS_DOT, "..", "dirl/.." },
+ { FTS_F, "file", "dirl/file" },
+ { FTS_D, "up", "dirl/up" },
+ { FTS_DOT, ".", "dirl/up/." },
+ { FTS_DOT, "..", "dirl/up/.." },
+ { FTS_DL, "dead", "dirl/up/dead" },
+ { FTS_DC, "dir", "dirl/up/dir" },
+ { FTS_DC, "dirl", "dirl/up/dirl" },
+ { FTS_F, "file", "dirl/up/file" },
+ { FTS_F, "filel", "dirl/up/filel" },
+ { FTS_DP, "up", "dirl/up" },
+ { FTS_DP, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_F, "filel", "filel" },
+ { FTS_NS, "noent", "noent" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TC(fts_options_physical);
+ATF_TC_HEAD(fts_options_physical, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL");
+}
+ATF_TC_BODY(fts_options_physical, tc)
+{
+ fts_options_prepare(tc);
+ fts_test(tc, &(struct fts_testcase){
+ all_paths,
+ FTS_PHYSICAL,
+ (struct fts_expect[]){
+ { FTS_SL, "dead", "dead" },
+ { FTS_D, "dir", "dir" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "up", "up" },
+ { FTS_DP, "dir", "dir" },
+ { FTS_SL, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "filel", "filel" },
+ { FTS_NS, "noent", "noent" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TC(fts_options_physical_nochdir);
+ATF_TC_HEAD(fts_options_physical_nochdir, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_NOCHDIR");
+}
+ATF_TC_BODY(fts_options_physical_nochdir, tc)
+{
+ fts_options_prepare(tc);
+ fts_test(tc, &(struct fts_testcase){
+ all_paths,
+ FTS_PHYSICAL | FTS_NOCHDIR,
+ (struct fts_expect[]){
+ { FTS_SL, "dead", "dead" },
+ { FTS_D, "dir", "dir" },
+ { FTS_F, "file", "dir/file" },
+ { FTS_SL, "up", "dir/up" },
+ { FTS_DP, "dir", "dir" },
+ { FTS_SL, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "filel", "filel" },
+ { FTS_NS, "noent", "noent" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TC(fts_options_physical_comfollow);
+ATF_TC_HEAD(fts_options_physical_comfollow, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_COMFOLLOW");
+}
+ATF_TC_BODY(fts_options_physical_comfollow, tc)
+{
+ fts_options_prepare(tc);
+ fts_test(tc, &(struct fts_testcase){
+ all_paths,
+ FTS_PHYSICAL | FTS_COMFOLLOW,
+ (struct fts_expect[]){
+ { FTS_DL, "dead", "dead" },
+ { FTS_D, "dir", "dir" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "up", "up" },
+ { FTS_DP, "dir", "dir" },
+ { FTS_D, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "up", "up" },
+ { FTS_DP, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_F, "filel", "filel" },
+ { FTS_NS, "noent", "noent" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TC(fts_options_physical_comfollowdir);
+ATF_TC_HEAD(fts_options_physical_comfollowdir, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_COMFOLLOWDIR");
+}
+ATF_TC_BODY(fts_options_physical_comfollowdir, tc)
+{
+ fts_options_prepare(tc);
+ fts_test(tc, &(struct fts_testcase){
+ all_paths,
+ FTS_PHYSICAL | FTS_COMFOLLOWDIR,
+ (struct fts_expect[]){
+ { FTS_DL, "dead", "dead" },
+ { FTS_D, "dir", "dir" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "up", "up" },
+ { FTS_DP, "dir", "dir" },
+ { FTS_D, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "up", "up" },
+ { FTS_DP, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "filel", "filel" },
+ { FTS_NS, "noent", "noent" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TC(fts_options_physical_nostat);
+ATF_TC_HEAD(fts_options_physical_nostat, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_NOSTAT");
+}
+ATF_TC_BODY(fts_options_physical_nostat, tc)
+{
+ fts_options_prepare(tc);
+ fts_test(tc, &(struct fts_testcase){
+ all_paths,
+ FTS_PHYSICAL | FTS_NOSTAT,
+ (struct fts_expect[]){
+ { FTS_SL, "dead", "dead" },
+ { FTS_D, "dir", "dir" },
+ { FTS_NSOK, "file", "file" },
+ { FTS_NSOK, "up", "up" },
+ { FTS_DP, "dir", "dir" },
+ { FTS_SL, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "filel", "filel" },
+ { FTS_NS, "noent", "noent" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TC(fts_options_physical_nostat_type);
+ATF_TC_HEAD(fts_options_physical_nostat_type, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_NOSTAT_TYPE");
+}
+ATF_TC_BODY(fts_options_physical_nostat_type, tc)
+{
+ fts_options_prepare(tc);
+ fts_test(tc, &(struct fts_testcase){
+ all_paths,
+ FTS_PHYSICAL | FTS_NOSTAT_TYPE,
+ (struct fts_expect[]){
+ { FTS_SL, "dead", "dead" },
+ { FTS_D, "dir", "dir" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "up", "up" },
+ { FTS_DP, "dir", "dir" },
+ { FTS_SL, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "filel", "filel" },
+ { FTS_NS, "noent", "noent" },
+ { 0 }
+ },
+ });
+}
+
+ATF_TC(fts_options_physical_seedot);
+ATF_TC_HEAD(fts_options_physical_seedot, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "FTS_PHYSICAL | FTS_SEEDOT");
+}
+ATF_TC_BODY(fts_options_physical_seedot, tc)
+{
+ fts_options_prepare(tc);
+ fts_test(tc, &(struct fts_testcase){
+ all_paths,
+ FTS_PHYSICAL | FTS_SEEDOT,
+ (struct fts_expect[]){
+ { FTS_SL, "dead", "dead" },
+ { FTS_D, "dir", "dir" },
+ { FTS_DOT, ".", "." },
+ { FTS_DOT, "..", ".." },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "up", "up" },
+ { FTS_DP, "dir", "dir" },
+ { FTS_SL, "dirl", "dirl" },
+ { FTS_F, "file", "file" },
+ { FTS_SL, "filel", "filel" },
+ { FTS_NS, "noent", "noent" },
+ { 0 }
+ },
+ });
+}
+
+/*
+ * TODO: Add tests for FTS_XDEV and FTS_WHITEOUT
+ */
+
+ATF_TP_ADD_TCS(tp)
+{
+ fts_check_debug();
+ ATF_TP_ADD_TC(tp, fts_options_logical);
+ ATF_TP_ADD_TC(tp, fts_options_logical_nostat);
+ ATF_TP_ADD_TC(tp, fts_options_logical_seedot);
+ ATF_TP_ADD_TC(tp, fts_options_physical);
+ ATF_TP_ADD_TC(tp, fts_options_physical_nochdir);
+ ATF_TP_ADD_TC(tp, fts_options_physical_comfollow);
+ ATF_TP_ADD_TC(tp, fts_options_physical_comfollowdir);
+ ATF_TP_ADD_TC(tp, fts_options_physical_nostat);
+ ATF_TP_ADD_TC(tp, fts_options_physical_nostat_type);
+ ATF_TP_ADD_TC(tp, fts_options_physical_seedot);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/fts_test.h b/lib/libc/tests/gen/fts_test.h
new file mode 100644
index 000000000000..b3f15050f265
--- /dev/null
+++ b/lib/libc/tests/gen/fts_test.h
@@ -0,0 +1,81 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef FTS_TEST_H_INCLUDED
+#define FTS_TEST_H_INCLUDED
+
+struct fts_expect {
+ int fts_info;
+ const char *fts_name;
+ const char *fts_accpath;
+};
+
+struct fts_testcase {
+ char **paths;
+ int fts_options;
+ struct fts_expect *fts_expect;
+};
+
+/* shorter name for dead links */
+#define FTS_DL FTS_SLNONE
+
+/* are we being debugged? */
+static bool fts_test_debug;
+
+/*
+ * Set debug flag if appropriate.
+ */
+static void
+fts_check_debug(void)
+{
+ fts_test_debug = !getenv("__RUNNING_INSIDE_ATF_RUN") &&
+ isatty(STDERR_FILENO);
+}
+
+/*
+ * Lexical order for reproducability.
+ */
+static int
+fts_lexical_compar(const FTSENT * const *a, const FTSENT * const *b)
+{
+ return (strcmp((*a)->fts_name, (*b)->fts_name));
+}
+
+/*
+ * Run FTS with the specified paths and options and verify that it
+ * produces the expected result in the correct order.
+ */
+static void
+fts_test(const struct atf_tc *tc, const struct fts_testcase *fts_tc)
+{
+ FTS *fts;
+ FTSENT *ftse;
+ const struct fts_expect *expect = fts_tc->fts_expect;
+ long level = 0;
+
+ fts = fts_open(fts_tc->paths, fts_tc->fts_options, fts_lexical_compar);
+ ATF_REQUIRE_MSG(fts != NULL, "fts_open(): %m");
+ while ((ftse = fts_read(fts)) != NULL && expect->fts_name != NULL) {
+ if (expect->fts_info == FTS_DP || expect->fts_info == FTS_DNR)
+ level--;
+ if (fts_test_debug) {
+ fprintf(stderr, "%2ld %2d %s\n", level,
+ ftse->fts_info, ftse->fts_name);
+ }
+ ATF_CHECK_STREQ(expect->fts_name, ftse->fts_name);
+ ATF_CHECK_STREQ(expect->fts_accpath, ftse->fts_accpath);
+ ATF_CHECK_INTEQ(expect->fts_info, ftse->fts_info);
+ ATF_CHECK_INTEQ(level, ftse->fts_level);
+ if (expect->fts_info == FTS_D)
+ level++;
+ expect++;
+ }
+ ATF_CHECK_EQ(NULL, ftse);
+ ATF_CHECK_EQ(NULL, expect->fts_name);
+ ATF_REQUIRE_EQ_MSG(0, fts_close(fts), "fts_close(): %m");
+}
+
+#endif /* FTS_TEST_H_INCLUDED */
diff --git a/lib/libc/tests/gen/glob2_test.c b/lib/libc/tests/gen/glob2_test.c
index 8f69c36fece7..ff1b36b830b8 100644
--- a/lib/libc/tests/gen/glob2_test.c
+++ b/lib/libc/tests/gen/glob2_test.c
@@ -25,9 +25,12 @@
*/
#include <sys/param.h>
+#include <sys/stat.h>
+
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -102,10 +105,80 @@ ATF_TC_BODY(glob_pathological_test, tc)
}
}
+ATF_TC(glob_period);
+ATF_TC_HEAD(glob_period, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test behaviour when matching files that start with a period"
+ "(documented in the glob(3) CAVEATS section).");
+}
+ATF_TC_BODY(glob_period, tc)
+{
+ int i;
+ glob_t g;
+
+ atf_utils_create_file(".test", "");
+ glob(".", 0, NULL, &g);
+ ATF_REQUIRE_MSG(g.gl_matchc == 1,
+ "glob(3) shouldn't match files starting with a period when using '.'");
+ for (i = 0; i < g.gl_matchc; i++)
+ printf("%s\n", g.gl_pathv[i]);
+ glob(".*", 0, NULL, &g);
+ ATF_REQUIRE_MSG(g.gl_matchc == 3 && strcmp(g.gl_pathv[2], ".test") == 0,
+ "glob(3) should match files starting with a period when using '.*'");
+}
+
+static bool glob_callback_invoked;
+
+static int
+errfunc(const char *path, int err)
+{
+ ATF_CHECK_STREQ(path, "test/");
+ ATF_CHECK(err == EACCES);
+ glob_callback_invoked = true;
+ /* Suppress EACCES errors. */
+ return (0);
+}
+
+ATF_TC(glob_callback);
+ATF_TC_HEAD(glob_callback, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test ability of callback function to suppress errors");
+ atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+ATF_TC_BODY(glob_callback, tc)
+{
+ glob_t g;
+ int rv;
+
+ ATF_REQUIRE_EQ(0, mkdir("test", 0755));
+ ATF_REQUIRE_EQ(0, symlink("foo", "test/foo"));
+ ATF_REQUIRE_EQ(0, chmod("test", 0));
+
+ glob_callback_invoked = false;
+ rv = glob("test/*", 0, errfunc, &g);
+ ATF_CHECK_MSG(glob_callback_invoked,
+ "glob(3) failed to invoke callback function");
+ ATF_CHECK_EQ_MSG(GLOB_NOMATCH, rv,
+ "callback function failed to suppress EACCES");
+ globfree(&g);
+
+ /* GLOB_ERR should ignore the suppressed error. */
+ glob_callback_invoked = false;
+ rv = glob("test/*", GLOB_ERR, errfunc, &g);
+ ATF_CHECK_MSG(glob_callback_invoked,
+ "glob(3) failed to invoke callback function");
+ ATF_CHECK_EQ_MSG(GLOB_ABORTED, rv,
+ "GLOB_ERR didn't override callback function");
+ globfree(&g);
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, glob_pathological_test);
-
+ ATF_TP_ADD_TC(tp, glob_period);
+ ATF_TP_ADD_TC(tp, glob_callback);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/glob_blocks_test.c b/lib/libc/tests/gen/glob_blocks_test.c
new file mode 100644
index 000000000000..629b90bee762
--- /dev/null
+++ b/lib/libc/tests/gen/glob_blocks_test.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <glob.h>
+#include <stdbool.h>
+
+#include <atf-c.h>
+
+ATF_TC(glob_b_callback);
+ATF_TC_HEAD(glob_b_callback, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test ability of callback block to suppress errors");
+ atf_tc_set_md_var(tc, "require.user", "unprivileged");
+}
+ATF_TC_BODY(glob_b_callback, tc)
+{
+ static bool glob_callback_invoked;
+ static int (^errblk)(const char *, int) =
+ ^(const char *path, int err) {
+ ATF_CHECK_STREQ(path, "test/");
+ ATF_CHECK(err == EACCES);
+ glob_callback_invoked = true;
+ /* Suppress EACCES errors. */
+ return (0);
+ };
+ glob_t g;
+ int rv;
+
+ ATF_REQUIRE_EQ(0, mkdir("test", 0755));
+ ATF_REQUIRE_EQ(0, symlink("foo", "test/foo"));
+ ATF_REQUIRE_EQ(0, chmod("test", 0));
+
+ glob_callback_invoked = false;
+ rv = glob_b("test/*", 0, errblk, &g);
+ ATF_CHECK_MSG(glob_callback_invoked,
+ "glob(3) failed to invoke callback block");
+ ATF_CHECK_EQ_MSG(GLOB_NOMATCH, rv,
+ "callback function failed to suppress EACCES");
+ globfree(&g);
+
+ /* GLOB_ERR should ignore the suppressed error. */
+ glob_callback_invoked = false;
+ rv = glob_b("test/*", GLOB_ERR, errblk, &g);
+ ATF_CHECK_MSG(glob_callback_invoked,
+ "glob(3) failed to invoke callback block");
+ ATF_CHECK_EQ_MSG(GLOB_ABORTED, rv,
+ "GLOB_ERR didn't override callback block");
+ globfree(&g);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, glob_b_callback);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/opendir_test.c b/lib/libc/tests/gen/opendir_test.c
new file mode 100644
index 000000000000..b7481255654f
--- /dev/null
+++ b/lib/libc/tests/gen/opendir_test.c
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+/*
+ * Create a directory with a single subdirectory.
+ */
+static void
+opendir_prepare(const struct atf_tc *tc)
+{
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("dir/subdir", 0755));
+}
+
+/*
+ * Assuming dirp represents the directory created by opendir_prepare(),
+ * verify that readdir() returns what we expected to see there.
+ */
+static void
+opendir_check(const struct atf_tc *tc, DIR *dirp)
+{
+ struct dirent *ent;
+
+ ATF_REQUIRE((ent = readdir(dirp)) != NULL);
+ ATF_CHECK_EQ(1, ent->d_namlen);
+ ATF_CHECK_STREQ(".", ent->d_name);
+ ATF_CHECK_EQ(DT_DIR, ent->d_type);
+ ATF_REQUIRE((ent = readdir(dirp)) != NULL);
+ ATF_CHECK_EQ(2, ent->d_namlen);
+ ATF_CHECK_STREQ("..", ent->d_name);
+ ATF_CHECK_EQ(DT_DIR, ent->d_type);
+ ATF_REQUIRE((ent = readdir(dirp)) != NULL);
+ ATF_CHECK_EQ(sizeof("subdir") - 1, ent->d_namlen);
+ ATF_CHECK_STREQ("subdir", ent->d_name);
+ ATF_CHECK_EQ(DT_DIR, ent->d_type);
+ ATF_CHECK(readdir(dirp) == NULL);
+ ATF_CHECK(readdir(dirp) == NULL);
+}
+
+ATF_TC(opendir_ok);
+ATF_TC_HEAD(opendir_ok, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Open a directory.");
+}
+ATF_TC_BODY(opendir_ok, tc)
+{
+ DIR *dirp;
+
+ opendir_prepare(tc);
+ ATF_REQUIRE((dirp = opendir("dir")) != NULL);
+ opendir_check(tc, dirp);
+ ATF_CHECK_EQ(0, closedir(dirp));
+}
+
+ATF_TC(opendir_fifo);
+ATF_TC_HEAD(opendir_fifo, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Do not hang if given a named pipe.");
+}
+ATF_TC_BODY(opendir_fifo, tc)
+{
+ DIR *dirp;
+ int fd;
+
+ ATF_REQUIRE((fd = mkfifo("fifo", 0644)) >= 0);
+ ATF_REQUIRE_EQ(0, close(fd));
+ ATF_REQUIRE((dirp = opendir("fifo")) == NULL);
+ ATF_CHECK_EQ(ENOTDIR, errno);
+}
+
+ATF_TC(fdopendir_ok);
+ATF_TC_HEAD(fdopendir_ok, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Open a directory from a directory descriptor.");
+}
+ATF_TC_BODY(fdopendir_ok, tc)
+{
+ DIR *dirp;
+ int dd;
+
+ opendir_prepare(tc);
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_REQUIRE((dirp = fdopendir(dd)) != NULL);
+ opendir_check(tc, dirp);
+ ATF_CHECK_EQ(dd, fdclosedir(dirp));
+ ATF_CHECK_EQ(0, close(dd));
+}
+
+ATF_TC(fdopendir_ebadf);
+ATF_TC_HEAD(fdopendir_ebadf, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Open a directory from an invalid descriptor.");
+}
+ATF_TC_BODY(fdopendir_ebadf, tc)
+{
+ DIR *dirp;
+ int dd;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE((dd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ATF_CHECK_EQ(0, close(dd));
+ ATF_REQUIRE((dirp = fdopendir(dd)) == NULL);
+ ATF_CHECK_EQ(EBADF, errno);
+}
+
+ATF_TC(fdopendir_enotdir);
+ATF_TC_HEAD(fdopendir_enotdir, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Open a directory from a non-directory descriptor.");
+}
+ATF_TC_BODY(fdopendir_enotdir, tc)
+{
+ DIR *dirp;
+ int fd;
+
+ ATF_REQUIRE((fd = open("file", O_CREAT | O_RDWR, 0644)) >= 0);
+ ATF_REQUIRE((dirp = fdopendir(fd)) == NULL);
+ ATF_CHECK_EQ(ENOTDIR, errno);
+ ATF_CHECK_EQ(0, close(fd));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, opendir_ok);
+ ATF_TP_ADD_TC(tp, fdopendir_ok);
+ ATF_TP_ADD_TC(tp, fdopendir_ebadf);
+ ATF_TP_ADD_TC(tp, fdopendir_enotdir);
+ ATF_TP_ADD_TC(tp, opendir_fifo);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/scandir_blocks_test.c b/lib/libc/tests/gen/scandir_blocks_test.c
new file mode 100644
index 000000000000..b94270bc410e
--- /dev/null
+++ b/lib/libc/tests/gen/scandir_blocks_test.c
@@ -0,0 +1,118 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+static void
+scandir_blocks_prepare(const struct atf_tc *tc)
+{
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("dir/dir", 0755));
+ ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644)));
+ ATF_REQUIRE_EQ(0, symlink("file", "dir/link"));
+ ATF_REQUIRE_EQ(0, mkdir("dir/skip", 0755));
+}
+
+static void
+scandir_blocks_verify(const struct atf_tc *tc, int n, struct dirent **namelist)
+{
+ ATF_REQUIRE_EQ_MSG(5, n, "return value is %d", n);
+ ATF_CHECK_STREQ("link", namelist[0]->d_name);
+ ATF_CHECK_STREQ("file", namelist[1]->d_name);
+ ATF_CHECK_STREQ("dir", namelist[2]->d_name);
+ ATF_CHECK_STREQ("..", namelist[3]->d_name);
+ ATF_CHECK_STREQ(".", namelist[4]->d_name);
+}
+
+ATF_TC(scandir_b_test);
+ATF_TC_HEAD(scandir_b_test, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test scandir_b()");
+}
+ATF_TC_BODY(scandir_b_test, tc)
+{
+ struct dirent **namelist = NULL;
+ int i, ret;
+
+ scandir_blocks_prepare(tc);
+ ret = scandir_b("dir", &namelist,
+ ^(const struct dirent *ent) {
+ return (strcmp(ent->d_name, "skip") != 0);
+ },
+ ^(const struct dirent **a, const struct dirent **b) {
+ return (strcmp((*b)->d_name, (*a)->d_name));
+ });
+ scandir_blocks_verify(tc, ret, namelist);
+ for (i = 0; i < ret; i++)
+ free(namelist[i]);
+ free(namelist);
+}
+
+ATF_TC(fdscandir_b_test);
+ATF_TC_HEAD(fdscandir_b_test, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test fdscandir_b()");
+}
+ATF_TC_BODY(fdscandir_b_test, tc)
+{
+ struct dirent **namelist = NULL;
+ int fd, i, ret;
+
+ scandir_blocks_prepare(tc);
+ ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ret = fdscandir_b(fd, &namelist,
+ ^(const struct dirent *ent) {
+ return (strcmp(ent->d_name, "skip") != 0);
+ },
+ ^(const struct dirent **a, const struct dirent **b) {
+ return (strcmp((*b)->d_name, (*a)->d_name));
+ });
+ scandir_blocks_verify(tc, ret, namelist);
+ for (i = 0; i < ret; i++)
+ free(namelist[i]);
+ free(namelist);
+ ATF_REQUIRE_EQ(0, close(fd));
+}
+
+ATF_TC(scandirat_b_test);
+ATF_TC_HEAD(scandirat_b_test, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test scandirat_b()");
+}
+ATF_TC_BODY(scandirat_b_test, tc)
+{
+ struct dirent **namelist = NULL;
+ int fd, i, ret;
+
+ scandir_blocks_prepare(tc);
+ ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_SEARCH)) >= 0);
+ ret = scandirat_b(fd, ".", &namelist,
+ ^(const struct dirent *ent) {
+ return (strcmp(ent->d_name, "skip") != 0);
+ },
+ ^(const struct dirent **a, const struct dirent **b) {
+ return (strcmp((*b)->d_name, (*a)->d_name));
+ });
+ scandir_blocks_verify(tc, ret, namelist);
+ for (i = 0; i < ret; i++)
+ free(namelist[i]);
+ free(namelist);
+ ATF_REQUIRE_EQ(0, close(fd));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, scandir_b_test);
+ ATF_TP_ADD_TC(tp, fdscandir_b_test);
+ ATF_TP_ADD_TC(tp, scandirat_b_test);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/scandir_test.c b/lib/libc/tests/gen/scandir_test.c
new file mode 100644
index 000000000000..afd25bf7c0b2
--- /dev/null
+++ b/lib/libc/tests/gen/scandir_test.c
@@ -0,0 +1,195 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+static void
+scandir_prepare(const struct atf_tc *tc)
+{
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("dir/dir", 0755));
+ ATF_REQUIRE_EQ(0, close(creat("dir/file", 0644)));
+ ATF_REQUIRE_EQ(0, symlink("file", "dir/link"));
+ ATF_REQUIRE_EQ(0, mkdir("dir/skip", 0755));
+}
+
+static void
+scandir_verify(const struct atf_tc *tc, int n, struct dirent **namelist)
+{
+ ATF_REQUIRE_EQ_MSG(5, n, "return value is %d", n);
+ ATF_CHECK_STREQ("link", namelist[0]->d_name);
+ ATF_CHECK_STREQ("file", namelist[1]->d_name);
+ ATF_CHECK_STREQ("dir", namelist[2]->d_name);
+ ATF_CHECK_STREQ("..", namelist[3]->d_name);
+ ATF_CHECK_STREQ(".", namelist[4]->d_name);
+}
+
+static int
+scandir_select(const struct dirent *ent)
+{
+ return (strcmp(ent->d_name, "skip") != 0);
+}
+
+static int
+scandir_compare(const struct dirent **a, const struct dirent **b)
+{
+ return (strcmp((*b)->d_name, (*a)->d_name));
+}
+
+ATF_TC(scandir_test);
+ATF_TC_HEAD(scandir_test, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test scandir()");
+}
+ATF_TC_BODY(scandir_test, tc)
+{
+ struct dirent **namelist = NULL;
+ int i, ret;
+
+ scandir_prepare(tc);
+ ret = scandir("dir", &namelist, scandir_select, scandir_compare);
+ scandir_verify(tc, ret, namelist);
+ for (i = 0; i < ret; i++)
+ free(namelist[i]);
+ free(namelist);
+}
+
+ATF_TC(fdscandir_test);
+ATF_TC_HEAD(fdscandir_test, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test fdscandir()");
+}
+ATF_TC_BODY(fdscandir_test, tc)
+{
+ struct dirent **namelist = NULL;
+ int fd, i, ret;
+
+ scandir_prepare(tc);
+ ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ ret = fdscandir(fd, &namelist, scandir_select, scandir_compare);
+ scandir_verify(tc, ret, namelist);
+ for (i = 0; i < ret; i++)
+ free(namelist[i]);
+ free(namelist);
+ ATF_REQUIRE_EQ(0, close(fd));
+}
+
+ATF_TC(scandirat_test);
+ATF_TC_HEAD(scandirat_test, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test scandirat()");
+}
+ATF_TC_BODY(scandirat_test, tc)
+{
+ struct dirent **namelist = NULL;
+ int fd, i, ret;
+
+ scandir_prepare(tc);
+ ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_SEARCH)) >= 0);
+ ret = scandirat(fd, ".", &namelist, scandir_select, scandir_compare);
+ scandir_verify(tc, ret, namelist);
+ for (i = 0; i < ret; i++)
+ free(namelist[i]);
+ free(namelist);
+ ATF_REQUIRE_EQ(0, close(fd));
+}
+
+static int
+scandir_none(const struct dirent *ent __unused)
+{
+ return (0);
+}
+
+ATF_TC(scandir_none);
+ATF_TC_HEAD(scandir_none, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test scandir() when no entries are selected");
+}
+ATF_TC_BODY(scandir_none, tc)
+{
+ struct dirent **namelist = NULL;
+
+ ATF_REQUIRE_EQ(0, scandir(".", &namelist, scandir_none, alphasort));
+ ATF_REQUIRE(namelist);
+ free(namelist);
+}
+
+/*
+ * Test that scandir() propagates errors from readdir(): we create a
+ * directory with enough entries that it can't be read in a single
+ * getdirentries() call, then abuse the selection callback to close the
+ * file descriptor scandir() is using after the first call, causing the
+ * next one to fail, and verify that readdir() returns an error instead of
+ * a partial result. We make two passes, one in which nothing was
+ * selected before the error occurred, and one in which everything was.
+ */
+static int scandir_error_count;
+static int scandir_error_fd;
+static int scandir_error_select_return;
+
+static int
+scandir_error_select(const struct dirent *ent __unused)
+{
+ if (scandir_error_count++ == 0)
+ close(scandir_error_fd);
+ return (scandir_error_select_return);
+}
+
+ATF_TC(scandir_error);
+ATF_TC_HEAD(scandir_error, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test that scandir() propagates errors from readdir()");
+}
+ATF_TC_BODY(scandir_error, tc)
+{
+ char path[16];
+ struct dirent **namelist = NULL;
+ int fd, i;
+
+ ATF_REQUIRE_EQ(0, mkdir("dir", 0755));
+ for (i = 0; i < 1024; i++) {
+ snprintf(path, sizeof(path), "dir/%04x", i);
+ ATF_REQUIRE_EQ(0, symlink(path + 4, path));
+ }
+
+ /* first pass, select nothing */
+ ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ scandir_error_count = 0;
+ scandir_error_fd = fd;
+ scandir_error_select_return = 0;
+ ATF_CHECK_ERRNO(EBADF,
+ fdscandir(fd, &namelist, scandir_error_select, NULL) < 0);
+ ATF_CHECK_EQ(NULL, namelist);
+
+ /* second pass, select everything */
+ ATF_REQUIRE((fd = open("dir", O_DIRECTORY | O_RDONLY)) >= 0);
+ scandir_error_count = 0;
+ scandir_error_fd = fd;
+ scandir_error_select_return = 1;
+ ATF_CHECK_ERRNO(EBADF,
+ fdscandir(fd, &namelist, scandir_error_select, NULL) < 0);
+ ATF_CHECK_EQ(NULL, namelist);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, scandir_test);
+ ATF_TP_ADD_TC(tp, fdscandir_test);
+ ATF_TP_ADD_TC(tp, scandirat_test);
+ ATF_TP_ADD_TC(tp, scandir_none);
+ ATF_TP_ADD_TC(tp, scandir_error);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/sig2str_test.c b/lib/libc/tests/gen/sig2str_test.c
new file mode 100644
index 000000000000..00b6ebb2349a
--- /dev/null
+++ b/lib/libc/tests/gen/sig2str_test.c
@@ -0,0 +1,213 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Ricardo Branco <rbranco@suse.de>
+ * 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.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+static void
+test_roundtrip(int signum)
+{
+ char str[SIG2STR_MAX];
+ int sig;
+
+ ATF_REQUIRE_EQ_MSG(sig2str(signum, str), 0,
+ "sig2str(%d) failed", signum);
+ ATF_REQUIRE_EQ_MSG(str2sig(str, &sig), 0,
+ "str2sig(\"%s\") failed", str);
+ ATF_REQUIRE_INTEQ_MSG(sig, signum,
+ "Mismatch: roundtrip conversion gave %d instead of %d",
+ sig, signum);
+}
+
+ATF_TC_WITHOUT_HEAD(sig2str_valid);
+ATF_TC_BODY(sig2str_valid, tc)
+{
+ int sig;
+
+ for (sig = 1; sig < sys_nsig; sig++) {
+ test_roundtrip(sig);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(sig2str_invalid);
+ATF_TC_BODY(sig2str_invalid, tc)
+{
+ char buf[SIG2STR_MAX];
+
+ ATF_CHECK(sig2str(0, buf) != 0);
+ ATF_CHECK(sig2str(-1, buf) != 0);
+ ATF_CHECK(sig2str(SIGRTMAX + 1, buf) != 0);
+}
+
+ATF_TC_WITHOUT_HEAD(str2sig_rtmin_rtmax);
+ATF_TC_BODY(str2sig_rtmin_rtmax, tc)
+{
+ int sig;
+
+ ATF_CHECK_MSG(str2sig("RTMIN", &sig) == 0,
+ "str2sig(\"RTMIN\") failed");
+ ATF_CHECK_INTEQ_MSG(sig, SIGRTMIN,
+ "RTMIN mapped to %d, expected %d", sig, SIGRTMIN);
+
+ ATF_CHECK_MSG(str2sig("RTMAX", &sig) == 0,
+ "str2sig(\"RTMAX\") failed");
+ ATF_CHECK_INTEQ_MSG(sig, SIGRTMAX,
+ "RTMAX mapped to %d, expected %d", sig, SIGRTMAX);
+
+ ATF_CHECK_MSG(str2sig("RTMIN+1", &sig) == 0,
+ "str2sig(\"RTMIN+1\") failed");
+ ATF_CHECK_INTEQ_MSG(sig, SIGRTMIN + 1,
+ "RTMIN+1 mapped to %d, expected %d", sig, SIGRTMIN + 1);
+
+ ATF_CHECK_MSG(str2sig("RTMAX-1", &sig) == 0,
+ "str2sig(\"RTMAX-1\") failed");
+ ATF_CHECK_INTEQ_MSG(sig, SIGRTMAX - 1,
+ "RTMAX-1 mapped to %d, expected %d", sig, SIGRTMAX - 1);
+}
+
+ATF_TC_WITHOUT_HEAD(str2sig_invalid_rt);
+ATF_TC_BODY(str2sig_invalid_rt, tc)
+{
+ int i, sig;
+
+ const char *invalid[] = {
+ "RTMIN+0",
+ "RTMAX-0",
+ "RTMIN-777",
+ "RTMIN+777",
+ "RTMAX-777",
+ "RTMAX+777",
+ "RTMIN-",
+ "RTMAX-",
+ "RTMIN0",
+ "RTMAX1",
+ "RTMIN+abc",
+ "RTMIN-abc",
+ NULL
+ };
+
+ for (i = 0; invalid[i] != NULL; i++) {
+ ATF_CHECK_MSG(str2sig(invalid[i], &sig) != 0,
+ "str2sig(\"%s\") unexpectedly succeeded", invalid[i]);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(str2sig_fullname);
+ATF_TC_BODY(str2sig_fullname, tc)
+{
+ char fullname[SIG2STR_MAX + 3];
+ int n, sig;
+
+ for (sig = 1; sig < sys_nsig; sig++) {
+ snprintf(fullname, sizeof(fullname), "SIG%s", sys_signame[sig]);
+
+ ATF_CHECK_MSG(str2sig(fullname, &n) == 0,
+ "str2sig(\"%s\") failed with errno %d (%s)",
+ fullname, errno, strerror(errno));
+
+ ATF_CHECK_INTEQ_MSG(n, sig,
+ "Mismatch: %s = %d, str2sig(\"%s\") = %d",
+ sys_signame[sig], sig, fullname, n);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(str2sig_lowercase);
+ATF_TC_BODY(str2sig_lowercase, tc)
+{
+ char fullname[SIG2STR_MAX + 3];
+ int n, sig;
+
+ for (sig = 1; sig < sys_nsig; sig++) {
+ snprintf(fullname, sizeof(fullname), "sig%s", sys_signame[sig]);
+ for (size_t i = 3; i < strlen(fullname); i++)
+ fullname[i] = toupper((unsigned char)fullname[i]);
+
+ ATF_CHECK_MSG(str2sig(fullname, &n) == 0,
+ "str2sig(\"%s\") failed with errno %d (%s)",
+ fullname, errno, strerror(errno));
+
+ ATF_CHECK_INTEQ_MSG(n, sig,
+ "Mismatch: %s = %d, str2sig(\"%s\") = %d",
+ sys_signame[sig], sig, fullname, n);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(str2sig_numeric);
+ATF_TC_BODY(str2sig_numeric, tc)
+{
+ char buf[16];
+ int n, sig;
+
+ for (sig = NSIG; sig < SIGRTMIN; sig++) {
+ snprintf(buf, sizeof(buf), "%d", sig);
+ ATF_CHECK_MSG(str2sig(buf, &n) == 0,
+ "str2sig(\"%s\") failed", buf);
+ ATF_CHECK_INTEQ_MSG(n, sig,
+ "Mismatch: str2sig(\"%s\") = %d, expected %d",
+ buf, n, sig);
+ }
+}
+
+ATF_TC_WITHOUT_HEAD(str2sig_invalid);
+ATF_TC_BODY(str2sig_invalid, tc)
+{
+ const char *invalid[] = {
+ "SIGDOESNOTEXIST",
+ "DOESNOTEXIST",
+ "INTERRUPT",
+ "",
+ "SIG",
+ "123abc",
+ "sig1extra",
+ NULL
+ };
+ int i, sig;
+
+ for (i = 0; invalid[i] != NULL; i++) {
+ ATF_CHECK_MSG(str2sig(invalid[i], &sig) != 0,
+ "str2sig(\"%s\") unexpectedly succeeded", invalid[i]);
+ }
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, sig2str_valid);
+ ATF_TP_ADD_TC(tp, sig2str_invalid);
+ ATF_TP_ADD_TC(tp, str2sig_rtmin_rtmax);
+ ATF_TP_ADD_TC(tp, str2sig_invalid_rt);
+ ATF_TP_ADD_TC(tp, str2sig_fullname);
+ ATF_TP_ADD_TC(tp, str2sig_lowercase);
+ ATF_TP_ADD_TC(tp, str2sig_numeric);
+ ATF_TP_ADD_TC(tp, str2sig_invalid);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/wordexp_test.c b/lib/libc/tests/gen/wordexp_test.c
index 909097fbf51e..a8b9d5509633 100644
--- a/lib/libc/tests/gen/wordexp_test.c
+++ b/lib/libc/tests/gen/wordexp_test.c
@@ -292,6 +292,31 @@ ATF_TC_BODY(with_SIGCHILD_handler_test, tc)
ATF_REQUIRE(r == 0);
}
+ATF_TC_WITHOUT_HEAD(with_SIGCHILD_ignore_test);
+ATF_TC_BODY(with_SIGCHILD_ignore_test, tc)
+{
+ struct sigaction sa;
+ wordexp_t we;
+ int r;
+
+ /* With SIGCHLD set to ignore so that the kernel auto-reaps zombies. */
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_handler = SIG_IGN;
+ r = sigaction(SIGCHLD, &sa, NULL);
+ ATF_REQUIRE(r == 0);
+ r = wordexp("hello world", &we, 0);
+ ATF_REQUIRE(r == 0);
+ ATF_REQUIRE(we.we_wordc == 2);
+ ATF_REQUIRE(strcmp(we.we_wordv[0], "hello") == 0);
+ ATF_REQUIRE(strcmp(we.we_wordv[1], "world") == 0);
+ ATF_REQUIRE(we.we_wordv[2] == NULL);
+ wordfree(&we);
+ sa.sa_handler = SIG_DFL;
+ r = sigaction(SIGCHLD, &sa, NULL);
+ ATF_REQUIRE(r == 0);
+}
+
ATF_TC_WITHOUT_HEAD(with_unused_non_default_IFS_test);
ATF_TC_BODY(with_unused_non_default_IFS_test, tc)
{
@@ -350,6 +375,7 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, WRDE_BADCHAR_test);
ATF_TP_ADD_TC(tp, WRDE_SYNTAX_test);
ATF_TP_ADD_TC(tp, with_SIGCHILD_handler_test);
+ ATF_TP_ADD_TC(tp, with_SIGCHILD_ignore_test);
ATF_TP_ADD_TC(tp, with_unused_non_default_IFS_test);
ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test);
diff --git a/lib/libc/tests/locale/wctomb_test.c b/lib/libc/tests/locale/wctomb_test.c
index 1e142ed74c48..ef2a6dcbe1e3 100644
--- a/lib/libc/tests/locale/wctomb_test.c
+++ b/lib/libc/tests/locale/wctomb_test.c
@@ -41,6 +41,18 @@
#include <atf-c.h>
+ATF_TC_WITHOUT_HEAD(euccs1_test);
+ATF_TC_BODY(euccs1_test, tc)
+{
+ wchar_t wc = 0x8e000000;
+ char buf[MB_LEN_MAX];
+
+ ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "zh_CN.eucCN"),
+ "zh_CN.eucCN") == 0);
+
+ ATF_REQUIRE(wctomb(&buf[0], wc) == 4);
+}
+
ATF_TC_WITHOUT_HEAD(wctomb_test);
ATF_TC_BODY(wctomb_test, tc)
{
@@ -104,6 +116,7 @@ ATF_TC_BODY(wctomb_test, tc)
ATF_TP_ADD_TCS(tp)
{
+ ATF_TP_ADD_TC(tp, euccs1_test);
ATF_TP_ADD_TC(tp, wctomb_test);
return (atf_no_error());
diff --git a/lib/libc/tests/net/Makefile b/lib/libc/tests/net/Makefile
index 0a49683ea3d1..24cff61e8d24 100644
--- a/lib/libc/tests/net/Makefile
+++ b/lib/libc/tests/net/Makefile
@@ -3,6 +3,9 @@ PACKAGE= tests
ATF_TESTS_C+= ether_test
ATF_TESTS_C+= eui64_aton_test
ATF_TESTS_C+= eui64_ntoa_test
+ATF_TESTS_CXX+= link_addr_test
+
+CXXSTD.link_addr_test= c++20
CFLAGS+= -I${.CURDIR}
@@ -31,8 +34,7 @@ aton_ether_subr.c: gen_ether_subr ${SRCTOP}/sys/net/if_ethersubr.c
.include "../Makefile.netbsd-tests"
-# TODO: the testcases needs to be ported to FreeBSD
-#TESTS_SUBDIRS= getaddrinfo
+TESTS_SUBDIRS= getaddrinfo
${PACKAGE}FILES+= hosts
${PACKAGE}FILES+= resolv.conf
diff --git a/lib/libc/tests/net/getaddrinfo/Makefile b/lib/libc/tests/net/getaddrinfo/Makefile
index 5d98aa31a86a..1299e91615b7 100644
--- a/lib/libc/tests/net/getaddrinfo/Makefile
+++ b/lib/libc/tests/net/getaddrinfo/Makefile
@@ -1,14 +1,11 @@
PACKAGE= tests
-TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libc/net/${.CURDIR:T}
-
.include <bsd.own.mk>
BINDIR= ${TESTSDIR}
-.error This testcase needs to be ported to FreeBSD (the output from getaddrinfo_test differs from NetBSD)
-
-NETBSD_ATF_TESTS_SH= getaddrinfo_test
+ATF_TESTS_SH= getaddrinfo_test
+ATF_TESTS_C= getaddrinfo
PROGS= h_gai
@@ -17,13 +14,33 @@ ${PACKAGE}DATA_FILESPACKAGE= tests
${PACKAGE}DATA_FILESDIR= ${TESTSDIR}/data
-${PACKAGE}DATA_FILES+= basics_v4.exp basics_v4v6.exp
-${PACKAGE}DATA_FILES+= no_host_v4.exp no_host_v4v6.exp
-${PACKAGE}DATA_FILES+= no_serv_v4.exp no_serv_v4v6.exp
-${PACKAGE}DATA_FILES+= sock_raw_v4.exp sock_raw_v4v6.exp
-${PACKAGE}DATA_FILES+= spec_fam_v4.exp spec_fam_v4v6.exp
-${PACKAGE}DATA_FILES+= scoped.exp
-${PACKAGE}DATA_FILES+= unsup_fam.exp
+${PACKAGE}DATA_FILES+= data/basics_v4.exp
+${PACKAGE}DATA_FILES+= data/basics_v4_only.exp
+${PACKAGE}DATA_FILES+= data/basics_v4v6.exp
+${PACKAGE}DATA_FILES+= data/basics_v4v6_prefer_v4.exp
+${PACKAGE}DATA_FILES+= data/no_host_v4.exp
+${PACKAGE}DATA_FILES+= data/no_host_v4_only.exp
+${PACKAGE}DATA_FILES+= data/no_host_v4v6.exp
+${PACKAGE}DATA_FILES+= data/no_host_v4v6_prefer_v4.exp
+${PACKAGE}DATA_FILES+= data/no_serv_v4.exp
+${PACKAGE}DATA_FILES+= data/no_serv_v4_only.exp
+${PACKAGE}DATA_FILES+= data/no_serv_v4v6.exp
+${PACKAGE}DATA_FILES+= data/no_serv_v4v6_prefer_v4.exp
+${PACKAGE}DATA_FILES+= data/scoped.exp
+${PACKAGE}DATA_FILES+= data/scoped_v4_only.exp
+${PACKAGE}DATA_FILES+= data/scoped_v4v6_prefer_v4.exp
+${PACKAGE}DATA_FILES+= data/sock_raw_v4.exp
+${PACKAGE}DATA_FILES+= data/sock_raw_v4_only.exp
+${PACKAGE}DATA_FILES+= data/sock_raw_v4v6.exp
+${PACKAGE}DATA_FILES+= data/sock_raw_v4v6_prefer_v4.exp
+${PACKAGE}DATA_FILES+= data/spec_fam_v4.exp
+${PACKAGE}DATA_FILES+= data/spec_fam_v4_only.exp
+${PACKAGE}DATA_FILES+= data/spec_fam_v4v6.exp
+${PACKAGE}DATA_FILES+= data/spec_fam_v4v6_prefer_v4.exp
+${PACKAGE}DATA_FILES+= data/unsup_fam.exp
+${PACKAGE}DATA_FILES+= data/unsup_fam_v4_only.exp
+${PACKAGE}DATA_FILES+= data/unsup_fam_v4v6_prefer_v4.exp
+
.include "../../Makefile.netbsd-tests"
diff --git a/lib/libc/tests/net/getaddrinfo/data/basics_v4.exp b/lib/libc/tests/net/getaddrinfo/data/basics_v4.exp
new file mode 100644
index 000000000000..4f1ee3517211
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/basics_v4.exp
@@ -0,0 +1,42 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv tftp
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv tftp
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv tftp
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv echo
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv echo
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv echo
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/basics_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/basics_v4_only.exp
new file mode 100644
index 000000000000..0a37d3212649
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/basics_v4_only.exp
@@ -0,0 +1,50 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv tftp
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv tftp
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv tftp
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+ai3: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp
+ai4: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv echo
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv echo
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv echo
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo
+ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo
+ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/basics_v4v6.exp b/lib/libc/tests/net/getaddrinfo/data/basics_v4v6.exp
new file mode 100644
index 000000000000..b74758e93e2e
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/basics_v4v6.exp
@@ -0,0 +1,50 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv tftp
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv tftp
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv tftp
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp
+ai3: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai4: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv echo
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv echo
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv echo
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/basics_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/basics_v4v6_prefer_v4.exp
new file mode 100644
index 000000000000..0a37d3212649
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/basics_v4v6_prefer_v4.exp
@@ -0,0 +1,50 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv tftp
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv tftp
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv tftp
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+ai3: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp
+ai4: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv echo
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv echo
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv echo
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo
+ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo
+ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/generate_testdata.sh b/lib/libc/tests/net/getaddrinfo/data/generate_testdata.sh
new file mode 100755
index 000000000000..f0425a3b0283
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/generate_testdata.sh
@@ -0,0 +1,45 @@
+#service ip6addrctl prefer_ipv4
+TEST=./h_gai
+family=v4_only
+
+( $TEST ::1 http
+ $TEST 127.0.0.1 http
+ $TEST localhost http
+ $TEST ::1 tftp
+ $TEST 127.0.0.1 tftp
+ $TEST localhost tftp
+ $TEST ::1 echo
+ $TEST 127.0.0.1 echo
+ $TEST localhost echo ) > basics_${family}.exp
+
+( $TEST -4 localhost http
+ $TEST -6 localhost http ) > spec_fam_${family}.exp
+
+( $TEST '' http
+ $TEST '' echo
+ $TEST '' tftp
+ $TEST '' 80
+ $TEST -P '' http
+ $TEST -P '' echo
+ $TEST -P '' tftp
+ $TEST -P '' 80
+ $TEST -S '' 80
+ $TEST -D '' 80 ) > no_host_${family}.exp
+
+( $TEST ::1 ''
+ $TEST 127.0.0.1 ''
+ $TEST localhost ''
+ $TEST '' '' ) > no_serv_${family}.exp
+
+( $TEST -R -p 0 localhost ''
+ $TEST -R -p 59 localhost ''
+ $TEST -R -p 59 localhost 80
+ $TEST -R -p 59 localhost www
+ $TEST -R -p 59 ::1 '' ) > sock_raw_${family}.exp
+
+( $TEST -f 99 localhost '' ) > unsup_fam_${family}.exp
+
+( $TEST fe80::1%lo0 http
+# IF=`ifconfig -a | grep -v '^ ' | sed -e 's/:.*//' | head -1 | awk '{print $1}'`
+# $TEST fe80::1%$IF http
+) > scoped_${family}.exp
diff --git a/lib/libc/tests/net/getaddrinfo/data/no_host_v4.exp b/lib/libc/tests/net/getaddrinfo/data/no_host_v4.exp
new file mode 100644
index 000000000000..7ed41cd9d88a
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/no_host_v4.exp
@@ -0,0 +1,44 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http
+ai1: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http
+ai2: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http
+ai3: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo
+ai1: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv echo
+ai2: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv echo
+ai3: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv echo
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp
+ai1: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv tftp
+ai2: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv tftp
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http
+ai2: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http
+ai3: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http
+
+arg: flags 0x2 family 0 socktype 1 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 2 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/no_host_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/no_host_v4_only.exp
new file mode 100644
index 000000000000..596799305117
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/no_host_v4_only.exp
@@ -0,0 +1,68 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp
+ai3: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai4: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http
+ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http
+ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http
+ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http
+ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv echo
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv echo
+ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv echo
+ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv echo
+ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv echo
+ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv echo
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv tftp
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv tftp
+ai3: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv tftp
+ai4: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv tftp
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http
+ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http
+ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http
+ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http
+ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http
+
+arg: flags 0x2 family 0 socktype 1 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 2 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6.exp b/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6.exp
new file mode 100644
index 000000000000..596799305117
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6.exp
@@ -0,0 +1,68 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp
+ai3: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai4: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http
+ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http
+ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http
+ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http
+ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv echo
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv echo
+ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv echo
+ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv echo
+ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv echo
+ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv echo
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv tftp
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv tftp
+ai3: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv tftp
+ai4: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv tftp
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http
+ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http
+ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http
+ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http
+ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http
+
+arg: flags 0x2 family 0 socktype 1 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 2 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6_prefer_v4.exp
new file mode 100644
index 000000000000..596799305117
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/no_host_v4v6_prefer_v4.exp
@@ -0,0 +1,68 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv echo
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv echo
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv echo
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv echo
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv echo
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv echo
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv tftp
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv tftp
+ai3: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv tftp
+ai4: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv tftp
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv http
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http
+ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http
+ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http
+ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http
+ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv echo
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv echo
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv echo
+ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv echo
+ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv echo
+ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv echo
+ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv echo
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv tftp
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv tftp
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv tftp
+ai3: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv tftp
+ai4: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv tftp
+
+arg: flags 0x3 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x3 family 28 socktype 2 protocol 17 addrlen 28 host :: serv http
+ai2: flags 0x3 family 28 socktype 1 protocol 6 addrlen 28 host :: serv http
+ai3: flags 0x3 family 28 socktype 5 protocol 132 addrlen 28 host :: serv http
+ai4: flags 0x3 family 2 socktype 2 protocol 17 addrlen 16 host 0.0.0.0 serv http
+ai5: flags 0x3 family 2 socktype 1 protocol 6 addrlen 16 host 0.0.0.0 serv http
+ai6: flags 0x3 family 2 socktype 5 protocol 132 addrlen 16 host 0.0.0.0 serv http
+
+arg: flags 0x2 family 0 socktype 1 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 0 socktype 2 protocol 0 addrlen 0 host (empty) serv 80
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/no_serv_v4.exp b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4.exp
new file mode 100644
index 000000000000..667234d2161f
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4.exp
@@ -0,0 +1,17 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv (empty)
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv (empty)
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv (empty)
+Name does not resolve
diff --git a/lib/libc/tests/net/getaddrinfo/data/no_serv_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4_only.exp
new file mode 100644
index 000000000000..0d28490c8d81
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4_only.exp
@@ -0,0 +1,20 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv (empty)
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv (empty)
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0
+ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0
+ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0
+ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv (empty)
+Name does not resolve
diff --git a/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6.exp b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6.exp
new file mode 100644
index 000000000000..53502547c40e
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6.exp
@@ -0,0 +1,20 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv (empty)
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv (empty)
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0
+ai4: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0
+ai5: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0
+ai6: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv (empty)
+Name does not resolve
diff --git a/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6_prefer_v4.exp
new file mode 100644
index 000000000000..0d28490c8d81
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/no_serv_v4v6_prefer_v4.exp
@@ -0,0 +1,20 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host ::1 serv (empty)
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host 127.0.0.1 serv (empty)
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv 0
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv 0
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv 0
+ai4: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv 0
+ai5: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv 0
+ai6: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv 0
+
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host (empty) serv (empty)
+Name does not resolve
diff --git a/lib/libc/tests/net/getaddrinfo/data/scoped.exp b/lib/libc/tests/net/getaddrinfo/data/scoped.exp
new file mode 100644
index 000000000000..f5ddb4bf6feb
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/scoped.exp
@@ -0,0 +1,5 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host fe80::1%lo0 serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host fe80::1%lo0 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host fe80::1%lo0 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host fe80::1%lo0 serv http
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/scoped_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/scoped_v4_only.exp
new file mode 100644
index 000000000000..f5ddb4bf6feb
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/scoped_v4_only.exp
@@ -0,0 +1,5 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host fe80::1%lo0 serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host fe80::1%lo0 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host fe80::1%lo0 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host fe80::1%lo0 serv http
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/scoped_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/scoped_v4v6_prefer_v4.exp
new file mode 100644
index 000000000000..f5ddb4bf6feb
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/scoped_v4v6_prefer_v4.exp
@@ -0,0 +1,5 @@
+arg: flags 0x2 family 0 socktype 0 protocol 0 addrlen 0 host fe80::1%lo0 serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host fe80::1%lo0 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host fe80::1%lo0 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host fe80::1%lo0 serv http
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4.exp b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4.exp
new file mode 100644
index 000000000000..021038b81dcc
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4.exp
@@ -0,0 +1,13 @@
+arg: flags 0x2 family 0 socktype 3 protocol 0 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 2 socktype 3 protocol 0 addrlen 16 host 127.0.0.1 serv 0
+
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 2 socktype 3 protocol 59 addrlen 16 host 127.0.0.1 serv 0
+
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv 80
+Service was not recognized for socket type
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv www
+Service was not recognized for socket type
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host ::1 serv (empty)
+ai1: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4_only.exp
new file mode 100644
index 000000000000..932c1faab0d3
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4_only.exp
@@ -0,0 +1,15 @@
+arg: flags 0x2 family 0 socktype 3 protocol 0 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 2 socktype 3 protocol 0 addrlen 16 host 127.0.0.1 serv 0
+ai2: flags 0x2 family 28 socktype 3 protocol 0 addrlen 28 host ::1 serv 0
+
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 2 socktype 3 protocol 59 addrlen 16 host 127.0.0.1 serv 0
+ai2: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0
+
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv 80
+Service was not recognized for socket type
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv www
+Service was not recognized for socket type
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host ::1 serv (empty)
+ai1: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6.exp b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6.exp
new file mode 100644
index 000000000000..e494271a3d35
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6.exp
@@ -0,0 +1,15 @@
+arg: flags 0x2 family 0 socktype 3 protocol 0 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 28 socktype 3 protocol 0 addrlen 28 host ::1 serv 0
+ai2: flags 0x2 family 2 socktype 3 protocol 0 addrlen 16 host 127.0.0.1 serv 0
+
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0
+ai2: flags 0x2 family 2 socktype 3 protocol 59 addrlen 16 host 127.0.0.1 serv 0
+
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv 80
+Service was not recognized for socket type
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv www
+Service was not recognized for socket type
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host ::1 serv (empty)
+ai1: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6_prefer_v4.exp
new file mode 100644
index 000000000000..932c1faab0d3
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/sock_raw_v4v6_prefer_v4.exp
@@ -0,0 +1,15 @@
+arg: flags 0x2 family 0 socktype 3 protocol 0 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 2 socktype 3 protocol 0 addrlen 16 host 127.0.0.1 serv 0
+ai2: flags 0x2 family 28 socktype 3 protocol 0 addrlen 28 host ::1 serv 0
+
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv (empty)
+ai1: flags 0x2 family 2 socktype 3 protocol 59 addrlen 16 host 127.0.0.1 serv 0
+ai2: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0
+
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv 80
+Service was not recognized for socket type
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host localhost serv www
+Service was not recognized for socket type
+arg: flags 0x2 family 0 socktype 3 protocol 59 addrlen 0 host ::1 serv (empty)
+ai1: flags 0x2 family 28 socktype 3 protocol 59 addrlen 28 host ::1 serv 0
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4.exp b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4.exp
new file mode 100644
index 000000000000..924d2a16f47c
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4.exp
@@ -0,0 +1,7 @@
+arg: flags 0x2 family 2 socktype 0 protocol 0 addrlen 0 host localhost serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 28 socktype 0 protocol 0 addrlen 0 host localhost serv http
+Address family for hostname not supported
diff --git a/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4_only.exp
new file mode 100644
index 000000000000..af3506938503
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4_only.exp
@@ -0,0 +1,10 @@
+arg: flags 0x2 family 2 socktype 0 protocol 0 addrlen 0 host localhost serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 28 socktype 0 protocol 0 addrlen 0 host localhost serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6.exp b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6.exp
new file mode 100644
index 000000000000..af3506938503
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6.exp
@@ -0,0 +1,10 @@
+arg: flags 0x2 family 2 socktype 0 protocol 0 addrlen 0 host localhost serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 28 socktype 0 protocol 0 addrlen 0 host localhost serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6_prefer_v4.exp
new file mode 100644
index 000000000000..af3506938503
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/spec_fam_v4v6_prefer_v4.exp
@@ -0,0 +1,10 @@
+arg: flags 0x2 family 2 socktype 0 protocol 0 addrlen 0 host localhost serv http
+ai1: flags 0x2 family 2 socktype 2 protocol 17 addrlen 16 host 127.0.0.1 serv http
+ai2: flags 0x2 family 2 socktype 1 protocol 6 addrlen 16 host 127.0.0.1 serv http
+ai3: flags 0x2 family 2 socktype 5 protocol 132 addrlen 16 host 127.0.0.1 serv http
+
+arg: flags 0x2 family 28 socktype 0 protocol 0 addrlen 0 host localhost serv http
+ai1: flags 0x2 family 28 socktype 2 protocol 17 addrlen 28 host ::1 serv http
+ai2: flags 0x2 family 28 socktype 1 protocol 6 addrlen 28 host ::1 serv http
+ai3: flags 0x2 family 28 socktype 5 protocol 132 addrlen 28 host ::1 serv http
+
diff --git a/lib/libc/tests/net/getaddrinfo/data/unsup_fam.exp b/lib/libc/tests/net/getaddrinfo/data/unsup_fam.exp
new file mode 100644
index 000000000000..69e6b48a854b
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/unsup_fam.exp
@@ -0,0 +1,2 @@
+arg: flags 0x2 family 99 socktype 0 protocol 0 addrlen 0 host localhost serv (empty)
+Address family not recognized
diff --git a/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4_only.exp b/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4_only.exp
new file mode 100644
index 000000000000..69e6b48a854b
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4_only.exp
@@ -0,0 +1,2 @@
+arg: flags 0x2 family 99 socktype 0 protocol 0 addrlen 0 host localhost serv (empty)
+Address family not recognized
diff --git a/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4v6_prefer_v4.exp b/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4v6_prefer_v4.exp
new file mode 100644
index 000000000000..69e6b48a854b
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/data/unsup_fam_v4v6_prefer_v4.exp
@@ -0,0 +1,2 @@
+arg: flags 0x2 family 99 socktype 0 protocol 0 addrlen 0 host localhost serv (empty)
+Address family not recognized
diff --git a/lib/libc/tests/net/getaddrinfo/getaddrinfo.c b/lib/libc/tests/net/getaddrinfo/getaddrinfo.c
new file mode 100644
index 000000000000..1e066add3119
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/getaddrinfo.c
@@ -0,0 +1,271 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 Gleb Smirnoff <glebius@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.
+ * 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.
+ */
+
+#include <dlfcn.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <string.h>
+#include <resolv.h>
+
+#include <atf-c.h>
+
+static const char goodname[] = "www.freebsd.org";
+static const char goodname_dot[] = "www.freebsd.org.";
+static const char badname[] = "does-not-exist.freebsd.org";
+static const char badname_dot[] = "does-not-exist.freebsd.org.";
+static const char ipv6onlyname[] = "beefy15.nyi.freebsd.org";
+static const char ipv6onlyname_dot[] = "beefy15.nyi.freebsd.org.";
+static const char ipv4onlyname[] = "ipv4only.arpa";
+static const char ipv4onlyname_dot[] = "ipv4only.arpa.";
+/*
+ * We need an IP address that doesn't exist, but not reported with ICMP
+ * unreachable by the nearest router. Let's try TEST-NET-3.
+ */
+static char badresolvconf[] = "nameserver 203.0.113.1";
+static char badresolvconf2[] = "nameserver 203.0.113.1\n"
+ "nameserver 203.0.113.2";
+static char *resconf = NULL;
+FILE *
+fopen(const char * restrict path, const char * restrict mode)
+{
+ static FILE *(*orig)(const char *, const char *);
+
+ if (orig == NULL && (orig = dlsym(RTLD_NEXT, "fopen")) == NULL)
+ atf_libc_error(ENOENT, "dlsym(fopen): %s", dlerror());
+ if (resconf != NULL && strcmp(path, _PATH_RESCONF) == 0)
+ return (fmemopen(resconf, strlen(resconf), mode));
+ else
+ return (orig(path, mode));
+}
+
+static int send_error = 0;
+ssize_t
+send(int s, const void *msg, size_t len, int flags)
+{
+ static ssize_t (*orig)(int, const void *, size_t, int);
+
+ if (orig == NULL && (orig = dlsym(RTLD_NEXT, "send")) == NULL)
+ atf_libc_error(ENOENT, "dlsym(send): %s", dlerror());
+ if (send_error != 0) {
+ errno = send_error;
+ return (-1);
+ } else {
+ return (orig(s, msg, len, flags));
+ }
+}
+
+ATF_TC(basic);
+ATF_TC_HEAD(basic, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+
+ATF_TC_BODY(basic, tc)
+{
+ static const struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_flags = AI_CANONNAME,
+ };
+ struct addrinfo *res;
+ int rv;
+
+ rv = getaddrinfo(goodname, NULL, &hints, &res);
+ ATF_REQUIRE_MSG(rv == 0,
+ "Expected 0, got %d (%s)", rv, gai_strerror(rv));
+ freeaddrinfo(res);
+
+ rv = getaddrinfo(goodname_dot, NULL, &hints, &res);
+ ATF_REQUIRE_MSG(rv == 0,
+ "Expected 0, got %d (%s)", rv, gai_strerror(rv));
+ freeaddrinfo(res);
+
+ rv = getaddrinfo(badname, NULL, &hints, &res);
+ ATF_REQUIRE_MSG(rv == EAI_NONAME,
+ "Expected %d (EAI_NONAME), got %d (%s)",
+ EAI_NONAME, rv, gai_strerror(rv));
+
+ rv = getaddrinfo(badname_dot, NULL, &hints, &res);
+ ATF_REQUIRE_MSG(rv == EAI_NONAME,
+ "Expected %d (EAI_NONAME), got %d (%s)",
+ EAI_NONAME, rv, gai_strerror(rv));
+}
+
+ATF_TC_WITHOUT_HEAD(timeout);
+ATF_TC_BODY(timeout, tc)
+{
+ static const struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_flags = AI_CANONNAME,
+ };
+ struct addrinfo *res;
+ int rv;
+
+ resconf = badresolvconf;
+ rv = getaddrinfo(goodname, NULL, &hints, &res);
+ ATF_REQUIRE_MSG(rv == EAI_AGAIN,
+ "Expected %d (EAI_AGAIN), got %d (%s)",
+ EAI_AGAIN, rv, gai_strerror(rv));
+
+ rv = getaddrinfo(goodname_dot, NULL, &hints, &res);
+ ATF_REQUIRE_MSG(rv == EAI_AGAIN,
+ "Expected %d (EAI_AGAIN), got %d (%s)",
+ EAI_AGAIN, rv, gai_strerror(rv));
+}
+
+ATF_TC_WITHOUT_HEAD(timeout_specific);
+ATF_TC_BODY(timeout_specific, tc)
+{
+ static const struct addrinfo hints = {
+ .ai_family = AF_INET,
+ .ai_socktype = SOCK_STREAM,
+ .ai_flags = AI_CANONNAME,
+ };
+ struct addrinfo *res;
+ int rv;
+
+ resconf = badresolvconf;
+ rv = getaddrinfo(goodname, "666", &hints, &res);
+ ATF_REQUIRE_MSG(rv == EAI_AGAIN,
+ "Expected %d (EAI_AGAIN), got %d (%s)",
+ EAI_AGAIN, rv, gai_strerror(rv));
+
+ rv = getaddrinfo(goodname_dot, "666", &hints, &res);
+ ATF_REQUIRE_MSG(rv == EAI_AGAIN,
+ "Expected %d (EAI_AGAIN), got %d (%s)",
+ EAI_AGAIN, rv, gai_strerror(rv));
+}
+
+ATF_TC_WITHOUT_HEAD(timeout2);
+ATF_TC_BODY(timeout2, tc)
+{
+ static const struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_flags = AI_CANONNAME,
+ };
+ struct addrinfo *res;
+ int rv;
+
+ resconf = badresolvconf2;
+ rv = getaddrinfo(goodname, NULL, &hints, &res);
+ ATF_REQUIRE_MSG(rv == EAI_AGAIN,
+ "Expected %d (EAI_AGAIN), got %d (%s)",
+ EAI_AGAIN, rv, gai_strerror(rv));
+
+ rv = getaddrinfo(goodname_dot, NULL, &hints, &res);
+ ATF_REQUIRE_MSG(rv == EAI_AGAIN,
+ "Expected %d (EAI_AGAIN), got %d (%s)",
+ EAI_AGAIN, rv, gai_strerror(rv));
+}
+
+/*
+ * Emulate interface/network down.
+ */
+ATF_TC_WITHOUT_HEAD(netdown);
+ATF_TC_BODY(netdown, tc)
+{
+ static const struct addrinfo hints = {
+ .ai_family = AF_UNSPEC,
+ .ai_flags = AI_CANONNAME,
+ };
+ struct addrinfo *res;
+ int rv;
+
+ send_error = ENETDOWN;
+ rv = getaddrinfo(goodname, NULL, &hints, &res);
+ ATF_REQUIRE_MSG(rv == EAI_AGAIN,
+ "Expected %d (EAI_AGAIN), got %d (%s)",
+ EAI_AGAIN, rv, gai_strerror(rv));
+
+ rv = getaddrinfo(goodname_dot, NULL, &hints, &res);
+ ATF_REQUIRE_MSG(rv == EAI_AGAIN,
+ "Expected %d (EAI_AGAIN), got %d (%s)",
+ EAI_AGAIN, rv, gai_strerror(rv));
+}
+
+/*
+ * See https://reviews.freebsd.org/D37139.
+ */
+ATF_TC(nofamily);
+ATF_TC_HEAD(nofamily, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
+ATF_TC_BODY(nofamily, tc)
+{
+ static const struct addrinfo hints4 = {
+ .ai_family = AF_INET,
+ .ai_flags = AI_CANONNAME,
+ }, hints6 = {
+ .ai_family = AF_INET6,
+ .ai_flags = AI_CANONNAME,
+ };
+ struct addrinfo *res;
+ int rv;
+
+ rv = getaddrinfo(ipv6onlyname, NULL, &hints4, &res);
+ ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY,
+ "Expected %d (EAI_ADDRFAMILY), got %d (%s)",
+ EAI_ADDRFAMILY, rv, gai_strerror(rv));
+
+ rv = getaddrinfo(ipv6onlyname_dot, NULL, &hints4, &res);
+ ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY,
+ "Expected %d (EAI_ADDRFAMILY), got %d (%s)",
+ EAI_ADDRFAMILY, rv, gai_strerror(rv));
+
+ rv = getaddrinfo(ipv4onlyname, NULL, &hints6, &res);
+ ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY,
+ "Expected %d (EAI_ADDRFAMILY), got %d (%s)",
+ EAI_ADDRFAMILY, rv, gai_strerror(rv));
+
+ rv = getaddrinfo(ipv4onlyname_dot, NULL, &hints6, &res);
+ ATF_REQUIRE_MSG(rv == EAI_ADDRFAMILY,
+ "Expected %d (EAI_ADDRFAMILY), got %d (%s)",
+ EAI_ADDRFAMILY, rv, gai_strerror(rv));
+
+ rv = getaddrinfo(badname, NULL, &hints4, &res);
+ ATF_REQUIRE_MSG(rv == EAI_NONAME,
+ "Expected %d (EAI_NONAME), got %d (%s)",
+ EAI_NONAME, rv, gai_strerror(rv));
+
+ rv = getaddrinfo(badname_dot, NULL, &hints6, &res);
+ ATF_REQUIRE_MSG(rv == EAI_NONAME,
+ "Expected %d (EAI_NONAME), got %d (%s)",
+ EAI_NONAME, rv, gai_strerror(rv));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, basic);
+ ATF_TP_ADD_TC(tp, timeout);
+ ATF_TP_ADD_TC(tp, timeout_specific);
+ ATF_TP_ADD_TC(tp, timeout2);
+ ATF_TP_ADD_TC(tp, netdown);
+ ATF_TP_ADD_TC(tp, nofamily);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/net/getaddrinfo/getaddrinfo_test.sh b/lib/libc/tests/net/getaddrinfo/getaddrinfo_test.sh
new file mode 100755
index 000000000000..dd17ab2e3f4a
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/getaddrinfo_test.sh
@@ -0,0 +1,443 @@
+# $NetBSD: t_getaddrinfo.sh,v 1.2 2011/06/15 07:54:32 jmmv Exp $
+
+#
+# Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, and 2002 WIDE Project.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the project nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE PROJECT 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 PROJECT 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.
+#
+
+if [ "$(sysctl -i -n kern.features.vimage)" != 1 ]; then
+ atf_skip "This test requires VIMAGE"
+fi
+
+vnet_mkjail()
+{
+ jailname=getaddrinfo_test_$1
+ jail -c name=${jailname} persist vnet
+ ifconfig -j ${jailname} lo0 inet 127.0.0.1/8
+ # For those machines not support IPv6
+ ifconfig -j ${jailname} lo0 inet6 ::1/64 || true
+ service -j ${jailname} ip6addrctl $2 || true
+}
+
+vnet_cleanup()
+{
+ jailname=getaddrinfo_test_$1
+ jail -r ${jailname}
+}
+
+check_output()
+{
+ if [ "$2" = "none" ]; then
+ if [ "$3" = "prefer_v6" ]; then
+ exp="${1}.exp"
+ else
+ exp="${1}_v4_only.exp"
+ fi
+ elif [ "$2" = "hosts" ]; then
+ lcl=$(cat /etc/hosts | sed -e 's/#.*$//' -e 's/[ ][ ]*/ /g' | awk '/ localhost($| )/ {printf "%s ", $1}')
+ if [ "${lcl%*::*}" = "${lcl}" ]; then
+ exp="${1}_v4_only.exp"
+ else
+ if [ "$3" = "prefer_v6" ]; then
+ exp="${1}_v4v6.exp"
+ else
+ exp="${1}_v4v6_prefer_v4.exp"
+ fi
+ fi
+ elif [ "$2" = "ifconfig" ]; then
+ lcl=$(ifconfig lo0 | grep inet6)
+ if [ -n "${lcl}" ]; then
+ if [ "$3" = "prefer_v6" ]; then
+ exp="${1}_v4v6.exp"
+ else
+ exp="${1}_v4v6_prefer_v4.exp"
+ fi
+ else
+ exp="${1}_v4_only.exp"
+ fi
+ else
+ atf_fail "Invalid family_match_type $2 requested."
+ fi
+
+ cmp -s "$(atf_get_srcdir)/data/${exp}" out && return
+ diff -u "$(atf_get_srcdir)/data/${exp}" out || atf_fail "Actual output does not match expected output"
+}
+
+atf_test_case basic_prefer_v4 cleanup
+basic_prefer_v4_head()
+{
+ atf_set "descr" "Testing basic ones with prefer_v4"
+ atf_set "require.user" "root"
+}
+basic_prefer_v4_body()
+{
+ vnet_mkjail basic_prefer_v4 prefer_ipv4
+ TEST="jexec getaddrinfo_test_basic_prefer_v4 $(atf_get_srcdir)/h_gai"
+
+ ( $TEST ::1 http
+ $TEST 127.0.0.1 http
+ $TEST localhost http
+ $TEST ::1 tftp
+ $TEST 127.0.0.1 tftp
+ $TEST localhost tftp
+ $TEST ::1 echo
+ $TEST 127.0.0.1 echo
+ $TEST localhost echo ) > out 2>&1
+
+ check_output basics hosts prefer_v4
+}
+basic_prefer_v4_cleanup()
+{
+ vnet_cleanup basic_prefer_v4
+}
+
+atf_test_case basic cleanup
+basic_head()
+{
+ atf_set "descr" "Testing basic ones with prefer_v6"
+ atf_set "require.user" "root"
+}
+basic_body()
+{
+ vnet_mkjail basic prefer_ipv6
+ TEST="jexec getaddrinfo_test_basic $(atf_get_srcdir)/h_gai"
+
+ ( $TEST ::1 http
+ $TEST 127.0.0.1 http
+ $TEST localhost http
+ $TEST ::1 tftp
+ $TEST 127.0.0.1 tftp
+ $TEST localhost tftp
+ $TEST ::1 echo
+ $TEST 127.0.0.1 echo
+ $TEST localhost echo ) > out 2>&1
+
+ check_output basics ifconfig prefer_v6
+}
+basic_cleanup()
+{
+ vnet_cleanup basic
+}
+
+atf_test_case specific_prefer_v4 cleanup
+specific_prefer_v4_head()
+{
+ atf_set "descr" "Testing specific address family with prefer_v4"
+ atf_set "require.user" "root"
+}
+specific_prefer_v4_body()
+{
+ vnet_mkjail specific_prefer_v4 prefer_ipv4
+ TEST="jexec getaddrinfo_test_specific_prefer_v4 $(atf_get_srcdir)/h_gai"
+
+ ( $TEST -4 localhost http
+ $TEST -6 localhost http ) > out 2>&1
+
+ check_output spec_fam hosts prefer_v4
+}
+specific_prefer_v4_cleanup()
+{
+ vnet_cleanup specific_prefer_v4
+}
+
+atf_test_case specific cleanup
+specific_head()
+{
+ atf_set "descr" "Testing specific address family with prefer_v6"
+ atf_set "require.user" "root"
+}
+specific_body()
+{
+ vnet_mkjail specific prefer_ipv6
+ TEST="jexec getaddrinfo_test_specific $(atf_get_srcdir)/h_gai"
+
+ ( $TEST -4 localhost http
+ $TEST -6 localhost http ) > out 2>&1
+
+ check_output spec_fam hosts prefer_v6
+}
+specific_cleanup()
+{
+ vnet_cleanup specific
+}
+
+atf_test_case empty_hostname_prefer_v4 cleanup
+empty_hostname_prefer_v4_head()
+{
+ atf_set "descr" "Testing empty hostname with prefer_v4"
+ atf_set "require.user" "root"
+}
+empty_hostname_prefer_v4_body()
+{
+ vnet_mkjail empty_hostname_prefer_v4 prefer_ipv4
+ TEST="jexec getaddrinfo_test_empty_hostname_prefer_v4 $(atf_get_srcdir)/h_gai"
+
+ ( $TEST '' http
+ $TEST '' echo
+ $TEST '' tftp
+ $TEST '' 80
+ $TEST -P '' http
+ $TEST -P '' echo
+ $TEST -P '' tftp
+ $TEST -P '' 80
+ $TEST -S '' 80
+ $TEST -D '' 80 ) > out 2>&1
+
+ check_output no_host ifconfig prefer_v4
+}
+empty_hostname_prefer_v4_cleanup()
+{
+ vnet_cleanup empty_hostname_prefer_v4
+}
+
+atf_test_case empty_hostname cleanup
+empty_hostname_head()
+{
+ atf_set "descr" "Testing empty hostname with prefer_v6"
+ atf_set "require.user" "root"
+}
+empty_hostname_body()
+{
+ vnet_mkjail empty_hostname prefer_ipv6
+ TEST="jexec getaddrinfo_test_empty_hostname $(atf_get_srcdir)/h_gai"
+
+ ( $TEST '' http
+ $TEST '' echo
+ $TEST '' tftp
+ $TEST '' 80
+ $TEST -P '' http
+ $TEST -P '' echo
+ $TEST -P '' tftp
+ $TEST -P '' 80
+ $TEST -S '' 80
+ $TEST -D '' 80 ) > out 2>&1
+
+ check_output no_host ifconfig prefer_v6
+}
+empty_hostname_cleanup()
+{
+ vnet_cleanup empty_hostname
+}
+
+atf_test_case empty_servname_prefer_v4 cleanup
+empty_servname_prefer_v4_head()
+{
+ atf_set "descr" "Testing empty service name with prefer_v4"
+ atf_set "require.user" "root"
+}
+empty_servname_prefer_v4_body()
+{
+ vnet_mkjail empty_servname_prefer_v4 prefer_ipv4
+ TEST="jexec getaddrinfo_test_empty_servname_prefer_v4 $(atf_get_srcdir)/h_gai"
+
+ ( $TEST ::1 ''
+ $TEST 127.0.0.1 ''
+ $TEST localhost ''
+ $TEST '' '' ) > out 2>&1
+
+ check_output no_serv hosts prefer_v4
+}
+empty_servname_prefer_v4_cleanup()
+{
+ vnet_cleanup empty_servname_prefer_v4
+}
+
+atf_test_case empty_servname cleanup
+empty_servname_head()
+{
+ atf_set "descr" "Testing empty service name with prefer_v6"
+ atf_set "require.user" "root"
+}
+empty_servname_body()
+{
+ vnet_mkjail empty_servname prefer_ipv6
+ TEST="jexec getaddrinfo_test_empty_servname $(atf_get_srcdir)/h_gai"
+
+ ( $TEST ::1 ''
+ $TEST 127.0.0.1 ''
+ $TEST localhost ''
+ $TEST '' '' ) > out 2>&1
+
+ check_output no_serv ifconfig prefer_v6
+}
+empty_servname_cleanup()
+{
+ vnet_cleanup empty_servname
+}
+
+atf_test_case sock_raw_prefer_v4 cleanup
+sock_raw_prefer_v4_head()
+{
+ atf_set "descr" "Testing raw socket with prefer_v4"
+ atf_set "require.user" "root"
+}
+sock_raw_prefer_v4_body()
+{
+ vnet_mkjail sock_raw_prefer_v4 prefer_ipv4
+ TEST="jexec getaddrinfo_test_sock_raw_prefer_v4 $(atf_get_srcdir)/h_gai"
+
+ ( $TEST -R -p 0 localhost ''
+ $TEST -R -p 59 localhost ''
+ $TEST -R -p 59 localhost 80
+ $TEST -R -p 59 localhost www
+ $TEST -R -p 59 ::1 '' ) > out 2>&1
+
+ check_output sock_raw hosts prefer_v4
+}
+sock_raw_prefer_v4_cleanup()
+{
+ vnet_cleanup sock_raw_prefer_v4
+}
+
+atf_test_case sock_raw cleanup
+sock_raw_head()
+{
+ atf_set "descr" "Testing raw socket with prefer_v6"
+ atf_set "require.user" "root"
+}
+sock_raw_body()
+{
+ vnet_mkjail sock_raw prefer_ipv6
+ TEST="jexec getaddrinfo_test_sock_raw $(atf_get_srcdir)/h_gai"
+
+ ( $TEST -R -p 0 localhost ''
+ $TEST -R -p 59 localhost ''
+ $TEST -R -p 59 localhost 80
+ $TEST -R -p 59 localhost www
+ $TEST -R -p 59 ::1 '' ) > out 2>&1
+
+ check_output sock_raw ifconfig prefer_v6
+}
+sock_raw_cleanup()
+{
+ vnet_cleanup sock_raw
+}
+
+atf_test_case unsupported_family_prefer_v4 cleanup
+unsupported_family_prefer_v4_head()
+{
+ atf_set "descr" "Testing unsupported family with prefer_v4"
+ atf_set "require.user" "root"
+}
+unsupported_family_prefer_v4_body()
+{
+ vnet_mkjail unsupported_family_prefer_v4 prefer_ipv4
+ TEST="jexec getaddrinfo_test_unsupported_family_prefer_v4 $(atf_get_srcdir)/h_gai"
+
+ ( $TEST -f 99 localhost '' ) > out 2>&1
+
+ check_output unsup_fam ifconfig prefer_v4
+}
+unsupported_family_prefer_v4_cleanup()
+{
+ vnet_cleanup unsupported_family_prefer_v4
+}
+
+atf_test_case unsupported_family cleanup
+unsupported_family_head()
+{
+ atf_set "descr" "Testing unsupported family with prefer_v6"
+ atf_set "require.user" "root"
+}
+unsupported_family_body()
+{
+ vnet_mkjail unsupported_family prefer_ipv6
+ TEST="jexec getaddrinfo_test_unsupported_family $(atf_get_srcdir)/h_gai"
+
+ ( $TEST -f 99 localhost '' ) > out 2>&1
+
+ check_output unsup_fam none prefer_v6
+}
+unsupported_family_cleanup()
+{
+ vnet_cleanup unsupported_family
+}
+
+atf_test_case scopeaddr_prefer_v4 cleanup
+scopeaddr_prefer_v4_head()
+{
+ atf_set "descr" "Testing scoped address format with prefer_v4"
+ atf_set "require.user" "root"
+}
+scopeaddr_prefer_v4_body()
+{
+ vnet_mkjail scopeaddr_prefer_v4 prefer_ipv4
+ TEST="jexec getaddrinfo_test_scopeaddr_prefer_v4 $(atf_get_srcdir)/h_gai"
+
+ ( $TEST fe80::1%lo0 http
+# IF=ifconfig -a | grep -v '^ ' | sed -e 's/:.*//' | head -1 | awk '{print $1}'
+# $TEST fe80::1%$IF http
+ ) > out 2>&1
+
+ check_output scoped ifconfig prefer_v4
+}
+scopeaddr_prefer_v4_cleanup()
+{
+ vnet_cleanup scopeaddr_prefer_v4
+}
+
+atf_test_case scopeaddr cleanup
+scopeaddr_head()
+{
+ atf_set "descr" "Testing scoped address format with prefer_v6"
+ atf_set "require.user" "root"
+}
+scopeaddr_body()
+{
+ vnet_mkjail scopeaddr prefer_ipv6
+ TEST="jexec getaddrinfo_test_scopeaddr $(atf_get_srcdir)/h_gai"
+
+ ( $TEST fe80::1%lo0 http
+# IF=ifconfig -a | grep -v '^ ' | sed -e 's/:.*//' | head -1 | awk '{print $1}'
+# $TEST fe80::1%$IF http
+ ) > out 2>&1
+
+ check_output scoped none prefer_v6
+}
+scopeaddr_cleanup()
+{
+ vnet_cleanup scopeaddr
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case basic_prefer_v4
+ atf_add_test_case specific_prefer_v4
+ atf_add_test_case empty_hostname_prefer_v4
+ atf_add_test_case empty_servname_prefer_v4
+ atf_add_test_case sock_raw_prefer_v4
+ atf_add_test_case unsupported_family_prefer_v4
+ atf_add_test_case scopeaddr_prefer_v4
+
+ atf_add_test_case basic
+ atf_add_test_case specific
+ atf_add_test_case empty_hostname
+ atf_add_test_case empty_servname
+ atf_add_test_case sock_raw
+ atf_add_test_case unsupported_family
+ atf_add_test_case scopeaddr
+}
diff --git a/lib/libc/tests/net/link_addr_test.cc b/lib/libc/tests/net/link_addr_test.cc
new file mode 100644
index 000000000000..b973b924dc13
--- /dev/null
+++ b/lib/libc/tests/net/link_addr_test.cc
@@ -0,0 +1,532 @@
+/*
+ * Copyright (c) 2025 Lexi Winter
+ *
+ * SPDX-License-Identifier: ISC
+ */
+
+/*
+ * Tests for link_addr() and link_ntoa().
+ *
+ * link_addr converts a string representing an (optionally null) interface name
+ * followed by an Ethernet address into a sockaddr_dl. The expected format is
+ * "[ifname]:lladdr". This means if ifname is not specified, the leading colon
+ * is still required.
+ *
+ * link_ntoa does the inverse of link_addr, returning a string representation
+ * of the address.
+ *
+ * Note that the output format of link_ntoa is not valid input for link_addr
+ * since the leading colon may be omitted. This is by design.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <net/ethernet.h>
+#include <net/if_dl.h>
+
+#include <format>
+#include <iostream>
+#include <ranges>
+#include <span>
+#include <utility>
+#include <vector>
+
+#include <cstddef>
+#include <cstdint>
+
+#include <atf-c++.hpp>
+
+using namespace std::literals;
+
+/*
+ * Define operator== and operator<< for ether_addr so we can use them in
+ * ATF_EXPECT_EQ expressions.
+ */
+
+bool
+operator==(ether_addr a, ether_addr b)
+{
+ return (std::ranges::equal(a.octet, b.octet));
+}
+
+std::ostream &
+operator<<(std::ostream &s, ether_addr a)
+{
+ for (unsigned i = 0; i < ETHER_ADDR_LEN; ++i) {
+ if (i > 0)
+ s << ":";
+
+ s << std::format("{:02x}", static_cast<int>(a.octet[i]));
+ }
+
+ return (s);
+}
+
+/*
+ * Create a sockaddr_dl from a string using link_addr(), and ensure the
+ * returned struct looks valid.
+ */
+sockaddr_dl
+make_linkaddr(const std::string &addr)
+{
+ auto sdl = sockaddr_dl{};
+ int ret;
+
+ sdl.sdl_len = sizeof(sdl);
+ ret = ::link_addr(addr.c_str(), &sdl);
+
+ ATF_REQUIRE_EQ(0, ret);
+ ATF_REQUIRE_EQ(AF_LINK, static_cast<int>(sdl.sdl_family));
+ ATF_REQUIRE_EQ(true, sdl.sdl_len > 0);
+ ATF_REQUIRE_EQ(true, sdl.sdl_nlen >= 0);
+
+ return (sdl);
+}
+
+/*
+ * Return the data stored in a sockaddr_dl as a span.
+ */
+std::span<const char>
+data(const sockaddr_dl &sdl)
+{
+ // sdl_len is the entire structure, but we only want the length of the
+ // data area.
+ auto dlen = sdl.sdl_len - offsetof(sockaddr_dl, sdl_data);
+ return {&sdl.sdl_data[0], dlen};
+}
+
+/*
+ * Return the interface name stored in a sockaddr_dl as a string.
+ */
+std::string_view
+ifname(const sockaddr_dl &sdl)
+{
+ auto name = data(sdl).subspan(0, sdl.sdl_nlen);
+ return {name.begin(), name.end()};
+}
+
+/*
+ * Return the Ethernet address stored in a sockaddr_dl as an ether_addr.
+ */
+ether_addr
+addr(const sockaddr_dl &sdl)
+{
+ ether_addr ret{};
+ ATF_REQUIRE_EQ(ETHER_ADDR_LEN, sdl.sdl_alen);
+ std::ranges::copy(data(sdl).subspan(sdl.sdl_nlen, ETHER_ADDR_LEN),
+ &ret.octet[0]);
+ return (ret);
+}
+
+/*
+ * Return the link address stored in a sockaddr_dl as a span of octets.
+ */
+std::span<const std::uint8_t>
+lladdr(const sockaddr_dl &sdl)
+{
+ auto data = reinterpret_cast<const uint8_t *>(LLADDR(&sdl));
+ return {data, data + sdl.sdl_alen};
+}
+
+
+/*
+ * Some sample addresses we use for testing. Include at least one address for
+ * each format we want to support.
+ */
+
+struct test_address {
+ std::string input; /* value passed to link_addr */
+ std::string ntoa; /* expected return from link_ntoa */
+ ether_addr addr{}; /* expected return from link_addr */
+};
+
+std::vector<test_address> test_addresses{
+ // No delimiter
+ {"001122334455"s, "0.11.22.33.44.55",
+ ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
+
+ // Colon delimiter
+ {"00:11:22:33:44:55"s, "0.11.22.33.44.55",
+ ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
+
+ // Dash delimiter
+ {"00-11-22-33-44-55"s, "0.11.22.33.44.55",
+ ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
+
+ // Period delimiter (link_ntoa format)
+ {"00.11.22.33.44.55"s, "0.11.22.33.44.55",
+ ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
+
+ // Period delimiter (Cisco format)
+ {"0011.2233.4455"s, "0.11.22.33.44.55",
+ ether_addr{0x00, 0x11, 0x22, 0x33, 0x44, 0x55}},
+
+ // An addresses without leading zeroes.
+ {"0:1:02:30:4:55"s, "0.1.2.30.4.55",
+ ether_addr{0x00, 0x01, 0x02, 0x30, 0x04, 0x55}},
+
+ // An address with some uppercase letters.
+ {"AA:B:cC:Dd:e0:1f"s, "aa.b.cc.dd.e0.1f",
+ ether_addr{0xaa, 0x0b, 0xcc, 0xdd, 0xe0, 0x1f}},
+
+ // Addresses composed only of letters, to make sure they're not
+ // confused with an interface name.
+
+ {"aabbccddeeff"s, "aa.bb.cc.dd.ee.ff",
+ ether_addr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}},
+
+ {"aa:bb:cc:dd:ee:ff"s, "aa.bb.cc.dd.ee.ff",
+ ether_addr{0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff}},
+
+ // Address with a blank octet; this is an old form of Ethernet address.
+ {"00:11::33:44:55"s, "0.11.0.33.44.55",
+ ether_addr{0x00, 0x11, 0x00, 0x33, 0x44, 0x55}},
+};
+
+/*
+ * Test without an interface name.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(basic)
+ATF_TEST_CASE_BODY(basic)
+{
+ for (const auto &ta : test_addresses) {
+ // This does basic tests on the returned value.
+ auto sdl = make_linkaddr(":" + ta.input);
+
+ // Check the ifname and address.
+ ATF_REQUIRE_EQ(""s, ifname(sdl));
+ ATF_REQUIRE_EQ(ETHER_ADDR_LEN, static_cast<int>(sdl.sdl_alen));
+ ATF_REQUIRE_EQ(ta.addr, addr(sdl));
+
+ // Check link_ntoa returns the expected value.
+ auto ntoa = std::string(::link_ntoa(&sdl));
+ ATF_REQUIRE_EQ(ta.ntoa, ntoa);
+ }
+
+}
+
+/*
+ * Test with an interface name.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(ifname)
+ATF_TEST_CASE_BODY(ifname)
+{
+ for (const auto &ta : test_addresses) {
+ auto sdl = make_linkaddr("ix0:" + ta.input);
+
+ ATF_REQUIRE_EQ("ix0", ifname(sdl));
+ ATF_REQUIRE_EQ(ETHER_ADDR_LEN, static_cast<int>(sdl.sdl_alen));
+ ATF_REQUIRE_EQ(ta.addr, addr(sdl));
+
+ auto ntoa = std::string(::link_ntoa(&sdl));
+ ATF_REQUIRE_EQ("ix0:" + ta.ntoa, ntoa);
+ }
+
+}
+
+/*
+ * Test with some invalid addresses.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(invalid)
+ATF_TEST_CASE_BODY(invalid)
+{
+ auto const invalid_addresses = std::vector{
+ // Invalid separator
+ ":1/2/3"s,
+ "ix0:1/2/3"s,
+
+ // Multiple different separators
+ ":1.2-3"s,
+ "ix0:1.2-3"s,
+
+ // An IP address
+ ":10.1.2.200/28"s,
+ "ix0:10.1.2.200/28"s,
+
+ // Valid address followed by garbage
+ ":1.2.3xxx"s,
+ ":1.2.3.xxx"s,
+ "ix0:1.2.3xxx"s,
+ "ix0:1.2.3.xxx"s,
+ };
+
+ for (auto const &addr : invalid_addresses) {
+ int ret;
+
+ auto sdl = sockaddr_dl{};
+ sdl.sdl_len = sizeof(sdl);
+
+ ret = link_addr(addr.c_str(), &sdl);
+ ATF_REQUIRE_EQ(-1, ret);
+ }
+}
+
+/*
+ * Test some non-Ethernet addresses.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(nonether)
+ATF_TEST_CASE_BODY(nonether)
+{
+ sockaddr_dl sdl;
+
+ /* A short address */
+ sdl = make_linkaddr(":1:23:cc");
+ ATF_REQUIRE_EQ("", ifname(sdl));
+ ATF_REQUIRE_EQ("1.23.cc"s, ::link_ntoa(&sdl));
+ ATF_REQUIRE_EQ(3, sdl.sdl_alen);
+ ATF_REQUIRE_EQ(true,
+ std::ranges::equal(std::vector{0x01u, 0x23u, 0xccu}, lladdr(sdl)));
+
+ /* A long address */
+ sdl = make_linkaddr(":1:23:cc:a:b:c:d:e:f");
+ ATF_REQUIRE_EQ("", ifname(sdl));
+ ATF_REQUIRE_EQ("1.23.cc.a.b.c.d.e.f"s, ::link_ntoa(&sdl));
+ ATF_REQUIRE_EQ(9, sdl.sdl_alen);
+ ATF_REQUIRE_EQ(true, std::ranges::equal(
+ std::vector{0x01u, 0x23u, 0xccu, 0xau, 0xbu, 0xcu, 0xdu, 0xeu, 0xfu},
+ lladdr(sdl)));
+}
+
+/*
+ * Test link_addr behaviour with undersized buffers.
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(smallbuf)
+ATF_TEST_CASE_BODY(smallbuf)
+{
+ static constexpr auto garbage = std::byte{0xcc};
+ auto buf = std::vector<std::byte>();
+ sockaddr_dl *sdl;
+ int ret;
+
+ /*
+ * Make an sdl with an sdl_data member of the appropriate size, and
+ * place it in buf. Ensure it's followed by a trailing byte of garbage
+ * so we can test that link_addr doesn't write past the end.
+ */
+ auto mksdl = [&buf](std::size_t datalen) -> sockaddr_dl * {
+ auto actual_size = datalen + offsetof(sockaddr_dl, sdl_data);
+
+ buf.resize(actual_size + 1);
+ std::ranges::fill(buf, garbage);
+
+ auto *sdl = new(reinterpret_cast<sockaddr_dl *>(&buf[0]))
+ sockaddr_dl;
+ sdl->sdl_len = actual_size;
+ return (sdl);
+ };
+
+ /* An sdl large enough to store the interface name */
+ sdl = mksdl(3);
+ ret = link_addr("ix0:1.2.3", sdl);
+ ATF_REQUIRE(*rbegin(buf) == garbage);
+ ATF_REQUIRE_EQ(-1, ret);
+ ATF_REQUIRE_EQ(ENOSPC, errno);
+ ATF_REQUIRE_EQ(3, sdl->sdl_nlen);
+ ATF_REQUIRE_EQ("ix0", ifname(*sdl));
+ ATF_REQUIRE_EQ(0, static_cast<int>(sdl->sdl_alen));
+
+ /*
+ * For these tests, test both with and without an interface name, since
+ * that will overflow the buffer in different places.
+ */
+
+ /* An empty sdl. Nothing may grow on this cursed ground. */
+
+ sdl = mksdl(0);
+ ret = link_addr("ix0:1.2.3", sdl);
+ ATF_REQUIRE(*rbegin(buf) == garbage);
+ ATF_REQUIRE_EQ(-1, ret);
+ ATF_REQUIRE_EQ(ENOSPC, errno);
+ ATF_REQUIRE_EQ(0, sdl->sdl_nlen);
+ ATF_REQUIRE_EQ(0, static_cast<int>(sdl->sdl_alen));
+
+ sdl = mksdl(0);
+ ret = link_addr(":1.2.3", sdl);
+ ATF_REQUIRE(*rbegin(buf) == garbage);
+ ATF_REQUIRE_EQ(-1, ret);
+ ATF_REQUIRE_EQ(ENOSPC, errno);
+ ATF_REQUIRE_EQ(0, sdl->sdl_nlen);
+ ATF_REQUIRE_EQ(0, static_cast<int>(sdl->sdl_alen));
+
+ /*
+ * An sdl large enough to store the interface name and two octets of the
+ * address.
+ */
+
+ sdl = mksdl(5);
+ ret = link_addr("ix0:1.2.3", sdl);
+ ATF_REQUIRE(*rbegin(buf) == garbage);
+ ATF_REQUIRE_EQ(-1, ret);
+ ATF_REQUIRE_EQ(ENOSPC, errno);
+ ATF_REQUIRE_EQ("ix0", ifname(*sdl));
+ ATF_REQUIRE(std::ranges::equal(
+ std::vector{ 0x01, 0x02 }, lladdr(*sdl)));
+
+ sdl = mksdl(2);
+ ret = link_addr(":1.2.3", sdl);
+ ATF_REQUIRE(*rbegin(buf) == garbage);
+ ATF_REQUIRE_EQ(-1, ret);
+ ATF_REQUIRE_EQ(ENOSPC, errno);
+ ATF_REQUIRE_EQ("", ifname(*sdl));
+ ATF_REQUIRE(std::ranges::equal(
+ std::vector{ 0x01, 0x02 }, lladdr(*sdl)));
+
+ /*
+ * An sdl large enough to store the entire address.
+ */
+
+ sdl = mksdl(6);
+ ret = link_addr("ix0:1.2.3", sdl);
+ ATF_REQUIRE(*rbegin(buf) == garbage);
+ ATF_REQUIRE_EQ(0, ret);
+ ATF_REQUIRE_EQ("ix0", ifname(*sdl));
+ ATF_REQUIRE(std::ranges::equal(
+ std::vector{ 0x01, 0x02, 0x03 }, lladdr(*sdl)));
+
+ sdl = mksdl(3);
+ ret = link_addr(":1.2.3", sdl);
+ ATF_REQUIRE(*rbegin(buf) == garbage);
+ ATF_REQUIRE_EQ(0, ret);
+ ATF_REQUIRE_EQ("", ifname(*sdl));
+ ATF_REQUIRE(std::ranges::equal(
+ std::vector{ 0x01, 0x02, 0x03 }, lladdr(*sdl)));
+}
+
+/*
+ * Test an extremely long address which would overflow link_ntoa's internal
+ * buffer. It should handle this by truncating the output.
+ * (Test for SA-16:37.libc / CVE-2016-6559.)
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(overlong)
+ATF_TEST_CASE_BODY(overlong)
+{
+ auto sdl = make_linkaddr(
+ ":01.02.03.04.05.06.07.08.09.0a.0b.0c.0d.0e.0f."
+ "11.12.13.14.15.16.17.18.19.1a.1b.1c.1d.1e.1f."
+ "22.22.23.24.25.26.27.28.29.2a.2b.2c.2d.2e.2f");
+
+ ATF_REQUIRE_EQ(
+ "1.2.3.4.5.6.7.8.9.a.b.c.d.e.f.11.12.13.14.15.16.17.18.19.1a.1b."s,
+ ::link_ntoa(&sdl));
+}
+
+/*
+ * Test link_ntoa_r, the re-entrant version of link_ntoa().
+ */
+ATF_TEST_CASE_WITHOUT_HEAD(link_ntoa_r)
+ATF_TEST_CASE_BODY(link_ntoa_r)
+{
+ static constexpr char garbage = 0x41;
+ std::vector<char> buf;
+ sockaddr_dl sdl;
+ size_t len;
+ int ret;
+
+ // Return the contents of buf as a string, using the NUL terminator to
+ // determine length. This is to ensure we're using the return value in
+ // the same way C code would, but we do a bit more verification to
+ // elicit a test failure rather than a SEGV if it's broken.
+ auto bufstr = [&buf]() -> std::string_view {
+ // Find the NUL.
+ auto end = std::ranges::find(buf, '\0');
+ ATF_REQUIRE(end != buf.end());
+
+ // Intentionally chopping the NUL off.
+ return {begin(buf), end};
+ };
+
+ // Resize the buffer and set the contents to a known garbage value, so
+ // we don't accidentally have a NUL in the right place when link_ntoa_r
+ // didn't put it there.
+ auto resetbuf = [&buf, &len](std::size_t size) {
+ len = size;
+ buf.resize(len);
+ std::ranges::fill(buf, garbage);
+ };
+
+ // Test a short address with a large buffer.
+ sdl = make_linkaddr("ix0:1.2.3");
+ resetbuf(64);
+ ret = ::link_ntoa_r(&sdl, &buf[0], &len);
+ ATF_REQUIRE_EQ(0, ret);
+ ATF_REQUIRE_EQ(10, len);
+ ATF_REQUIRE_EQ("ix0:1.2.3"s, bufstr());
+
+ // Test a buffer which is exactly the right size.
+ sdl = make_linkaddr("ix0:1.2.3");
+ resetbuf(10);
+ ret = ::link_ntoa_r(&sdl, &buf[0], &len);
+ ATF_REQUIRE_EQ(0, ret);
+ ATF_REQUIRE_EQ(10, len);
+ ATF_REQUIRE_EQ("ix0:1.2.3"sv, bufstr());
+
+ // Test various short buffers, using a table of buffer length and the
+ // output we expect. All of these should produce valid but truncated
+ // strings, with a trailing NUL and with buflen set correctly.
+
+ auto buftests = std::vector<std::pair<std::size_t, std::string_view>>{
+ {1u, ""sv},
+ {2u, ""sv},
+ {3u, ""sv},
+ {4u, "ix0"sv},
+ {5u, "ix0:"sv},
+ {6u, "ix0:1"sv},
+ {7u, "ix0:1."sv},
+ {8u, "ix0:1.2"sv},
+ {9u, "ix0:1.2."sv},
+ };
+
+ for (auto const &[buflen, expected] : buftests) {
+ sdl = make_linkaddr("ix0:1.2.3");
+ resetbuf(buflen);
+ ret = ::link_ntoa_r(&sdl, &buf[0], &len);
+ ATF_REQUIRE_EQ(-1, ret);
+ ATF_REQUIRE_EQ(10, len);
+ ATF_REQUIRE_EQ(expected, bufstr());
+ }
+
+ // Test a NULL buffer, which should just set buflen.
+ sdl = make_linkaddr("ix0:1.2.3");
+ len = 0;
+ ret = ::link_ntoa_r(&sdl, NULL, &len);
+ ATF_REQUIRE_EQ(-1, ret);
+ ATF_REQUIRE_EQ(10, len);
+
+ // A NULL buffer with a non-zero length should also be accepted.
+ sdl = make_linkaddr("ix0:1.2.3");
+ len = 64;
+ ret = ::link_ntoa_r(&sdl, NULL, &len);
+ ATF_REQUIRE_EQ(-1, ret);
+ ATF_REQUIRE_EQ(10, len);
+
+ // Test a non-NULL buffer, but with a length of zero.
+ sdl = make_linkaddr("ix0:1.2.3");
+ resetbuf(1);
+ len = 0;
+ ret = ::link_ntoa_r(&sdl, &buf[0], &len);
+ ATF_REQUIRE_EQ(-1, ret);
+ ATF_REQUIRE_EQ(10, len);
+ // Check we really didn't write anything.
+ ATF_REQUIRE_EQ(garbage, buf[0]);
+
+ // Test a buffer which would be truncated in the middle of a two-digit
+ // hex octet, which should not write the truncated octet at all.
+ sdl = make_linkaddr("ix0:1.22.3");
+ resetbuf(8);
+ ret = ::link_ntoa_r(&sdl, &buf[0], &len);
+ ATF_REQUIRE_EQ(-1, ret);
+ ATF_REQUIRE_EQ(11, len);
+ ATF_REQUIRE_EQ("ix0:1."sv, bufstr());
+}
+
+ATF_INIT_TEST_CASES(tcs)
+{
+ ATF_ADD_TEST_CASE(tcs, basic);
+ ATF_ADD_TEST_CASE(tcs, ifname);
+ ATF_ADD_TEST_CASE(tcs, smallbuf);
+ ATF_ADD_TEST_CASE(tcs, invalid);
+ ATF_ADD_TEST_CASE(tcs, nonether);
+ ATF_ADD_TEST_CASE(tcs, overlong);
+ ATF_ADD_TEST_CASE(tcs, link_ntoa_r);
+}
diff --git a/lib/libc/tests/secure/Makefile b/lib/libc/tests/secure/Makefile
index beaa01457cfe..515f8f53a43e 100644
--- a/lib/libc/tests/secure/Makefile
+++ b/lib/libc/tests/secure/Makefile
@@ -10,6 +10,7 @@ FORTIFY_TCATS+= uio
# non-sys/ headers
FORTIFY_TCATS+= poll
+FORTIFY_TCATS+= signal
FORTIFY_TCATS+= stdlib
FORTIFY_TCATS+= stdio
FORTIFY_TCATS+= string
diff --git a/lib/libc/tests/secure/fortify_signal_test.c b/lib/libc/tests/secure/fortify_signal_test.c
new file mode 100644
index 000000000000..03cfb9a9a13a
--- /dev/null
+++ b/lib/libc/tests/secure/fortify_signal_test.c
@@ -0,0 +1,316 @@
+/* @generated by `generate-fortify-tests.lua "signal"` */
+
+#define _FORTIFY_SOURCE 2
+#define TMPFILE_SIZE (1024 * 32)
+
+#include <sys/param.h>
+#include <sys/jail.h>
+#include <sys/random.h>
+#include <sys/resource.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <wchar.h>
+#include <atf-c.h>
+
+static FILE * __unused
+new_fp(size_t __len)
+{
+ static char fpbuf[LINE_MAX];
+ FILE *fp;
+
+ ATF_REQUIRE(__len <= sizeof(fpbuf));
+
+ memset(fpbuf, 'A', sizeof(fpbuf) - 1);
+ fpbuf[sizeof(fpbuf) - 1] = '\0';
+
+ fp = fmemopen(fpbuf, sizeof(fpbuf), "rb");
+ ATF_REQUIRE(fp != NULL);
+
+ return (fp);
+}
+
+/*
+ * Create a new symlink to use for readlink(2) style tests, we'll just use a
+ * random target name to have something interesting to look at.
+ */
+static const char * __unused
+new_symlink(size_t __len)
+{
+ static const char linkname[] = "link";
+ char target[MAXNAMLEN];
+ int error;
+
+ ATF_REQUIRE(__len <= sizeof(target));
+
+ arc4random_buf(target, sizeof(target));
+
+ error = unlink(linkname);
+ ATF_REQUIRE(error == 0 || errno == ENOENT);
+
+ error = symlink(target, linkname);
+ ATF_REQUIRE(error == 0);
+
+ return (linkname);
+}
+
+/*
+ * For our purposes, first descriptor will be the reader; we'll send both
+ * raw data and a control message over it so that the result can be used for
+ * any of our recv*() tests.
+ */
+static void __unused
+new_socket(int sock[2])
+{
+ unsigned char ctrl[CMSG_SPACE(sizeof(int))] = { 0 };
+ static char sockbuf[256];
+ ssize_t rv;
+ size_t total = 0;
+ struct msghdr hdr = { 0 };
+ struct cmsghdr *cmsg;
+ int error, fd;
+
+ error = socketpair(AF_UNIX, SOCK_STREAM, 0, sock);
+ ATF_REQUIRE(error == 0);
+
+ while (total != sizeof(sockbuf)) {
+ rv = send(sock[1], &sockbuf[total], sizeof(sockbuf) - total, 0);
+
+ ATF_REQUIRE_MSG(rv > 0,
+ "expected bytes sent, got %zd with %zu left (size %zu, total %zu)",
+ rv, sizeof(sockbuf) - total, sizeof(sockbuf), total);
+ ATF_REQUIRE_MSG(total + (size_t)rv <= sizeof(sockbuf),
+ "%zd exceeds total %zu", rv, sizeof(sockbuf));
+ total += rv;
+ }
+
+ hdr.msg_control = ctrl;
+ hdr.msg_controllen = sizeof(ctrl);
+
+ cmsg = CMSG_FIRSTHDR(&hdr);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+ fd = STDIN_FILENO;
+ memcpy(CMSG_DATA(cmsg), &fd, sizeof(fd));
+
+ error = sendmsg(sock[1], &hdr, 0);
+ ATF_REQUIRE(error != -1);
+}
+
+/*
+ * Constructs a tmpfile that we can use for testing read(2) and friends.
+ */
+static int __unused
+new_tmpfile(void)
+{
+ char buf[1024];
+ ssize_t rv;
+ size_t written;
+ int fd;
+
+ fd = open("tmpfile", O_RDWR | O_CREAT | O_TRUNC, 0644);
+ ATF_REQUIRE(fd >= 0);
+
+ written = 0;
+ while (written < TMPFILE_SIZE) {
+ rv = write(fd, buf, sizeof(buf));
+ ATF_REQUIRE(rv > 0);
+
+ written += rv;
+ }
+
+ ATF_REQUIRE_EQ(0, lseek(fd, 0, SEEK_SET));
+ return (fd);
+}
+
+static void
+disable_coredumps(void)
+{
+ struct rlimit rl = { 0 };
+
+ if (setrlimit(RLIMIT_CORE, &rl) == -1)
+ _exit(EX_OSERR);
+}
+
+/*
+ * Replaces stdin with a file that we can actually read from, for tests where
+ * we want a FILE * or fd that we can get data from.
+ */
+static void __unused
+replace_stdin(void)
+{
+ int fd;
+
+ fd = new_tmpfile();
+
+ (void)dup2(fd, STDIN_FILENO);
+ if (fd != STDIN_FILENO)
+ close(fd);
+}
+
+ATF_TC(sig2str_before_end);
+ATF_TC_HEAD(sig2str_before_end, tc)
+{
+}
+ATF_TC_BODY(sig2str_before_end, tc)
+{
+#define BUF &__stack.__buf
+ struct {
+ uint8_t padding_l;
+ unsigned char __buf[SIG2STR_MAX + 1];
+ uint8_t padding_r;
+ } __stack;
+ const size_t __bufsz __unused = sizeof(__stack.__buf);
+ const size_t __len = SIG2STR_MAX + 1;
+ const size_t __idx __unused = __len - 1;
+
+ sig2str(1, __stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC(sig2str_end);
+ATF_TC_HEAD(sig2str_end, tc)
+{
+}
+ATF_TC_BODY(sig2str_end, tc)
+{
+#define BUF &__stack.__buf
+ struct {
+ uint8_t padding_l;
+ unsigned char __buf[SIG2STR_MAX];
+ uint8_t padding_r;
+ } __stack;
+ const size_t __bufsz __unused = sizeof(__stack.__buf);
+ const size_t __len = SIG2STR_MAX;
+ const size_t __idx __unused = __len - 1;
+
+ sig2str(1, __stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC(sig2str_heap_before_end);
+ATF_TC_HEAD(sig2str_heap_before_end, tc)
+{
+}
+ATF_TC_BODY(sig2str_heap_before_end, tc)
+{
+#define BUF __stack.__buf
+ struct {
+ uint8_t padding_l;
+ unsigned char * __buf;
+ uint8_t padding_r;
+ } __stack;
+ const size_t __bufsz __unused = sizeof(*__stack.__buf) * (SIG2STR_MAX + 1);
+ const size_t __len = SIG2STR_MAX + 1;
+ const size_t __idx __unused = __len - 1;
+
+ __stack.__buf = malloc(__bufsz);
+
+ sig2str(1, __stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC(sig2str_heap_end);
+ATF_TC_HEAD(sig2str_heap_end, tc)
+{
+}
+ATF_TC_BODY(sig2str_heap_end, tc)
+{
+#define BUF __stack.__buf
+ struct {
+ uint8_t padding_l;
+ unsigned char * __buf;
+ uint8_t padding_r;
+ } __stack;
+ const size_t __bufsz __unused = sizeof(*__stack.__buf) * (SIG2STR_MAX);
+ const size_t __len = SIG2STR_MAX;
+ const size_t __idx __unused = __len - 1;
+
+ __stack.__buf = malloc(__bufsz);
+
+ sig2str(1, __stack.__buf);
+#undef BUF
+
+}
+
+ATF_TC(sig2str_heap_after_end);
+ATF_TC_HEAD(sig2str_heap_after_end, tc)
+{
+}
+ATF_TC_BODY(sig2str_heap_after_end, tc)
+{
+#define BUF __stack.__buf
+ struct {
+ uint8_t padding_l;
+ unsigned char * __buf;
+ uint8_t padding_r;
+ } __stack;
+ const size_t __bufsz __unused = sizeof(*__stack.__buf) * (SIG2STR_MAX - 1);
+ const size_t __len = SIG2STR_MAX - 1;
+ const size_t __idx __unused = __len - 1;
+ pid_t __child;
+ int __status;
+
+ __child = fork();
+ ATF_REQUIRE(__child >= 0);
+ if (__child > 0)
+ goto monitor;
+
+ /* Child */
+ disable_coredumps();
+ __stack.__buf = malloc(__bufsz);
+
+ sig2str(1, __stack.__buf);
+ _exit(EX_SOFTWARE); /* Should have aborted. */
+
+monitor:
+ while (waitpid(__child, &__status, 0) != __child) {
+ ATF_REQUIRE_EQ(EINTR, errno);
+ }
+
+ if (!WIFSIGNALED(__status)) {
+ switch (WEXITSTATUS(__status)) {
+ case EX_SOFTWARE:
+ atf_tc_fail("FORTIFY_SOURCE failed to abort");
+ break;
+ case EX_OSERR:
+ atf_tc_fail("setrlimit(2) failed");
+ break;
+ default:
+ atf_tc_fail("child exited with status %d",
+ WEXITSTATUS(__status));
+ }
+ } else {
+ ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status));
+ }
+#undef BUF
+
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, sig2str_before_end);
+ ATF_TP_ADD_TC(tp, sig2str_end);
+ ATF_TP_ADD_TC(tp, sig2str_heap_before_end);
+ ATF_TP_ADD_TC(tp, sig2str_heap_end);
+ ATF_TP_ADD_TC(tp, sig2str_heap_after_end);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/secure/fortify_stdlib_test.c b/lib/libc/tests/secure/fortify_stdlib_test.c
index ae021e8418f7..d0b1af78da86 100644
--- a/lib/libc/tests/secure/fortify_stdlib_test.c
+++ b/lib/libc/tests/secure/fortify_stdlib_test.c
@@ -305,6 +305,148 @@ monitor:
}
+ATF_TC(getenv_r_before_end);
+ATF_TC_HEAD(getenv_r_before_end, tc)
+{
+}
+ATF_TC_BODY(getenv_r_before_end, tc)
+{
+#define BUF &__stack.__buf
+ struct {
+ uint8_t padding_l;
+ unsigned char __buf[42];
+ uint8_t padding_r;
+ } __stack;
+ const size_t __bufsz __unused = sizeof(__stack.__buf);
+ const size_t __len = 42 - 1;
+ const size_t __idx __unused = __len - 1;
+
+ getenv_r("PATH", __stack.__buf, __len);
+#undef BUF
+
+}
+
+ATF_TC(getenv_r_end);
+ATF_TC_HEAD(getenv_r_end, tc)
+{
+}
+ATF_TC_BODY(getenv_r_end, tc)
+{
+#define BUF &__stack.__buf
+ struct {
+ uint8_t padding_l;
+ unsigned char __buf[42];
+ uint8_t padding_r;
+ } __stack;
+ const size_t __bufsz __unused = sizeof(__stack.__buf);
+ const size_t __len = 42;
+ const size_t __idx __unused = __len - 1;
+
+ getenv_r("PATH", __stack.__buf, __len);
+#undef BUF
+
+}
+
+ATF_TC(getenv_r_heap_before_end);
+ATF_TC_HEAD(getenv_r_heap_before_end, tc)
+{
+}
+ATF_TC_BODY(getenv_r_heap_before_end, tc)
+{
+#define BUF __stack.__buf
+ struct {
+ uint8_t padding_l;
+ unsigned char * __buf;
+ uint8_t padding_r;
+ } __stack;
+ const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+ const size_t __len = 42 - 1;
+ const size_t __idx __unused = __len - 1;
+
+ __stack.__buf = malloc(__bufsz);
+
+ getenv_r("PATH", __stack.__buf, __len);
+#undef BUF
+
+}
+
+ATF_TC(getenv_r_heap_end);
+ATF_TC_HEAD(getenv_r_heap_end, tc)
+{
+}
+ATF_TC_BODY(getenv_r_heap_end, tc)
+{
+#define BUF __stack.__buf
+ struct {
+ uint8_t padding_l;
+ unsigned char * __buf;
+ uint8_t padding_r;
+ } __stack;
+ const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+ const size_t __len = 42;
+ const size_t __idx __unused = __len - 1;
+
+ __stack.__buf = malloc(__bufsz);
+
+ getenv_r("PATH", __stack.__buf, __len);
+#undef BUF
+
+}
+
+ATF_TC(getenv_r_heap_after_end);
+ATF_TC_HEAD(getenv_r_heap_after_end, tc)
+{
+}
+ATF_TC_BODY(getenv_r_heap_after_end, tc)
+{
+#define BUF __stack.__buf
+ struct {
+ uint8_t padding_l;
+ unsigned char * __buf;
+ uint8_t padding_r;
+ } __stack;
+ const size_t __bufsz __unused = sizeof(*__stack.__buf) * (42);
+ const size_t __len = 42 + 1;
+ const size_t __idx __unused = __len - 1;
+ pid_t __child;
+ int __status;
+
+ __child = fork();
+ ATF_REQUIRE(__child >= 0);
+ if (__child > 0)
+ goto monitor;
+
+ /* Child */
+ disable_coredumps();
+ __stack.__buf = malloc(__bufsz);
+
+ getenv_r("PATH", __stack.__buf, __len);
+ _exit(EX_SOFTWARE); /* Should have aborted. */
+
+monitor:
+ while (waitpid(__child, &__status, 0) != __child) {
+ ATF_REQUIRE_EQ(EINTR, errno);
+ }
+
+ if (!WIFSIGNALED(__status)) {
+ switch (WEXITSTATUS(__status)) {
+ case EX_SOFTWARE:
+ atf_tc_fail("FORTIFY_SOURCE failed to abort");
+ break;
+ case EX_OSERR:
+ atf_tc_fail("setrlimit(2) failed");
+ break;
+ default:
+ atf_tc_fail("child exited with status %d",
+ WEXITSTATUS(__status));
+ }
+ } else {
+ ATF_REQUIRE_EQ(SIGABRT, WTERMSIG(__status));
+ }
+#undef BUF
+
+}
+
ATF_TC(realpath_before_end);
ATF_TC_HEAD(realpath_before_end, tc)
{
@@ -454,6 +596,11 @@ ATF_TP_ADD_TCS(tp)
ATF_TP_ADD_TC(tp, arc4random_buf_heap_before_end);
ATF_TP_ADD_TC(tp, arc4random_buf_heap_end);
ATF_TP_ADD_TC(tp, arc4random_buf_heap_after_end);
+ ATF_TP_ADD_TC(tp, getenv_r_before_end);
+ ATF_TP_ADD_TC(tp, getenv_r_end);
+ ATF_TP_ADD_TC(tp, getenv_r_heap_before_end);
+ ATF_TP_ADD_TC(tp, getenv_r_heap_end);
+ ATF_TP_ADD_TC(tp, getenv_r_heap_after_end);
ATF_TP_ADD_TC(tp, realpath_before_end);
ATF_TP_ADD_TC(tp, realpath_end);
ATF_TP_ADD_TC(tp, realpath_heap_before_end);
diff --git a/lib/libc/tests/secure/generate-fortify-tests.lua b/lib/libc/tests/secure/generate-fortify-tests.lua
index 36ff01af7a17..c9cd9353a869 100755
--- a/lib/libc/tests/secure/generate-fortify-tests.lua
+++ b/lib/libc/tests/secure/generate-fortify-tests.lua
@@ -478,6 +478,18 @@ local all_tests = {
init = poll_init,
},
},
+ signal = {
+ -- <signal.h>
+ {
+ func = "sig2str",
+ bufsize = "SIG2STR_MAX",
+ arguments = {
+ "1",
+ "__buf",
+ },
+ exclude = excludes_stack_overflow,
+ },
+ },
stdio = {
-- <stdio.h>
{
@@ -585,6 +597,15 @@ local all_tests = {
exclude = excludes_stack_overflow,
},
{
+ func = "getenv_r",
+ arguments = {
+ "\"PATH\"",
+ "__buf",
+ "__len",
+ },
+ exclude = excludes_stack_overflow,
+ },
+ {
func = "realpath",
bufsize = "PATH_MAX",
arguments = {
diff --git a/lib/libc/tests/stdio/scanfloat_test.c b/lib/libc/tests/stdio/scanfloat_test.c
index a93238504dd1..635d93d560b3 100644
--- a/lib/libc/tests/stdio/scanfloat_test.c
+++ b/lib/libc/tests/stdio/scanfloat_test.c
@@ -59,88 +59,88 @@ ATF_TC_BODY(normalized_numbers, tc)
buf[0] = '\0';
ATF_REQUIRE(setlocale(LC_NUMERIC, ""));
- sscanf("3.141592", "%e", &f);
+ ATF_REQUIRE_EQ(1, sscanf("3.141592", "%e", &f));
ATF_REQUIRE(eq(FLT, f, 3.141592));
- sscanf("3.141592653589793", "%lf", &d);
+ ATF_REQUIRE_EQ(1, sscanf("3.141592653589793", "%lf", &d));
ATF_REQUIRE(eq(DBL, d, 3.141592653589793));
- sscanf("1.234568e+06", "%E", &f);
+ ATF_REQUIRE_EQ(1, sscanf("1.234568e+06", "%E", &f));
ATF_REQUIRE(eq(FLT, f, 1.234568e+06));
- sscanf("-1.234568e6", "%lF", &d);
+ ATF_REQUIRE_EQ(1, sscanf("-1.234568e6", "%lF", &d));
ATF_REQUIRE(eq(DBL, d, -1.234568e6));
- sscanf("+1.234568e-52", "%LG", &ld);
+ ATF_REQUIRE_EQ(1, sscanf("+1.234568e-52", "%LG", &ld));
ATF_REQUIRE(eq(LDBL, ld, 1.234568e-52L));
- sscanf("0.1", "%la", &d);
+ ATF_REQUIRE_EQ(1, sscanf("0.1", "%la", &d));
ATF_REQUIRE(eq(DBL, d, 0.1));
- sscanf("00.2", "%lA", &d);
+ ATF_REQUIRE_EQ(1, sscanf("00.2", "%lA", &d));
ATF_REQUIRE(eq(DBL, d, 0.2));
- sscanf("123456", "%5le%s", &d, buf);
+ ATF_REQUIRE_EQ(2, sscanf("123456", "%5le%s", &d, buf));
ATF_REQUIRE(eq(DBL, d, 12345.));
ATF_REQUIRE(strcmp(buf, "6") == 0);
- sscanf("1.0Q", "%*5le%s", buf);
+ ATF_REQUIRE_EQ(1, sscanf("1.0Q", "%*5le%s", buf));
ATF_REQUIRE(strcmp(buf, "Q") == 0);
- sscanf("-1.23e", "%e%s", &f, buf);
+ ATF_REQUIRE_EQ(2, sscanf("-1.23e", "%e%s", &f, buf));
ATF_REQUIRE(eq(FLT, f, -1.23));
ATF_REQUIRE(strcmp(buf, "e") == 0);
- sscanf("1.25e+", "%le%s", &d, buf);
+ ATF_REQUIRE_EQ(2, sscanf("1.25e+", "%le%s", &d, buf));
ATF_REQUIRE(eq(DBL, d, 1.25));
ATF_REQUIRE(strcmp(buf, "e+") == 0);
- sscanf("1.23E4E5", "%le%s", &d, buf);
+ ATF_REQUIRE_EQ(2, sscanf("1.23E4E5", "%le%s", &d, buf));
ATF_REQUIRE(eq(DBL, d, 1.23e4));
ATF_REQUIRE(strcmp(buf, "E5") == 0);
- sscanf("12e6", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("12e6", "%le", &d));
ATF_REQUIRE(eq(DBL, d, 12e6));
- sscanf("1.a", "%le%s", &d, buf);
+ ATF_REQUIRE_EQ(2, sscanf("1.a", "%le%s", &d, buf));
ATF_REQUIRE(eq(DBL, d, 1.0));
ATF_REQUIRE(strcmp(buf, "a") == 0);
- sscanf(".0p4", "%le%s", &d, buf);
+ ATF_REQUIRE_EQ(2, sscanf(".0p4", "%le%s", &d, buf));
ATF_REQUIRE(eq(DBL, d, 0.0));
ATF_REQUIRE(strcmp(buf, "p4") == 0);
d = 0.25;
- ATF_REQUIRE(sscanf(".", "%le", &d) == 0);
+ ATF_REQUIRE_EQ(0, sscanf(".", "%le", &d));
ATF_REQUIRE(d == 0.25);
- sscanf("0x08", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("0x08", "%le", &d));
ATF_REQUIRE(d == 0x8p0);
- sscanf("0x90a.bcdefP+09a", "%le%s", &d, buf);
+ ATF_REQUIRE_EQ(2, sscanf("0x90a.bcdefP+09a", "%le%s", &d, buf));
ATF_REQUIRE(d == 0x90a.bcdefp+09);
ATF_REQUIRE(strcmp(buf, "a") == 0);
#if (LDBL_MANT_DIG > DBL_MANT_DIG) && !defined(__i386__)
- sscanf("3.14159265358979323846", "%Lg", &ld);
+ ATF_REQUIRE_EQ(1, sscanf("3.14159265358979323846", "%Lg", &ld));
ATF_REQUIRE(eq(LDBL, ld, 3.14159265358979323846L));
- sscanf(" 0X.0123456789abcdefffp-3g", "%Le%s", &ld, buf);
+ ATF_REQUIRE_EQ(2, sscanf(" 0X.0123456789abcdefffp-3g", "%Le%s", &ld, buf));
ATF_REQUIRE(ld == 0x0.0123456789abcdefffp-3L);
ATF_REQUIRE(strcmp(buf, "g") == 0);
#endif
- sscanf("0xg", "%le%s", &d, buf);
+ ATF_REQUIRE_EQ(2, sscanf("0xg", "%le%s", &d, buf));
ATF_REQUIRE(d == 0.0);
ATF_REQUIRE(strcmp(buf, "xg") == 0);
ATF_REQUIRE(setlocale(LC_NUMERIC, "ru_RU.ISO8859-5")); /* decimalpoint==, */
- sscanf("1.23", "%le%s", &d, buf);
+ ATF_REQUIRE_EQ(2, sscanf("1.23", "%le%s", &d, buf));
ATF_REQUIRE(d == 1.0);
ATF_REQUIRE(strcmp(buf, ".23") == 0);
- sscanf("1,23", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("1,23", "%le", &d));
ATF_REQUIRE(d == 1.23);
ATF_REQUIRE(setlocale(LC_NUMERIC, ""));
@@ -156,40 +156,40 @@ ATF_TC_BODY(infinities_and_nans, tc)
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
- sscanf("-Inf", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("-Inf", "%le", &d));
ATF_REQUIRE(d < 0.0 && isinf(d));
- sscanf("iNfInItY and beyond", "%le%s", &d, buf);
+ ATF_REQUIRE_EQ(2, sscanf("iNfInItY and beyond", "%le%s", &d, buf));
ATF_REQUIRE(d > 0.0 && isinf(d));
ATF_REQUIRE(strcmp(buf, " and beyond"));
- sscanf("NaN", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("NaN", "%le", &d));
ATF_REQUIRE(isnan(d));
- sscanf("NAN(123Y", "%le%s", &d, buf);
+ ATF_REQUIRE_EQ(2, sscanf("NAN(123Y", "%le%s", &d, buf));
ATF_REQUIRE(isnan(d));
ATF_REQUIRE(strcmp(buf, "(123Y") == 0);
- sscanf("nan(f00f)plugh", "%le%s", &d, buf);
+ ATF_REQUIRE_EQ(2, sscanf("nan(f00f)plugh", "%le%s", &d, buf));
ATF_REQUIRE(isnan(d));
ATF_REQUIRE(strcmp(buf, "plugh") == 0);
- sscanf("-nan", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("-nan", "%le", &d));
ATF_REQUIRE(isnan(d));
/* Only quiet NaNs should be returned. */
- sscanf("NaN", "%e", &f);
- sscanf("nan", "%le", &d);
- sscanf("nan", "%Le", &ld);
- feclearexcept(FE_ALL_EXCEPT);
+ ATF_REQUIRE_EQ(1, sscanf("NaN", "%e", &f));
+ ATF_REQUIRE_EQ(1, sscanf("nan", "%le", &d));
+ ATF_REQUIRE_EQ(1, sscanf("nan", "%Le", &ld));
+ ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT));
ATF_REQUIRE(f != f);
ATF_REQUIRE(d != d);
ATF_REQUIRE(ld != ld);
ATF_REQUIRE(fetestexcept(FE_INVALID) == 0);
- sscanf("nan(1234)", "%e", &f);
- sscanf("nan(1234)", "%le", &d);
- sscanf("nan(1234)", "%Le", &ld);
- feclearexcept(FE_ALL_EXCEPT);
+ ATF_REQUIRE_EQ(1, sscanf("nan(1234)", "%e", &f));
+ ATF_REQUIRE_EQ(1, sscanf("nan(1234)", "%le", &d));
+ ATF_REQUIRE_EQ(1, sscanf("nan(1234)", "%Le", &ld));
+ ATF_REQUIRE_EQ(0, feclearexcept(FE_ALL_EXCEPT));
ATF_REQUIRE(f != f);
ATF_REQUIRE(d != d);
ATF_REQUIRE(ld != ld);
@@ -205,74 +205,74 @@ ATF_TC_BODY(rounding_tests, tc)
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
- fesetround(FE_DOWNWARD);
+ ATF_REQUIRE_EQ(0, fesetround(FE_DOWNWARD));
- sscanf("1.999999999999999999999999999999999", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("1.999999999999999999999999999999999", "%le", &d));
ATF_REQUIRE(d < 2.0);
- sscanf("0x1.ffffffffffffffp0", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("0x1.ffffffffffffffp0", "%le", &d));
ATF_REQUIRE(d < 2.0);
- sscanf("1.999999999999999999999999999999999", "%Le", &ld);
+ ATF_REQUIRE_EQ(1, sscanf("1.999999999999999999999999999999999", "%Le", &ld));
ATF_REQUIRE(ld < 2.0);
- sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("1.0571892669084007", "%le", &d));
ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
- sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("-1.0571892669084007", "%le", &d));
ATF_REQUIRE(d == -0x1.0ea3f4af0dc5ap0);
- sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("1.0571892669084010", "%le", &d));
ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
- sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("0x1.23p-5000", "%le", &d));
ATF_REQUIRE(d == 0.0);
- sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("0x1.2345678p-1050", "%le", &d));
ATF_REQUIRE(d == 0x1.234567p-1050);
- fesetround(FE_UPWARD);
+ ATF_REQUIRE_EQ(0, fesetround(FE_UPWARD));
- sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("1.0571892669084007", "%le", &d));
ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
- sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("-1.0571892669084007", "%le", &d));
ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
- sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("1.0571892669084010", "%le", &d));
ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0);
- sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("0x1.23p-5000", "%le", &d));
ATF_REQUIRE(d == 0x1p-1074);
- sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("0x1.2345678p-1050", "%le", &d));
ATF_REQUIRE(d == 0x1.234568p-1050);
- fesetround(FE_TOWARDZERO);
+ ATF_REQUIRE_EQ(0, fesetround(FE_TOWARDZERO));
- sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("1.0571892669084007", "%le", &d));
ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
- sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("-1.0571892669084007", "%le", &d));
ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
- sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("1.0571892669084010", "%le", &d));
ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
- sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("0x1.23p-5000", "%le", &d));
ATF_REQUIRE(d == 0.0);
- sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("0x1.2345678p-1050", "%le", &d));
ATF_REQUIRE(d == 0x1.234567p-1050);
- fesetround(FE_TONEAREST);
+ ATF_REQUIRE_EQ(0, fesetround(FE_TONEAREST));
/* 1.0571892669084007 is slightly closer to 0x1.0ea3f4af0dc59p0 */
- sscanf("1.0571892669084007", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("1.0571892669084007", "%le", &d));
ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
- sscanf("-1.0571892669084007", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("-1.0571892669084007", "%le", &d));
ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
- sscanf("1.0571892669084010", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("1.0571892669084010", "%le", &d));
ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0);
/* strtod() should round small numbers to 0. */
- sscanf("0x1.23p-5000", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("0x1.23p-5000", "%le", &d));
ATF_REQUIRE(d == 0.0);
/* Extra digits in a denormal shouldn't break anything. */
- sscanf("0x1.2345678p-1050", "%le", &d);
+ ATF_REQUIRE_EQ(1, sscanf("0x1.2345678p-1050", "%le", &d));
ATF_REQUIRE(d == 0x1.234568p-1050);
}
@@ -287,16 +287,16 @@ ATF_TC_BODY(strtod, tc)
ATF_REQUIRE(strcmp("xy", endp) == 0);
/* This used to cause an infinite loop and round the wrong way. */
- fesetround(FE_DOWNWARD);
+ ATF_REQUIRE_EQ(0, fesetround(FE_DOWNWARD));
ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX);
ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX);
- fesetround(FE_UPWARD);
+ ATF_REQUIRE_EQ(0, fesetround(FE_UPWARD));
ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY);
ATF_REQUIRE(strtod("2e308", &endp) == INFINITY);
- fesetround(FE_TOWARDZERO);
+ ATF_REQUIRE_EQ(0, fesetround(FE_TOWARDZERO));
ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX);
ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX);
- fesetround(FE_TONEAREST);
+ ATF_REQUIRE_EQ(0, fesetround(FE_TONEAREST));
ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY);
ATF_REQUIRE(strtod("2e308", &endp) == INFINITY);
}
diff --git a/lib/libc/tests/stdlib/Makefile b/lib/libc/tests/stdlib/Makefile
index 6f57b8014a1e..50726a5d8af6 100644
--- a/lib/libc/tests/stdlib/Makefile
+++ b/lib/libc/tests/stdlib/Makefile
@@ -1,12 +1,14 @@
.include <src.opts.mk>
ATF_TESTS_C+= clearenv_test
+ATF_TESTS_C+= cxa_atexit_test
ATF_TESTS_C+= dynthr_test
+ATF_TESTS_C+= getenv_r_test
ATF_TESTS_C+= heapsort_test
ATF_TESTS_C+= libc_exit_test
ATF_TESTS_C+= mergesort_test
ATF_TESTS_C+= qsort_test
-.if ${COMPILER_TYPE} == "clang"
+.if ${COMPILER_FEATURES:Mblocks}
ATF_TESTS_C+= qsort_b_test
.endif
ATF_TESTS_C+= qsort_r_compat_test
@@ -58,11 +60,9 @@ PROGS+= h_getopt h_getopt_long
CFLAGS+= -I${.CURDIR}
-CXXSTD.cxa_thread_atexit_test= c++11
-CXXSTD.cxa_thread_atexit_nothr_test= c++11
LIBADD.cxa_thread_atexit_test+= pthread
-# Tests that requires Blocks feature
+# Tests that require blocks support
.for t in qsort_b_test
CFLAGS.${t}.c+= -fblocks
LIBADD.${t}+= BlocksRuntime
@@ -79,5 +79,6 @@ LIBADD.libc_exit_test+= pthread
LIBADD.strtod_test+= m
SUBDIR+= dynthr_mod
+SUBDIR+= libatexit
.include <bsd.test.mk>
diff --git a/lib/libc/tests/stdlib/cxa_atexit_test.c b/lib/libc/tests/stdlib/cxa_atexit_test.c
new file mode 100644
index 000000000000..7e2cafbce850
--- /dev/null
+++ b/lib/libc/tests/stdlib/cxa_atexit_test.c
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 2025 Kyle Evans <kevans@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/wait.h>
+
+#include <dlfcn.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+#define ARBITRARY_EXIT_CODE 42
+
+static char *
+get_shlib(const char *srcdir)
+{
+ char *shlib;
+
+ shlib = NULL;
+ if (asprintf(&shlib, "%s/libatexit.so", srcdir) < 0)
+ atf_tc_fail("failed to construct path to libatexit.so");
+ return (shlib);
+}
+
+static void
+run_test(const atf_tc_t *tc, bool with_fatal_atexit, bool with_exit)
+{
+ pid_t p;
+ void (*set_fatal_atexit)(bool);
+ void (*set_exit_code)(int);
+ void *hdl;
+ char *shlib;
+
+ shlib = get_shlib(atf_tc_get_config_var(tc, "srcdir"));
+
+ hdl = dlopen(shlib, RTLD_LAZY);
+ ATF_REQUIRE_MSG(hdl != NULL, "dlopen: %s", dlerror());
+
+ free(shlib);
+
+ if (with_fatal_atexit) {
+ set_fatal_atexit = dlsym(hdl, "set_fatal_atexit");
+ ATF_REQUIRE_MSG(set_fatal_atexit != NULL,
+ "set_fatal_atexit: %s", dlerror());
+ }
+ if (with_exit) {
+ set_exit_code = dlsym(hdl, "set_exit_code");
+ ATF_REQUIRE_MSG(set_exit_code != NULL, "set_exit_code: %s",
+ dlerror());
+ }
+
+ p = atf_utils_fork();
+ if (p == 0) {
+ /*
+ * Don't let the child clobber the results file; stderr/stdout
+ * have been replaced by atf_utils_fork() to capture it. We're
+ * intentionally using exit() instead of _exit() here to run
+ * __cxa_finalize at exit, otherwise we'd just leave it be.
+ */
+ closefrom(3);
+
+ if (with_fatal_atexit)
+ set_fatal_atexit(true);
+ if (with_exit)
+ set_exit_code(ARBITRARY_EXIT_CODE);
+
+ dlclose(hdl);
+
+ /*
+ * If the dtor was supposed to exit (most cases), then we should
+ * not have made it to this point. If it's not supposed to
+ * exit, then we just exit with success here because we might
+ * be expecting either a clean exit or a signal on our way out
+ * as the final __cxa_finalize tries to run a callback in the
+ * unloaded DSO.
+ */
+ if (with_exit)
+ exit(1);
+ exit(0);
+ }
+
+ dlclose(hdl);
+ atf_utils_wait(p, with_exit ? ARBITRARY_EXIT_CODE : 0, "", "");
+}
+
+ATF_TC_WITHOUT_HEAD(simple_cxa_atexit);
+ATF_TC_BODY(simple_cxa_atexit, tc)
+{
+ /*
+ * This test exits in a global object's dtor so that we check for our
+ * dtor being run at dlclose() time. If it isn't, then the forked child
+ * will have a chance to exit(1) after dlclose() to raise a failure.
+ */
+ run_test(tc, false, true);
+}
+
+ATF_TC_WITHOUT_HEAD(late_cxa_atexit);
+ATF_TC_BODY(late_cxa_atexit, tc)
+{
+ /*
+ * This test creates another global object during a __cxa_atexit handler
+ * invocation. It's been observed in the wild that we weren't executing
+ * it, then the DSO gets torn down and it was executed at application
+ * exit time instead. In the best case scenario we would crash if
+ * something else hadn't been mapped there.
+ */
+ run_test(tc, true, false);
+}
+
+ATF_TC_WITHOUT_HEAD(late_cxa_atexit_ran);
+ATF_TC_BODY(late_cxa_atexit_ran, tc)
+{
+ /*
+ * This is a slight variation of the previous test where we trigger an
+ * exit() in our late-registered __cxa_atexit handler so that we can
+ * ensure it was ran *before* dlclose() finished and not through some
+ * weird chain of events afterwards.
+ */
+ run_test(tc, true, true);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, simple_cxa_atexit);
+ ATF_TP_ADD_TC(tp, late_cxa_atexit);
+ ATF_TP_ADD_TC(tp, late_cxa_atexit_ran);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdlib/getenv_r_test.c b/lib/libc/tests/stdlib/getenv_r_test.c
new file mode 100644
index 000000000000..8085b92b1064
--- /dev/null
+++ b/lib/libc/tests/stdlib/getenv_r_test.c
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(getenv_r_ok);
+ATF_TC_BODY(getenv_r_ok, tc)
+{
+ const char *ident = atf_tc_get_ident(tc);
+ char buf[256];
+
+ ATF_REQUIRE_EQ(0, setenv("ATF_TC_IDENT", ident, 1));
+ ATF_REQUIRE_EQ(0, getenv_r("ATF_TC_IDENT", buf, sizeof(buf)));
+ ATF_REQUIRE_STREQ(ident, buf);
+}
+
+ATF_TC_WITHOUT_HEAD(getenv_r_einval);
+ATF_TC_BODY(getenv_r_einval, tc)
+{
+ char buf[256];
+
+ errno = 0;
+ ATF_REQUIRE_EQ(-1, getenv_r(NULL, buf, sizeof(buf)));
+ ATF_REQUIRE_EQ(EINVAL, errno);
+ errno = 0;
+ ATF_REQUIRE_EQ(-1, getenv_r("", buf, sizeof(buf)));
+ ATF_REQUIRE_EQ(EINVAL, errno);
+ errno = 0;
+ ATF_REQUIRE_EQ(-1, getenv_r("A=B", buf, sizeof(buf)));
+ ATF_REQUIRE_EQ(EINVAL, errno);
+}
+
+ATF_TC_WITHOUT_HEAD(getenv_r_enoent);
+ATF_TC_BODY(getenv_r_enoent, tc)
+{
+ char buf[256];
+
+ errno = 0;
+ ATF_REQUIRE_EQ(-1, getenv_r("no such variable", buf, sizeof(buf)));
+ ATF_REQUIRE_EQ(ENOENT, errno);
+}
+
+ATF_TC_WITHOUT_HEAD(getenv_r_erange);
+ATF_TC_BODY(getenv_r_erange, tc)
+{
+ const char *ident = atf_tc_get_ident(tc);
+ char buf[256];
+
+ ATF_REQUIRE_EQ(0, setenv("ATF_TC_IDENT", ident, 1));
+ errno = 0;
+ ATF_REQUIRE_EQ(-1, getenv_r("ATF_TC_IDENT", buf, strlen(ident)));
+ ATF_REQUIRE_EQ(ERANGE, errno);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, getenv_r_ok);
+ ATF_TP_ADD_TC(tp, getenv_r_einval);
+ ATF_TP_ADD_TC(tp, getenv_r_enoent);
+ ATF_TP_ADD_TC(tp, getenv_r_erange);
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdlib/libatexit/Makefile b/lib/libc/tests/stdlib/libatexit/Makefile
new file mode 100644
index 000000000000..9ba04c77af62
--- /dev/null
+++ b/lib/libc/tests/stdlib/libatexit/Makefile
@@ -0,0 +1,11 @@
+SHLIB_CXX= libatexit
+SHLIB_NAME= libatexit.so
+SHLIB_MAJOR= 1
+SHLIBDIR= ${TESTSDIR}
+PACKAGE= tests
+SRCS= libatexit.cc
+
+TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/:H}
+
+
+.include <bsd.lib.mk>
diff --git a/lib/libc/tests/stdlib/libatexit/libatexit.cc b/lib/libc/tests/stdlib/libatexit/libatexit.cc
new file mode 100644
index 000000000000..bb286c97e421
--- /dev/null
+++ b/lib/libc/tests/stdlib/libatexit/libatexit.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2025 Kyle Evans <kevans@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ */
+
+#include <unistd.h>
+
+static int exit_code = -1;
+static bool fatal_atexit;
+
+extern "C" {
+ void set_fatal_atexit(bool);
+ void set_exit_code(int);
+}
+
+void
+set_fatal_atexit(bool fexit)
+{
+ fatal_atexit = fexit;
+}
+
+void
+set_exit_code(int code)
+{
+ exit_code = code;
+}
+
+struct other_object {
+ ~other_object() {
+
+ /*
+ * In previous versions of our __cxa_atexit handling, we would
+ * never actually execute this handler because it's added during
+ * ~object() below; __cxa_finalize would never revisit it. We
+ * will allow the caller to configure us to exit with a certain
+ * exit code so that it can run us twice: once to ensure we
+ * don't crash at the end, and again to make sure the handler
+ * actually ran.
+ */
+ if (exit_code != -1)
+ _exit(exit_code);
+ }
+};
+
+void
+create_staticobj()
+{
+ static other_object obj;
+}
+
+struct object {
+ ~object() {
+ /*
+ * If we're doing the fatal_atexit behavior (i.e., create an
+ * object that will add its own dtor for __cxa_finalize), then
+ * we don't exit here.
+ */
+ if (fatal_atexit)
+ create_staticobj();
+ else if (exit_code != -1)
+ _exit(exit_code);
+ }
+};
+
+static object obj;
diff --git a/lib/libcam/Makefile b/lib/libcam/Makefile
index c2f7b75bc878..d4efbbdf4d9b 100644
--- a/lib/libcam/Makefile
+++ b/lib/libcam/Makefile
@@ -3,7 +3,7 @@ PACKAGE= runtime
LIB= cam
SHLIBDIR?= /lib
SRCS= camlib.c scsi_cmdparse.c scsi_all.c scsi_da.c scsi_sa.c cam.c \
- ata_all.c nvme_all.c smp_all.c scsi_wrap.c
+ ata_all.c nvme_all.c nvme_util.c smp_all.c scsi_wrap.c
INCS= camlib.h scsi_wrap.h
LIBADD= sbuf
@@ -39,7 +39,8 @@ MLINKS+= cam.3 cam_open_device.3 \
${SRCTOP}/sys/cam/ata \
${SRCTOP}/sys/cam/nvme \
${SRCTOP}/sys/cam/mmc \
- ${SRCTOP}/sys/cam/scsi
+ ${SRCTOP}/sys/cam/scsi \
+ ${SRCTOP}/sys/dev/nvme
CFLAGS+= -I${.CURDIR} -I${SRCTOP}/sys
diff --git a/lib/libcasper/services/cap_dns/tests/dns_test.c b/lib/libcasper/services/cap_dns/tests/dns_test.c
index 76534bbbebad..56d867e474f5 100644
--- a/lib/libcasper/services/cap_dns/tests/dns_test.c
+++ b/lib/libcasper/services/cap_dns/tests/dns_test.c
@@ -198,18 +198,17 @@ hostent_compare(const struct hostent *hp0, const struct hostent *hp1)
static void
runtest(cap_channel_t *capdns, unsigned int expected)
{
- unsigned int result, failure;
+ unsigned int result;
struct addrinfo *ais, *aic, hints, *hintsp;
struct hostent *hps, *hpc;
struct in_addr ip4;
struct in6_addr ip6;
int caperr, syserr;
- failure = result = 0;
+ result = 0;
hps = gethostbyname("example.com");
if (hps == NULL) {
- failure |= GETHOSTBYNAME;
fprintf(stderr, "Unable to resolve %s IPv4.\n", "example.com");
} else {
hpc = cap_gethostbyname(capdns, "example.com");
@@ -219,7 +218,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hps = gethostbyname2("example.com", AF_INET);
if (hps == NULL) {
- failure |= GETHOSTBYNAME2_AF_INET;
fprintf(stderr, "Unable to resolve %s IPv4.\n", "example.com");
} else {
hpc = cap_gethostbyname2(capdns, "example.com", AF_INET);
@@ -229,7 +227,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hps = gethostbyname2("example.com", AF_INET6);
if (hps == NULL) {
- failure |= GETHOSTBYNAME2_AF_INET6;
fprintf(stderr, "Unable to resolve %s IPv6.\n", "example.com");
} else {
hpc = cap_gethostbyname2(capdns, "example.com", AF_INET6);
@@ -250,7 +247,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
syserr = getaddrinfo("freebsd.org", "25", hintsp, &ais);
if (syserr != 0) {
- failure |= GETADDRINFO_AF_UNSPEC;
fprintf(stderr,
"Unable to issue [system] getaddrinfo() for AF_UNSPEC: %s\n",
gai_strerror(syserr));
@@ -268,7 +264,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hints.ai_family = AF_INET;
syserr = getaddrinfo("freebsd.org", "25", hintsp, &ais);
if (syserr != 0) {
- failure |= GETADDRINFO_AF_INET;
fprintf(stderr,
"Unable to issue [system] getaddrinfo() for AF_UNSPEC: %s\n",
gai_strerror(syserr));
@@ -286,7 +281,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
hints.ai_family = AF_INET6;
syserr = getaddrinfo("freebsd.org", "25", hintsp, &ais);
if (syserr != 0) {
- failure |= GETADDRINFO_AF_INET6;
fprintf(stderr,
"Unable to issue [system] getaddrinfo() for AF_UNSPEC: %s\n",
gai_strerror(syserr));
@@ -308,7 +302,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
inet_pton(AF_INET, GOOGLE_DNS_IPV4, &ip4);
hps = gethostbyaddr(&ip4, sizeof(ip4), AF_INET);
if (hps == NULL) {
- failure |= GETHOSTBYADDR_AF_INET;
fprintf(stderr, "Unable to resolve %s.\n", GOOGLE_DNS_IPV4);
} else {
hpc = cap_gethostbyaddr(capdns, &ip4, sizeof(ip4), AF_INET);
@@ -319,7 +312,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
inet_pton(AF_INET6, GOOGLE_DNS_IPV6, &ip6);
hps = gethostbyaddr(&ip6, sizeof(ip6), AF_INET6);
if (hps == NULL) {
- failure |= GETHOSTBYADDR_AF_INET6;
fprintf(stderr, "Unable to resolve %s.\n", GOOGLE_DNS_IPV6);
} else {
hpc = cap_gethostbyaddr(capdns, &ip6, sizeof(ip6), AF_INET6);
@@ -329,21 +321,6 @@ runtest(cap_channel_t *capdns, unsigned int expected)
}
}
- /*
- * If we had any failures, make sure that all lookups failed. If some
- * succeeded and some failed, there's a problem with the test or the DNS
- * and we should not fail silently.
- */
- if (failure != 0) {
- ATF_REQUIRE_MSG(failure == (GETHOSTBYNAME |
- GETHOSTBYNAME2_AF_INET | GETHOSTBYNAME2_AF_INET6 |
- GETADDRINFO_AF_UNSPEC | GETADDRINFO_AF_INET |
- GETADDRINFO_AF_INET6 |
- GETHOSTBYADDR_AF_INET | GETHOSTBYADDR_AF_INET6),
- "expected all tests to fail, got 0x%x", failure);
- atf_tc_skip(
- "no name lookups succeeded, tests require Internet access");
- }
ATF_REQUIRE_MSG(result == expected,
"expected 0x%x, got 0x%x", expected, result);
}
@@ -367,6 +344,7 @@ cap_dns_init(void)
ATF_TC(dns_no_limits);
ATF_TC_HEAD(dns_no_limits, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_no_limits, tc)
{
@@ -386,6 +364,7 @@ ATF_TC_BODY(dns_no_limits, tc)
ATF_TC(dns_all_limits);
ATF_TC_HEAD(dns_all_limits, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_all_limits, tc)
{
@@ -417,6 +396,7 @@ ATF_TC_BODY(dns_all_limits, tc)
ATF_TC(dns_name_limit);
ATF_TC_HEAD(dns_name_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_name_limit, tc)
{
@@ -448,6 +428,7 @@ ATF_TC_BODY(dns_name_limit, tc)
ATF_TC(dns_addr_limit);
ATF_TC_HEAD(dns_addr_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_addr_limit, tc)
{
@@ -478,6 +459,7 @@ ATF_TC_BODY(dns_addr_limit, tc)
ATF_TC(dns_inet_limit);
ATF_TC_HEAD(dns_inet_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_inet_limit, tc)
{
@@ -509,6 +491,7 @@ ATF_TC_BODY(dns_inet_limit, tc)
ATF_TC(dns_inet6_limit);
ATF_TC_HEAD(dns_inet6_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_inet6_limit, tc)
{
@@ -540,6 +523,7 @@ ATF_TC_BODY(dns_inet6_limit, tc)
ATF_TC(dns_name_inet_limit);
ATF_TC_HEAD(dns_name_inet_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_name_inet_limit, tc)
{
@@ -581,6 +565,7 @@ ATF_TC_BODY(dns_name_inet_limit, tc)
ATF_TC(dns_name_inet6_limit);
ATF_TC_HEAD(dns_name_inet6_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_name_inet6_limit, tc)
{
@@ -622,6 +607,7 @@ ATF_TC_BODY(dns_name_inet6_limit, tc)
ATF_TC(dns_addr_inet_limit);
ATF_TC_HEAD(dns_addr_inet_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_addr_inet_limit, tc)
{
@@ -662,6 +648,7 @@ ATF_TC_BODY(dns_addr_inet_limit, tc)
ATF_TC(dns_addr_inet6_limit);
ATF_TC_HEAD(dns_addr_inet6_limit, tc)
{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
}
ATF_TC_BODY(dns_addr_inet6_limit, tc)
{
diff --git a/lib/libcasper/services/cap_net/cap_net.c b/lib/libcasper/services/cap_net/cap_net.c
index 40d18319ae28..5887fe3c407e 100644
--- a/lib/libcasper/services/cap_net/cap_net.c
+++ b/lib/libcasper/services/cap_net/cap_net.c
@@ -288,7 +288,7 @@ cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
const nvlist_t *nvlai;
char nvlname[64];
nvlist_t *nvl;
- int error, n;
+ int error, serrno, n;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "getaddrinfo");
@@ -311,7 +311,9 @@ cap_getaddrinfo(cap_channel_t *chan, const char *hostname, const char *servname,
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {
error = (int)nvlist_get_number(nvl, "error");
+ serrno = dnvlist_get_number(nvl, "errno", 0);
nvlist_destroy(nvl);
+ errno = (error == EAI_SYSTEM) ? serrno : 0;
return (error);
}
@@ -350,7 +352,7 @@ cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen, char *serv, size_t servlen, int flags)
{
nvlist_t *nvl;
- int error;
+ int error, serrno;
nvl = nvlist_create(0);
nvlist_add_string(nvl, "cmd", "getnameinfo");
@@ -363,7 +365,9 @@ cap_getnameinfo(cap_channel_t *chan, const struct sockaddr *sa, socklen_t salen,
return (EAI_MEMORY);
if (nvlist_get_number(nvl, "error") != 0) {
error = (int)nvlist_get_number(nvl, "error");
+ serrno = dnvlist_get_number(nvl, "errno", 0);
nvlist_destroy(nvl);
+ errno = (error == EAI_SYSTEM) ? serrno : 0;
return (error);
}
@@ -858,19 +862,21 @@ net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
char *host, *serv;
size_t sabinsize, hostlen, servlen;
socklen_t salen;
- int error, flags;
+ int error, serrno, flags;
const nvlist_t *funclimit;
- if (!net_allowed_mode(limits, CAPNET_ADDR2NAME))
- return (ENOTCAPABLE);
+ host = serv = NULL;
+ if (!net_allowed_mode(limits, CAPNET_ADDR2NAME)) {
+ serrno = ENOTCAPABLE;
+ error = EAI_SYSTEM;
+ goto out;
+ }
funclimit = NULL;
if (limits != NULL) {
funclimit = dnvlist_get_nvlist(limits, LIMIT_NV_ADDR2NAME,
NULL);
}
-
error = 0;
- host = serv = NULL;
memset(&sast, 0, sizeof(sast));
hostlen = (size_t)nvlist_get_number(nvlin, "hostlen");
@@ -897,7 +903,8 @@ net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
goto out;
}
if (!net_allowed_bsaddr(funclimit, sabin, sabinsize)) {
- error = ENOTCAPABLE;
+ serrno = ENOTCAPABLE;
+ error = EAI_SYSTEM;
goto out;
}
@@ -913,7 +920,8 @@ net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
}
if (!net_allowed_family(funclimit, (int)sast.ss_family)) {
- error = ENOTCAPABLE;
+ serrno = ENOTCAPABLE;
+ error = EAI_SYSTEM;
goto out;
}
@@ -921,6 +929,7 @@ net_getnameinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
error = getnameinfo((struct sockaddr *)&sast, salen, host, hostlen,
serv, servlen, flags);
+ serrno = errno;
if (error != 0)
goto out;
@@ -932,6 +941,8 @@ out:
if (error != 0) {
free(host);
free(serv);
+ if (error == EAI_SYSTEM)
+ nvlist_add_number(nvlout, "errno", serrno);
}
return (error);
}
@@ -961,12 +972,15 @@ net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
char nvlname[64];
nvlist_t *elem;
unsigned int ii;
- int error, family, n;
+ int error, serrno, family, n;
const nvlist_t *funclimit;
bool dnscache;
- if (!net_allowed_mode(limits, CAPNET_NAME2ADDR))
- return (ENOTCAPABLE);
+ if (!net_allowed_mode(limits, CAPNET_NAME2ADDR)) {
+ serrno = ENOTCAPABLE;
+ error = EAI_SYSTEM;
+ goto out;
+ }
dnscache = net_allowed_mode(limits, CAPNET_CONNECTDNS);
funclimit = NULL;
if (limits != NULL) {
@@ -996,11 +1010,18 @@ net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
family = AF_UNSPEC;
}
- if (!net_allowed_family(funclimit, family))
- return (ENOTCAPABLE);
- if (!net_allowed_hosts(funclimit, hostname, servname))
- return (ENOTCAPABLE);
+ if (!net_allowed_family(funclimit, family)) {
+ errno = ENOTCAPABLE;
+ error = EAI_SYSTEM;
+ goto out;
+ }
+ if (!net_allowed_hosts(funclimit, hostname, servname)) {
+ errno = ENOTCAPABLE;
+ error = EAI_SYSTEM;
+ goto out;
+ }
error = getaddrinfo(hostname, servname, hintsp, &res);
+ serrno = errno;
if (error != 0) {
goto out;
}
@@ -1019,6 +1040,8 @@ net_getaddrinfo(const nvlist_t *limits, const nvlist_t *nvlin, nvlist_t *nvlout)
freeaddrinfo(res);
error = 0;
out:
+ if (error == EAI_SYSTEM)
+ nvlist_add_number(nvlout, "errno", serrno);
return (error);
}
diff --git a/lib/libcasper/services/cap_net/cap_net.h b/lib/libcasper/services/cap_net/cap_net.h
index 1e9a6021d240..75f936954199 100644
--- a/lib/libcasper/services/cap_net/cap_net.h
+++ b/lib/libcasper/services/cap_net/cap_net.h
@@ -93,18 +93,14 @@ struct hostent *cap_gethostbyaddr(cap_channel_t *chan, const void *addr,
socklen_t len, int af);
#else
/* Capability functions. */
-#define cap_bind(chan, s, addr, addrlen) \
- bind(s, addr, addrlen)
-#define cap_connect(chan, s, name, namelen) \
- connect(s, name, namelen)
-#define cap_getaddrinfo(chan, hostname, servname, hints, res) \
- getaddrinfo(hostname, servname, hints, res)
-#define cap_getnameinfo(chan, sa, salen, host, hostlen, serv, servlen, flags) \
- getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
+#define cap_bind(chan, ...) bind(__VA_ARGS__)
+#define cap_connect(chan, ...) connect(__VA_ARGS__)
+#define cap_getaddrinfo(chan, ...) getaddrinfo(__VA_ARGS__)
+#define cap_getnameinfo(chan, ...) getnameinfo(__VA_ARGS__)
/* Limit functions. */
-#define cap_net_limit_init(chan, mode) ((cap_net_limit_t *)malloc(8))
-#define cap_net_free(limit) free(limit)
+#define cap_net_limit_init(chan, ...) ((cap_net_limit_t *)malloc(8))
+#define cap_net_free(...) free(__VA_ARGS__)
static inline int
cap_net_limit(cap_net_limit_t *limit)
{
@@ -155,9 +151,9 @@ cap_net_limit_bind(cap_net_limit_t *limit,
}
/* Deprecated functions. */
-#define cap_gethostbyname(chan, name) gethostbyname(name)
-#define cap_gethostbyname2(chan, name, type) gethostbyname2(name, type)
-#define cap_gethostbyaddr(chan, addr, len, type) gethostbyaddr(addr, len, type)
+#define cap_gethostbyname(chan, ...) gethostbyname(__VA_ARGS__)
+#define cap_gethostbyname2(chan, ...) gethostbyname2(__VA_ARGS__)
+#define cap_gethostbyaddr(chan, ...) gethostbyaddr(__VA_ARGS__)
#endif
#endif /* !_CAP_NETWORK_H_ */
diff --git a/lib/libcom_err/Makefile b/lib/libcom_err/Makefile
index 2bfd26bae968..f070fd534469 100644
--- a/lib/libcom_err/Makefile
+++ b/lib/libcom_err/Makefile
@@ -7,7 +7,7 @@ MAN= com_err.3
COM_ERRDIR= ${SRCTOP}/contrib/com_err
CFLAGS+= -I${COM_ERRDIR}
-LDFLAGS= -Wl,--no-undefined
+LDFLAGS+= -Wl,--no-undefined
VERSION_MAP= ${COM_ERRDIR}/version-script.map
.include <bsd.lib.mk>
diff --git a/lib/libcompiler_rt/Makefile.inc b/lib/libcompiler_rt/Makefile.inc
index e2a2618232e1..57cfdee95541 100644
--- a/lib/libcompiler_rt/Makefile.inc
+++ b/lib/libcompiler_rt/Makefile.inc
@@ -208,7 +208,7 @@ SRCF+= trunctfsf2
.endif
# These are already shipped by libc.a on some architectures.
-.if ${MACHINE_CPUARCH} != "arm" && ${MACHINE_CPUARCH} != "riscv"
+.if ${MACHINE_CPUARCH} != "riscv"
SRCF+= adddf3
SRCF+= addsf3
SRCF+= divdf3
@@ -225,10 +225,8 @@ SRCF+= subsf3
SRCF+= truncdfsf2
.endif
-.if ${MACHINE_CPUARCH} != "arm"
SRCF+= comparedf2
SRCF+= comparesf2
-.endif
# Helper to reduce complexity of _Float16 and __bf16 statements below.
.if ${MACHINE_CPUARCH} == "aarch64" || \
@@ -274,10 +272,7 @@ CFLAGS+= -DEMIT_SYNC_ATOMICS
.endif
.for file in ${SRCF}
-.if ${MACHINE_CPUARCH} == "arm" && (!defined(CPUTYPE) || ${CPUTYPE:M*soft*} == "") \
- && exists(${CRTSRC}/${CRTARCH}/${file}vfp.S)
-SRCS+= ${file}vfp.S
-. elif exists(${CRTSRC}/${CRTARCH}/${file}.S)
+. if exists(${CRTSRC}/${CRTARCH}/${file}.S)
SRCS+= ${file}.S
. else
SRCS+= ${file}.c
@@ -285,7 +280,15 @@ SRCS+= ${file}.c
.endfor
.if ${MACHINE_CPUARCH} == "arm"
+SRCS+= aeabi_cdcmp.S
+SRCS+= aeabi_cdcmpeq_check_nan.c
+SRCS+= aeabi_cfcmp.S
+SRCS+= aeabi_cfcmpeq_check_nan.c
+SRCS+= aeabi_dcmp.S
SRCS+= aeabi_div0.c
+SRCS+= aeabi_drsub.c
+SRCS+= aeabi_fcmp.S
+SRCS+= aeabi_frsub.c
SRCS+= aeabi_idivmod.S
SRCS+= aeabi_ldivmod.S
SRCS+= aeabi_memcmp.S
@@ -294,6 +297,7 @@ SRCS+= aeabi_memmove.S
SRCS+= aeabi_memset.S
SRCS+= aeabi_uidivmod.S
SRCS+= aeabi_uldivmod.S
+
SRCS+= switch16.S
SRCS+= switch32.S
SRCS+= switch8.S
diff --git a/lib/libcxxrt/Makefile b/lib/libcxxrt/Makefile
index 7a683ba779f6..0f203b3a7cb1 100644
--- a/lib/libcxxrt/Makefile
+++ b/lib/libcxxrt/Makefile
@@ -23,7 +23,6 @@ SRCS+= typeinfo.cc
WARNS?= 0
CFLAGS+= -isystem ${SRCDIR} -nostdinc++
-CXXSTD?= c++14
.if exists(Version.map.${MACHINE})
VERSION_MAP= ${.CURDIR}/Version.map.${MACHINE}
diff --git a/lib/libedit/Makefile b/lib/libedit/Makefile
index c307cd3e7880..f0254c1f42bc 100644
--- a/lib/libedit/Makefile
+++ b/lib/libedit/Makefile
@@ -8,7 +8,6 @@ EDITDIR= ${SRCTOP}/contrib/libedit
SHLIB_MAJOR= 8
SHLIBDIR?= /lib
-WARNS?= 3
LIB= edit
LIBADD= tinfow
diff --git a/lib/libefivar/efivar-dp-format.c b/lib/libefivar/efivar-dp-format.c
index 3fa2833a7e7a..f2dcf1b91c01 100644
--- a/lib/libefivar/efivar-dp-format.c
+++ b/lib/libefivar/efivar-dp-format.c
@@ -28,7 +28,6 @@
* this file is taken from EDK2 and rototilled.
*/
-#include <sys/cdefs.h>
#include <efivar.h>
#include <stdio.h>
#include <string.h>
diff --git a/lib/libefivar/efivar-dp-parse.c b/lib/libefivar/efivar-dp-parse.c
index 3382666730c4..51c134692f1e 100644
--- a/lib/libefivar/efivar-dp-parse.c
+++ b/lib/libefivar/efivar-dp-parse.c
@@ -28,7 +28,6 @@
* this file is taken from EDK2 and rototilled.
*/
-#include <sys/cdefs.h>
#include <ctype.h>
#include <efivar.h>
#include <stdio.h>
diff --git a/lib/libefivar/efivar.c b/lib/libefivar/efivar.c
index fdcffc5403d6..c91bf5ea71bb 100644
--- a/lib/libefivar/efivar.c
+++ b/lib/libefivar/efivar.c
@@ -23,12 +23,12 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <efivar.h>
#include <sys/efiio.h>
#include <sys/param.h>
#include <errno.h>
#include <fcntl.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -37,11 +37,11 @@
static int efi_fd = -2;
-#define Z { 0, 0, 0, 0, 0, { 0 } }
+#define Z { 0 }
const efi_guid_t efi_guid_empty = Z;
-static struct uuid_table guid_tbl [] =
+static struct guid_table guid_tbl [] =
{
{ "00000000-0000-0000-0000-000000000000", "zero", Z },
{ "093e0fae-a6c4-4f50-9f1b-d41e2b89c19a", "sha512", Z },
@@ -75,32 +75,39 @@ static struct uuid_table guid_tbl [] =
{ "e2b36190-879b-4a3d-ad8d-f2e7bba32784", "rsa2048_sha256", Z },
{ "ff3e5307-9fd0-48c9-85f1-8ad56c701e01", "sha384", Z },
{ "f46ee6f4-4785-43a3-923d-7f786c3c8479", "lenovo_startup_interrupt", Z },
- { "ffffffff-ffff-ffff-ffff-ffffffffffff", "zzignore-this-guid", Z },
};
-#undef Z
+
+int
+efi_str_to_guid(const char *s, efi_guid_t *guid)
+{
+ uint32_t status;
+
+ /* knows efi_guid_t is binary compatible with uuid_t */
+ uuid_from_string(s, (uuid_t *)guid, &status);
+
+ return (status == uuid_s_ok ? 0 : -1);
+}
static void
efi_guid_tbl_compile(void)
{
size_t i;
- uint32_t status;
- static int done = 0;
+ static bool done = false;
+ struct guid_table *ent;
if (done)
return;
for (i = 0; i < nitems(guid_tbl); i++) {
- uuid_from_string(guid_tbl[i].uuid_str, &guid_tbl[i].guid,
- &status);
- /* all f's is a bad version, so ignore that error */
- if (status != uuid_s_ok && status != uuid_s_bad_version)
- fprintf(stderr, "Can't convert %s to a uuid for %s: %d\n",
- guid_tbl[i].uuid_str, guid_tbl[i].name, (int)status);
+ ent = &guid_tbl[i];
+ if (efi_str_to_guid(ent->uuid_str, &ent->guid) != 0)
+ fprintf(stderr, "Can't convert %s to a guid for %s\n",
+ ent->uuid_str, ent->name);
}
- done = 1;
+ done = true;
}
int
-efi_known_guid(struct uuid_table **tbl)
+efi_known_guid(struct guid_table **tbl)
{
*tbl = guid_tbl;
@@ -121,7 +128,7 @@ efi_open_dev(void)
}
static void
-efi_var_reset(struct efi_var_ioc *var)
+efi_var_reset(struct efi_var_ioctl *var)
{
var->name = NULL;
var->namesize = 0;
@@ -162,7 +169,7 @@ int
efi_get_variable(efi_guid_t guid, const char *name,
uint8_t **data, size_t *data_size, uint32_t *attributes)
{
- struct efi_var_ioc var;
+ struct efi_var_ioctl var;
int rv;
static uint8_t buf[1024*32];
@@ -212,7 +219,7 @@ efi_get_variable_size(efi_guid_t guid, const char *name,
int
efi_get_next_variable_name(efi_guid_t **guid, char **name)
{
- struct efi_var_ioc var;
+ struct efi_var_ioctl var;
int rv;
static efi_char *buf;
static size_t buflen = 256 * sizeof(efi_char);
@@ -287,28 +294,23 @@ done:
int
efi_guid_cmp(const efi_guid_t *guid1, const efi_guid_t *guid2)
{
- uint32_t status;
-
- return uuid_compare(guid1, guid2, &status);
+ return (memcmp(guid1, guid2, sizeof(*guid1)));
}
int
efi_guid_is_zero(const efi_guid_t *guid)
{
- uint32_t status;
-
- return uuid_is_nil(guid, &status);
+ return (memcmp(guid, &efi_guid_empty, sizeof(*guid)) == 0);
}
int
efi_guid_to_name(efi_guid_t *guid, char **name)
{
size_t i;
- uint32_t status;
efi_guid_tbl_compile();
for (i = 0; i < nitems(guid_tbl); i++) {
- if (uuid_equal(guid, &guid_tbl[i].guid, &status)) {
+ if (memcmp(guid, &guid_tbl[i].guid, sizeof(*guid)) == 0) {
*name = strdup(guid_tbl[i].name);
return (0);
}
@@ -332,8 +334,8 @@ efi_guid_to_str(const efi_guid_t *guid, char **sp)
{
uint32_t status;
- /* knows efi_guid_t is a typedef of uuid_t */
- uuid_to_string(guid, sp, &status);
+ /* knows efi_guid_t is binary compatible with uuid_t */
+ uuid_to_string((const uuid_t *)guid, sp, &status);
return (status == uuid_s_ok ? 0 : -1);
}
@@ -357,7 +359,7 @@ int
efi_set_variable(efi_guid_t guid, const char *name,
uint8_t *data, size_t data_size, uint32_t attributes)
{
- struct efi_var_ioc var;
+ struct efi_var_ioctl var;
int rv;
if (efi_open_dev() == -1)
@@ -379,17 +381,6 @@ errout:
}
int
-efi_str_to_guid(const char *s, efi_guid_t *guid)
-{
- uint32_t status;
-
- /* knows efi_guid_t is a typedef of uuid_t */
- uuid_from_string(s, guid, &status);
-
- return (status == uuid_s_ok ? 0 : -1);
-}
-
-int
efi_variables_supported(void)
{
diff --git a/lib/libefivar/efivar.h b/lib/libefivar/efivar.h
index 7551205fda38..e159f4cccd3d 100644
--- a/lib/libefivar/efivar.h
+++ b/lib/libefivar/efivar.h
@@ -46,19 +46,14 @@
#endif
-#ifndef _EFIVAR_EFI_GUID_T_DEF
-#define _EFIVAR_EFI_GUID_T_DEF
-typedef uuid_t efi_guid_t;
-#endif
-
#if BYTE_ORDER == LITTLE_ENDIAN
#define EFI_GUID(a, b, c, d, e0, e1, e2, e3, e4, e5) \
- ((efi_guid_t) {(a), (b), (c), (d) >> 8, (d) & 0xff, \
- { (e0), (e1), (e2), (e3), (e4), (e5) }})
+ ((efi_guid_t) {(a), (b), (c), { (d) >> 8, (d) & 0xff, \
+ (e0), (e1), (e2), (e3), (e4), (e5) }})
#else
#define EFI_GUID(a, b, c, d, e0, e1, e2, e3, e4, e5) \
- ((efi_guid_t) {(a), (b), (c), (d) & 0xff, (d) >> 8, \
- { (e0), (e1), (e2), (e3), (e4), (e5) }})
+ ((efi_guid_t) {(a), (b), (c), { (d) & 0xff, (d) >> 8, \
+ (e0), (e1), (e2), (e3), (e4), (e5) }})
#endif
#define EFI_GLOBAL_GUID EFI_GUID(0x8be4df61, 0x93ca, 0x11d2, 0xaa0d, \
@@ -85,14 +80,14 @@ int efi_str_to_guid(const char *s, efi_guid_t *guid);
int efi_variables_supported(void);
/* FreeBSD extensions */
-struct uuid_table
+struct guid_table
{
const char *uuid_str;
const char *name;
efi_guid_t guid;
};
-int efi_known_guid(struct uuid_table **);
+int efi_known_guid(struct guid_table **);
extern const efi_guid_t efi_guid_empty;
diff --git a/lib/libefivar/uefi-dplib.h b/lib/libefivar/uefi-dplib.h
index e801b5f26a81..6f76a9763a34 100644
--- a/lib/libefivar/uefi-dplib.h
+++ b/lib/libefivar/uefi-dplib.h
@@ -547,7 +547,7 @@ AllocateCopyPool(size_t l, const void *p)
}
static inline BOOLEAN
-CompareGuid (const GUID *g1, const GUID *g2)
+CompareGuid (const EFI_GUID *g1, const EFI_GUID *g2)
{
uint32_t ignored_status;
@@ -578,7 +578,7 @@ StrHexToBytes(const char *str, size_t len, uint8_t *buf, size_t buflen)
}
static inline void
-StrToGuid(const char *str, GUID *guid)
+StrToGuid(const char *str, EFI_GUID *guid)
{
uint32_t status;
@@ -599,7 +599,7 @@ WriteUnaligned64(void *ptr, uint64_t val)
* Not to mention it's name.... Also, the error GUID is horrific.
*/
static inline const char *
-guid_str(const GUID *g)
+guid_str(const EFI_GUID *g)
{
static char buf[36 + 1];
char *str = NULL;
@@ -614,7 +614,7 @@ guid_str(const GUID *g)
free(str);
return buf;
}
-#define G(x) guid_str((const GUID *)(const void *)x)
+#define G(x) guid_str((const EFI_GUID *)(const void *)x)
#endif
#undef GLOBAL_REMOVE_IF_UNREFERENCED
diff --git a/lib/libefivar/uefi-dputil.c b/lib/libefivar/uefi-dputil.c
index 7969054e2ce2..6e8f3aeca2ce 100644
--- a/lib/libefivar/uefi-dputil.c
+++ b/lib/libefivar/uefi-dputil.c
@@ -28,7 +28,6 @@
* this file is taken from EDK2 and rototilled.
*/
-#include <sys/cdefs.h>
#include <efivar.h>
#include <limits.h>
#include <stdio.h>
diff --git a/lib/libexpat/expat_config.h b/lib/libexpat/expat_config.h
index 2bb52a4baa03..748f75ee157d 100644
--- a/lib/libexpat/expat_config.h
+++ b/lib/libexpat/expat_config.h
@@ -89,7 +89,7 @@
#define PACKAGE_NAME "expat"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "expat 2.6.4"
+#define PACKAGE_STRING "expat 2.7.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "expat"
@@ -98,7 +98,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "2.6.4"
+#define PACKAGE_VERSION "2.7.1"
/* Define to 1 if all of the C90 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
@@ -106,7 +106,7 @@
#define STDC_HEADERS 1
/* Version number of package */
-#define VERSION "2.6.4"
+#define VERSION "2.7.1"
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
diff --git a/lib/libexpat/libbsdxml.3 b/lib/libexpat/libbsdxml.3
index 21c07d39e5e2..c91184840b70 100644
--- a/lib/libexpat/libbsdxml.3
+++ b/lib/libexpat/libbsdxml.3
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"/
-.Dd December 8, 2024
+.Dd April 7, 2025
.Dt LIBBSDXML 3
.Os
.Sh NAME
@@ -34,7 +34,7 @@
.Sh DESCRIPTION
The
.Nm
-library is a verbatim copy of the eXpat XML library version 2.6.4.
+library is a verbatim copy of the eXpat XML library version 2.7.1.
.Pp
The
.Nm
diff --git a/lib/libgcc_eh/Makefile.inc b/lib/libgcc_eh/Makefile.inc
index af59ee7aaa65..529ef7170485 100644
--- a/lib/libgcc_eh/Makefile.inc
+++ b/lib/libgcc_eh/Makefile.inc
@@ -38,7 +38,6 @@ CFLAGS+= -I${UNWINDINCDIR}
CFLAGS+= -D_LIBUNWIND_IS_NATIVE_ONLY
CFLAGS+= -D_LIBUNWIND_USE_FRAME_HEADER_CACHE
CXXFLAGS+= -fno-rtti
-CXXSTD?= c++11
STATIC_CXXFLAGS+= -fvisibility=hidden -fPIC
# Probably need to just move this earlier or use CXXFLAGS
.if ${MK_DIRDEPS_BUILD} == "yes"
diff --git a/lib/libgcc_s/arm/Symbol.map b/lib/libgcc_s/arm/Symbol.map
index 92b54761d810..ea0189eabaa0 100644
--- a/lib/libgcc_s/arm/Symbol.map
+++ b/lib/libgcc_s/arm/Symbol.map
@@ -2,6 +2,74 @@
*/
GCC_3.5 {
+ __aeabi_cdcmple;
+ __aeabi_cdrcmple;
+ __aeabi_cfcmpeq;
+ __aeabi_cfcmple;
+ __aeabi_cfrcmple;
+ __aeabi_d2f;
+ __aeabi_d2h;
+/* __aeabi_d2h_alt; */
+ __aeabi_d2iz;
+ __aeabi_d2lz;
+ __aeabi_d2uiz;
+ __aeabi_d2ulz;
+ __aeabi_dadd;
+ __aeabi_dcmpeq;
+ __aeabi_dcmpge;
+ __aeabi_dcmpgt;
+ __aeabi_dcmple;
+ __aeabi_dcmplt;
+ __aeabi_dcmpun;
+ __aeabi_ddiv;
+ __aeabi_dmul;
+ __aeabi_dneg;
+ __aeabi_drsub;
+ __aeabi_dsub;
+ __aeabi_f2d;
+ __aeabi_f2h;
+/* __aeabi_f2h_alt; */
+ __aeabi_f2iz;
+ __aeabi_f2lz;
+ __aeabi_f2uiz;
+ __aeabi_f2ulz;
+ __aeabi_fadd;
+ __aeabi_fcmpeq;
+ __aeabi_fcmpge;
+ __aeabi_fcmpgt;
+ __aeabi_fcmple;
+ __aeabi_fcmplt;
+ __aeabi_fcmpun;
+ __aeabi_fdiv;
+ __aeabi_fmul;
+ __aeabi_fneg;
+ __aeabi_frsub;
+ __aeabi_fsub;
+ __aeabi_h2f;
+/* __aeabi_h2f_alt; */
+ __aeabi_i2d;
+ __aeabi_i2f;
+ __aeabi_idiv;
+ __aeabi_idiv0;
+ __aeabi_idivmod;
+ __aeabi_l2d;
+ __aeabi_l2f;
+ __aeabi_lasr;
+ __aeabi_lcmp;
+ __aeabi_ldiv0;
+ __aeabi_ldivmod;
+ __aeabi_llsl;
+ __aeabi_llsr;
+ __aeabi_lmul;
+ __aeabi_ui2d;
+ __aeabi_ui2f;
+ __aeabi_uidiv;
+ __aeabi_uidivmod;
+ __aeabi_ul2d;
+ __aeabi_ul2f;
+ __aeabi_ulcmp;
+ __aeabi_uldivmod;
+
_Unwind_Complete;
_Unwind_VRS_Get;
_Unwind_VRS_Set;
diff --git a/lib/libifconfig/libifconfig.h b/lib/libifconfig/libifconfig.h
index 8d5ca01b0ce6..fc835485a51e 100644
--- a/lib/libifconfig/libifconfig.h
+++ b/lib/libifconfig/libifconfig.h
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <net/if.h>
+#include <net/if_bridgevar.h> /* for ifbvlan_set_t */
#include <netinet/in.h>
#include <netinet/ip_carp.h>
@@ -64,6 +65,7 @@ struct lagg_reqport;
struct ifconfig_bridge_status {
struct ifbropreq *params; /**< current operational parameters */
struct ifbreq *members; /**< list of bridge members */
+ ifbvlan_set_t *member_vlans; /**< bridge member vlan sets */
size_t members_count; /**< how many member interfaces */
uint32_t cache_size; /**< size of address cache */
uint32_t cache_lifetime; /**< address cache entry lifetime */
diff --git a/lib/libifconfig/libifconfig_bridge.c b/lib/libifconfig/libifconfig_bridge.c
index 2a9bbc35858b..b4a920f488c5 100644
--- a/lib/libifconfig/libifconfig_bridge.c
+++ b/lib/libifconfig/libifconfig_bridge.c
@@ -66,40 +66,37 @@ ifconfig_bridge_get_bridge_status(ifconfig_handle_t *h,
{
struct ifbifconf members;
struct ifbrparam cache_param;
- struct _ifconfig_bridge_status *bridge;
- char *buf;
+ struct _ifconfig_bridge_status *bridge = NULL;
+ char *buf = NULL;
+ members.ifbic_buf = NULL;
*bridgep = NULL;
bridge = calloc(1, sizeof(struct _ifconfig_bridge_status));
if (bridge == NULL) {
h->error.errtype = OTHER;
h->error.errcode = ENOMEM;
- return (-1);
+ goto err;
}
bridge->inner.params = &bridge->params;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGGCACHE,
&cache_param, sizeof(cache_param), false) != 0) {
- free(bridge);
- return (-1);
+ goto err;
}
bridge->inner.cache_size = cache_param.ifbrp_csize;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGGTO,
&cache_param, sizeof(cache_param), false) != 0) {
- free(bridge);
- return (-1);
+ goto err;
}
bridge->inner.cache_lifetime = cache_param.ifbrp_ctime;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGPARAM,
&bridge->params, sizeof(bridge->params), false) != 0) {
- free(bridge);
- return (-1);
+ goto err;
}
- members.ifbic_buf = NULL;
for (size_t len = 8192;
(buf = realloc(members.ifbic_buf, len)) != NULL;
len *= 2) {
@@ -107,27 +104,52 @@ ifconfig_bridge_get_bridge_status(ifconfig_handle_t *h,
members.ifbic_len = len;
if (ifconfig_bridge_ioctlwrap(h, name, BRDGGIFS,
&members, sizeof(members), false) != 0) {
- free(buf);
- free(bridge);
- return (-1);
+ goto err;
}
if ((members.ifbic_len + sizeof(*members.ifbic_req)) < len)
break;
}
if (buf == NULL) {
- free(members.ifbic_buf);
- free(bridge);
h->error.errtype = OTHER;
h->error.errcode = ENOMEM;
- return (-1);
+ goto err;
}
bridge->inner.members = members.ifbic_req;
bridge->inner.members_count =
members.ifbic_len / sizeof(*members.ifbic_req);
+ bridge->inner.member_vlans = calloc(bridge->inner.members_count,
+ sizeof(ifbvlan_set_t));
+ if (bridge->inner.member_vlans == NULL) {
+ h->error.errtype = OTHER;
+ h->error.errcode = ENOMEM;
+ goto err;
+ }
+ for (size_t i = 0; i < bridge->inner.members_count; ++i) {
+ struct ifbif_vlan_req vreq;
+ memset(&vreq, 0, sizeof(vreq));
+ strlcpy(vreq.bv_ifname, bridge->inner.members[i].ifbr_ifsname,
+ sizeof(vreq.bv_ifname));
+
+ if (ifconfig_bridge_ioctlwrap(h, name, BRDGGIFVLANSET, &vreq,
+ sizeof(vreq), false) != 0) {
+ goto err;
+ }
+
+ __BIT_COPY(BRVLAN_SETSIZE, &vreq.bv_set,
+ &bridge->inner.member_vlans[i]);
+ }
+
*bridgep = &bridge->inner;
return (0);
+
+err:
+ free(members.ifbic_buf);
+ if (bridge)
+ free(bridge->inner.member_vlans);
+ free(bridge);
+ return (-1);
}
void
diff --git a/lib/libifconfig/libifconfig_sfp.c b/lib/libifconfig/libifconfig_sfp.c
index 8292135d3e47..1ba6d231a992 100644
--- a/lib/libifconfig/libifconfig_sfp.c
+++ b/lib/libifconfig/libifconfig_sfp.c
@@ -24,6 +24,8 @@
* SUCH DAMAGE.
*/
+#define _WANT_SFF_8024_ID
+
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
diff --git a/lib/libiscsiutil/libiscsiutil.h b/lib/libiscsiutil/libiscsiutil.h
index c091c1d9753a..b50afa1c9409 100644
--- a/lib/libiscsiutil/libiscsiutil.h
+++ b/lib/libiscsiutil/libiscsiutil.h
@@ -95,6 +95,8 @@ struct rchap {
size_t rchap_challenge_len;
};
+__BEGIN_DECLS
+
struct chap *chap_new(void);
char *chap_get_id(const struct chap *chap);
char *chap_get_challenge(const struct chap *chap);
@@ -174,4 +176,6 @@ void log_debugx(const char *, ...) __printflike(1, 2);
char *checked_strdup(const char *);
+__END_DECLS
+
#endif /* !__LIBISCSIUTIL_H__ */
diff --git a/lib/libjail/jail.c b/lib/libjail/jail.c
index 8e5b420d677b..30282e67866c 100644
--- a/lib/libjail/jail.c
+++ b/lib/libjail/jail.c
@@ -59,6 +59,7 @@ static int jailparam_type(struct jailparam *jp);
static int kldload_param(const char *name);
static char *noname(const char *name);
static char *nononame(const char *name);
+static char *kvname(const char *name);
char jail_errmsg[JAIL_ERRMSGLEN];
@@ -521,6 +522,11 @@ jailparam_set(struct jailparam *jp, unsigned njp, int flags)
jiov[i - 1].iov_len = strlen(nname) + 1;
}
+ } else if (jp[j].jp_flags & JP_KEYVALUE &&
+ jp[j].jp_value == NULL) {
+ /* No value means key removal. */
+ jiov[i].iov_base = NULL;
+ jiov[i].iov_len = 0;
} else {
/*
* Try to fill in missing values with an empty string.
@@ -907,22 +913,41 @@ jailparam_type(struct jailparam *jp)
* the "no" counterpart to a boolean.
*/
nname = nononame(name);
- if (nname == NULL) {
- unknown_parameter:
- snprintf(jail_errmsg, JAIL_ERRMSGLEN,
- "unknown parameter: %s", jp->jp_name);
- errno = ENOENT;
- return (-1);
+ if (nname != NULL) {
+ snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", nname);
+ miblen = sizeof(mib) - 2 * sizeof(int);
+ if (sysctl(mib, 2, mib + 2, &miblen, desc.s,
+ strlen(desc.s)) >= 0) {
+ name = alloca(strlen(nname) + 1);
+ strcpy(name, nname);
+ free(nname);
+ jp->jp_flags |= JP_NOBOOL;
+ goto mib_desc;
+ }
+ free(nname);
}
- name = alloca(strlen(nname) + 1);
- strcpy(name, nname);
- free(nname);
- snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", name);
- miblen = sizeof(mib) - 2 * sizeof(int);
- if (sysctl(mib, 2, mib + 2, &miblen, desc.s,
- strlen(desc.s)) < 0)
- goto unknown_parameter;
- jp->jp_flags |= JP_NOBOOL;
+ /*
+ * It might be an assumed sub-node of a fmt='A,keyvalue' sysctl.
+ */
+ nname = kvname(name);
+ if (nname != NULL) {
+ snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", nname);
+ miblen = sizeof(mib) - 2 * sizeof(int);
+ if (sysctl(mib, 2, mib + 2, &miblen, desc.s,
+ strlen(desc.s)) >= 0) {
+ name = alloca(strlen(nname) + 1);
+ strcpy(name, nname);
+ free(nname);
+ jp->jp_flags |= JP_KEYVALUE;
+ goto mib_desc;
+ }
+ free(nname);
+ }
+unknown_parameter:
+ snprintf(jail_errmsg, JAIL_ERRMSGLEN,
+ "unknown parameter: %s", jp->jp_name);
+ errno = ENOENT;
+ return (-1);
}
mib_desc:
mib[1] = 4;
@@ -943,6 +968,12 @@ jailparam_type(struct jailparam *jp)
else if ((desc.i & CTLTYPE) != CTLTYPE_NODE)
goto unknown_parameter;
}
+ /* Make sure it is a valid keyvalue param. */
+ if (jp->jp_flags & JP_KEYVALUE) {
+ if ((desc.i & CTLTYPE) != CTLTYPE_STRING ||
+ strcmp(desc.s, "A,keyvalue") != 0)
+ goto unknown_parameter;
+ }
/* See if this is an array type. */
p = strchr(desc.s, '\0');
isarray = 0;
@@ -1119,3 +1150,26 @@ nononame(const char *name)
strcpy(nname, name + 2);
return (nname);
}
+
+static char *
+kvname(const char *name)
+{
+ const char *p;
+ char *kvname;
+ size_t len;
+
+ p = strchr(name, '.');
+ if (p == NULL)
+ return (NULL);
+
+ len = p - name;
+ kvname = malloc(len + 1);
+ if (kvname == NULL) {
+ strerror_r(errno, jail_errmsg, JAIL_ERRMSGLEN);
+ return (NULL);
+ }
+ strncpy(kvname, name, len);
+ kvname[len] = '\0';
+
+ return (kvname);
+}
diff --git a/lib/libjail/jail.h b/lib/libjail/jail.h
index 27f07cd98802..6ce79b1b0528 100644
--- a/lib/libjail/jail.h
+++ b/lib/libjail/jail.h
@@ -33,6 +33,7 @@
#define JP_BOOL 0x02
#define JP_NOBOOL 0x04
#define JP_JAILSYS 0x08
+#define JP_KEYVALUE 0x10
#define JAIL_ERRMSGLEN 1024
diff --git a/lib/libkvm/kvm_amd64.c b/lib/libkvm/kvm_amd64.c
index e3640cf12243..acc7ac017a3c 100644
--- a/lib/libkvm/kvm_amd64.c
+++ b/lib/libkvm/kvm_amd64.c
@@ -109,8 +109,9 @@ _amd64_initvtop(kvm_t *kd)
{
struct kvm_nlist nl[2];
amd64_physaddr_t pa;
- kvaddr_t kernbase;
+ kvaddr_t kernbase, kernphys;
amd64_pml4e_t *PML4;
+ int found = 0;
kd->vmst = (struct vmstate *)_kvm_malloc(kd, sizeof(*kd->vmst));
if (kd->vmst == NULL) {
@@ -123,16 +124,43 @@ _amd64_initvtop(kvm_t *kd)
if (_kvm_read_core_phdrs(kd, &kd->vmst->phnum,
&kd->vmst->phdr) == -1)
return (-1);
+
+ for (size_t i = 0; i < kd->vmst->phnum; i++) {
+ if (kd->vmst->phdr[i].p_type == PT_DUMP_DELTA) {
+ /* Account for the 2M hole at KERNBASE. */
+ kernphys = kd->vmst->phdr[i].p_paddr -
+ kd->vmst->phdr[i].p_align;
+ kernbase = kd->vmst->phdr[i].p_vaddr;
+
+ found = 1;
+ break;
+ }
+ }
}
- nl[0].n_name = "kernbase";
- nl[1].n_name = 0;
+ if (found == 0) {
+ nl[0].n_name = "kernbase";
+ nl[1].n_name = 0;
- if (kvm_nlist2(kd, nl) != 0) {
- _kvm_err(kd, kd->program, "bad namelist - no kernbase");
- return (-1);
+ if (kvm_nlist2(kd, nl) != 0) {
+ _kvm_err(kd, kd->program, "bad namelist - no kernbase");
+ return (-1);
+ }
+
+ nl[0].n_name = "kernphys";
+ nl[1].n_name = 0;
+
+ /* XXX
+ * Relocatable kernels can still be loaded at 2M.
+ */
+ if (kvm_nlist2(kd, nl) != 1) {
+ _kvm_err(kd, kd->program, "cannot determine kernphys");
+ return (-1);
+ }
+
+ kernphys = 0;
+ kernbase = nl[0].n_value;
}
- kernbase = nl[0].n_value;
nl[0].n_name = "KPML4phys";
nl[1].n_name = 0;
@@ -141,8 +169,8 @@ _amd64_initvtop(kvm_t *kd)
_kvm_err(kd, kd->program, "bad namelist - no KPML4phys");
return (-1);
}
- if (kvm_read2(kd, (nl[0].n_value - kernbase), &pa, sizeof(pa)) !=
- sizeof(pa)) {
+ if (kvm_read2(kd, (nl[0].n_value - kernbase + kernphys), &pa,
+ sizeof(pa)) != sizeof(pa)) {
_kvm_err(kd, kd->program, "cannot read KPML4phys");
return (-1);
}
diff --git a/lib/libkvm/kvm_open.3 b/lib/libkvm/kvm_open.3
index a7e428748215..9a32719d537b 100644
--- a/lib/libkvm/kvm_open.3
+++ b/lib/libkvm/kvm_open.3
@@ -29,7 +29,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 20, 2017
+.Dd June 22, 2025
.Dt KVM_OPEN 3
.Os
.Sh NAME
@@ -245,7 +245,20 @@ The value passed via
was
.Dv NULL .
.El
+.Sh NOTE
+Full memory dumps taken on 13.x (excluding 13.0) and 14.x amd64 kernels
+will cause both
+.Fn kvm_open
+and
+.Fn kvm_open2
+to fail since they do not provide sufficient information to figure out
+where in physical memory the kernel was loaded.
+Full memory dumps have to be explicitly enabled by setting the
+.Va debug.minidump
+.Xr sysctl 8
+to 0.
.Sh SEE ALSO
+.Xr dumpon 8 ,
.Xr close 2 ,
.Xr open 2 ,
.Xr kvm 3 ,
diff --git a/lib/liblutok/Makefile b/lib/liblutok/Makefile
index abb6ecd13ad4..08737afbb61a 100644
--- a/lib/liblutok/Makefile
+++ b/lib/liblutok/Makefile
@@ -18,8 +18,4 @@ CFLAGS+= -I${SRCTOP}/contrib/lutok/include \
WARNS?= 3
SHLIB_MAJOR= 0
-# lutok uses auto_ptr
-CFLAGS+= -Wno-deprecated-declarations
-CXXSTD= c++11
-
.include <bsd.lib.mk>
diff --git a/lib/liblzma/Makefile b/lib/liblzma/Makefile
index 9f8ac443a8fc..27e0521f5884 100644
--- a/lib/liblzma/Makefile
+++ b/lib/liblzma/Makefile
@@ -80,16 +80,13 @@ SRCS+= common.c \
.PATH: ${LZMADIR}/check
-SRCS+= check.c \
- crc32_table.c \
- crc64_table.c
+SRCS+= check.c \
+ crc32_fast.c \
+ crc64_fast.c
.if defined(MACHINE_ARCH) && ${MACHINE_ARCH} == "i386"
SRCS+= crc32_x86.S \
crc64_x86.S
ACFLAGS+= -Wa,--noexecstack
-.else
-SRCS+= crc32_fast.c \
- crc64_fast.c
.endif
.PATH: ${LZMADIR}/lz
diff --git a/lib/liblzma/Symbol.map b/lib/liblzma/Symbol.map
index 938b6191b4f4..0976e26a3c8d 100644
--- a/lib/liblzma/Symbol.map
+++ b/lib/liblzma/Symbol.map
@@ -118,6 +118,15 @@ XZ_5.6 {
lzma_mt_block_size;
};
+XZ_5.8 {
+ lzma_bcj_arm64_encode;
+ lzma_bcj_arm64_decode;
+ lzma_bcj_riscv_encode;
+ lzma_bcj_riscv_decode;
+ lzma_bcj_x86_encode;
+ lzma_bcj_x86_decode;
+};
+
XZprivate_1.0 {
lzma_alloc;
lzma_alloc_zero;
diff --git a/lib/liblzma/Versions.def b/lib/liblzma/Versions.def
index 25064d9d50e7..555ef25c8801 100644
--- a/lib/liblzma/Versions.def
+++ b/lib/liblzma/Versions.def
@@ -11,6 +11,9 @@ XZ_5.4 {
XZ_5.6 {
} XZ_5.4;
-XZprivate_1.0 {
+XZ_5.8 {
} XZ_5.6;
+XZprivate_1.0 {
+} XZ_5.8;
+
diff --git a/lib/liblzma/config.h b/lib/liblzma/config.h
index 3e51b0b92463..963d08c93e7a 100644
--- a/lib/liblzma/config.h
+++ b/lib/liblzma/config.h
@@ -68,6 +68,12 @@
/* Define to 1 if you have the <cpuid.h> header file. */
#define HAVE_CPUID_H 1
+/* Define to 1 if the 32-bit x86 CRC assembly files are used. */
+/* FreeBSD - only enabled for i386 */
+#if defined(__FreeBSD__) && defined(__i386__)
+#define HAVE_CRC_X86_ASM 1
+#endif
+
/* Define if the GNU dcgettext() function is already present or preinstalled.
*/
/* FreeBSD - disabled intentionally */
@@ -193,6 +199,9 @@
*/
/* #undef HAVE_LINUX_LANDLOCK */
+/* Define to 1 if 64-bit LoongArch CRC32 instructions are supported. */
+/* #undef HAVE_LOONGARCH_CRC32 */
+
/* Define to 1 if .lz (lzip) decompression support is enabled. */
#define HAVE_LZIP_DECODER 1
@@ -335,6 +344,9 @@
/* Define to 1 if you have the 'utimes' function. */
/* #undef HAVE_UTIMES */
+/* Define to 1 if you have the 'vasprintf' function. */
+#define HAVE_VASPRINTF 1
+
/* Define to 1 or 0, depending whether the compiler supports simple visibility
declarations. */
#define HAVE_VISIBILITY 1
@@ -391,7 +403,7 @@
#define PACKAGE_NAME "XZ Utils"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "XZ Utils 5.6.3"
+#define PACKAGE_STRING "XZ Utils 5.8.1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "xz"
@@ -400,7 +412,7 @@
#define PACKAGE_URL "https://tukaani.org/xz/"
/* Define to the version of this package. */
-#define PACKAGE_VERSION "5.6.3"
+#define PACKAGE_VERSION "5.8.1"
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
@@ -565,7 +577,7 @@
/* Version number of package */
-#define VERSION "5.6.3"
+#define VERSION "5.8.1"
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */
diff --git a/lib/libmd/Makefile b/lib/libmd/Makefile
index d8c32063d6ce..547a134fc440 100644
--- a/lib/libmd/Makefile
+++ b/lib/libmd/Makefile
@@ -117,9 +117,12 @@ USE_ASM_SOURCES:=0
.endif
.if ${USE_ASM_SOURCES} != 0
-.if exists(${MACHINE_ARCH}/sha.S)
-SRCS+= sha.S
+.if exists(${MACHINE_ARCH}/sha1block.S)
+SRCS+= sha1block.S
CFLAGS+= -DSHA1_ASM
+.if exists(${MACHINE_ARCH}/sha1dispatch.c)
+SRCS+= sha1dispatch.c
+.endif
.endif
.if exists(${MACHINE_ARCH}/rmd160.S)
SRCS+= rmd160.S
@@ -135,7 +138,7 @@ CFLAGS+= -DSKEIN_ASM -DSKEIN_USE_ASM=1792 # list of block functions to replace w
# the assembly vs C versions, and skein_block needs to be rebuilt if it changes.
skein_block.o skein_block.pico: Makefile
.endif
-.if exists(${MACHINE_ARCH}/sha.S) || exists(${MACHINE_ARCH}/rmd160.S) || exists(${MACHINE_ARCH}/skein_block_asm.S)
+.if exists(${MACHINE_ARCH}/rmd160.S) || exists(${MACHINE_ARCH}/skein_block_asm.S)
ACFLAGS+= -DELF -Wa,--noexecstack
.endif
.if ${MACHINE_CPUARCH} == "aarch64"
diff --git a/lib/libmd/aarch64/sha1block.S b/lib/libmd/aarch64/sha1block.S
new file mode 100644
index 000000000000..56a0297efadd
--- /dev/null
+++ b/lib/libmd/aarch64/sha1block.S
@@ -0,0 +1,490 @@
+/*-
+ * Copyright (c) 2024 Robert Clausecker <fuz@freebsd.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * sha1block_sha1 implementation based on sha1-arm.c,
+ * written and placed in public domain by Jeffrey Walton
+ * based on code from ARM, and by Johannes Schneiders, Skip
+ * Hovsmith and Barry O'Rourke for the mbedTLS project.
+ */
+
+#include <machine/asm.h>
+
+/*
+ * Scalar SHA1 implementation.
+ *
+ * Due to the ample register file available on AArch64, the w array is
+ * kept entirely in registers. The saved a-e variables are instead kept
+ * in memory as we don't have that much memory.
+ */
+
+ // sha1block(SHA1_CTX, buf, len)
+ENTRY(_libmd_sha1block_scalar)
+ctx .req x0
+buf .req x1
+len .req x2
+w .req sp
+a .req w3
+b .req w4
+c .req w5
+d .req w6
+e .req w7
+k .req w8
+f .req w9
+tmp .req w10
+w_0 .req w11
+w_1 .req w12
+w_2 .req w13
+w_3 .req w14
+w_4 .req w15
+w_5 .req w16
+w_6 .req w17
+// w18 is the platform register
+w_7 .req w19
+w_8 .req w20
+w_9 .req w21
+w_10 .req w22
+w_11 .req w23
+w_12 .req w24
+w_13 .req w25
+w_14 .req w26
+w_15 .req w27
+
+.macro shuffle w_i, w_i3, w_i8, w_i14
+ eor \w_i, \w_i, \w_i3
+ eor tmp, \w_i8, \w_i14
+ eor \w_i, \w_i, tmp // w[i-16] ^ w[i-14] ^ w[i-8] ^ w[i-3]
+ ror \w_i, \w_i, #31 // w[i] = ... ror #31
+.endm
+
+.macro func1 a, b, c, d, e
+ and f, \c, \b
+ bic tmp, \d, \b
+ orr f, f, tmp
+.endm
+
+.macro func2 a, b, c, d, e
+ eor f, \b, \c
+ eor f, f, \d
+.endm
+
+.macro func3 a, b, c, d, e
+ eor tmp, \b, \c
+ and f, \b, \c
+ and tmp, tmp, \d
+ orr f, f, tmp
+.endm
+
+.macro func4 a, b, c, d, e
+ func2 \a, \b, \c, \d, \e
+.endm
+
+.macro mix a, b, c, d, e, w_i
+ ror \b, \b, #2
+ ror tmp, \a, #27
+ add \e, \e, \w_i
+ add tmp, tmp, k
+ add \e, \e, f
+ add \e, \e, tmp // (a ror 27) + e + f + k + w[i]
+.endm
+
+.macro round1 a, b, c, d, e, w_i
+ func1 \a, \b, \c, \d, \e
+ rev \w_i, \w_i
+ mix \a, \b, \c, \d, \e, \w_i
+.endm
+
+.macro round func, a, b, c, d, e, w_i, w_i3, w_i8, w_i14
+ shuffle \w_i, \w_i3, \w_i8, \w_i14
+ \func \a, \b, \c, \d, \e
+ mix \a, \b, \c, \d, \e, \w_i
+.endm
+
+.macro round1x a, b, c, d, e, w_i, w_i3, w_i8, w_i14
+ round func1, \a, \b, \c, \d, \e, \w_i, \w_i3, \w_i8, \w_i14
+.endm
+
+.macro round2 a, b, c, d, e, w_i, w_i3, w_i8, w_i14
+ round func2, \a, \b, \c, \d, \e, \w_i, \w_i3, \w_i8, \w_i14
+.endm
+
+.macro round3 a, b, c, d, e, w_i, w_i3, w_i8, w_i14
+ round func3, \a, \b, \c, \d, \e, \w_i, \w_i3, \w_i8, \w_i14
+.endm
+
+.macro round4 a, b, c, d, e, w_i, w_i3, w_i8, w_i14
+ round func4, \a, \b, \c, \d, \e, \w_i, \w_i3, \w_i8, \w_i14
+.endm
+
+ ands len, len, #~63 // take length in multiples of block length
+ beq 1f // bail out if input empty
+
+ sub sp, sp, #24+9*8 // allocate stack space
+ str x19, [sp, #24+0*8]
+ stp x20, x21, [sp, #24+1*8]
+ stp x22, x23, [sp, #24+3*8]
+ stp x24, x25, [sp, #24+5*8]
+ stp x26, x27, [sp, #24+7*8]
+
+ ldp a, b, [ctx, #0] // load SHA1 state from context
+ ldp c, d, [ctx, #8]
+ ldr e, [ctx, #16]
+
+0: stp a, b, [sp, #0] // save old SHA1 state
+ stp c, d, [sp, #8]
+ str e, [sp, #16]
+
+ movz k, #0x7999 // round constant 1
+ movk k, #0x5a82, lsl #16
+
+ ldp w_0, w_1, [buf, #0*4]
+ round1 a, b, c, d, e, w_0
+ round1 e, a, b, c, d, w_1
+
+ ldp w_2, w_3, [buf, #2*4]
+ round1 d, e, a, b, c, w_2
+ round1 c, d, e, a, b, w_3
+
+ ldp w_4, w_5, [buf, #4*4]
+ round1 b, c, d, e, a, w_4
+ round1 a, b, c, d, e, w_5
+
+ ldp w_6, w_7, [buf, #6*4]
+ round1 e, a, b, c, d, w_6
+ round1 d, e, a, b, c, w_7
+
+ ldp w_8, w_9, [buf, #8*4]
+ round1 c, d, e, a, b, w_8
+ round1 b, c, d, e, a, w_9
+
+ ldp w_10, w_11, [buf, #10*4]
+ round1 a, b, c, d, e, w_10
+ round1 e, a, b, c, d, w_11
+
+ ldp w_12, w_13, [buf, #12*4]
+ round1 d, e, a, b, c, w_12
+ round1 c, d, e, a, b, w_13
+
+ ldp w_14, w_15, [buf, #14*4]
+ round1 b, c, d, e, a, w_14
+ round1 a, b, c, d, e, w_15
+
+ round1x e, a, b, c, d, w_0, w_13, w_8, w_2
+ round1x d, e, a, b, c, w_1, w_14, w_9, w_3
+ round1x c, d, e, a, b, w_2, w_15, w_10, w_4
+ round1x b, c, d, e, a, w_3, w_0, w_11, w_5
+
+ movz k, #0xeba1 // round constant 2
+ movk k, #0x6ed9, lsl #16
+
+ round2 a, b, c, d, e, w_4, w_1, w_12, w_6
+ round2 e, a, b, c, d, w_5, w_2, w_13, w_7
+ round2 d, e, a, b, c, w_6, w_3, w_14, w_8
+ round2 c, d, e, a, b, w_7, w_4, w_15, w_9
+ round2 b, c, d, e, a, w_8, w_5, w_0, w_10
+
+ round2 a, b, c, d, e, w_9, w_6, w_1, w_11
+ round2 e, a, b, c, d, w_10, w_7, w_2, w_12
+ round2 d, e, a, b, c, w_11, w_8, w_3, w_13
+ round2 c, d, e, a, b, w_12, w_9, w_4, w_14
+ round2 b, c, d, e, a, w_13, w_10, w_5, w_15
+
+ round2 a, b, c, d, e, w_14, w_11, w_6, w_0
+ round2 e, a, b, c, d, w_15, w_12, w_7, w_1
+ round2 d, e, a, b, c, w_0, w_13, w_8, w_2
+ round2 c, d, e, a, b, w_1, w_14, w_9, w_3
+ round2 b, c, d, e, a, w_2, w_15, w_10, w_4
+
+ round2 a, b, c, d, e, w_3, w_0, w_11, w_5
+ round2 e, a, b, c, d, w_4, w_1, w_12, w_6
+ round2 d, e, a, b, c, w_5, w_2, w_13, w_7
+ round2 c, d, e, a, b, w_6, w_3, w_14, w_8
+ round2 b, c, d, e, a, w_7, w_4, w_15, w_9
+
+ movz k, #0xbcdc // round constant 3
+ movk k, #0x8f1b, lsl #16
+
+ round3 a, b, c, d, e, w_8, w_5, w_0, w_10
+ round3 e, a, b, c, d, w_9, w_6, w_1, w_11
+ round3 d, e, a, b, c, w_10, w_7, w_2, w_12
+ round3 c, d, e, a, b, w_11, w_8, w_3, w_13
+ round3 b, c, d, e, a, w_12, w_9, w_4, w_14
+
+ round3 a, b, c, d, e, w_13, w_10, w_5, w_15
+ round3 e, a, b, c, d, w_14, w_11, w_6, w_0
+ round3 d, e, a, b, c, w_15, w_12, w_7, w_1
+ round3 c, d, e, a, b, w_0, w_13, w_8, w_2
+ round3 b, c, d, e, a, w_1, w_14, w_9, w_3
+
+ round3 a, b, c, d, e, w_2, w_15, w_10, w_4
+ round3 e, a, b, c, d, w_3, w_0, w_11, w_5
+ round3 d, e, a, b, c, w_4, w_1, w_12, w_6
+ round3 c, d, e, a, b, w_5, w_2, w_13, w_7
+ round3 b, c, d, e, a, w_6, w_3, w_14, w_8
+
+ round3 a, b, c, d, e, w_7, w_4, w_15, w_9
+ round3 e, a, b, c, d, w_8, w_5, w_0, w_10
+ round3 d, e, a, b, c, w_9, w_6, w_1, w_11
+ round3 c, d, e, a, b, w_10, w_7, w_2, w_12
+ round3 b, c, d, e, a, w_11, w_8, w_3, w_13
+
+ movz k, #0xc1d6 // round constant 4
+ movk k, #0xca62, lsl #16
+
+ round4 a, b, c, d, e, w_12, w_9, w_4, w_14
+ round4 e, a, b, c, d, w_13, w_10, w_5, w_15
+ round4 d, e, a, b, c, w_14, w_11, w_6, w_0
+ round4 c, d, e, a, b, w_15, w_12, w_7, w_1
+ round4 b, c, d, e, a, w_0, w_13, w_8, w_2
+
+ round4 a, b, c, d, e, w_1, w_14, w_9, w_3
+ round4 e, a, b, c, d, w_2, w_15, w_10, w_4
+ round4 d, e, a, b, c, w_3, w_0, w_11, w_5
+ round4 c, d, e, a, b, w_4, w_1, w_12, w_6
+ round4 b, c, d, e, a, w_5, w_2, w_13, w_7
+
+ round4 a, b, c, d, e, w_6, w_3, w_14, w_8
+ round4 e, a, b, c, d, w_7, w_4, w_15, w_9
+ round4 d, e, a, b, c, w_8, w_5, w_0, w_10
+ round4 c, d, e, a, b, w_9, w_6, w_1, w_11
+ round4 b, c, d, e, a, w_10, w_7, w_2, w_12
+
+ round4 a, b, c, d, e, w_11, w_8, w_3, w_13
+ round4 e, a, b, c, d, w_12, w_9, w_4, w_14
+ round4 d, e, a, b, c, w_13, w_10, w_5, w_15
+ round4 c, d, e, a, b, w_14, w_11, w_6, w_0
+ round4 b, c, d, e, a, w_15, w_12, w_7, w_1
+
+ ldp w_0, w_1, [sp, #0] // reload saved SHA1 state
+ ldp w_2, w_3, [sp, #8]
+ ldr w_4, [sp, #16]
+
+ add a, a, w_0
+ add b, b, w_1
+ add c, c, w_2
+ add d, d, w_3
+ add e, e, w_4
+
+ add buf, buf, #64
+ subs len, len, #64
+ bhi 0b
+
+ stp a, b, [ctx, #0] // write updated SHA1 state
+ stp c, d, [ctx, #8]
+ str e, [ctx, #16]
+
+ ldr x19, [sp, #24+0*8]
+ ldp x20, x21, [sp, #24+1*8]
+ ldp x22, x23, [sp, #24+3*8]
+ ldp x24, x25, [sp, #24+5*8]
+ ldp x26, x27, [sp, #24+7*8]
+ add sp, sp, #24+9*8
+
+1: ret
+END(_libmd_sha1block_scalar)
+
+/*
+ * SHA1 implementation using the SHA1 instruction set extension.
+ */
+
+ .arch_extension sha2
+
+ // sha1block(SHA1_CTX, buf, len)
+ENTRY(_libmd_sha1block_sha1)
+ /* ctx, buf, len: same as for sha1block_scalar */
+kaddr .req x3
+abcd .req v0
+abcd_q .req q0 // alias for use with scalar instructions
+abcd_s .req s0
+e0 .req s1
+e0_v .req v1
+e1 .req s2
+abcd_saved .req v3
+e0_saved .req v4
+tmp0 .req v5
+tmp1 .req v6
+msg0 .req v16
+msg1 .req v17
+msg2 .req v18
+msg3 .req v19
+k0 .req v20
+k1 .req v21
+k2 .req v22
+k3 .req v23
+
+ ands len, len, #~63 // take length in multiples of block length
+ beq 1f // bail out if input empty
+
+ ldr abcd_q, [ctx, #0]
+ ldr e0, [ctx, #16]
+
+ adrp kaddr, k1234
+ add kaddr, kaddr, #:lo12:k1234
+ ld4r {k0.4s, k1.4s, k2.4s, k3.4s}, [kaddr]
+
+0: mov abcd_saved.16b, abcd.16b
+ mov e0_saved.16b, e0_v.16b
+
+ ld1 {msg0.4s, msg1.4s, msg2.4s, msg3.4s}, [buf], #64
+ rev32 msg0.16b, msg0.16b
+ rev32 msg1.16b, msg1.16b
+ rev32 msg2.16b, msg2.16b
+ rev32 msg3.16b, msg3.16b
+
+ add tmp0.4s, msg0.4s, k0.4s
+ add tmp1.4s, msg1.4s, k0.4s
+
+ /* rounds 0--3 */
+ sha1h e1, abcd_s
+ sha1c abcd_q, e0, tmp0.4s
+ add tmp0.4s, msg2.4s, k0.4s
+ sha1su0 msg0.4s, msg1.4s, msg2.4s
+
+ /* rounds 4--7 */
+ sha1h e0, abcd_s
+ sha1c abcd_q, e1, tmp1.4s
+ add tmp1.4s, msg3.4s, k0.4s
+ sha1su1 msg0.4s, msg3.4s
+ sha1su0 msg1.4s, msg2.4s, msg3.4s
+
+ /* rounds 8--11 */
+ sha1h e1, abcd_s
+ sha1c abcd_q, e0, tmp0.4s
+ add tmp0.4s, msg0.4s, k0.4s
+ sha1su1 msg1.4s, msg0.4s
+ sha1su0 msg2.4s, msg3.4s, msg0.4s
+
+ /* rounds 12--15 */
+ sha1h e0, abcd_s
+ sha1c abcd_q, e1, tmp1.4s
+ add tmp1.4s, msg1.4s, k1.4s
+ sha1su1 msg2.4s, msg1.4s
+ sha1su0 msg3.4s, msg0.4s, msg1.4s
+
+ /* rounds 16--19 */
+ sha1h e1, abcd_s
+ sha1c abcd_q, e0, tmp0.4s
+ add tmp0.4s, msg2.4s, k1.4s
+ sha1su1 msg3.4s, msg2.4s
+ sha1su0 msg0.4s, msg1.4s, msg2.4s
+
+ /* rounds 20--23 */
+ sha1h e0, abcd_s
+ sha1p abcd_q, e1, tmp1.4s
+ add tmp1.4s, msg3.4s, k1.4s
+ sha1su1 msg0.4s, msg3.4s
+ sha1su0 msg1.4s, msg2.4s, msg3.4s
+
+ /* rounds 24--27 */
+ sha1h e1, abcd_s
+ sha1p abcd_q, e0, tmp0.4s
+ add tmp0.4s, msg0.4s, k1.4s
+ sha1su1 msg1.4s, msg0.4s
+ sha1su0 msg2.4s, msg3.4s, msg0.4s
+
+ /* rounds 28--31 */
+ sha1h e0, abcd_s
+ sha1p abcd_q, e1, tmp1.4s
+ add tmp1.4s, msg1.4s, k1.4s
+ sha1su1 msg2.4s, msg1.4s
+ sha1su0 msg3.4s, msg0.4s, msg1.4s
+
+ /* rounds 32--35 */
+ sha1h e1, abcd_s
+ sha1p abcd_q, e0, tmp0.4s
+ add tmp0.4s, msg2.4s, k2.4s
+ sha1su1 msg3.4s, msg2.4s
+ sha1su0 msg0.4s, msg1.4s, msg2.4s
+
+ /* rounds 36--39 */
+ sha1h e0, abcd_s
+ sha1p abcd_q, e1, tmp1.4s
+ add tmp1.4s, msg3.4s, k2.4s
+ sha1su1 msg0.4s, msg3.4s
+ sha1su0 msg1.4s, msg2.4s, msg3.4s
+
+ /* rounds 40--43 */
+ sha1h e1, abcd_s
+ sha1m abcd_q, e0, tmp0.4s
+ add tmp0.4s, msg0.4s, k2.4s
+ sha1su1 msg1.4s, msg0.4s
+ sha1su0 msg2.4s, msg3.4s, msg0.4s
+
+ /* rounds 44--47 */
+ sha1h e0, abcd_s
+ sha1m abcd_q, e1, tmp1.4s
+ add tmp1.4s, msg1.4s, k2.4s
+ sha1su1 msg2.4s, msg1.4s
+ sha1su0 msg3.4s, msg0.4s, msg1.4s
+
+ /* rounds 48--51 */
+ sha1h e1, abcd_s
+ sha1m abcd_q, e0, tmp0.4s
+ add tmp0.4s, msg2.4s, k2.4s
+ sha1su1 msg3.4s, msg2.4s
+ sha1su0 msg0.4s, msg1.4s, msg2.4s
+
+ /* rounds 52--55 */
+ sha1h e0, abcd_s
+ sha1m abcd_q, e1, tmp1.4s
+ add tmp1.4s, msg3.4s, k3.4s
+ sha1su1 msg0.4s, msg3.4s
+ sha1su0 msg1.4s, msg2.4s, msg3.4s
+
+ /* rounds 56--59 */
+ sha1h e1, abcd_s
+ sha1m abcd_q, e0, tmp0.4s
+ add tmp0.4s, msg0.4s, k3.4s
+ sha1su1 msg1.4s, msg0.4s
+ sha1su0 msg2.4s, msg3.4s, msg0.4s
+
+ /* rounds 60--63 */
+ sha1h e0, abcd_s
+ sha1p abcd_q, e1, tmp1.4s
+ add tmp1.4s, msg1.4s, k3.4s
+ sha1su1 msg2.4s, msg1.4s
+ sha1su0 msg3.4s, msg0.4s, msg1.4s
+
+ /* rounds 64--67 */
+ sha1h e1, abcd_s
+ sha1p abcd_q, e0, tmp0.4s
+ add tmp0.4s, msg2.4s, k3.4s
+ sha1su1 msg3.4s, msg2.4s
+ sha1su0 msg0.4s, msg1.4s, msg2.4s
+
+ /* rounds 68--71 */
+ sha1h e0, abcd_s
+ sha1p abcd_q, e1, tmp1.4s
+ add tmp1.4s, msg3.4s, k3.4s
+ sha1su1 msg0.4s, msg3.4s
+
+ /* rounds 72--75 */
+ sha1h e1, abcd_s
+ sha1p abcd_q, e0, tmp0.4s
+
+ /* rounds 76--79 */
+ sha1h e0, abcd_s
+ sha1p abcd_q, e1, tmp1.4s
+
+ add e0_v.4s, e0_v.4s, e0_saved.4s
+ add abcd.4s, abcd.4s, abcd_saved.4s
+
+ subs len, len, #64
+ bhi 0b
+
+ str abcd_q, [ctx, #0]
+ str e0, [ctx, #16]
+
+1: ret
+END(_libmd_sha1block_sha1)
+
+ .section .rodata
+ .balign 16
+k1234: .4byte 0x5a827999
+ .4byte 0x6ed9eba1
+ .4byte 0x8f1bbcdc
+ .4byte 0xca62c1d6
+ .size k1234, .-k1234
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libmd/aarch64/sha1dispatch.c b/lib/libmd/aarch64/sha1dispatch.c
new file mode 100644
index 000000000000..e34bf0a1a344
--- /dev/null
+++ b/lib/libmd/aarch64/sha1dispatch.c
@@ -0,0 +1,24 @@
+/*-
+ * Copyright (c) 2024 Robert Clausecker <fuz@freebsd.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <machine/ifunc.h>
+#include <sha.h>
+#include <sys/auxv.h>
+
+extern void _libmd_sha1block_scalar(SHA1_CTX *, const void *, size_t);
+extern void _libmd_sha1block_sha1(SHA1_CTX *, const void *, size_t);
+
+DEFINE_IFUNC(, void, sha1_block, (SHA1_CTX *, const void *, size_t))
+{
+ unsigned long hwcap = 0;
+
+ elf_aux_info(AT_HWCAP, &hwcap, sizeof(hwcap));
+
+ if (hwcap & HWCAP_SHA1)
+ return (_libmd_sha1block_sha1);
+ else
+ return (_libmd_sha1block_scalar);
+}
diff --git a/lib/libmd/amd64/sha1block.S b/lib/libmd/amd64/sha1block.S
new file mode 100644
index 000000000000..f1291ef2647a
--- /dev/null
+++ b/lib/libmd/amd64/sha1block.S
@@ -0,0 +1,1851 @@
+/*-
+ * Copyright (c) 2013 The Go Authors. All rights reserved.
+ * Copyright (c) 2024 Robert Clausecker <fuz@freebsd.org>
+ *
+ * Adapted from Go's crypto/sha1/sha1block_amd64.s.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+
+/*
+ * SHA-1 block routine. See sha1c.c for C equivalent.
+ *
+ * There are 80 rounds of 4 types:
+ * - rounds 0-15 are type 1 and load data (round1 macro).
+ * - rounds 16-19 are type 1 and do not load data (round1x macro).
+ * - rounds 20-39 are type 2 and do not load data (round2 macro).
+ * - rounds 40-59 are type 3 and do not load data (round3 macro).
+ * - rounds 60-79 are type 4 and do not load data (round4 macro).
+ *
+ * Each round loads or shuffles the data, then computes a per-round
+ * function of b, c, d, and then mixes the result into and rotates the
+ * five registers a, b, c, d, e holding the intermediate results.
+ *
+ * The register rotation is implemented by rotating the arguments to
+ * the round macros instead of by explicit move instructions.
+ */
+.macro load index
+ mov (\index)*4(%rsi), %r10d
+ bswap %r10d
+ mov %r10d, (\index)*4(%rsp)
+.endm
+
+.macro shuffle index
+ mov ((\index )&0xf)*4(%rsp), %r10d
+ xor ((\index- 3)&0xf)*4(%rsp), %r10d
+ xor ((\index- 8)&0xf)*4(%rsp), %r10d
+ xor ((\index-14)&0xf)*4(%rsp), %r10d
+ rol $1, %r10d
+ mov %r10d, ((\index)&0xf)*4(%rsp)
+.endm
+
+.macro func1 a, b, c, d, e
+ mov \d, %r9d
+ xor \c, %r9d
+ and \b, %r9d
+ xor \d, %r9d
+.endm
+
+.macro func2 a, b, c, d, e
+ mov \b, %r9d
+ xor \c, %r9d
+ xor \d, %r9d
+.endm
+
+.macro func3 a, b, c, d, e
+ mov \b, %r8d
+ or \c, %r8d
+ and \d, %r8d
+ mov \b, %r9d
+ and \c, %r9d
+ or %r8d, %r9d
+.endm
+
+.macro func4 a, b, c, d, e
+ func2 \a, \b, \c, \d, \e
+.endm
+
+.macro mix a, b, c, d, e, const
+ rol $30, \b
+ add %r9d, \e
+ mov \a, %r8d
+ rol $5, %r8d
+ lea \const(\e, %r10d, 1), \e
+ add %r8d, \e
+.endm
+
+.macro round1 a, b, c, d, e, index
+ load \index
+ func1 \a, \b, \c, \d, \e
+ mix \a, \b, \c, \d, \e, 0x5a827999
+.endm
+
+.macro round1x a, b, c, d, e, index
+ shuffle \index
+ func1 \a, \b, \c, \d, \e
+ mix \a, \b, \c, \d, \e, 0x5a827999
+.endm
+
+.macro round2 a, b, c, d, e, index
+ shuffle \index
+ func2 \a, \b, \c, \d, \e
+ mix \a, \b, \c, \d, \e, 0x6ed9eba1
+.endm
+
+.macro round3 a, b, c, d, e, index
+ shuffle \index
+ func3 \a, \b, \c, \d, \e
+ mix \a, \b, \c, \d, \e, 0x8f1bbcdc
+.endm
+
+.macro round4 a, b, c, d, e, index
+ shuffle \index
+ func4 \a, \b, \c, \d, \e
+ mix \a, \b, \c, \d, \e, 0xca62c1d6
+.endm
+
+ // sha1block(SHA1_CTX, buf, len)
+ENTRY(_libmd_sha1block_scalar)
+ push %rbp
+ push %rbx
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ push %rdi // rdi: SHA1_CTX
+ sub $64+8, %rsp // 64 bytes for round keys
+ // plus alignment
+
+ mov %rdi, %rbp
+ // rsi: buf
+ and $~63, %rdx // rdx: length in blocks
+ lea (%rsi, %rdx, 1), %rdi // rdi: end pointer
+ mov (%rbp), %eax // c->h0
+ mov 4(%rbp), %ebx // c->h1
+ mov 8(%rbp), %ecx // c->h2
+ mov 12(%rbp), %edx // c->h3
+ mov 16(%rbp), %ebp // c->h4
+
+ cmp %rsi, %rdi // any data to process?
+ je .Lend
+
+.Lloop: mov %eax, %r11d
+ mov %ebx, %r12d
+ mov %ecx, %r13d
+ mov %edx, %r14d
+ mov %ebp, %r15d
+
+ round1 %eax, %ebx, %ecx, %edx, %ebp, 0
+ round1 %ebp, %eax, %ebx, %ecx, %edx, 1
+ round1 %edx, %ebp, %eax, %ebx, %ecx, 2
+ round1 %ecx, %edx, %ebp, %eax, %ebx, 3
+ round1 %ebx, %ecx, %edx, %ebp, %eax, 4
+
+ round1 %eax, %ebx, %ecx, %edx, %ebp, 5
+ round1 %ebp, %eax, %ebx, %ecx, %edx, 6
+ round1 %edx, %ebp, %eax, %ebx, %ecx, 7
+ round1 %ecx, %edx, %ebp, %eax, %ebx, 8
+ round1 %ebx, %ecx, %edx, %ebp, %eax, 9
+
+ round1 %eax, %ebx, %ecx, %edx, %ebp, 10
+ round1 %ebp, %eax, %ebx, %ecx, %edx, 11
+ round1 %edx, %ebp, %eax, %ebx, %ecx, 12
+ round1 %ecx, %edx, %ebp, %eax, %ebx, 13
+ round1 %ebx, %ecx, %edx, %ebp, %eax, 14
+
+ round1 %eax, %ebx, %ecx, %edx, %ebp, 15
+ round1x %ebp, %eax, %ebx, %ecx, %edx, 16
+ round1x %edx, %ebp, %eax, %ebx, %ecx, 17
+ round1x %ecx, %edx, %ebp, %eax, %ebx, 18
+ round1x %ebx, %ecx, %edx, %ebp, %eax, 19
+
+ round2 %eax, %ebx, %ecx, %edx, %ebp, 20
+ round2 %ebp, %eax, %ebx, %ecx, %edx, 21
+ round2 %edx, %ebp, %eax, %ebx, %ecx, 22
+ round2 %ecx, %edx, %ebp, %eax, %ebx, 23
+ round2 %ebx, %ecx, %edx, %ebp, %eax, 24
+
+ round2 %eax, %ebx, %ecx, %edx, %ebp, 25
+ round2 %ebp, %eax, %ebx, %ecx, %edx, 26
+ round2 %edx, %ebp, %eax, %ebx, %ecx, 27
+ round2 %ecx, %edx, %ebp, %eax, %ebx, 28
+ round2 %ebx, %ecx, %edx, %ebp, %eax, 29
+
+ round2 %eax, %ebx, %ecx, %edx, %ebp, 30
+ round2 %ebp, %eax, %ebx, %ecx, %edx, 31
+ round2 %edx, %ebp, %eax, %ebx, %ecx, 32
+ round2 %ecx, %edx, %ebp, %eax, %ebx, 33
+ round2 %ebx, %ecx, %edx, %ebp, %eax, 34
+
+ round2 %eax, %ebx, %ecx, %edx, %ebp, 35
+ round2 %ebp, %eax, %ebx, %ecx, %edx, 36
+ round2 %edx, %ebp, %eax, %ebx, %ecx, 37
+ round2 %ecx, %edx, %ebp, %eax, %ebx, 38
+ round2 %ebx, %ecx, %edx, %ebp, %eax, 39
+
+ round3 %eax, %ebx, %ecx, %edx, %ebp, 40
+ round3 %ebp, %eax, %ebx, %ecx, %edx, 41
+ round3 %edx, %ebp, %eax, %ebx, %ecx, 42
+ round3 %ecx, %edx, %ebp, %eax, %ebx, 43
+ round3 %ebx, %ecx, %edx, %ebp, %eax, 44
+
+ round3 %eax, %ebx, %ecx, %edx, %ebp, 45
+ round3 %ebp, %eax, %ebx, %ecx, %edx, 46
+ round3 %edx, %ebp, %eax, %ebx, %ecx, 47
+ round3 %ecx, %edx, %ebp, %eax, %ebx, 48
+ round3 %ebx, %ecx, %edx, %ebp, %eax, 49
+
+ round3 %eax, %ebx, %ecx, %edx, %ebp, 50
+ round3 %ebp, %eax, %ebx, %ecx, %edx, 51
+ round3 %edx, %ebp, %eax, %ebx, %ecx, 52
+ round3 %ecx, %edx, %ebp, %eax, %ebx, 53
+ round3 %ebx, %ecx, %edx, %ebp, %eax, 54
+
+ round3 %eax, %ebx, %ecx, %edx, %ebp, 55
+ round3 %ebp, %eax, %ebx, %ecx, %edx, 56
+ round3 %edx, %ebp, %eax, %ebx, %ecx, 57
+ round3 %ecx, %edx, %ebp, %eax, %ebx, 58
+ round3 %ebx, %ecx, %edx, %ebp, %eax, 59
+
+ round4 %eax, %ebx, %ecx, %edx, %ebp, 60
+ round4 %ebp, %eax, %ebx, %ecx, %edx, 61
+ round4 %edx, %ebp, %eax, %ebx, %ecx, 62
+ round4 %ecx, %edx, %ebp, %eax, %ebx, 63
+ round4 %ebx, %ecx, %edx, %ebp, %eax, 64
+
+ round4 %eax, %ebx, %ecx, %edx, %ebp, 65
+ round4 %ebp, %eax, %ebx, %ecx, %edx, 66
+ round4 %edx, %ebp, %eax, %ebx, %ecx, 67
+ round4 %ecx, %edx, %ebp, %eax, %ebx, 68
+ round4 %ebx, %ecx, %edx, %ebp, %eax, 69
+
+ round4 %eax, %ebx, %ecx, %edx, %ebp, 70
+ round4 %ebp, %eax, %ebx, %ecx, %edx, 71
+ round4 %edx, %ebp, %eax, %ebx, %ecx, 72
+ round4 %ecx, %edx, %ebp, %eax, %ebx, 73
+ round4 %ebx, %ecx, %edx, %ebp, %eax, 74
+
+ round4 %eax, %ebx, %ecx, %edx, %ebp, 75
+ round4 %ebp, %eax, %ebx, %ecx, %edx, 76
+ round4 %edx, %ebp, %eax, %ebx, %ecx, 77
+ round4 %ecx, %edx, %ebp, %eax, %ebx, 78
+ round4 %ebx, %ecx, %edx, %ebp, %eax, 79
+
+ add %r11d, %eax
+ add %r12d, %ebx
+ add %r13d, %ecx
+ add %r14d, %edx
+ add %r15d, %ebp
+
+ add $64, %rsi
+ cmp %rdi, %rsi
+ jb .Lloop
+
+.Lend: add $64+8, %rsp
+ pop %rdi // SHA1_CTX
+ mov %eax, (%rdi)
+ mov %ebx, 4(%rdi)
+ mov %ecx, 8(%rdi)
+ mov %edx, 12(%rdi)
+ mov %ebp, 16(%rdi)
+
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbx
+ pop %rbp
+ ret
+END(_libmd_sha1block_scalar)
+
+/*
+ * This is the implementation using AVX2, BMI1 and BMI2. It is based on:
+ * "SHA-1 implementation with Intel(R) AVX2 instruction set extensions"
+ * From http://software.intel.com/en-us/articles
+ * (look for improving-the-performance-of-the-secure-hash-algorithm-1)
+ * This implementation is 2x unrolled, and interleaves vector instructions,
+ * used to precompute W, with scalar computation of current round
+ * for optimal scheduling.
+ */
+
+ /* trivial helper macros */
+.macro update_hash a, tb, c, d, e
+ add (%r9), \a
+ mov \a, (%r9)
+ add 4(%r9), \tb
+ mov \tb, 4(%r9)
+ add 8(%r9), \c
+ mov \c, 8(%r9)
+ add 12(%r9), \d
+ mov \d, 12(%r9)
+ add 16(%r9), \e
+ mov \e, 16(%r9)
+.endm
+
+ /* help macros for recalc, which does precomputations */
+.macro precalc0 offset
+ vmovdqu \offset(%r10), %xmm0
+.endm
+
+.macro precalc1 offset
+ vinserti128 $1, \offset(%r13), %ymm0, %ymm0
+.endm
+
+.macro precalc2 yreg
+ vpshufb %ymm10, %ymm0, \yreg
+.endm
+
+.macro precalc4 yreg, k_offset
+ vpaddd \k_offset(%r8), \yreg, %ymm0
+.endm
+
+.macro precalc7 offset
+ vmovdqu %ymm0, (\offset)*2(%r14)
+.endm
+
+/*
+ * Message scheduling pre-compute for rounds 0-15
+ * r13 is a pointer to the even 64-byte block
+ * r10 is a pointer to the odd 64-byte block
+ * r14 is a pointer to the temp buffer
+ * xmm0 is used as a temp register
+ * yreg is clobbered as part of the computation
+ * offset chooses a 16 byte chunk within a block
+ * r8 is a pointer to the constants block
+ * k_offset chooses K constants relevant to this round
+ * xmm10 holds the swap mask
+ */
+.macro precalc00_15 offset, yreg
+ precalc0 \offset
+ precalc1 \offset
+ precalc2 \yreg
+ precalc4 \yreg, 0
+ precalc7 \offset
+.endm
+
+ /* helper macros for precalc16_31 */
+.macro precalc16 reg_sub16, reg_sub12, reg_sub4, reg
+ vpalignr $8, \reg_sub16, \reg_sub12, \reg // w[i - 14]
+ vpsrldq $4, \reg_sub4, %ymm0 // w[i - 3]
+.endm
+
+.macro precalc17 reg_sub16, reg_sub8, reg
+ vpxor \reg_sub8, \reg, \reg
+ vpxor \reg_sub16, %ymm0, %ymm0
+.endm
+
+.macro precalc18 reg
+ vpxor %ymm0, \reg, \reg
+ vpslldq $12, \reg, %ymm9
+.endm
+
+.macro precalc19 reg
+ vpslld $1, \reg, %ymm0
+ vpsrld $31, \reg, \reg
+ .endm
+
+.macro precalc20 reg
+ vpor \reg, %ymm0, %ymm0
+ vpslld $2, %ymm9, \reg
+.endm
+
+.macro precalc21 reg
+ vpsrld $30, %ymm9, %ymm9
+ vpxor \reg, %ymm0, %ymm0
+.endm
+
+.macro precalc23 reg, k_offset, offset
+ vpxor %ymm9, %ymm0, \reg
+ vpaddd \k_offset(%r8), \reg, %ymm0
+ vmovdqu %ymm0, (\offset)(%r14)
+.endm
+
+/*
+ * Message scheduling pre-compute for rounds 16-31
+ * calculating last 32 w[i] values in 8 XMM registers
+ * pre-calculate K+w[i] values and store to mem
+ * for later load by ALU add instruction.
+ * "brute force" vectorization for rounds 16-31 only
+ * due to w[i]->w[i-3] dependency.
+ + clobbers 5 input ymm registers REG_SUB*
+ * uses xmm0 and xmm9 as temp registers
+ * As always, r8 is a pointer to constants block
+ * and r14 is a pointer to temp buffer
+ */
+.macro precalc16_31 reg, reg_sub4, reg_sub8, reg_sub12, reg_sub16, k_offset, offset
+ precalc16 \reg_sub16, \reg_sub12, \reg_sub4, \reg
+ precalc17 \reg_sub16, \reg_sub8, \reg
+ precalc18 \reg
+ precalc19 \reg
+ precalc20 \reg
+ precalc21 \reg
+ precalc23 \reg, \k_offset, \offset
+.endm
+
+ /* helper macros for precalc_32_79 */
+.macro precalc32 reg_sub8, reg_sub4
+ vpalignr $8, \reg_sub8, \reg_sub4, %ymm0
+.endm
+
+.macro precalc33 reg_sub28, reg
+ vpxor \reg_sub28, \reg, \reg
+.endm
+
+.macro precalc34 reg_sub16
+ vpxor \reg_sub16, %ymm0, %ymm0
+.endm
+
+.macro precalc35 reg
+ vpxor %ymm0, \reg, \reg
+.endm
+
+.macro precalc36 reg
+ vpslld $2, \reg, %ymm0
+.endm
+
+.macro precalc37 reg
+ vpsrld $30, \reg, \reg
+ vpor \reg, %ymm0, \reg
+.endm
+
+.macro precalc39 reg, k_offset, offset
+ vpaddd \k_offset(%r8), \reg, %ymm0
+ vmovdqu %ymm0, \offset(%r14)
+.endm
+
+.macro precalc32_79 reg, reg_sub4, reg_sub8, reg_sub16, reg_sub28, k_offset, offset
+ precalc32 \reg_sub8, \reg_sub4
+ precalc33 \reg_sub28, \reg
+ precalc34 \reg_sub16
+ precalc35 \reg
+ precalc36 \reg
+ precalc37 \reg
+ precalc39 \reg, \k_offset, \offset
+.endm
+
+.macro precalc
+ precalc00_15 0x00, %ymm15
+ precalc00_15 0x10, %ymm14
+ precalc00_15 0x20, %ymm13
+ precalc00_15 0x30, %ymm12
+ precalc16_31 %ymm8, %ymm12, %ymm13, %ymm14, %ymm15, 0x00, 0x080
+ precalc16_31 %ymm7, %ymm8, %ymm12, %ymm13, %ymm14, 0x20, 0x0a0
+ precalc16_31 %ymm5, %ymm7, %ymm8, %ymm12, %ymm13, 0x20, 0x0c0
+ precalc16_31 %ymm3, %ymm5, %ymm7, %ymm8, %ymm12, 0x20, 0x0e0
+ precalc32_79 %ymm15, %ymm3, %ymm5, %ymm8, %ymm14, 0x20, 0x100
+ precalc32_79 %ymm14, %ymm15, %ymm3, %ymm7, %ymm13, 0x20, 0x120
+ precalc32_79 %ymm13, %ymm14, %ymm15, %ymm5, %ymm12, 0x40, 0x140
+ precalc32_79 %ymm12, %ymm13, %ymm14, %ymm3, %ymm8, 0x40, 0x160
+ precalc32_79 %ymm8, %ymm12, %ymm13, %ymm15, %ymm7, 0x40, 0x180
+ precalc32_79 %ymm7, %ymm8, %ymm12, %ymm14, %ymm5, 0x40, 0x1a0
+ precalc32_79 %ymm5, %ymm7, %ymm8, %ymm13, %ymm3, 0x40, 0x1c0
+ precalc32_79 %ymm3, %ymm5, %ymm7, %ymm12, %ymm15, 0x60, 0x1e0
+ precalc32_79 %ymm15, %ymm3, %ymm5, %ymm8, %ymm14, 0x60, 0x200
+ precalc32_79 %ymm14, %ymm15, %ymm3, %ymm7, %ymm13, 0x60, 0x220
+ precalc32_79 %ymm13, %ymm14, %ymm15, %ymm5, %ymm12, 0x60, 0x240
+ precalc32_79 %ymm12, %ymm13, %ymm14, %ymm3, %ymm8, 0x60, 0x260
+.endm
+
+/*
+ * Macros calculating individual rounds have general form
+ * calc_round_pre + precalc_round + calc_round_post
+ * calc_round_{pre,post} macros follow
+ */
+.macro calc_f1_pre offset, reg_a, reg_b, reg_c, reg_e
+ add \offset(%r15), \reg_e
+ andn \reg_c, \reg_a, %ebp
+ add \reg_b, \reg_e // add F from the previous round
+ rorx $0x1b, \reg_a, %r12d
+ rorx $2, \reg_a, \reg_b // for the next round
+.endm
+
+/*
+ * Calculate F for the next round
+ */
+.macro calc_f1_post reg_a, reg_b, reg_e
+ and \reg_b, \reg_a // b & c
+ xor %ebp, \reg_a // F1 = (b&c) ^ (~b&d)
+ add %r12d, \reg_e
+.endm
+
+/*
+ * Registers are cyclically rotated:
+ * edx -> eax -> edi -> esi -> ebx -> ecx
+ */
+.macro calc0
+ mov %esi, %ebx // precalculate first round
+ rorx $2, %esi, %esi
+ andn %eax, %ebx, %ebp
+ and %edi, %ebx
+ xor %ebp, %ebx
+ calc_f1_pre 0x0, %ecx, %ebx, %edi, %edx
+ precalc0 0x80
+ calc_f1_post %ecx, %esi, %edx
+.endm
+
+.macro calc1
+ calc_f1_pre 0x4, %edx, %ecx, %esi, %eax
+ precalc1 0x80
+ calc_f1_post %edx, %ebx, %eax
+.endm
+
+.macro calc2
+ calc_f1_pre 0x8, %eax, %edx, %ebx, %edi
+ precalc2 %ymm15
+ calc_f1_post %eax, %ecx, %edi
+.endm
+
+.macro calc3
+ calc_f1_pre 0xc, %edi, %eax, %ecx, %esi
+ calc_f1_post %edi, %edx, %esi
+.endm
+
+.macro calc4
+ calc_f1_pre 0x20, %esi, %edi, %edx, %ebx
+ precalc4 %ymm15, 0x0
+ calc_f1_post %esi, %eax, %ebx
+.endm
+
+.macro calc5
+ calc_f1_pre 0x24, %ebx, %esi, %eax, %ecx
+ calc_f1_post %ebx, %edi, %ecx
+.endm
+
+.macro calc6
+ calc_f1_pre 0x28, %ecx, %ebx, %edi, %edx
+ calc_f1_post %ecx, %esi, %edx
+.endm
+
+.macro calc7
+ calc_f1_pre 0x2c, %edx, %ecx, %esi, %eax
+ precalc7 0x0
+ calc_f1_post %edx, %ebx, %eax
+.endm
+
+.macro calc8
+ calc_f1_pre 0x40, %eax, %edx, %ebx, %edi
+ precalc0 0x90
+ calc_f1_post %eax, %ecx, %edi
+.endm
+
+.macro calc9
+ calc_f1_pre 0x44, %edi, %eax, %ecx, %esi
+ precalc1 0x90
+ calc_f1_post %edi, %edx, %esi
+.endm
+
+.macro calc10
+ calc_f1_pre 0x48, %esi, %edi, %edx, %ebx
+ precalc2 %ymm14
+ calc_f1_post %esi, %eax, %ebx
+.endm
+
+.macro calc11
+ calc_f1_pre 0x4c, %ebx, %esi, %eax, %ecx
+ calc_f1_post %ebx, %edi, %ecx
+.endm
+
+.macro calc12
+ calc_f1_pre 0x60, %ecx, %ebx, %edi, %edx
+ precalc4 %ymm14, 0
+ calc_f1_post %ecx, %esi, %edx
+.endm
+
+.macro calc13
+ calc_f1_pre 0x64, %edx, %ecx, %esi, %eax
+ calc_f1_post %edx, %ebx, %eax
+.endm
+
+.macro calc14
+ calc_f1_pre 0x68, %eax, %edx, %ebx, %edi
+ calc_f1_post %eax, %ecx, %edi
+.endm
+
+.macro calc15
+ calc_f1_pre 0x6c, %edi, %eax, %ecx, %esi
+ precalc7 0x10
+ calc_f1_post %edi, %edx, %esi
+.endm
+
+.macro calc16
+ calc_f1_pre 0x80, %esi, %edi, %edx, %ebx
+ precalc0 0xa0
+ calc_f1_post %esi, %eax, %ebx
+.endm
+
+.macro calc17
+ calc_f1_pre 0x84, %ebx, %esi, %eax, %ecx
+ precalc1 0xa0
+ calc_f1_post %ebx, %edi, %ecx
+.endm
+
+.macro calc18
+ calc_f1_pre 0x88, %ecx, %ebx, %edi, %edx
+ precalc2 %ymm13
+ calc_f1_post %ecx, %esi, %edx
+.endm
+
+.macro calc_f2_pre offset, reg_a, reg_b, reg_e
+ add \offset(%r15), \reg_e
+ add \reg_b, \reg_e // add F from the previous round
+ rorx $0x1b, \reg_a, %r12d
+ rorx $2, \reg_a, \reg_b // for next round
+.endm
+
+.macro calc_f2_post reg_a, reg_b, reg_c, reg_e
+ xor \reg_b, \reg_a
+ add %r12d, \reg_e
+ xor \reg_c, \reg_a
+.endm
+
+.macro calc19
+ calc_f2_pre 0x8c, %edx, %ecx, %eax
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc20
+ calc_f2_pre 0xa0, %eax, %edx, %edi
+ precalc4 %ymm13, 0x0
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc21
+ calc_f2_pre 0xa4, %edi, %eax, %esi
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc22
+ calc_f2_pre 0xa8, %esi, %edi, %ebx
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc23
+ calc_f2_pre 0xac, %ebx, %esi, %ecx
+ precalc7 0x20
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc24
+ calc_f2_pre 0xc0, %ecx, %ebx, %edx
+ precalc0 0xb0
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc25
+ calc_f2_pre 0xc4, %edx, %ecx, %eax
+ precalc1 0xb0
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc26
+ calc_f2_pre 0xc8, %eax, %edx, %edi
+ precalc2 %ymm12
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc27
+ calc_f2_pre 0xcc, %edi, %eax, %esi
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc28
+ calc_f2_pre 0xe0, %esi, %edi, %ebx
+ precalc4 %ymm12, 0x0
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc29
+ calc_f2_pre 0xe4, %ebx, %esi, %ecx
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc30
+ calc_f2_pre 0xe8, %ecx, %ebx, %edx
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc31
+ calc_f2_pre 0xec, %edx, %ecx, %eax
+ precalc7 0x30
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc32
+ calc_f2_pre 0x100, %eax, %edx, %edi
+ precalc16 %ymm15, %ymm14, %ymm12, %ymm8
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc33
+ calc_f2_pre 0x104, %edi, %eax, %esi
+ precalc17 %ymm15, %ymm13, %ymm8
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc34
+ calc_f2_pre 0x108, %esi, %edi, %ebx
+ precalc18 %ymm8
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc35
+ calc_f2_pre 0x10c, %ebx, %esi, %ecx
+ precalc19 %ymm8
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc36
+ calc_f2_pre 0x120, %ecx, %ebx, %edx
+ precalc20 %ymm8
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc37
+ calc_f2_pre 0x124, %edx, %ecx, %eax
+ precalc21 %ymm8
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc38
+ calc_f2_pre 0x128, %eax, %edx, %edi
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc_f3_pre offset, reg_e
+ add \offset(%r15), \reg_e
+.endm
+
+.macro calc_f3_post reg_a, reg_b, reg_c, reg_e, reg_tb
+ add \reg_tb, \reg_e // add F from the previous round
+ mov \reg_b, %ebp
+ or \reg_a, %ebp
+ rorx $0x1b, \reg_a, %r12d
+ rorx $2, \reg_a, \reg_tb
+ and \reg_c, %ebp // calculate F for the next round
+ and \reg_b, \reg_a
+ or %ebp, \reg_a
+ add %r12d, \reg_e
+.endm
+
+.macro calc39
+ calc_f3_pre 0x12c, %esi
+ precalc23 %ymm8, 0x0, 0x80
+ calc_f3_post %edi, %edx, %ecx, %esi, %eax
+.endm
+
+.macro calc40
+ calc_f3_pre 0x140, %ebx
+ precalc16 %ymm14, %ymm13, %ymm8, %ymm7
+ calc_f3_post %esi, %eax, %edx, %ebx, %edi
+.endm
+
+.macro calc41
+ calc_f3_pre 0x144, %ecx
+ precalc17 %ymm14, %ymm12, %ymm7
+ calc_f3_post %ebx, %edi, %eax, %ecx, %esi
+.endm
+
+.macro calc42
+ calc_f3_pre 0x148, %edx
+ precalc18 %ymm7
+ calc_f3_post %ecx, %esi, %edi, %edx, %ebx
+.endm
+
+.macro calc43
+ calc_f3_pre 0x14c, %eax
+ precalc19 %ymm7
+ calc_f3_post %edx, %ebx, %esi, %eax, %ecx
+.endm
+
+.macro calc44
+ calc_f3_pre 0x160, %edi
+ precalc20 %ymm7
+ calc_f3_post %eax, %ecx, %ebx, %edi, %edx
+.endm
+
+.macro calc45
+ calc_f3_pre 0x164, %esi
+ precalc21 %ymm7
+ calc_f3_post %edi, %edx, %ecx, %esi, %eax
+.endm
+
+.macro calc46
+ calc_f3_pre 0x168, %ebx
+ calc_f3_post %esi, %eax, %edx, %ebx, %edi
+.endm
+
+.macro calc47
+ calc_f3_pre 0x16c, %ecx
+ vpxor %ymm9, %ymm0, %ymm7
+ vpaddd 0x20(%r8), %ymm7, %ymm0
+ vmovdqu %ymm0, 0xa0(%r14)
+ calc_f3_post %ebx, %edi, %eax, %ecx, %esi
+.endm
+
+.macro calc48
+ calc_f3_pre 0x180, %edx
+ precalc16 %ymm13, %ymm12, %ymm7, %ymm5
+ calc_f3_post %ecx, %esi, %edi, %edx, %ebx
+.endm
+
+.macro calc49
+ calc_f3_pre 0x184, %eax
+ precalc17 %ymm13, %ymm8, %ymm5
+ calc_f3_post %edx, %ebx, %esi, %eax, %ecx
+.endm
+
+.macro calc50
+ calc_f3_pre 0x188, %edi
+ precalc18 %ymm5
+ calc_f3_post %eax, %ecx, %ebx, %edi, %edx
+.endm
+
+.macro calc51
+ calc_f3_pre 0x18c, %esi
+ precalc19 %ymm5
+ calc_f3_post %edi, %edx, %ecx, %esi, %eax
+.endm
+
+.macro calc52
+ calc_f3_pre 0x1a0, %ebx
+ precalc20 %ymm5
+ calc_f3_post %esi, %eax, %edx, %ebx, %edi
+.endm
+
+.macro calc53
+ calc_f3_pre 0x1a4, %ecx
+ precalc21 %ymm5
+ calc_f3_post %ebx, %edi, %eax, %ecx, %esi
+.endm
+
+.macro calc54
+ calc_f3_pre 0x1a8, %edx
+ calc_f3_post %ecx, %esi, %edi, %edx, %ebx
+.endm
+
+.macro calc55
+ calc_f3_pre 0x1ac, %eax
+ precalc23 %ymm5, 0x20, 0xc0
+ calc_f3_post %edx, %ebx, %esi, %eax, %ecx
+.endm
+
+.macro calc56
+ calc_f3_pre 0x1c0, %edi
+ precalc16 %ymm12, %ymm8, %ymm5, %ymm3
+ calc_f3_post %eax, %ecx, %ebx, %edi, %edx
+.endm
+
+.macro calc57
+ calc_f3_pre 0x1c4, %esi
+ precalc17 %ymm12, %ymm7, %ymm3
+ calc_f3_post %edi, %edx, %ecx, %esi, %eax
+.endm
+
+.macro calc58
+ calc_f3_pre 0x1c8, %ebx
+ precalc18 %ymm3
+ calc_f3_post %esi, %eax, %edx, %ebx, %edi
+.endm
+
+.macro calc59
+ calc_f2_pre 0x1cc, %ebx, %esi, %ecx
+ precalc19 %ymm3
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc60
+ calc_f2_pre 0x1e0, %ecx, %ebx, %edx
+ precalc20 %ymm3
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc61
+ calc_f2_pre 0x1e4, %edx, %ecx, %eax
+ precalc21 %ymm3
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc62
+ calc_f2_pre 0x1e8, %eax, %edx, %edi
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc63
+ calc_f2_pre 0x1ec, %edi, %eax, %esi
+ precalc23 %ymm3, 0x20, 0xe0
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc64
+ calc_f2_pre 0x200, %esi, %edi, %ebx
+ precalc32 %ymm5, %ymm3
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc65
+ calc_f2_pre 0x204, %ebx, %esi, %ecx
+ precalc33 %ymm14, %ymm15
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc66
+ calc_f2_pre 0x208, %ecx, %ebx, %edx
+ precalc34 %ymm8
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc67
+ calc_f2_pre 0x20c, %edx, %ecx, %eax
+ precalc35 %ymm15
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc68
+ calc_f2_pre 0x220, %eax, %edx, %edi
+ precalc36 %ymm15
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc69
+ calc_f2_pre 0x224, %edi, %eax, %esi
+ precalc37 %ymm15
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc70
+ calc_f2_pre 0x228, %esi, %edi, %ebx
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc71
+ calc_f2_pre 0x22c, %ebx, %esi, %ecx
+ precalc39 %ymm15, 0x20, 0x100
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc72
+ calc_f2_pre 0x240, %ecx, %ebx, %edx
+ precalc32 %ymm3, %ymm15
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc73
+ calc_f2_pre 0x244, %edx, %ecx, %eax
+ precalc33 %ymm13, %ymm14
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc74
+ calc_f2_pre 0x248, %eax, %edx, %edi
+ precalc34 %ymm7
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc75
+ calc_f2_pre 0x24c, %edi, %eax, %esi
+ precalc35 %ymm14
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc76
+ calc_f2_pre 0x260, %esi, %edi, %ebx
+ precalc36 %ymm14
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc77
+ calc_f2_pre 0x264, %ebx, %esi, %ecx
+ precalc37 %ymm14
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc78
+ calc_f2_pre 0x268, %ecx, %ebx, %edx
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc79
+ add 0x26c(%r15), %eax
+ add %ecx, %eax
+ rorx $0x1b, %edx, %r12d
+ precalc39 %ymm14, 0x20, 0x120
+ add %r12d, %eax
+.endm
+
+/*
+ * Similar to calc0
+ */
+.macro calc80
+ mov %ecx, %edx // precalculate first round
+ rorx $2, %ecx, %ecx
+ andn %esi, %edx, %ebp
+ and %ebx, %edx
+ xor %ebp, %edx
+ calc_f1_pre 0x10, %eax, %edx, %ebx, %edi
+ precalc32 %ymm15, %ymm14
+ calc_f1_post %eax, %ecx, %edi
+.endm
+
+.macro calc81
+ calc_f1_pre 0x14, %edi, %eax, %ecx, %esi
+ precalc33 %ymm12, %ymm13
+ calc_f1_post %edi, %edx, %esi
+.endm
+
+.macro calc82
+ calc_f1_pre 0x18, %esi, %edi, %edx, %ebx
+ precalc34 %ymm5
+ calc_f1_post %esi, %eax, %ebx
+.endm
+
+.macro calc83
+ calc_f1_pre 0x1c, %ebx, %esi, %eax, %ecx
+ precalc35 %ymm13
+ calc_f1_post %ebx, %edi, %ecx
+.endm
+
+.macro calc84
+ calc_f1_pre 0x30, %ecx, %ebx, %edi, %edx
+ precalc36 %ymm13
+ calc_f1_post %ecx, %esi, %edx
+.endm
+
+.macro calc85
+ calc_f1_pre 0x34, %edx, %ecx, %esi, %eax
+ precalc37 %ymm13
+ calc_f1_post %edx, %ebx, %eax
+.endm
+
+.macro calc86
+ calc_f1_pre 0x38, %eax, %edx, %ebx, %edi
+ calc_f1_post %eax, %ecx, %edi
+.endm
+
+.macro calc87
+ calc_f1_pre 0x3c, %edi, %eax, %ecx, %esi
+ precalc39 %ymm13, 0x40, 0x140
+ calc_f1_post %edi, %edx, %esi
+.endm
+
+.macro calc88
+ calc_f1_pre 0x50, %esi, %edi, %edx, %ebx
+ precalc32 %ymm14, %ymm13
+ calc_f1_post %esi, %eax, %ebx
+.endm
+
+.macro calc89
+ calc_f1_pre 0x54, %ebx, %esi, %eax, %ecx
+ precalc33 %ymm8, %ymm12
+ calc_f1_post %ebx, %edi, %ecx
+.endm
+
+.macro calc90
+ calc_f1_pre 0x58, %ecx, %ebx, %edi, %edx
+ precalc34 %ymm3
+ calc_f1_post %ecx, %esi, %edx
+.endm
+
+.macro calc91
+ calc_f1_pre 0x5c, %edx, %ecx, %esi, %eax
+ precalc35 %ymm12
+ calc_f1_post %edx, %ebx, %eax
+.endm
+
+.macro calc92
+ calc_f1_pre 0x70, %eax, %edx, %ebx, %edi
+ precalc36 %ymm12
+ calc_f1_post %eax, %ecx, %edi
+.endm
+
+.macro calc93
+ calc_f1_pre 0x74, %edi, %eax, %ecx, %esi
+ precalc37 %ymm12
+ calc_f1_post %edi, %edx, %esi
+.endm
+
+.macro calc94
+ calc_f1_pre 0x78, %esi, %edi, %edx, %ebx
+ calc_f1_post %esi, %eax, %ebx
+.endm
+
+.macro calc95
+ calc_f1_pre 0x7c, %ebx, %esi, %eax, %ecx
+ precalc39 %ymm12, 0x40, 0x160
+ calc_f1_post %ebx, %edi, %ecx
+.endm
+
+.macro calc96
+ calc_f1_pre 0x90, %ecx, %ebx, %edi, %edx
+ precalc32 %ymm13, %ymm12
+ calc_f1_post %ecx, %esi, %edx
+.endm
+
+.macro calc97
+ calc_f1_pre 0x94, %edx, %ecx, %esi, %eax
+ precalc33 %ymm7, %ymm8
+ calc_f1_post %edx, %ebx, %eax
+.endm
+
+.macro calc98
+ calc_f1_pre 0x98, %eax, %edx, %ebx, %edi
+ precalc34 %ymm15
+ calc_f1_post %eax, %ecx, %edi
+.endm
+
+.macro calc99
+ calc_f2_pre 0x9c, %edi, %eax, %esi
+ precalc35 %ymm8
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc100
+ calc_f2_pre 0xb0, %esi, %edi, %ebx
+ precalc36 %ymm8
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc101
+ calc_f2_pre 0xb4, %ebx, %esi, %ecx
+ precalc37 %ymm8
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc102
+ calc_f2_pre 0xb8, %ecx, %ebx, %edx
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc103
+ calc_f2_pre 0xbc, %edx, %ecx, %eax
+ precalc39 %ymm8, 0x40, 0x180
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc104
+ calc_f2_pre 0xd0, %eax, %edx, %edi
+ precalc32 %ymm12, %ymm8
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc105
+ calc_f2_pre 0xd4, %edi, %eax, %esi
+ precalc33 %ymm5, %ymm7
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc106
+ calc_f2_pre 0xd8, %esi, %edi, %ebx
+ precalc34 %ymm14
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc107
+ calc_f2_pre 0xdc, %ebx, %esi, %ecx
+ precalc35 %ymm7
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc108
+ calc_f2_pre 0xf0, %ecx, %ebx, %edx
+ precalc36 %ymm7
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc109
+ calc_f2_pre 0xf4, %edx, %ecx, %eax
+ precalc37 %ymm7
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc110
+ calc_f2_pre 0xf8, %eax, %edx, %edi
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc111
+ calc_f2_pre 0xfc, %edi, %eax, %esi
+ precalc39 %ymm7, 0x40, 0x1a0
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc112
+ calc_f2_pre 0x110, %esi, %edi, %ebx
+ precalc32 %ymm8, %ymm7
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc113
+ calc_f2_pre 0x114, %ebx, %esi, %ecx
+ precalc33 %ymm3, %ymm5
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc114
+ calc_f2_pre 0x118, %ecx, %ebx, %edx
+ precalc34 %ymm13
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc115
+ calc_f2_pre 0x11c, %edx, %ecx, %eax
+ precalc35 %ymm5
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc116
+ calc_f2_pre 0x130, %eax, %edx, %edi
+ precalc36 %ymm5
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc117
+ calc_f2_pre 0x134, %edi, %eax, %esi
+ precalc37 %ymm5
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc118
+ calc_f2_pre 0x138, %esi, %edi, %ebx
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc119
+ calc_f3_pre 0x13c, %ecx
+ precalc39 %ymm5, 0x40, 0x1c0
+ calc_f3_post %ebx, %edi, %eax, %ecx, %esi
+.endm
+
+.macro calc120
+ calc_f3_pre 0x150, %edx
+ precalc32 %ymm7, %ymm5
+ calc_f3_post %ecx, %esi, %edi, %edx, %ebx
+.endm
+
+.macro calc121
+ calc_f3_pre 0x154, %eax
+ precalc33 %ymm15, %ymm3
+ calc_f3_post %edx, %ebx, %esi, %eax, %ecx
+.endm
+
+.macro calc122
+ calc_f3_pre 0x158, %edi
+ precalc34 %ymm12
+ calc_f3_post %eax, %ecx, %ebx, %edi, %edx
+.endm
+
+.macro calc123
+ calc_f3_pre 0x15c, %esi
+ precalc35 %ymm3
+ calc_f3_post %edi, %edx, %ecx, %esi, %eax
+.endm
+
+.macro calc124
+ calc_f3_pre 0x170, %ebx
+ precalc36 %ymm3
+ calc_f3_post %esi, %eax, %edx, %ebx, %edi
+.endm
+
+.macro calc125
+ calc_f3_pre 0x174, %ecx
+ precalc37 %ymm3
+ calc_f3_post %ebx, %edi, %eax, %ecx, %esi
+.endm
+
+.macro calc126
+ calc_f3_pre 0x178, %edx
+ calc_f3_post %ecx, %esi, %edi, %edx, %ebx
+.endm
+
+.macro calc127
+ calc_f3_pre 0x17c, %eax
+ precalc39 %ymm3, 0x60, 0x1e0
+ calc_f3_post %edx, %ebx, %esi, %eax, %ecx
+.endm
+
+.macro calc128
+ calc_f3_pre 0x190, %edi
+ precalc32 %ymm5, %ymm3
+ calc_f3_post %eax, %ecx, %ebx, %edi, %edx
+.endm
+
+.macro calc129
+ calc_f3_pre 0x194, %esi
+ precalc33 %ymm14, %ymm15
+ calc_f3_post %edi, %edx, %ecx, %esi, %eax
+.endm
+
+.macro calc130
+ calc_f3_pre 0x198, %ebx
+ precalc34 %ymm8
+ calc_f3_post %esi, %eax, %edx, %ebx, %edi
+.endm
+
+.macro calc131
+ calc_f3_pre 0x19c, %ecx
+ precalc35 %ymm15
+ calc_f3_post %ebx, %edi, %eax, %ecx, %esi
+.endm
+
+.macro calc132
+ calc_f3_pre 0x1b0, %edx
+ precalc36 %ymm15
+ calc_f3_post %ecx, %esi, %edi, %edx, %ebx
+.endm
+
+.macro calc133
+ calc_f3_pre 0x1b4, %eax
+ precalc37 %ymm15
+ calc_f3_post %edx, %ebx, %esi, %eax, %ecx
+.endm
+
+.macro calc134
+ calc_f3_pre 0x1b8, %edi
+ calc_f3_post %eax, %ecx, %ebx, %edi, %edx
+.endm
+
+.macro calc135
+ calc_f3_pre 0x1bc, %esi
+ precalc39 %ymm15, 0x60, 0x200
+ calc_f3_post %edi, %edx, %ecx, %esi, %eax
+.endm
+
+.macro calc136
+ calc_f3_pre 0x1d0, %ebx
+ precalc32 %ymm3, %ymm15
+ calc_f3_post %esi, %eax, %edx, %ebx, %edi
+.endm
+
+.macro calc137
+ calc_f3_pre 0x1d4, %ecx
+ precalc33 %ymm13, %ymm14
+ calc_f3_post %ebx, %edi, %eax, %ecx, %esi
+.endm
+
+.macro calc138
+ calc_f3_pre 0x1d8, %edx
+ precalc34 %ymm7
+ calc_f3_post %ecx, %esi, %edi, %edx, %ebx
+.endm
+
+.macro calc139
+ calc_f2_pre 0x1dc, %edx, %ecx, %eax
+ precalc35 %ymm14
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc140
+ calc_f2_pre 0x1f0, %eax, %edx, %edi
+ precalc36 %ymm14
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc141
+ calc_f2_pre 0x1f4, %edi, %eax, %esi
+ precalc37 %ymm14
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc142
+ calc_f2_pre 0x1f8, %esi, %edi, %ebx
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc143
+ calc_f2_pre 0x1fc, %ebx, %esi, %ecx
+ precalc39 %ymm14, 0x60, 0x220
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc144
+ calc_f2_pre 0x210, %ecx, %ebx, %edx
+ precalc32 %ymm15, %ymm14
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc145
+ calc_f2_pre 0x214, %edx, %ecx, %eax
+ precalc33 %ymm12, %ymm13
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc146
+ calc_f2_pre 0x218, %eax, %edx, %edi
+ precalc34 %ymm5
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc147
+ calc_f2_pre 0x21c, %edi, %eax, %esi
+ precalc35 %ymm13
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc148
+ calc_f2_pre 0x230, %esi, %edi, %ebx
+ precalc36 %ymm13
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc149
+ calc_f2_pre 0x234, %ebx, %esi, %ecx
+ precalc37 %ymm13
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc150
+ calc_f2_pre 0x238, %ecx, %ebx, %edx
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc151
+ calc_f2_pre 0x23c, %edx, %ecx, %eax
+ precalc39 %ymm13, 0x60, 0x240
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc152
+ calc_f2_pre 0x250, %eax, %edx, %edi
+ precalc32 %ymm14, %ymm13
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc153
+ calc_f2_pre 0x254, %edi, %eax, %esi
+ precalc33 %ymm8, %ymm12
+ calc_f2_post %edi, %edx, %ecx, %esi
+.endm
+
+.macro calc154
+ calc_f2_pre 0x258, %esi, %edi, %ebx
+ precalc34 %ymm3
+ calc_f2_post %esi, %eax, %edx, %ebx
+.endm
+
+.macro calc155
+ calc_f2_pre 0x25c, %ebx, %esi, %ecx
+ precalc35 %ymm12
+ calc_f2_post %ebx, %edi, %eax, %ecx
+.endm
+
+.macro calc156
+ calc_f2_pre 0x270, %ecx, %ebx, %edx
+ precalc36 %ymm12
+ calc_f2_post %ecx, %esi, %edi, %edx
+.endm
+
+.macro calc157
+ calc_f2_pre 0x274, %edx, %ecx, %eax
+ precalc37 %ymm12
+ calc_f2_post %edx, %ebx, %esi, %eax
+.endm
+
+.macro calc158
+ calc_f2_pre 0x278, %eax, %edx, %edi
+ calc_f2_post %eax, %ecx, %ebx, %edi
+.endm
+
+.macro calc159
+ add 0x27c(%r15), %esi
+ add %eax, %esi
+ rorx $0x1b, %edi, %r12d
+ precalc39 %ymm12, 0x60, 0x260
+ add %r12d, %esi
+.endm
+
+ // sha1block(SHA1_CTX, buf, len)
+ENTRY(_libmd_sha1block_avx2)
+ push %rbx
+ push %rbp
+ push %r12
+ push %r13
+ push %r14
+ push %r15
+ sub $1408+8, %rsp
+
+ and $~63, %rdx
+ lea k_xmm_ar(%rip), %r8
+ mov %rdi, %r9
+ mov %rsi, %r10
+ lea 64(%rsi), %r13
+ lea 64(%rsi, %rdx), %r11
+ cmp %r11, %r13
+ cmovae %r8, %r13
+ vmovdqu bswap_shufb_ctl(%rip), %ymm10
+
+ mov (%r9), %ecx
+ mov 4(%r9), %esi
+ mov 8(%r9), %edi
+ mov 12(%r9), %eax
+ mov 16(%r9), %edx
+ mov %rsp, %r14
+ lea 2*4*80+32(%rsp), %r15
+ precalc // precalc WK for first 2 blocks
+ xchg %r14, %r15
+
+ // this is unrolled
+.Loop: cmp %r8, %r10 // we use the value of R8 (set below)
+ // as a signal of the last block
+ jne .Lbegin
+ add $1408+8, %rsp
+ pop %r15
+ pop %r14
+ pop %r13
+ pop %r12
+ pop %rbp
+ pop %rbx
+ vzeroupper
+ ret
+
+.Lbegin:
+ calc0
+ calc1
+ calc2
+ calc3
+ calc4
+ calc5
+ calc6
+ calc7
+ calc8
+ calc9
+ calc10
+ calc11
+ calc12
+ calc13
+ calc14
+ calc15
+ calc16
+ calc17
+ calc18
+ calc19
+ calc20
+ calc21
+ calc22
+ calc23
+ calc24
+ calc25
+ calc26
+ calc27
+ calc28
+ calc29
+ calc30
+ calc31
+ calc32
+ calc33
+ calc34
+ calc35
+ calc36
+ calc37
+ calc38
+ calc39
+ calc40
+ calc41
+ calc42
+ calc43
+ calc44
+ calc45
+ calc46
+ calc47
+ calc48
+ calc49
+ calc50
+ calc51
+ calc52
+ calc53
+ calc54
+ calc55
+ calc56
+ calc57
+ calc58
+ calc59
+
+ add $128, %r10 // move to the next even-64-byte block
+ cmp %r11, %r10 // is the current block the last one?
+ cmovae %r8, %r10 // signal the last iteration smartly
+
+ calc60
+ calc61
+ calc62
+ calc63
+ calc64
+ calc65
+ calc66
+ calc67
+ calc68
+ calc69
+ calc70
+ calc71
+ calc72
+ calc73
+ calc74
+ calc75
+ calc76
+ calc77
+ calc78
+ calc79
+
+ update_hash %eax, %edx, %ebx, %esi, %edi
+ cmp %r8, %r10 // is the current block the last one?
+ je .Loop
+ mov %edx, %ecx
+
+ calc80
+ calc81
+ calc82
+ calc83
+ calc84
+ calc85
+ calc86
+ calc87
+ calc88
+ calc89
+ calc90
+ calc91
+ calc92
+ calc93
+ calc94
+ calc95
+ calc96
+ calc97
+ calc98
+ calc99
+ calc100
+ calc101
+ calc102
+ calc103
+ calc104
+ calc105
+ calc106
+ calc107
+ calc108
+ calc109
+ calc110
+ calc111
+ calc112
+ calc113
+ calc114
+ calc115
+ calc116
+ calc117
+ calc118
+ calc119
+ calc120
+ calc121
+ calc122
+ calc123
+ calc124
+ calc125
+ calc126
+ calc127
+ calc128
+ calc129
+ calc130
+ calc131
+ calc132
+ calc133
+ calc134
+ calc135
+ calc136
+ calc137
+ calc138
+ calc139
+
+ add $128, %r13 // move to the next even-64-byte block
+ cmp %r11, %r13 // is the current block the last one?
+ cmovae %r8, %r10
+
+ calc140
+ calc141
+ calc142
+ calc143
+ calc144
+ calc145
+ calc146
+ calc147
+ calc148
+ calc149
+ calc150
+ calc151
+ calc152
+ calc153
+ calc154
+ calc155
+ calc156
+ calc157
+ calc158
+ calc159
+
+ update_hash %esi, %edi, %edx, %ecx, %ebx
+ mov %esi, %r12d // reset state for AVX2 reg permutation
+ mov %edi, %esi
+ mov %edx, %edi
+ mov %ebx, %edx
+ mov %ecx, %eax
+ mov %r12d, %ecx
+ xchg %r14, %r15
+ jmp .Loop
+END(_libmd_sha1block_avx2)
+
+ .section .rodata
+ .balign 32
+k_xmm_ar:
+ .fill 8, 4, 0x5a827999
+ .fill 8, 4, 0x6ed9eba1
+ .fill 8, 4, 0x8f1bbcdc
+ .fill 8, 4, 0xca62c1d6
+ .size k_xmm_ar, .-k_xmm_ar
+
+bswap_shufb_ctl:
+ .4byte 0x00010203
+ .4byte 0x04050607
+ .4byte 0x08090a0b
+ .4byte 0x0c0d0e0f
+ .4byte 0x00010203
+ .4byte 0x04050607
+ .4byte 0x08090a0b
+ .4byte 0x0c0d0e0f
+ .size bswap_shufb_ctl, .-bswap_shufb_ctl
+
+ /*
+ * SHA1 implementation using the Intel SHA extensions (SHANI).
+ *
+ * Imlemented according to the Intel white paper
+ *
+ * S. Gulley, V. Gopal, K. Yap, W. Feghali, J. Guilford,
+ * G. Wolrich: "Intel SHA Extensions: new instruction supporting
+ * the Secure Hash Algorithm on Intel® architecture processors",
+ * July 2013.
+ */
+ // sha1block(SHA1_CTX, buf, len)
+ENTRY(_libmd_sha1block_shani)
+ and $~63, %rdx // round length to block-size multiple
+ lea (%rsi, %rdx, 1), %rcx // end pointer
+ test %rdx, %rdx // nothing to do?
+ je 1f // if so, terminate immediately
+
+ movdqu (%rdi), %xmm6 // h0, h1, h2, h3
+ pxor %xmm7, %xmm7
+ pshufd $0x1b, %xmm6, %xmm6 // h3, h2, h1, h0
+ pinsrd $3, 16(%rdi), %xmm7 // h4 in the highest word of xmm7
+ movdqu shuf_mask(%rip), %xmm4
+
+ // main loop
+0: movdqa %xmm6, %xmm8 // stash ABCD
+ movdqa %xmm7, %xmm9 // stash E
+
+ // rounds 0--3
+ movdqu 0*16(%rsi), %xmm0 // load first message block
+ pshufb %xmm4, %xmm0 // and byte-swap
+ paddd %xmm0, %xmm7 // E += w[0]
+ movdqa %xmm6, %xmm5 // E' = A
+ sha1rnds4 $0, %xmm7, %xmm6 // perform rounds 0--3
+
+ // rounds 4--7
+ movdqu 1*16(%rsi), %xmm1
+ pshufb %xmm4, %xmm1
+ sha1nexte %xmm1, %xmm5
+ movdqa %xmm6, %xmm7
+ sha1rnds4 $0, %xmm5, %xmm6
+ sha1msg1 %xmm1, %xmm0
+
+ // rounds 8--11
+ movdqu 2*16(%rsi), %xmm2
+ pshufb %xmm4, %xmm2
+ sha1nexte %xmm2, %xmm7
+ movdqa %xmm6, %xmm5
+ sha1rnds4 $0, %xmm7, %xmm6
+ sha1msg1 %xmm2, %xmm1
+ pxor %xmm2, %xmm0
+
+.macro midround msg3, msg0, msg1, msg2, e1, e0, k
+ sha1nexte \msg3, \e1
+ movdqa %xmm6, \e0
+ sha1msg2 \msg3, \msg0
+ sha1rnds4 $\k, \e1, %xmm6
+ sha1msg1 \msg3, \msg2
+ pxor \msg3, \msg1
+.endm
+
+ movdqu 3*16(%rsi), %xmm3 // load third message block
+ pshufb %xmm4, %xmm3
+
+ add $4*16, %rsi
+
+ midround %xmm3, %xmm0, %xmm1, %xmm2, %xmm5, %xmm7, 0 // 12--15
+ midround %xmm0, %xmm1, %xmm2, %xmm3, %xmm7, %xmm5, 0 // 16--19
+ midround %xmm1, %xmm2, %xmm3, %xmm0, %xmm5, %xmm7, 1 // 20--23
+ midround %xmm2, %xmm3, %xmm0, %xmm1, %xmm7, %xmm5, 1 // 24--27
+ midround %xmm3, %xmm0, %xmm1, %xmm2, %xmm5, %xmm7, 1 // 28--31
+ midround %xmm0, %xmm1, %xmm2, %xmm3, %xmm7, %xmm5, 1 // 32--35
+ midround %xmm1, %xmm2, %xmm3, %xmm0, %xmm5, %xmm7, 1 // 36--39
+ midround %xmm2, %xmm3, %xmm0, %xmm1, %xmm7, %xmm5, 2 // 40--43
+ midround %xmm3, %xmm0, %xmm1, %xmm2, %xmm5, %xmm7, 2 // 44--47
+ midround %xmm0, %xmm1, %xmm2, %xmm3, %xmm7, %xmm5, 2 // 48--51
+ midround %xmm1, %xmm2, %xmm3, %xmm0, %xmm5, %xmm7, 2 // 52--55
+ midround %xmm2, %xmm3, %xmm0, %xmm1, %xmm7, %xmm5, 2 // 56--59
+ midround %xmm3, %xmm0, %xmm1, %xmm2, %xmm5, %xmm7, 3 // 60--63
+ midround %xmm0, %xmm1, %xmm2, %xmm3, %xmm7, %xmm5, 3 // 64--67
+
+ // rounds 68--71
+ sha1nexte %xmm1, %xmm5
+ movdqa %xmm6, %xmm7
+ sha1msg2 %xmm1, %xmm2
+ sha1rnds4 $3, %xmm5, %xmm6
+ pxor %xmm1, %xmm3
+
+ // rounds 72--75
+ sha1nexte %xmm2, %xmm7
+ movdqa %xmm6, %xmm5
+ sha1msg2 %xmm2, %xmm3
+ sha1rnds4 $3, %xmm7, %xmm6
+
+ // rounds 76--79
+ sha1nexte %xmm3, %xmm5
+ movdqa %xmm6, %xmm7
+ sha1rnds4 $3, %xmm5, %xmm6
+
+ sha1nexte %xmm9, %xmm7 // add saved E
+ paddd %xmm8, %xmm6 // add saved ABCD
+
+ cmp %rsi, %rcx // end reached?
+ jne 0b
+
+ pshufd $0x1b, %xmm6, %xmm6 // restore order of h0--h3
+ movdqu %xmm6, (%rdi) // write h0--h3
+ pextrd $3, %xmm7, 16(%rdi) // write h4
+1: ret
+END(_libmd_sha1block_shani)
+
+ .section .rodata
+ .balign 16
+shuf_mask:
+ .8byte 0x08090a0b0c0d0e0f
+ .8byte 0x0001020304050607
+ .size shuf_mask, .-shuf_mask
+
+ .section .note.GNU-stack,"",%progbits
diff --git a/lib/libmd/amd64/sha1dispatch.c b/lib/libmd/amd64/sha1dispatch.c
new file mode 100644
index 000000000000..86509195d56e
--- /dev/null
+++ b/lib/libmd/amd64/sha1dispatch.c
@@ -0,0 +1,77 @@
+/*-
+ * Copyright (c) 2016 The Go Authors. All rights reserved.
+ * Copyright (c) 2024 Robert Clausecker <fuz@freebsd.org>
+ *
+ * Adapted from Go's crypto/sha1/sha1block_amd64.go.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/specialreg.h>
+#include <sha.h>
+#include <x86/ifunc.h>
+
+extern void _libmd_sha1block_scalar(SHA1_CTX *, const void *, size_t);
+extern void _libmd_sha1block_avx2(SHA1_CTX *, const void *, size_t);
+extern void _libmd_sha1block_shani(SHA1_CTX *, const void *, size_t);
+static void sha1block_avx2_wrapper(SHA1_CTX *, const void *, size_t);
+
+#define AVX2_STDEXT_NEEDED \
+ (CPUID_STDEXT_BMI1 | CPUID_STDEXT_AVX2 | CPUID_STDEXT_BMI2)
+
+DEFINE_UIFUNC(, void, sha1_block, (SHA1_CTX *, const void *, size_t))
+{
+ if (cpu_stdext_feature & CPUID_STDEXT_SHA)
+ return (_libmd_sha1block_shani);
+ if ((cpu_stdext_feature & AVX2_STDEXT_NEEDED) == AVX2_STDEXT_NEEDED)
+ return (sha1block_avx2_wrapper);
+ else
+ return (_libmd_sha1block_scalar);
+}
+
+static void
+sha1block_avx2_wrapper(SHA1_CTX *c, const void *data, size_t len)
+{
+ if (len >= 256) {
+ /*
+ * sha1block_avx2 calculates sha1 for 2 block per iteration.
+ * It also interleaves the precalculation for next the block.
+ * So it may read up-to 192 bytes past the end of p.
+ * We may add checks inside sha1block_avx2, but this will
+ * just turn it into a copy of sha1block_scalar,
+ * so call it directly, instead.
+ */
+ size_t safe_len = len - 128;
+
+ if (safe_len % 128 != 0)
+ safe_len -= 64;
+
+ _libmd_sha1block_avx2(c, data, safe_len);
+ _libmd_sha1block_scalar(c, data + safe_len, len - safe_len);
+ } else
+ _libmd_sha1block_scalar(c, data, len);
+}
diff --git a/lib/libmd/i386/sha.S b/lib/libmd/i386/sha.S
deleted file mode 100644
index 3bb54aa9b251..000000000000
--- a/lib/libmd/i386/sha.S
+++ /dev/null
@@ -1,1951 +0,0 @@
-/* -*- Fundamental -*- Emacs' assembler mode hoses this file */
-#ifndef PIC
-/* Run the C pre-processor over this file with one of the following defined
- * ELF - elf object files,
- * OUT - a.out object files,
- * BSDI - BSDI style a.out object files
- * SOL - Solaris style elf
- */
-
-#define TYPE(a,b) .type a,b
-#define SIZE(a,b) .size a,b
-
-#if defined(OUT) || defined(BSDI)
-#define sha1_block_x86 _sha1_block_x86
-
-#endif
-
-#ifdef OUT
-#define OK 1
-#define ALIGN 4
-#endif
-
-#ifdef BSDI
-#define OK 1
-#define ALIGN 4
-#undef SIZE
-#undef TYPE
-#define SIZE(a,b)
-#define TYPE(a,b)
-#endif
-
-#if defined(ELF) || defined(SOL)
-#define OK 1
-#define ALIGN 4
-#endif
-
-#ifndef OK
-You need to define one of
-ELF - elf systems - linux-elf, NetBSD and DG-UX
-OUT - a.out systems - linux-a.out and FreeBSD
-SOL - solaris systems, which are elf with strange comment lines
-BSDI - a.out with a very primative version of as.
-#endif
-
-/* Let the Assembler begin :-) */
- /* Don't even think of reading this code */
- /* It was automatically generated by sha1-586.pl */
- /* Which is a perl program used to generate the x86 assember for */
- /* any of elf, a.out, BSDI,Win32, or Solaris */
- /* eric <eay@cryptsoft.com> */
-
- .file "sha1-586.s"
- .version "01.01"
-gcc2_compiled.:
-.text
- .p2align ALIGN
-.globl sha1_block_x86
- TYPE(sha1_block_x86,@function)
-sha1_block_x86:
- pushl %esi
- pushl %ebp
- movl 20(%esp), %eax
- movl 16(%esp), %esi
- addl %esi, %eax
- movl 12(%esp), %ebp
- pushl %ebx
- subl $64, %eax
- pushl %edi
- movl 4(%ebp), %ebx
- subl $72, %esp
- movl 12(%ebp), %edx
- movl 16(%ebp), %edi
- movl 8(%ebp), %ecx
- movl %eax, 68(%esp)
- /* First we need to setup the X array */
- movl (%esi), %eax
-.L000start:
- /* First, load the words onto the stack in network byte order */
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, (%esp)
- movl 4(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 4(%esp)
- movl 8(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 8(%esp)
- movl 12(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 12(%esp)
- movl 16(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 16(%esp)
- movl 20(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 20(%esp)
- movl 24(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 24(%esp)
- movl 28(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 28(%esp)
- movl 32(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 32(%esp)
- movl 36(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 36(%esp)
- movl 40(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 40(%esp)
- movl 44(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 44(%esp)
- movl 48(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 48(%esp)
- movl 52(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 52(%esp)
- movl 56(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 56(%esp)
- movl 60(%esi), %eax
-.byte 15
-.byte 200 /* bswapl %eax */
- movl %eax, 60(%esp)
- /* We now have the X array on the stack */
- /* starting at sp-4 */
- movl %esi, 64(%esp)
-
- /* Start processing */
- movl (%ebp), %eax
- /* 00_15 0 */
- movl %ecx, %esi
- movl %eax, %ebp
- xorl %edx, %esi
- roll $5, %ebp
- andl %ebx, %esi
- addl %edi, %ebp
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- movl (%esp), %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- xorl %edx, %esi
- leal 1518500249(%ebp,%edi,1),%ebp
- movl %ebx, %edi
- addl %ebp, %esi
- xorl %ecx, %edi
- movl %esi, %ebp
- andl %eax, %edi
- roll $5, %ebp
- addl %edx, %ebp
- movl 4(%esp), %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- xorl %ecx, %edi
-.byte 209
-.byte 200 /* rorl $1 %eax */
- leal 1518500249(%ebp,%edx,1),%ebp
- addl %ebp, %edi
- /* 00_15 2 */
- movl %eax, %edx
- movl %edi, %ebp
- xorl %ebx, %edx
- roll $5, %ebp
- andl %esi, %edx
- addl %ecx, %ebp
-.byte 209
-.byte 206 /* rorl $1 %esi */
- movl 8(%esp), %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- xorl %ebx, %edx
- leal 1518500249(%ebp,%ecx,1),%ebp
- movl %esi, %ecx
- addl %ebp, %edx
- xorl %eax, %ecx
- movl %edx, %ebp
- andl %edi, %ecx
- roll $5, %ebp
- addl %ebx, %ebp
- movl 12(%esp), %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- xorl %eax, %ecx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- leal 1518500249(%ebp,%ebx,1),%ebp
- addl %ebp, %ecx
- /* 00_15 4 */
- movl %edi, %ebx
- movl %ecx, %ebp
- xorl %esi, %ebx
- roll $5, %ebp
- andl %edx, %ebx
- addl %eax, %ebp
-.byte 209
-.byte 202 /* rorl $1 %edx */
- movl 16(%esp), %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- xorl %esi, %ebx
- leal 1518500249(%ebp,%eax,1),%ebp
- movl %edx, %eax
- addl %ebp, %ebx
- xorl %edi, %eax
- movl %ebx, %ebp
- andl %ecx, %eax
- roll $5, %ebp
- addl %esi, %ebp
- movl 20(%esp), %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- xorl %edi, %eax
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- leal 1518500249(%ebp,%esi,1),%ebp
- addl %ebp, %eax
- /* 00_15 6 */
- movl %ecx, %esi
- movl %eax, %ebp
- xorl %edx, %esi
- roll $5, %ebp
- andl %ebx, %esi
- addl %edi, %ebp
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- movl 24(%esp), %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- xorl %edx, %esi
- leal 1518500249(%ebp,%edi,1),%ebp
- movl %ebx, %edi
- addl %ebp, %esi
- xorl %ecx, %edi
- movl %esi, %ebp
- andl %eax, %edi
- roll $5, %ebp
- addl %edx, %ebp
- movl 28(%esp), %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- xorl %ecx, %edi
-.byte 209
-.byte 200 /* rorl $1 %eax */
- leal 1518500249(%ebp,%edx,1),%ebp
- addl %ebp, %edi
- /* 00_15 8 */
- movl %eax, %edx
- movl %edi, %ebp
- xorl %ebx, %edx
- roll $5, %ebp
- andl %esi, %edx
- addl %ecx, %ebp
-.byte 209
-.byte 206 /* rorl $1 %esi */
- movl 32(%esp), %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- xorl %ebx, %edx
- leal 1518500249(%ebp,%ecx,1),%ebp
- movl %esi, %ecx
- addl %ebp, %edx
- xorl %eax, %ecx
- movl %edx, %ebp
- andl %edi, %ecx
- roll $5, %ebp
- addl %ebx, %ebp
- movl 36(%esp), %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- xorl %eax, %ecx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- leal 1518500249(%ebp,%ebx,1),%ebp
- addl %ebp, %ecx
- /* 00_15 10 */
- movl %edi, %ebx
- movl %ecx, %ebp
- xorl %esi, %ebx
- roll $5, %ebp
- andl %edx, %ebx
- addl %eax, %ebp
-.byte 209
-.byte 202 /* rorl $1 %edx */
- movl 40(%esp), %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- xorl %esi, %ebx
- leal 1518500249(%ebp,%eax,1),%ebp
- movl %edx, %eax
- addl %ebp, %ebx
- xorl %edi, %eax
- movl %ebx, %ebp
- andl %ecx, %eax
- roll $5, %ebp
- addl %esi, %ebp
- movl 44(%esp), %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- xorl %edi, %eax
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- leal 1518500249(%ebp,%esi,1),%ebp
- addl %ebp, %eax
- /* 00_15 12 */
- movl %ecx, %esi
- movl %eax, %ebp
- xorl %edx, %esi
- roll $5, %ebp
- andl %ebx, %esi
- addl %edi, %ebp
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- movl 48(%esp), %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- xorl %edx, %esi
- leal 1518500249(%ebp,%edi,1),%ebp
- movl %ebx, %edi
- addl %ebp, %esi
- xorl %ecx, %edi
- movl %esi, %ebp
- andl %eax, %edi
- roll $5, %ebp
- addl %edx, %ebp
- movl 52(%esp), %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- xorl %ecx, %edi
-.byte 209
-.byte 200 /* rorl $1 %eax */
- leal 1518500249(%ebp,%edx,1),%ebp
- addl %ebp, %edi
- /* 00_15 14 */
- movl %eax, %edx
- movl %edi, %ebp
- xorl %ebx, %edx
- roll $5, %ebp
- andl %esi, %edx
- addl %ecx, %ebp
-.byte 209
-.byte 206 /* rorl $1 %esi */
- movl 56(%esp), %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- xorl %ebx, %edx
- leal 1518500249(%ebp,%ecx,1),%ebp
- movl %esi, %ecx
- addl %ebp, %edx
- xorl %eax, %ecx
- movl %edx, %ebp
- andl %edi, %ecx
- roll $5, %ebp
- addl %ebx, %ebp
- movl 60(%esp), %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- xorl %eax, %ecx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- leal 1518500249(%ebp,%ebx,1),%ebp
- addl %ebp, %ecx
- /* 16_19 16 */
- nop
- movl (%esp), %ebp
- movl 8(%esp), %ebx
- xorl %ebp, %ebx
- movl 32(%esp), %ebp
- xorl %ebp, %ebx
- movl 52(%esp), %ebp
- xorl %ebp, %ebx
- movl %edi, %ebp
-.byte 209
-.byte 195 /* roll $1 %ebx */
- xorl %esi, %ebp
- movl %ebx, (%esp)
- andl %edx, %ebp
- leal 1518500249(%ebx,%eax,1),%ebx
- xorl %esi, %ebp
- movl %ecx, %eax
- addl %ebp, %ebx
- roll $5, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %eax, %ebx
- movl 4(%esp), %eax
- movl 12(%esp), %ebp
- xorl %ebp, %eax
- movl 36(%esp), %ebp
- xorl %ebp, %eax
- movl 56(%esp), %ebp
-.byte 209
-.byte 202 /* rorl $1 %edx */
- xorl %ebp, %eax
-.byte 209
-.byte 192 /* roll $1 %eax */
- movl %edx, %ebp
- xorl %edi, %ebp
- movl %eax, 4(%esp)
- andl %ecx, %ebp
- leal 1518500249(%eax,%esi,1),%eax
- xorl %edi, %ebp
- movl %ebx, %esi
- roll $5, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %esi, %eax
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %ebp, %eax
- /* 16_19 18 */
- movl 8(%esp), %ebp
- movl 16(%esp), %esi
- xorl %ebp, %esi
- movl 40(%esp), %ebp
- xorl %ebp, %esi
- movl 60(%esp), %ebp
- xorl %ebp, %esi
- movl %ecx, %ebp
-.byte 209
-.byte 198 /* roll $1 %esi */
- xorl %edx, %ebp
- movl %esi, 8(%esp)
- andl %ebx, %ebp
- leal 1518500249(%esi,%edi,1),%esi
- xorl %edx, %ebp
- movl %eax, %edi
- addl %ebp, %esi
- roll $5, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %edi, %esi
- movl 12(%esp), %edi
- movl 20(%esp), %ebp
- xorl %ebp, %edi
- movl 44(%esp), %ebp
- xorl %ebp, %edi
- movl (%esp), %ebp
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- xorl %ebp, %edi
-.byte 209
-.byte 199 /* roll $1 %edi */
- movl %ebx, %ebp
- xorl %ecx, %ebp
- movl %edi, 12(%esp)
- andl %eax, %ebp
- leal 1518500249(%edi,%edx,1),%edi
- xorl %ecx, %ebp
- movl %esi, %edx
- roll $5, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %edx, %edi
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %ebp, %edi
- /* 20_39 20 */
- movl 16(%esp), %edx
- movl 24(%esp), %ebp
- xorl %ebp, %edx
- movl 48(%esp), %ebp
- xorl %ebp, %edx
- movl 4(%esp), %ebp
- xorl %ebp, %edx
- movl %esi, %ebp
-.byte 209
-.byte 194 /* roll $1 %edx */
- xorl %eax, %ebp
- movl %edx, 16(%esp)
- xorl %ebx, %ebp
- leal 1859775393(%edx,%ecx,1),%edx
- movl %edi, %ecx
- roll $5, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ebp, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ecx, %edx
- /* 20_39 21 */
- movl 20(%esp), %ecx
- movl 28(%esp), %ebp
- xorl %ebp, %ecx
- movl 52(%esp), %ebp
- xorl %ebp, %ecx
- movl 8(%esp), %ebp
- xorl %ebp, %ecx
- movl %edi, %ebp
-.byte 209
-.byte 193 /* roll $1 %ecx */
- xorl %esi, %ebp
- movl %ecx, 20(%esp)
- xorl %eax, %ebp
- leal 1859775393(%ecx,%ebx,1),%ecx
- movl %edx, %ebx
- roll $5, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebp, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebx, %ecx
- /* 20_39 22 */
- movl 24(%esp), %ebx
- movl 32(%esp), %ebp
- xorl %ebp, %ebx
- movl 56(%esp), %ebp
- xorl %ebp, %ebx
- movl 12(%esp), %ebp
- xorl %ebp, %ebx
- movl %edx, %ebp
-.byte 209
-.byte 195 /* roll $1 %ebx */
- xorl %edi, %ebp
- movl %ebx, 24(%esp)
- xorl %esi, %ebp
- leal 1859775393(%ebx,%eax,1),%ebx
- movl %ecx, %eax
- roll $5, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %ebp, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %eax, %ebx
- /* 20_39 23 */
- movl 28(%esp), %eax
- movl 36(%esp), %ebp
- xorl %ebp, %eax
- movl 60(%esp), %ebp
- xorl %ebp, %eax
- movl 16(%esp), %ebp
- xorl %ebp, %eax
- movl %ecx, %ebp
-.byte 209
-.byte 192 /* roll $1 %eax */
- xorl %edx, %ebp
- movl %eax, 28(%esp)
- xorl %edi, %ebp
- leal 1859775393(%eax,%esi,1),%eax
- movl %ebx, %esi
- roll $5, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %ebp, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %esi, %eax
- /* 20_39 24 */
- movl 32(%esp), %esi
- movl 40(%esp), %ebp
- xorl %ebp, %esi
- movl (%esp), %ebp
- xorl %ebp, %esi
- movl 20(%esp), %ebp
- xorl %ebp, %esi
- movl %ebx, %ebp
-.byte 209
-.byte 198 /* roll $1 %esi */
- xorl %ecx, %ebp
- movl %esi, 32(%esp)
- xorl %edx, %ebp
- leal 1859775393(%esi,%edi,1),%esi
- movl %eax, %edi
- roll $5, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %ebp, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %edi, %esi
- /* 20_39 25 */
- movl 36(%esp), %edi
- movl 44(%esp), %ebp
- xorl %ebp, %edi
- movl 4(%esp), %ebp
- xorl %ebp, %edi
- movl 24(%esp), %ebp
- xorl %ebp, %edi
- movl %eax, %ebp
-.byte 209
-.byte 199 /* roll $1 %edi */
- xorl %ebx, %ebp
- movl %edi, 36(%esp)
- xorl %ecx, %ebp
- leal 1859775393(%edi,%edx,1),%edi
- movl %esi, %edx
- roll $5, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %ebp, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %edx, %edi
- /* 20_39 26 */
- movl 40(%esp), %edx
- movl 48(%esp), %ebp
- xorl %ebp, %edx
- movl 8(%esp), %ebp
- xorl %ebp, %edx
- movl 28(%esp), %ebp
- xorl %ebp, %edx
- movl %esi, %ebp
-.byte 209
-.byte 194 /* roll $1 %edx */
- xorl %eax, %ebp
- movl %edx, 40(%esp)
- xorl %ebx, %ebp
- leal 1859775393(%edx,%ecx,1),%edx
- movl %edi, %ecx
- roll $5, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ebp, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ecx, %edx
- /* 20_39 27 */
- movl 44(%esp), %ecx
- movl 52(%esp), %ebp
- xorl %ebp, %ecx
- movl 12(%esp), %ebp
- xorl %ebp, %ecx
- movl 32(%esp), %ebp
- xorl %ebp, %ecx
- movl %edi, %ebp
-.byte 209
-.byte 193 /* roll $1 %ecx */
- xorl %esi, %ebp
- movl %ecx, 44(%esp)
- xorl %eax, %ebp
- leal 1859775393(%ecx,%ebx,1),%ecx
- movl %edx, %ebx
- roll $5, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebp, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebx, %ecx
- /* 20_39 28 */
- movl 48(%esp), %ebx
- movl 56(%esp), %ebp
- xorl %ebp, %ebx
- movl 16(%esp), %ebp
- xorl %ebp, %ebx
- movl 36(%esp), %ebp
- xorl %ebp, %ebx
- movl %edx, %ebp
-.byte 209
-.byte 195 /* roll $1 %ebx */
- xorl %edi, %ebp
- movl %ebx, 48(%esp)
- xorl %esi, %ebp
- leal 1859775393(%ebx,%eax,1),%ebx
- movl %ecx, %eax
- roll $5, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %ebp, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %eax, %ebx
- /* 20_39 29 */
- movl 52(%esp), %eax
- movl 60(%esp), %ebp
- xorl %ebp, %eax
- movl 20(%esp), %ebp
- xorl %ebp, %eax
- movl 40(%esp), %ebp
- xorl %ebp, %eax
- movl %ecx, %ebp
-.byte 209
-.byte 192 /* roll $1 %eax */
- xorl %edx, %ebp
- movl %eax, 52(%esp)
- xorl %edi, %ebp
- leal 1859775393(%eax,%esi,1),%eax
- movl %ebx, %esi
- roll $5, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %ebp, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %esi, %eax
- /* 20_39 30 */
- movl 56(%esp), %esi
- movl (%esp), %ebp
- xorl %ebp, %esi
- movl 24(%esp), %ebp
- xorl %ebp, %esi
- movl 44(%esp), %ebp
- xorl %ebp, %esi
- movl %ebx, %ebp
-.byte 209
-.byte 198 /* roll $1 %esi */
- xorl %ecx, %ebp
- movl %esi, 56(%esp)
- xorl %edx, %ebp
- leal 1859775393(%esi,%edi,1),%esi
- movl %eax, %edi
- roll $5, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %ebp, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %edi, %esi
- /* 20_39 31 */
- movl 60(%esp), %edi
- movl 4(%esp), %ebp
- xorl %ebp, %edi
- movl 28(%esp), %ebp
- xorl %ebp, %edi
- movl 48(%esp), %ebp
- xorl %ebp, %edi
- movl %eax, %ebp
-.byte 209
-.byte 199 /* roll $1 %edi */
- xorl %ebx, %ebp
- movl %edi, 60(%esp)
- xorl %ecx, %ebp
- leal 1859775393(%edi,%edx,1),%edi
- movl %esi, %edx
- roll $5, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %ebp, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %edx, %edi
- /* 20_39 32 */
- movl (%esp), %edx
- movl 8(%esp), %ebp
- xorl %ebp, %edx
- movl 32(%esp), %ebp
- xorl %ebp, %edx
- movl 52(%esp), %ebp
- xorl %ebp, %edx
- movl %esi, %ebp
-.byte 209
-.byte 194 /* roll $1 %edx */
- xorl %eax, %ebp
- movl %edx, (%esp)
- xorl %ebx, %ebp
- leal 1859775393(%edx,%ecx,1),%edx
- movl %edi, %ecx
- roll $5, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ebp, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ecx, %edx
- /* 20_39 33 */
- movl 4(%esp), %ecx
- movl 12(%esp), %ebp
- xorl %ebp, %ecx
- movl 36(%esp), %ebp
- xorl %ebp, %ecx
- movl 56(%esp), %ebp
- xorl %ebp, %ecx
- movl %edi, %ebp
-.byte 209
-.byte 193 /* roll $1 %ecx */
- xorl %esi, %ebp
- movl %ecx, 4(%esp)
- xorl %eax, %ebp
- leal 1859775393(%ecx,%ebx,1),%ecx
- movl %edx, %ebx
- roll $5, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebp, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebx, %ecx
- /* 20_39 34 */
- movl 8(%esp), %ebx
- movl 16(%esp), %ebp
- xorl %ebp, %ebx
- movl 40(%esp), %ebp
- xorl %ebp, %ebx
- movl 60(%esp), %ebp
- xorl %ebp, %ebx
- movl %edx, %ebp
-.byte 209
-.byte 195 /* roll $1 %ebx */
- xorl %edi, %ebp
- movl %ebx, 8(%esp)
- xorl %esi, %ebp
- leal 1859775393(%ebx,%eax,1),%ebx
- movl %ecx, %eax
- roll $5, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %ebp, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %eax, %ebx
- /* 20_39 35 */
- movl 12(%esp), %eax
- movl 20(%esp), %ebp
- xorl %ebp, %eax
- movl 44(%esp), %ebp
- xorl %ebp, %eax
- movl (%esp), %ebp
- xorl %ebp, %eax
- movl %ecx, %ebp
-.byte 209
-.byte 192 /* roll $1 %eax */
- xorl %edx, %ebp
- movl %eax, 12(%esp)
- xorl %edi, %ebp
- leal 1859775393(%eax,%esi,1),%eax
- movl %ebx, %esi
- roll $5, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %ebp, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %esi, %eax
- /* 20_39 36 */
- movl 16(%esp), %esi
- movl 24(%esp), %ebp
- xorl %ebp, %esi
- movl 48(%esp), %ebp
- xorl %ebp, %esi
- movl 4(%esp), %ebp
- xorl %ebp, %esi
- movl %ebx, %ebp
-.byte 209
-.byte 198 /* roll $1 %esi */
- xorl %ecx, %ebp
- movl %esi, 16(%esp)
- xorl %edx, %ebp
- leal 1859775393(%esi,%edi,1),%esi
- movl %eax, %edi
- roll $5, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %ebp, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %edi, %esi
- /* 20_39 37 */
- movl 20(%esp), %edi
- movl 28(%esp), %ebp
- xorl %ebp, %edi
- movl 52(%esp), %ebp
- xorl %ebp, %edi
- movl 8(%esp), %ebp
- xorl %ebp, %edi
- movl %eax, %ebp
-.byte 209
-.byte 199 /* roll $1 %edi */
- xorl %ebx, %ebp
- movl %edi, 20(%esp)
- xorl %ecx, %ebp
- leal 1859775393(%edi,%edx,1),%edi
- movl %esi, %edx
- roll $5, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %ebp, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %edx, %edi
- /* 20_39 38 */
- movl 24(%esp), %edx
- movl 32(%esp), %ebp
- xorl %ebp, %edx
- movl 56(%esp), %ebp
- xorl %ebp, %edx
- movl 12(%esp), %ebp
- xorl %ebp, %edx
- movl %esi, %ebp
-.byte 209
-.byte 194 /* roll $1 %edx */
- xorl %eax, %ebp
- movl %edx, 24(%esp)
- xorl %ebx, %ebp
- leal 1859775393(%edx,%ecx,1),%edx
- movl %edi, %ecx
- roll $5, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ebp, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ecx, %edx
- /* 20_39 39 */
- movl 28(%esp), %ecx
- movl 36(%esp), %ebp
- xorl %ebp, %ecx
- movl 60(%esp), %ebp
- xorl %ebp, %ecx
- movl 16(%esp), %ebp
- xorl %ebp, %ecx
- movl %edi, %ebp
-.byte 209
-.byte 193 /* roll $1 %ecx */
- xorl %esi, %ebp
- movl %ecx, 28(%esp)
- xorl %eax, %ebp
- leal 1859775393(%ecx,%ebx,1),%ecx
- movl %edx, %ebx
- roll $5, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebp, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebx, %ecx
- /* 40_59 40 */
- movl 32(%esp), %ebx
- movl 40(%esp), %ebp
- xorl %ebp, %ebx
- movl (%esp), %ebp
- xorl %ebp, %ebx
- movl 20(%esp), %ebp
- xorl %ebp, %ebx
- movl %edx, %ebp
-.byte 209
-.byte 195 /* roll $1 %ebx */
- orl %edi, %ebp
- movl %ebx, 32(%esp)
- andl %esi, %ebp
- leal 2400959708(%ebx,%eax,1),%ebx
- movl %edx, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- andl %edi, %eax
- orl %eax, %ebp
- movl %ecx, %eax
- roll $5, %eax
- addl %eax, %ebp
- movl 36(%esp), %eax
- addl %ebp, %ebx
- movl 44(%esp), %ebp
- xorl %ebp, %eax
- movl 4(%esp), %ebp
- xorl %ebp, %eax
- movl 24(%esp), %ebp
-.byte 209
-.byte 202 /* rorl $1 %edx */
- xorl %ebp, %eax
-.byte 209
-.byte 192 /* roll $1 %eax */
- movl %ecx, %ebp
- movl %eax, 36(%esp)
- orl %edx, %ebp
- leal 2400959708(%eax,%esi,1),%eax
- movl %ecx, %esi
- andl %edi, %ebp
- andl %edx, %esi
- orl %esi, %ebp
- movl %ebx, %esi
- roll $5, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %esi, %ebp
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %ebp, %eax
- /* 40_59 41 */
- /* 40_59 42 */
- movl 40(%esp), %esi
- movl 48(%esp), %ebp
- xorl %ebp, %esi
- movl 8(%esp), %ebp
- xorl %ebp, %esi
- movl 28(%esp), %ebp
- xorl %ebp, %esi
- movl %ebx, %ebp
-.byte 209
-.byte 198 /* roll $1 %esi */
- orl %ecx, %ebp
- movl %esi, 40(%esp)
- andl %edx, %ebp
- leal 2400959708(%esi,%edi,1),%esi
- movl %ebx, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- andl %ecx, %edi
- orl %edi, %ebp
- movl %eax, %edi
- roll $5, %edi
- addl %edi, %ebp
- movl 44(%esp), %edi
- addl %ebp, %esi
- movl 52(%esp), %ebp
- xorl %ebp, %edi
- movl 12(%esp), %ebp
- xorl %ebp, %edi
- movl 32(%esp), %ebp
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- xorl %ebp, %edi
-.byte 209
-.byte 199 /* roll $1 %edi */
- movl %eax, %ebp
- movl %edi, 44(%esp)
- orl %ebx, %ebp
- leal 2400959708(%edi,%edx,1),%edi
- movl %eax, %edx
- andl %ecx, %ebp
- andl %ebx, %edx
- orl %edx, %ebp
- movl %esi, %edx
- roll $5, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %edx, %ebp
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %ebp, %edi
- /* 40_59 43 */
- /* 40_59 44 */
- movl 48(%esp), %edx
- movl 56(%esp), %ebp
- xorl %ebp, %edx
- movl 16(%esp), %ebp
- xorl %ebp, %edx
- movl 36(%esp), %ebp
- xorl %ebp, %edx
- movl %esi, %ebp
-.byte 209
-.byte 194 /* roll $1 %edx */
- orl %eax, %ebp
- movl %edx, 48(%esp)
- andl %ebx, %ebp
- leal 2400959708(%edx,%ecx,1),%edx
- movl %esi, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- andl %eax, %ecx
- orl %ecx, %ebp
- movl %edi, %ecx
- roll $5, %ecx
- addl %ecx, %ebp
- movl 52(%esp), %ecx
- addl %ebp, %edx
- movl 60(%esp), %ebp
- xorl %ebp, %ecx
- movl 20(%esp), %ebp
- xorl %ebp, %ecx
- movl 40(%esp), %ebp
-.byte 209
-.byte 206 /* rorl $1 %esi */
- xorl %ebp, %ecx
-.byte 209
-.byte 193 /* roll $1 %ecx */
- movl %edi, %ebp
- movl %ecx, 52(%esp)
- orl %esi, %ebp
- leal 2400959708(%ecx,%ebx,1),%ecx
- movl %edi, %ebx
- andl %eax, %ebp
- andl %esi, %ebx
- orl %ebx, %ebp
- movl %edx, %ebx
- roll $5, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebx, %ebp
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebp, %ecx
- /* 40_59 45 */
- /* 40_59 46 */
- movl 56(%esp), %ebx
- movl (%esp), %ebp
- xorl %ebp, %ebx
- movl 24(%esp), %ebp
- xorl %ebp, %ebx
- movl 44(%esp), %ebp
- xorl %ebp, %ebx
- movl %edx, %ebp
-.byte 209
-.byte 195 /* roll $1 %ebx */
- orl %edi, %ebp
- movl %ebx, 56(%esp)
- andl %esi, %ebp
- leal 2400959708(%ebx,%eax,1),%ebx
- movl %edx, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- andl %edi, %eax
- orl %eax, %ebp
- movl %ecx, %eax
- roll $5, %eax
- addl %eax, %ebp
- movl 60(%esp), %eax
- addl %ebp, %ebx
- movl 4(%esp), %ebp
- xorl %ebp, %eax
- movl 28(%esp), %ebp
- xorl %ebp, %eax
- movl 48(%esp), %ebp
-.byte 209
-.byte 202 /* rorl $1 %edx */
- xorl %ebp, %eax
-.byte 209
-.byte 192 /* roll $1 %eax */
- movl %ecx, %ebp
- movl %eax, 60(%esp)
- orl %edx, %ebp
- leal 2400959708(%eax,%esi,1),%eax
- movl %ecx, %esi
- andl %edi, %ebp
- andl %edx, %esi
- orl %esi, %ebp
- movl %ebx, %esi
- roll $5, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %esi, %ebp
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %ebp, %eax
- /* 40_59 47 */
- /* 40_59 48 */
- movl (%esp), %esi
- movl 8(%esp), %ebp
- xorl %ebp, %esi
- movl 32(%esp), %ebp
- xorl %ebp, %esi
- movl 52(%esp), %ebp
- xorl %ebp, %esi
- movl %ebx, %ebp
-.byte 209
-.byte 198 /* roll $1 %esi */
- orl %ecx, %ebp
- movl %esi, (%esp)
- andl %edx, %ebp
- leal 2400959708(%esi,%edi,1),%esi
- movl %ebx, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- andl %ecx, %edi
- orl %edi, %ebp
- movl %eax, %edi
- roll $5, %edi
- addl %edi, %ebp
- movl 4(%esp), %edi
- addl %ebp, %esi
- movl 12(%esp), %ebp
- xorl %ebp, %edi
- movl 36(%esp), %ebp
- xorl %ebp, %edi
- movl 56(%esp), %ebp
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- xorl %ebp, %edi
-.byte 209
-.byte 199 /* roll $1 %edi */
- movl %eax, %ebp
- movl %edi, 4(%esp)
- orl %ebx, %ebp
- leal 2400959708(%edi,%edx,1),%edi
- movl %eax, %edx
- andl %ecx, %ebp
- andl %ebx, %edx
- orl %edx, %ebp
- movl %esi, %edx
- roll $5, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %edx, %ebp
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %ebp, %edi
- /* 40_59 49 */
- /* 40_59 50 */
- movl 8(%esp), %edx
- movl 16(%esp), %ebp
- xorl %ebp, %edx
- movl 40(%esp), %ebp
- xorl %ebp, %edx
- movl 60(%esp), %ebp
- xorl %ebp, %edx
- movl %esi, %ebp
-.byte 209
-.byte 194 /* roll $1 %edx */
- orl %eax, %ebp
- movl %edx, 8(%esp)
- andl %ebx, %ebp
- leal 2400959708(%edx,%ecx,1),%edx
- movl %esi, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- andl %eax, %ecx
- orl %ecx, %ebp
- movl %edi, %ecx
- roll $5, %ecx
- addl %ecx, %ebp
- movl 12(%esp), %ecx
- addl %ebp, %edx
- movl 20(%esp), %ebp
- xorl %ebp, %ecx
- movl 44(%esp), %ebp
- xorl %ebp, %ecx
- movl (%esp), %ebp
-.byte 209
-.byte 206 /* rorl $1 %esi */
- xorl %ebp, %ecx
-.byte 209
-.byte 193 /* roll $1 %ecx */
- movl %edi, %ebp
- movl %ecx, 12(%esp)
- orl %esi, %ebp
- leal 2400959708(%ecx,%ebx,1),%ecx
- movl %edi, %ebx
- andl %eax, %ebp
- andl %esi, %ebx
- orl %ebx, %ebp
- movl %edx, %ebx
- roll $5, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebx, %ebp
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebp, %ecx
- /* 40_59 51 */
- /* 40_59 52 */
- movl 16(%esp), %ebx
- movl 24(%esp), %ebp
- xorl %ebp, %ebx
- movl 48(%esp), %ebp
- xorl %ebp, %ebx
- movl 4(%esp), %ebp
- xorl %ebp, %ebx
- movl %edx, %ebp
-.byte 209
-.byte 195 /* roll $1 %ebx */
- orl %edi, %ebp
- movl %ebx, 16(%esp)
- andl %esi, %ebp
- leal 2400959708(%ebx,%eax,1),%ebx
- movl %edx, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- andl %edi, %eax
- orl %eax, %ebp
- movl %ecx, %eax
- roll $5, %eax
- addl %eax, %ebp
- movl 20(%esp), %eax
- addl %ebp, %ebx
- movl 28(%esp), %ebp
- xorl %ebp, %eax
- movl 52(%esp), %ebp
- xorl %ebp, %eax
- movl 8(%esp), %ebp
-.byte 209
-.byte 202 /* rorl $1 %edx */
- xorl %ebp, %eax
-.byte 209
-.byte 192 /* roll $1 %eax */
- movl %ecx, %ebp
- movl %eax, 20(%esp)
- orl %edx, %ebp
- leal 2400959708(%eax,%esi,1),%eax
- movl %ecx, %esi
- andl %edi, %ebp
- andl %edx, %esi
- orl %esi, %ebp
- movl %ebx, %esi
- roll $5, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %esi, %ebp
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %ebp, %eax
- /* 40_59 53 */
- /* 40_59 54 */
- movl 24(%esp), %esi
- movl 32(%esp), %ebp
- xorl %ebp, %esi
- movl 56(%esp), %ebp
- xorl %ebp, %esi
- movl 12(%esp), %ebp
- xorl %ebp, %esi
- movl %ebx, %ebp
-.byte 209
-.byte 198 /* roll $1 %esi */
- orl %ecx, %ebp
- movl %esi, 24(%esp)
- andl %edx, %ebp
- leal 2400959708(%esi,%edi,1),%esi
- movl %ebx, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- andl %ecx, %edi
- orl %edi, %ebp
- movl %eax, %edi
- roll $5, %edi
- addl %edi, %ebp
- movl 28(%esp), %edi
- addl %ebp, %esi
- movl 36(%esp), %ebp
- xorl %ebp, %edi
- movl 60(%esp), %ebp
- xorl %ebp, %edi
- movl 16(%esp), %ebp
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- xorl %ebp, %edi
-.byte 209
-.byte 199 /* roll $1 %edi */
- movl %eax, %ebp
- movl %edi, 28(%esp)
- orl %ebx, %ebp
- leal 2400959708(%edi,%edx,1),%edi
- movl %eax, %edx
- andl %ecx, %ebp
- andl %ebx, %edx
- orl %edx, %ebp
- movl %esi, %edx
- roll $5, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %edx, %ebp
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %ebp, %edi
- /* 40_59 55 */
- /* 40_59 56 */
- movl 32(%esp), %edx
- movl 40(%esp), %ebp
- xorl %ebp, %edx
- movl (%esp), %ebp
- xorl %ebp, %edx
- movl 20(%esp), %ebp
- xorl %ebp, %edx
- movl %esi, %ebp
-.byte 209
-.byte 194 /* roll $1 %edx */
- orl %eax, %ebp
- movl %edx, 32(%esp)
- andl %ebx, %ebp
- leal 2400959708(%edx,%ecx,1),%edx
- movl %esi, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- andl %eax, %ecx
- orl %ecx, %ebp
- movl %edi, %ecx
- roll $5, %ecx
- addl %ecx, %ebp
- movl 36(%esp), %ecx
- addl %ebp, %edx
- movl 44(%esp), %ebp
- xorl %ebp, %ecx
- movl 4(%esp), %ebp
- xorl %ebp, %ecx
- movl 24(%esp), %ebp
-.byte 209
-.byte 206 /* rorl $1 %esi */
- xorl %ebp, %ecx
-.byte 209
-.byte 193 /* roll $1 %ecx */
- movl %edi, %ebp
- movl %ecx, 36(%esp)
- orl %esi, %ebp
- leal 2400959708(%ecx,%ebx,1),%ecx
- movl %edi, %ebx
- andl %eax, %ebp
- andl %esi, %ebx
- orl %ebx, %ebp
- movl %edx, %ebx
- roll $5, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebx, %ebp
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebp, %ecx
- /* 40_59 57 */
- /* 40_59 58 */
- movl 40(%esp), %ebx
- movl 48(%esp), %ebp
- xorl %ebp, %ebx
- movl 8(%esp), %ebp
- xorl %ebp, %ebx
- movl 28(%esp), %ebp
- xorl %ebp, %ebx
- movl %edx, %ebp
-.byte 209
-.byte 195 /* roll $1 %ebx */
- orl %edi, %ebp
- movl %ebx, 40(%esp)
- andl %esi, %ebp
- leal 2400959708(%ebx,%eax,1),%ebx
- movl %edx, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- andl %edi, %eax
- orl %eax, %ebp
- movl %ecx, %eax
- roll $5, %eax
- addl %eax, %ebp
- movl 44(%esp), %eax
- addl %ebp, %ebx
- movl 52(%esp), %ebp
- xorl %ebp, %eax
- movl 12(%esp), %ebp
- xorl %ebp, %eax
- movl 32(%esp), %ebp
-.byte 209
-.byte 202 /* rorl $1 %edx */
- xorl %ebp, %eax
-.byte 209
-.byte 192 /* roll $1 %eax */
- movl %ecx, %ebp
- movl %eax, 44(%esp)
- orl %edx, %ebp
- leal 2400959708(%eax,%esi,1),%eax
- movl %ecx, %esi
- andl %edi, %ebp
- andl %edx, %esi
- orl %esi, %ebp
- movl %ebx, %esi
- roll $5, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %esi, %ebp
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %ebp, %eax
- /* 40_59 59 */
- /* 20_39 60 */
- movl 48(%esp), %esi
- movl 56(%esp), %ebp
- xorl %ebp, %esi
- movl 16(%esp), %ebp
- xorl %ebp, %esi
- movl 36(%esp), %ebp
- xorl %ebp, %esi
- movl %ebx, %ebp
-.byte 209
-.byte 198 /* roll $1 %esi */
- xorl %ecx, %ebp
- movl %esi, 48(%esp)
- xorl %edx, %ebp
- leal 3395469782(%esi,%edi,1),%esi
- movl %eax, %edi
- roll $5, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %ebp, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %edi, %esi
- /* 20_39 61 */
- movl 52(%esp), %edi
- movl 60(%esp), %ebp
- xorl %ebp, %edi
- movl 20(%esp), %ebp
- xorl %ebp, %edi
- movl 40(%esp), %ebp
- xorl %ebp, %edi
- movl %eax, %ebp
-.byte 209
-.byte 199 /* roll $1 %edi */
- xorl %ebx, %ebp
- movl %edi, 52(%esp)
- xorl %ecx, %ebp
- leal 3395469782(%edi,%edx,1),%edi
- movl %esi, %edx
- roll $5, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %ebp, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %edx, %edi
- /* 20_39 62 */
- movl 56(%esp), %edx
- movl (%esp), %ebp
- xorl %ebp, %edx
- movl 24(%esp), %ebp
- xorl %ebp, %edx
- movl 44(%esp), %ebp
- xorl %ebp, %edx
- movl %esi, %ebp
-.byte 209
-.byte 194 /* roll $1 %edx */
- xorl %eax, %ebp
- movl %edx, 56(%esp)
- xorl %ebx, %ebp
- leal 3395469782(%edx,%ecx,1),%edx
- movl %edi, %ecx
- roll $5, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ebp, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ecx, %edx
- /* 20_39 63 */
- movl 60(%esp), %ecx
- movl 4(%esp), %ebp
- xorl %ebp, %ecx
- movl 28(%esp), %ebp
- xorl %ebp, %ecx
- movl 48(%esp), %ebp
- xorl %ebp, %ecx
- movl %edi, %ebp
-.byte 209
-.byte 193 /* roll $1 %ecx */
- xorl %esi, %ebp
- movl %ecx, 60(%esp)
- xorl %eax, %ebp
- leal 3395469782(%ecx,%ebx,1),%ecx
- movl %edx, %ebx
- roll $5, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebp, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebx, %ecx
- /* 20_39 64 */
- movl (%esp), %ebx
- movl 8(%esp), %ebp
- xorl %ebp, %ebx
- movl 32(%esp), %ebp
- xorl %ebp, %ebx
- movl 52(%esp), %ebp
- xorl %ebp, %ebx
- movl %edx, %ebp
-.byte 209
-.byte 195 /* roll $1 %ebx */
- xorl %edi, %ebp
- movl %ebx, (%esp)
- xorl %esi, %ebp
- leal 3395469782(%ebx,%eax,1),%ebx
- movl %ecx, %eax
- roll $5, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %ebp, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %eax, %ebx
- /* 20_39 65 */
- movl 4(%esp), %eax
- movl 12(%esp), %ebp
- xorl %ebp, %eax
- movl 36(%esp), %ebp
- xorl %ebp, %eax
- movl 56(%esp), %ebp
- xorl %ebp, %eax
- movl %ecx, %ebp
-.byte 209
-.byte 192 /* roll $1 %eax */
- xorl %edx, %ebp
- movl %eax, 4(%esp)
- xorl %edi, %ebp
- leal 3395469782(%eax,%esi,1),%eax
- movl %ebx, %esi
- roll $5, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %ebp, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %esi, %eax
- /* 20_39 66 */
- movl 8(%esp), %esi
- movl 16(%esp), %ebp
- xorl %ebp, %esi
- movl 40(%esp), %ebp
- xorl %ebp, %esi
- movl 60(%esp), %ebp
- xorl %ebp, %esi
- movl %ebx, %ebp
-.byte 209
-.byte 198 /* roll $1 %esi */
- xorl %ecx, %ebp
- movl %esi, 8(%esp)
- xorl %edx, %ebp
- leal 3395469782(%esi,%edi,1),%esi
- movl %eax, %edi
- roll $5, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %ebp, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %edi, %esi
- /* 20_39 67 */
- movl 12(%esp), %edi
- movl 20(%esp), %ebp
- xorl %ebp, %edi
- movl 44(%esp), %ebp
- xorl %ebp, %edi
- movl (%esp), %ebp
- xorl %ebp, %edi
- movl %eax, %ebp
-.byte 209
-.byte 199 /* roll $1 %edi */
- xorl %ebx, %ebp
- movl %edi, 12(%esp)
- xorl %ecx, %ebp
- leal 3395469782(%edi,%edx,1),%edi
- movl %esi, %edx
- roll $5, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %ebp, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %edx, %edi
- /* 20_39 68 */
- movl 16(%esp), %edx
- movl 24(%esp), %ebp
- xorl %ebp, %edx
- movl 48(%esp), %ebp
- xorl %ebp, %edx
- movl 4(%esp), %ebp
- xorl %ebp, %edx
- movl %esi, %ebp
-.byte 209
-.byte 194 /* roll $1 %edx */
- xorl %eax, %ebp
- movl %edx, 16(%esp)
- xorl %ebx, %ebp
- leal 3395469782(%edx,%ecx,1),%edx
- movl %edi, %ecx
- roll $5, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ebp, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ecx, %edx
- /* 20_39 69 */
- movl 20(%esp), %ecx
- movl 28(%esp), %ebp
- xorl %ebp, %ecx
- movl 52(%esp), %ebp
- xorl %ebp, %ecx
- movl 8(%esp), %ebp
- xorl %ebp, %ecx
- movl %edi, %ebp
-.byte 209
-.byte 193 /* roll $1 %ecx */
- xorl %esi, %ebp
- movl %ecx, 20(%esp)
- xorl %eax, %ebp
- leal 3395469782(%ecx,%ebx,1),%ecx
- movl %edx, %ebx
- roll $5, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebp, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebx, %ecx
- /* 20_39 70 */
- movl 24(%esp), %ebx
- movl 32(%esp), %ebp
- xorl %ebp, %ebx
- movl 56(%esp), %ebp
- xorl %ebp, %ebx
- movl 12(%esp), %ebp
- xorl %ebp, %ebx
- movl %edx, %ebp
-.byte 209
-.byte 195 /* roll $1 %ebx */
- xorl %edi, %ebp
- movl %ebx, 24(%esp)
- xorl %esi, %ebp
- leal 3395469782(%ebx,%eax,1),%ebx
- movl %ecx, %eax
- roll $5, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %ebp, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %eax, %ebx
- /* 20_39 71 */
- movl 28(%esp), %eax
- movl 36(%esp), %ebp
- xorl %ebp, %eax
- movl 60(%esp), %ebp
- xorl %ebp, %eax
- movl 16(%esp), %ebp
- xorl %ebp, %eax
- movl %ecx, %ebp
-.byte 209
-.byte 192 /* roll $1 %eax */
- xorl %edx, %ebp
- movl %eax, 28(%esp)
- xorl %edi, %ebp
- leal 3395469782(%eax,%esi,1),%eax
- movl %ebx, %esi
- roll $5, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %ebp, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %esi, %eax
- /* 20_39 72 */
- movl 32(%esp), %esi
- movl 40(%esp), %ebp
- xorl %ebp, %esi
- movl (%esp), %ebp
- xorl %ebp, %esi
- movl 20(%esp), %ebp
- xorl %ebp, %esi
- movl %ebx, %ebp
-.byte 209
-.byte 198 /* roll $1 %esi */
- xorl %ecx, %ebp
- movl %esi, 32(%esp)
- xorl %edx, %ebp
- leal 3395469782(%esi,%edi,1),%esi
- movl %eax, %edi
- roll $5, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %ebp, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %edi, %esi
- /* 20_39 73 */
- movl 36(%esp), %edi
- movl 44(%esp), %ebp
- xorl %ebp, %edi
- movl 4(%esp), %ebp
- xorl %ebp, %edi
- movl 24(%esp), %ebp
- xorl %ebp, %edi
- movl %eax, %ebp
-.byte 209
-.byte 199 /* roll $1 %edi */
- xorl %ebx, %ebp
- movl %edi, 36(%esp)
- xorl %ecx, %ebp
- leal 3395469782(%edi,%edx,1),%edi
- movl %esi, %edx
- roll $5, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %ebp, %edx
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %edx, %edi
- /* 20_39 74 */
- movl 40(%esp), %edx
- movl 48(%esp), %ebp
- xorl %ebp, %edx
- movl 8(%esp), %ebp
- xorl %ebp, %edx
- movl 28(%esp), %ebp
- xorl %ebp, %edx
- movl %esi, %ebp
-.byte 209
-.byte 194 /* roll $1 %edx */
- xorl %eax, %ebp
- movl %edx, 40(%esp)
- xorl %ebx, %ebp
- leal 3395469782(%edx,%ecx,1),%edx
- movl %edi, %ecx
- roll $5, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ebp, %ecx
-.byte 209
-.byte 206 /* rorl $1 %esi */
- addl %ecx, %edx
- /* 20_39 75 */
- movl 44(%esp), %ecx
- movl 52(%esp), %ebp
- xorl %ebp, %ecx
- movl 12(%esp), %ebp
- xorl %ebp, %ecx
- movl 32(%esp), %ebp
- xorl %ebp, %ecx
- movl %edi, %ebp
-.byte 209
-.byte 193 /* roll $1 %ecx */
- xorl %esi, %ebp
- movl %ecx, 44(%esp)
- xorl %eax, %ebp
- leal 3395469782(%ecx,%ebx,1),%ecx
- movl %edx, %ebx
- roll $5, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebp, %ebx
-.byte 209
-.byte 207 /* rorl $1 %edi */
- addl %ebx, %ecx
- /* 20_39 76 */
- movl 48(%esp), %ebx
- movl 56(%esp), %ebp
- xorl %ebp, %ebx
- movl 16(%esp), %ebp
- xorl %ebp, %ebx
- movl 36(%esp), %ebp
- xorl %ebp, %ebx
- movl %edx, %ebp
-.byte 209
-.byte 195 /* roll $1 %ebx */
- xorl %edi, %ebp
- movl %ebx, 48(%esp)
- xorl %esi, %ebp
- leal 3395469782(%ebx,%eax,1),%ebx
- movl %ecx, %eax
- roll $5, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %ebp, %eax
-.byte 209
-.byte 202 /* rorl $1 %edx */
- addl %eax, %ebx
- /* 20_39 77 */
- movl 52(%esp), %eax
- movl 60(%esp), %ebp
- xorl %ebp, %eax
- movl 20(%esp), %ebp
- xorl %ebp, %eax
- movl 40(%esp), %ebp
- xorl %ebp, %eax
- movl %ecx, %ebp
-.byte 209
-.byte 192 /* roll $1 %eax */
- xorl %edx, %ebp
- movl %eax, 52(%esp)
- xorl %edi, %ebp
- leal 3395469782(%eax,%esi,1),%eax
- movl %ebx, %esi
- roll $5, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %ebp, %esi
-.byte 209
-.byte 201 /* rorl $1 %ecx */
- addl %esi, %eax
- /* 20_39 78 */
- movl 56(%esp), %esi
- movl (%esp), %ebp
- xorl %ebp, %esi
- movl 24(%esp), %ebp
- xorl %ebp, %esi
- movl 44(%esp), %ebp
- xorl %ebp, %esi
- movl %ebx, %ebp
-.byte 209
-.byte 198 /* roll $1 %esi */
- xorl %ecx, %ebp
- movl %esi, 56(%esp)
- xorl %edx, %ebp
- leal 3395469782(%esi,%edi,1),%esi
- movl %eax, %edi
- roll $5, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %ebp, %edi
-.byte 209
-.byte 203 /* rorl $1 %ebx */
- addl %edi, %esi
- /* 20_39 79 */
- movl 60(%esp), %edi
- movl 4(%esp), %ebp
- xorl %ebp, %edi
- movl 28(%esp), %ebp
- xorl %ebp, %edi
- movl 48(%esp), %ebp
- xorl %ebp, %edi
- movl %eax, %ebp
-.byte 209
-.byte 199 /* roll $1 %edi */
- xorl %ebx, %ebp
- movl %edi, 60(%esp)
- xorl %ecx, %ebp
- leal 3395469782(%edi,%edx,1),%edi
- movl %esi, %edx
- roll $5, %edx
- addl %ebp, %edx
- movl 92(%esp), %ebp
-.byte 209
-.byte 200 /* rorl $1 %eax */
- addl %edx, %edi
-.byte 209
-.byte 200 /* rorl $1 %eax */
- /* End processing */
-
- movl 12(%ebp), %edx
- addl %ebx, %edx
- movl 4(%ebp), %ebx
- addl %esi, %ebx
- movl %eax, %esi
- movl (%ebp), %eax
- movl %edx, 12(%ebp)
- addl %edi, %eax
- movl 16(%ebp), %edi
- addl %ecx, %edi
- movl 8(%ebp), %ecx
- addl %esi, %ecx
- movl %eax, (%ebp)
- movl 64(%esp), %esi
- movl %ecx, 8(%ebp)
- addl $64, %esi
- movl 68(%esp), %eax
- movl %edi, 16(%ebp)
- cmpl %esi, %eax
- movl %ebx, 4(%ebp)
- jb .L001end
- movl (%esi), %eax
- jmp .L000start
-.L001end:
- addl $72, %esp
- popl %edi
- popl %ebx
- popl %ebp
- popl %esi
- ret
-.sha1_block_x86_end:
- SIZE(sha1_block_x86,.sha1_block_x86_end-sha1_block_x86)
-.ident "desasm.pl"
-#endif
diff --git a/lib/libmd/sha1c.c b/lib/libmd/sha1c.c
index 83e402e132e7..128e0b991742 100644
--- a/lib/libmd/sha1c.c
+++ b/lib/libmd/sha1c.c
@@ -1,476 +1,244 @@
-/* crypto/sha/sha1dgst.c */
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
+/*-
+ * Copyright (c) 2009 The Go Authors. All rights reserved.
+ * Copyright (c) 2024 Robert Clausecker <fuz@freebsd.org>
+ *
+ * Adapted from Go's crypto/sha1/sha1.go.
*
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
* 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 copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the routines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``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.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/types.h>
-
-#include <stdio.h>
+#include <assert.h>
+#include <sha.h>
+#include <stdint.h>
#include <string.h>
+#include <strings.h>
+#include <sys/endian.h>
-#if 0
-#include <machine/ansi.h> /* we use the __ variants of bit-sized types */
+#ifdef SHA1_ASM
+extern void sha1_block(SHA1_CTX *, const void *, size_t);
+#else
+static void sha1_block(SHA1_CTX *, const void *, size_t);
#endif
-#include <machine/endian.h>
-#undef SHA_0
-#define SHA_1
-#include "sha.h"
-#include "sha_locl.h"
+#define INIT0 0x67452301
+#define INIT1 0xEFCDAB89
+#define INIT2 0x98BADCFE
+#define INIT3 0x10325476
+#define INIT4 0xC3D2E1F0
-/*
- * The assembly-language code is not position-independent, so don't
- * try to use it in a shared library.
- */
-#ifdef PIC
-#undef SHA1_ASM
-#endif
+#define K0 0x5A827999
+#define K1 0x6ED9EBA1
+#define K2 0x8F1BBCDC
+#define K3 0xCA62C1D6
-static char *SHA1_version="SHA1 part of SSLeay 0.9.0b 11-Oct-1998";
+void
+SHA1_Init(SHA1_CTX *c)
+{
+ c->h0 = INIT0;
+ c->h1 = INIT1;
+ c->h2 = INIT2;
+ c->h3 = INIT3;
+ c->h4 = INIT4;
+ c->Nl = 0;
+ c->Nh = 0;
+ c->num = 0;
+}
-/* Implemented from SHA-1 document - The Secure Hash Algorithm
- */
+void
+SHA1_Update(SHA1_CTX *c, const void *data, size_t len)
+{
+ uint64_t nn;
+ const char *p = data;
-#define INIT_DATA_h0 (unsigned long)0x67452301L
-#define INIT_DATA_h1 (unsigned long)0xefcdab89L
-#define INIT_DATA_h2 (unsigned long)0x98badcfeL
-#define INIT_DATA_h3 (unsigned long)0x10325476L
-#define INIT_DATA_h4 (unsigned long)0xc3d2e1f0L
-
-#define K_00_19 0x5a827999L
-#define K_20_39 0x6ed9eba1L
-#define K_40_59 0x8f1bbcdcL
-#define K_60_79 0xca62c1d6L
-
-#ifndef NOPROTO
-# ifdef SHA1_ASM
- void sha1_block_x86(SHA_CTX *c, const u_int32_t *p, int num);
-# define sha1_block sha1_block_x86
-# else
- void sha1_block(SHA_CTX *c, const u_int32_t *p, int num);
-# endif
-#else
-# ifdef SHA1_ASM
- void sha1_block_x86();
-# define sha1_block sha1_block_x86
-# else
- void sha1_block();
-# endif
-#endif
+ nn = (uint64_t)c->Nl | (uint64_t)c->Nh << 32;
+ nn += len;
+ c->Nl = (uint32_t)nn;
+ c->Nh = (uint32_t)(nn >> 32);
+ if (c->num > 0) {
+ size_t n = SHA_CBLOCK - c->num;
-#if BYTE_ORDER == LITTLE_ENDIAN && defined(SHA1_ASM)
-# define M_c2nl c2l
-# define M_p_c2nl p_c2l
-# define M_c2nl_p c2l_p
-# define M_p_c2nl_p p_c2l_p
-# define M_nl2c l2c
-#else
-# define M_c2nl c2nl
-# define M_p_c2nl p_c2nl
-# define M_c2nl_p c2nl_p
-# define M_p_c2nl_p p_c2nl_p
-# define M_nl2c nl2c
-#endif
+ if (n > len)
+ n = len;
+
+ memcpy((char *)c->data + c->num, p, n);
+ c->num += n;
+ if (c->num == SHA_CBLOCK) {
+ sha1_block(c, (void *)c->data, SHA_CBLOCK);
+ c->num = 0;
+ }
+
+ p += n;
+ len -= n;
+ }
+
+ if (len >= SHA_CBLOCK) {
+ size_t n = len & ~(size_t)(SHA_CBLOCK - 1);
+
+ sha1_block(c, p, n);
+ p += n;
+ len -= n;
+ }
-void SHA1_Init(SHA_CTX *c)
- {
- c->h0=INIT_DATA_h0;
- c->h1=INIT_DATA_h1;
- c->h2=INIT_DATA_h2;
- c->h3=INIT_DATA_h3;
- c->h4=INIT_DATA_h4;
- c->Nl=0;
- c->Nh=0;
- c->num=0;
+ if (len > 0) {
+ memcpy(c->data, p, len);
+ c->num = len;
}
+}
void
-SHA1_Update(SHA_CTX *c, const void *in, size_t len)
+SHA1_Final(unsigned char *md, SHA1_CTX *c)
{
- u_int32_t *p;
- int ew,ec,sw,sc;
- u_int32_t l;
- const unsigned char *data = in;
-
- if (len == 0) return;
-
- l=(c->Nl+(len<<3))&0xffffffffL;
- if (l < c->Nl) /* overflow */
- c->Nh++;
- c->Nh+=(len>>29);
- c->Nl=l;
-
- if (c->num != 0)
- {
- p=c->data;
- sw=c->num>>2;
- sc=c->num&0x03;
-
- if ((c->num+len) >= SHA_CBLOCK)
- {
- l= p[sw];
- M_p_c2nl(data,l,sc);
- p[sw++]=l;
- for (; sw<SHA_LBLOCK; sw++)
- {
- M_c2nl(data,l);
- p[sw]=l;
- }
- len-=(SHA_CBLOCK-c->num);
-
- sha1_block(c,p,64);
- c->num=0;
- /* drop through and do the rest */
- }
- else
- {
- c->num+=(int)len;
- if ((sc+len) < 4) /* ugly, add char's to a word */
- {
- l= p[sw];
- M_p_c2nl_p(data,l,sc,len);
- p[sw]=l;
- }
- else
- {
- ew=(c->num>>2);
- ec=(c->num&0x03);
- l= p[sw];
- M_p_c2nl(data,l,sc);
- p[sw++]=l;
- for (; sw < ew; sw++)
- { M_c2nl(data,l); p[sw]=l; }
- if (ec)
- {
- M_c2nl_p(data,l,ec);
- p[sw]=l;
- }
- }
- return;
- }
+ uint64_t len;
+ size_t t;
+ unsigned char tmp[SHA_CBLOCK + sizeof(uint64_t)] = {0x80, 0};
+
+ len = (uint64_t)c->Nl | (uint64_t)c->Nh << 32;
+ t = 64 + 56 - c->Nl % 64;
+ if (t > 64)
+ t -= 64;
+
+ /* length in bits */
+ len <<= 3;
+ be64enc(tmp + t, len);
+ SHA1_Update(c, tmp, t + 8);
+ assert(c->num == 0);
+
+ be32enc(md + 0, c->h0);
+ be32enc(md + 4, c->h1);
+ be32enc(md + 8, c->h2);
+ be32enc(md + 12, c->h3);
+ be32enc(md + 16, c->h4);
+
+ explicit_bzero(c, sizeof(*c));
+}
+
+#ifndef SHA1_ASM
+static void
+/* invariant: len is a multiple of SHA_CBLOCK */
+sha1_block(SHA1_CTX *c, const void *data, size_t len)
+{
+ uint32_t w[16];
+ uint32_t h0 = c->h0, h1 = c->h1, h2 = c->h2, h3 = c->h3, h4 = c->h4;
+ const char *p = data;
+
+ while (len >= SHA_CBLOCK) {
+ size_t i;
+ uint32_t a = h0, b = h1, c = h2, d = h3, e = h4;
+ uint32_t f, t, tmp;
+
+# pragma unroll
+ for (i = 0; i < 16; i++)
+ w[i] = be32dec(p + 4*i);
+
+# pragma unroll
+ for (i = 0; i < 16; i++) {
+ f = b & c | ~b & d;
+ t = (a << 5 | a >> 32 - 5) + f + e + w[i & 0xf] + K0;
+ e = d;
+ d = c;
+ c = b << 30 | b >> 32 - 30;
+ b = a;
+ a = t;
}
- /* We can only do the following code for assember, the reason
- * being that the sha1_block 'C' version changes the values
- * in the 'data' array. The assember code avoids this and
- * copies it to a local array. I should be able to do this for
- * the C version as well....
- */
-#if 1
-#if BYTE_ORDER == BIG_ENDIAN || defined(SHA1_ASM)
- if ((((unsigned int)data)%sizeof(u_int32_t)) == 0)
- {
- sw=len/SHA_CBLOCK;
- if (sw)
- {
- sw*=SHA_CBLOCK;
- sha1_block(c,(u_int32_t *)data,sw);
- data+=sw;
- len-=sw;
- }
+
+# pragma unroll
+ for (; i < 20; i++) {
+ tmp = w[i - 3 & 0xf] ^ w[i - 8 & 0xf] ^ w[i - 14 & 0xf] ^ w[i & 0xf];
+ w[i & 0xf] = tmp << 1 | tmp >> 32 - 1;
+
+ f = b & c | ~b & d;
+ t = (a << 5 | a >> 32 - 5) + f + e + w[i & 0xf] + K0;
+ e = d;
+ d = c;
+ c = b << 30 | b >> 32 - 30;
+ b = a;
+ a = t;
}
-#endif
-#endif
- /* we now can process the input data in blocks of SHA_CBLOCK
- * chars and save the leftovers to c->data. */
- p=c->data;
- while (len >= SHA_CBLOCK)
- {
-#if BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN
- if (p != (u_int32_t *)data)
- memcpy(p,data,SHA_CBLOCK);
- data+=SHA_CBLOCK;
-# if BYTE_ORDER == LITTLE_ENDIAN
-# ifndef SHA1_ASM /* Will not happen */
- for (sw=(SHA_LBLOCK/4); sw; sw--)
- {
- Endian_Reverse32(p[0]);
- Endian_Reverse32(p[1]);
- Endian_Reverse32(p[2]);
- Endian_Reverse32(p[3]);
- p+=4;
- }
- p=c->data;
-# endif
-# endif
-#else
- for (sw=(SHA_BLOCK/4); sw; sw--)
- {
- M_c2nl(data,l); *(p++)=l;
- M_c2nl(data,l); *(p++)=l;
- M_c2nl(data,l); *(p++)=l;
- M_c2nl(data,l); *(p++)=l;
- }
- p=c->data;
-#endif
- sha1_block(c,p,64);
- len-=SHA_CBLOCK;
+
+# pragma unroll
+ for (; i < 40; i++) {
+ tmp = w[i - 3 & 0xf] ^ w[i - 8 & 0xf] ^ w[i - 14 & 0xf] ^ w[i & 0xf];
+ w[i & 0xf] = tmp << 1 | tmp >> 32 - 1;
+
+ f = b ^ c ^ d;
+ t = (a << 5 | a >> 32 - 5) + f + e + w[i & 0xf] + K1;
+ e = d;
+ d = c;
+ c = b << 30 | b >> 32 - 30;
+ b = a;
+ a = t;
}
- ec=(int)len;
- c->num=ec;
- ew=(ec>>2);
- ec&=0x03;
-
- for (sw=0; sw < ew; sw++)
- { M_c2nl(data,l); p[sw]=l; }
- M_c2nl_p(data,l,ec);
- p[sw]=l;
- }
-static void SHA1_Transform(SHA_CTX *c, unsigned char *b)
- {
- u_int32_t p[16];
-#if BYTE_ORDER != BIG_ENDIAN
- u_int32_t *q;
- int i;
-#endif
+# pragma unroll
+ for (; i < 60; i++) {
+ tmp = w[i - 3 & 0xf] ^ w[i - 8 & 0xf] ^ w[i - 14 & 0xf] ^ w[i & 0xf];
+ w[i & 0xf] = tmp << 1 | tmp >> 32 - 1;
+
+ f = (b | c) & d | b & c;
+ t = (a << 5 | a >> 32 - 5) + f + e + w[i & 0xf] + K2;
+ e = d;
+ d = c;
+ c = b << 30 | b >> 32 - 30;
+ b = a;
+ a = t;
+ }
-#if BYTE_ORDER == BIG_ENDIAN || BYTE_ORDER == LITTLE_ENDIAN
- memcpy(p,b,64);
-#if BYTE_ORDER == LITTLE_ENDIAN
- q=p;
- for (i=(SHA_LBLOCK/4); i; i--)
- {
- Endian_Reverse32(q[0]);
- Endian_Reverse32(q[1]);
- Endian_Reverse32(q[2]);
- Endian_Reverse32(q[3]);
- q+=4;
+# pragma unroll
+ for (; i < 80; i++) {
+ tmp = w[i - 3 & 0xf] ^ w[i - 8 & 0xf] ^ w[i - 14 & 0xf] ^ w[i & 0xf];
+ w[i & 0xf] = tmp << 1 | tmp >> 32 - 1;
+
+ f = b ^ c ^ d;
+ t = (a << 5 | a >> 32 - 5) + f + e + w[i & 0xf] + K3;
+ e = d;
+ d = c;
+ c = b << 30 | b >> 32 - 30;
+ b = a;
+ a = t;
}
-#endif
-#else
- q=p;
- for (i=(SHA_LBLOCK/4); i; i--)
- {
- u_int32_t l;
- c2nl(b,l); *(q++)=l;
- c2nl(b,l); *(q++)=l;
- c2nl(b,l); *(q++)=l;
- c2nl(b,l); *(q++)=l;
- }
-#endif
- sha1_block(c,p,64);
- }
-#ifndef SHA1_ASM
+ h0 += a;
+ h1 += b;
+ h2 += c;
+ h3 += d;
+ h4 += e;
-void
-sha1_block(SHA_CTX *c, const u_int32_t *W, int num)
-{
- u_int32_t A,B,C,D,E,T;
- u_int32_t X[16];
-
- A=c->h0;
- B=c->h1;
- C=c->h2;
- D=c->h3;
- E=c->h4;
-
- for (;;)
- {
- BODY_00_15( 0,A,B,C,D,E,T,W);
- BODY_00_15( 1,T,A,B,C,D,E,W);
- BODY_00_15( 2,E,T,A,B,C,D,W);
- BODY_00_15( 3,D,E,T,A,B,C,W);
- BODY_00_15( 4,C,D,E,T,A,B,W);
- BODY_00_15( 5,B,C,D,E,T,A,W);
- BODY_00_15( 6,A,B,C,D,E,T,W);
- BODY_00_15( 7,T,A,B,C,D,E,W);
- BODY_00_15( 8,E,T,A,B,C,D,W);
- BODY_00_15( 9,D,E,T,A,B,C,W);
- BODY_00_15(10,C,D,E,T,A,B,W);
- BODY_00_15(11,B,C,D,E,T,A,W);
- BODY_00_15(12,A,B,C,D,E,T,W);
- BODY_00_15(13,T,A,B,C,D,E,W);
- BODY_00_15(14,E,T,A,B,C,D,W);
- BODY_00_15(15,D,E,T,A,B,C,W);
- BODY_16_19(16,C,D,E,T,A,B,W,W,W,W);
- BODY_16_19(17,B,C,D,E,T,A,W,W,W,W);
- BODY_16_19(18,A,B,C,D,E,T,W,W,W,W);
- BODY_16_19(19,T,A,B,C,D,E,W,W,W,X);
-
- BODY_20_31(20,E,T,A,B,C,D,W,W,W,X);
- BODY_20_31(21,D,E,T,A,B,C,W,W,W,X);
- BODY_20_31(22,C,D,E,T,A,B,W,W,W,X);
- BODY_20_31(23,B,C,D,E,T,A,W,W,W,X);
- BODY_20_31(24,A,B,C,D,E,T,W,W,X,X);
- BODY_20_31(25,T,A,B,C,D,E,W,W,X,X);
- BODY_20_31(26,E,T,A,B,C,D,W,W,X,X);
- BODY_20_31(27,D,E,T,A,B,C,W,W,X,X);
- BODY_20_31(28,C,D,E,T,A,B,W,W,X,X);
- BODY_20_31(29,B,C,D,E,T,A,W,W,X,X);
- BODY_20_31(30,A,B,C,D,E,T,W,X,X,X);
- BODY_20_31(31,T,A,B,C,D,E,W,X,X,X);
- BODY_32_39(32,E,T,A,B,C,D,X);
- BODY_32_39(33,D,E,T,A,B,C,X);
- BODY_32_39(34,C,D,E,T,A,B,X);
- BODY_32_39(35,B,C,D,E,T,A,X);
- BODY_32_39(36,A,B,C,D,E,T,X);
- BODY_32_39(37,T,A,B,C,D,E,X);
- BODY_32_39(38,E,T,A,B,C,D,X);
- BODY_32_39(39,D,E,T,A,B,C,X);
-
- BODY_40_59(40,C,D,E,T,A,B,X);
- BODY_40_59(41,B,C,D,E,T,A,X);
- BODY_40_59(42,A,B,C,D,E,T,X);
- BODY_40_59(43,T,A,B,C,D,E,X);
- BODY_40_59(44,E,T,A,B,C,D,X);
- BODY_40_59(45,D,E,T,A,B,C,X);
- BODY_40_59(46,C,D,E,T,A,B,X);
- BODY_40_59(47,B,C,D,E,T,A,X);
- BODY_40_59(48,A,B,C,D,E,T,X);
- BODY_40_59(49,T,A,B,C,D,E,X);
- BODY_40_59(50,E,T,A,B,C,D,X);
- BODY_40_59(51,D,E,T,A,B,C,X);
- BODY_40_59(52,C,D,E,T,A,B,X);
- BODY_40_59(53,B,C,D,E,T,A,X);
- BODY_40_59(54,A,B,C,D,E,T,X);
- BODY_40_59(55,T,A,B,C,D,E,X);
- BODY_40_59(56,E,T,A,B,C,D,X);
- BODY_40_59(57,D,E,T,A,B,C,X);
- BODY_40_59(58,C,D,E,T,A,B,X);
- BODY_40_59(59,B,C,D,E,T,A,X);
-
- BODY_60_79(60,A,B,C,D,E,T,X);
- BODY_60_79(61,T,A,B,C,D,E,X);
- BODY_60_79(62,E,T,A,B,C,D,X);
- BODY_60_79(63,D,E,T,A,B,C,X);
- BODY_60_79(64,C,D,E,T,A,B,X);
- BODY_60_79(65,B,C,D,E,T,A,X);
- BODY_60_79(66,A,B,C,D,E,T,X);
- BODY_60_79(67,T,A,B,C,D,E,X);
- BODY_60_79(68,E,T,A,B,C,D,X);
- BODY_60_79(69,D,E,T,A,B,C,X);
- BODY_60_79(70,C,D,E,T,A,B,X);
- BODY_60_79(71,B,C,D,E,T,A,X);
- BODY_60_79(72,A,B,C,D,E,T,X);
- BODY_60_79(73,T,A,B,C,D,E,X);
- BODY_60_79(74,E,T,A,B,C,D,X);
- BODY_60_79(75,D,E,T,A,B,C,X);
- BODY_60_79(76,C,D,E,T,A,B,X);
- BODY_60_79(77,B,C,D,E,T,A,X);
- BODY_60_79(78,A,B,C,D,E,T,X);
- BODY_60_79(79,T,A,B,C,D,E,X);
-
- c->h0=(c->h0+E)&0xffffffffL;
- c->h1=(c->h1+T)&0xffffffffL;
- c->h2=(c->h2+A)&0xffffffffL;
- c->h3=(c->h3+B)&0xffffffffL;
- c->h4=(c->h4+C)&0xffffffffL;
-
- num-=64;
- if (num <= 0) break;
-
- A=c->h0;
- B=c->h1;
- C=c->h2;
- D=c->h3;
- E=c->h4;
-
- W+=16;
- }
+ p += SHA_CBLOCK;
+ len -= SHA_CBLOCK;
}
-#endif
-void SHA1_Final(unsigned char *md, SHA_CTX *c)
- {
- int i,j;
- u_int32_t l;
- u_int32_t *p;
- static unsigned char end[4]={0x80,0x00,0x00,0x00};
- unsigned char *cp=end;
-
- /* c->num should definitly have room for at least one more byte. */
- p=c->data;
- j=c->num;
- i=j>>2;
-#ifdef PURIFY
- if ((j&0x03) == 0) p[i]=0;
+ c->h0 = h0;
+ c->h1 = h1;
+ c->h2 = h2;
+ c->h3 = h3;
+ c->h4 = h4;
+}
#endif
- l=p[i];
- M_p_c2nl(cp,l,j&0x03);
- p[i]=l;
- i++;
- /* i is the next 'undefined word' */
- if (c->num >= SHA_LAST_BLOCK)
- {
- for (; i<SHA_LBLOCK; i++)
- p[i]=0;
- sha1_block(c,p,64);
- i=0;
- }
- for (; i<(SHA_LBLOCK-2); i++)
- p[i]=0;
- p[SHA_LBLOCK-2]=c->Nh;
- p[SHA_LBLOCK-1]=c->Nl;
-#if BYTE_ORDER == LITTLE_ENDIAN && defined(SHA1_ASM)
- Endian_Reverse32(p[SHA_LBLOCK-2]);
- Endian_Reverse32(p[SHA_LBLOCK-1]);
-#endif
- sha1_block(c,p,64);
- cp=md;
- l=c->h0; nl2c(l,cp);
- l=c->h1; nl2c(l,cp);
- l=c->h2; nl2c(l,cp);
- l=c->h3; nl2c(l,cp);
- l=c->h4; nl2c(l,cp);
-
- /* Clear the context state */
- explicit_bzero(&c, sizeof(c));
- }
#ifdef WEAK_REFS
/* When building libmd, provide weak references. Note: this is not
diff --git a/lib/libnvmf/libnvmf.h b/lib/libnvmf/libnvmf.h
index 9840e190a24f..7cdd7e433455 100644
--- a/lib/libnvmf/libnvmf.h
+++ b/lib/libnvmf/libnvmf.h
@@ -342,7 +342,8 @@ int nvmf_host_request_queues(struct nvmf_qpair *qp, u_int requested,
*/
int nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata);
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout);
/*
* Disconnect an active host association previously handed off to the
@@ -370,7 +371,8 @@ int nvmf_reconnect_params(int fd, nvlist_t **nvlp);
*/
int nvmf_reconnect_host(int fd, const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata);
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout);
/*
* Fetch connection status from an existing kernel host.
diff --git a/lib/libnvmf/nvmf_host.c b/lib/libnvmf/nvmf_host.c
index 89cdd5c6bb70..3266f8898296 100644
--- a/lib/libnvmf/nvmf_host.c
+++ b/lib/libnvmf/nvmf_host.c
@@ -792,7 +792,8 @@ static int
prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
const struct nvme_discovery_log_entry *dle, const char *hostnqn,
struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
const struct nvmf_association *na = admin_qp->nq_association;
nvlist_t *nvl, *nvl_qp, *nvl_rparams;
@@ -820,6 +821,9 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
nvlist_add_string(nvl_rparams, "hostnqn", hostnqn);
nvlist_add_number(nvl_rparams, "num_io_queues", num_queues);
nvlist_add_number(nvl_rparams, "kato", admin_qp->nq_kato);
+ nvlist_add_number(nvl_rparams, "reconnect_delay", reconnect_delay);
+ nvlist_add_number(nvl_rparams, "controller_loss_timeout",
+ controller_loss_timeout);
nvlist_add_number(nvl_rparams, "io_qsize", io_queues[0]->nq_qsize);
nvlist_add_bool(nvl_rparams, "sq_flow_control",
na->na_params.sq_flow_control);
@@ -842,6 +846,9 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
nvl = nvlist_create(0);
nvlist_add_number(nvl, "trtype", na->na_trtype);
nvlist_add_number(nvl, "kato", admin_qp->nq_kato);
+ nvlist_add_number(nvl, "reconnect_delay", reconnect_delay);
+ nvlist_add_number(nvl, "controller_loss_timeout",
+ controller_loss_timeout);
nvlist_move_nvlist(nvl, "rparams", nvl_rparams);
/* First, the admin queue. */
@@ -872,7 +879,8 @@ prepare_queues_for_handoff(struct nvmf_ioc_nv *nv,
int
nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
struct nvmf_ioc_nv nv;
u_int i;
@@ -885,7 +893,8 @@ nvmf_handoff_host(const struct nvme_discovery_log_entry *dle,
}
error = prepare_queues_for_handoff(&nv, dle, hostnqn, admin_qp,
- num_queues, io_queues, cdata);
+ num_queues, io_queues, cdata, reconnect_delay,
+ controller_loss_timeout);
if (error != 0)
goto out;
@@ -981,14 +990,16 @@ nvmf_reconnect_params(int fd, nvlist_t **nvlp)
int
nvmf_reconnect_host(int fd, const struct nvme_discovery_log_entry *dle,
const char *hostnqn, struct nvmf_qpair *admin_qp, u_int num_queues,
- struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata)
+ struct nvmf_qpair **io_queues, const struct nvme_controller_data *cdata,
+ uint32_t reconnect_delay, uint32_t controller_loss_timeout)
{
struct nvmf_ioc_nv nv;
u_int i;
int error;
error = prepare_queues_for_handoff(&nv, dle, hostnqn, admin_qp,
- num_queues, io_queues, cdata);
+ num_queues, io_queues, cdata, reconnect_delay,
+ controller_loss_timeout);
if (error != 0)
goto out;
diff --git a/lib/libopenbsd/Makefile b/lib/libopenbsd/Makefile
index 675ed476c51d..dca1c08b0aed 100644
--- a/lib/libopenbsd/Makefile
+++ b/lib/libopenbsd/Makefile
@@ -2,7 +2,8 @@ PACKAGE=lib${LIB}
LIB= openbsd
SRCS= imsg-buffer.c \
imsg.c \
- ohash.c
+ ohash.c \
+ recallocarray.c
.if !defined(BOOTSTRAPPING)
# Skip getdtablecount.c when bootstrapping since it doesn't compile for Linux
# and is not used by any of the bootstrap tools
diff --git a/lib/libopenbsd/recallocarray.c b/lib/libopenbsd/recallocarray.c
new file mode 100644
index 000000000000..11e1fda744c7
--- /dev/null
+++ b/lib/libopenbsd/recallocarray.c
@@ -0,0 +1,82 @@
+/* $OpenBSD: recallocarray.c,v 1.1 2017/03/06 18:44:21 otto Exp $ */
+/*
+ * Copyright (c) 2008, 2017 Otto Moerbeek <otto@drijf.net>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+
+/*
+ * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
+ * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
+ */
+#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
+
+void *recallocarray(void *, size_t, size_t, size_t);
+
+void *
+recallocarray(void *ptr, size_t oldnmemb, size_t newnmemb, size_t size)
+{
+ size_t oldsize, newsize;
+ void *newptr;
+
+ if (ptr == NULL)
+ return calloc(newnmemb, size);
+
+ if ((newnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ newnmemb > 0 && SIZE_MAX / newnmemb < size) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ newsize = newnmemb * size;
+
+ if ((oldnmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
+ oldnmemb > 0 && SIZE_MAX / oldnmemb < size) {
+ errno = EINVAL;
+ return NULL;
+ }
+ oldsize = oldnmemb * size;
+
+ /*
+ * Don't bother too much if we're shrinking just a bit,
+ * we do not shrink for series of small steps, oh well.
+ */
+ if (newsize <= oldsize) {
+ size_t d = oldsize - newsize;
+
+ if (d < oldsize / 2 && d < (size_t)getpagesize()) {
+ memset((char *)ptr + newsize, 0, d);
+ return ptr;
+ }
+ }
+
+ newptr = malloc(newsize);
+ if (newptr == NULL)
+ return NULL;
+
+ if (newsize > oldsize) {
+ memcpy(newptr, ptr, oldsize);
+ memset((char *)newptr + oldsize, 0, newsize - oldsize);
+ } else
+ memcpy(newptr, ptr, newsize);
+
+ explicit_bzero(ptr, oldsize);
+ free(ptr);
+
+ return newptr;
+}
diff --git a/lib/libpam/libpam/Makefile b/lib/libpam/libpam/Makefile
index 9bd855f60ed8..dd19eba5c1ec 100644
--- a/lib/libpam/libpam/Makefile
+++ b/lib/libpam/libpam/Makefile
@@ -153,6 +153,7 @@ MAN?= openpam.3 \
MLINKS?= pam.conf.5 pam.d.5
+CFLAGS+= -DLOCALBASE=\"${LOCALBASE:U/usr/local}\"
CFLAGS+= -I${OPENPAM}/include
CFLAGS+= -DLIB_MAJ=${SHLIB_MAJOR}
CFLAGS+= -DHAVE_DLFUNC=1
diff --git a/lib/libpam/modules/pam_krb5/Makefile b/lib/libpam/modules/pam_krb5/Makefile
index 1c2831facd50..b537bf37b7f3 100644
--- a/lib/libpam/modules/pam_krb5/Makefile
+++ b/lib/libpam/modules/pam_krb5/Makefile
@@ -23,6 +23,59 @@
# SUCH DAMAGE.
#
+.include <src.opts.mk>
+
+.if ${MK_MITKRB5} != "no"
+SRCDIR= ${SRCTOP}/contrib/pam-krb5
+.PATH: ${SRCDIR}/module \
+ ${SRCDIR}/portable \
+ ${SRCDIR}/pam-util \
+ ${SRCDIR}
+
+PACKAGE= krb5
+LIB= pam_krb5
+LIBADD= com_err krb5
+
+SRCS= account.c \
+ alt-auth.c \
+ args.c \
+ auth.c \
+ cache.c \
+ context.c \
+ dummy.c \
+ fast.c \
+ krb5-extra.c \
+ logging.c \
+ pam-util_options.c \
+ module_options.c \
+ pam_syslog.c \
+ pam_vsyslog.c \
+ password.c \
+ prompting.c \
+ public.c \
+ setcred.c \
+ support.c \
+ vector.c
+
+MAN= pam-krb5.8
+MLINKS= pam-krb5.8 pam_krb5.8
+
+CFLAGS= -I${SRCDIR} \
+ -I${.CURDIR} \
+ -fno-strict-aliasing \
+ -Wno-error=incompatible-pointer-types-discards-qualifiers \
+ -DHAVE_CONFIG_H
+
+WARNS?= 3
+
+CLEANFILES= pam-util_options.c module_options.c
+
+pam-util_options.c: .PHONY
+ cp ${SRCDIR}/pam-util/options.c pam-util_options.c
+
+module_options.c: .PHONY
+ cp ${SRCDIR}/module/options.c module_options.c
+.else
PACKAGE= kerberos
LIB= pam_krb5
@@ -35,4 +88,6 @@ WARNS?= 3
LIBADD+= krb5
+.endif
+
.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_krb5/config.h b/lib/libpam/modules/pam_krb5/config.h
new file mode 100644
index 000000000000..75695eef66a1
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/config.h
@@ -0,0 +1,412 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Define to 1 if you have the `asprintf' function. */
+#define HAVE_ASPRINTF 1
+
+/* Define to 1 if you have the declaration of `krb5_kt_free_entry', and to 0
+ if you don't. */
+#define HAVE_DECL_KRB5_KT_FREE_ENTRY 1
+
+/* Define to 1 if you have the declaration of `reallocarray', and to 0 if you
+ don't. */
+#define HAVE_DECL_REALLOCARRAY 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <et/com_err.h> header file. */
+/* #undef HAVE_ET_COM_ERR_H */
+
+/* Define to 1 if you have the `explicit_bzero' function. */
+#define HAVE_EXPLICIT_BZERO 1
+
+/* Define to 1 if you have the <hx509_err.h> header file. */
+/* #undef HAVE_HX509_ERR_H */
+
+/* Define to 1 if you have the <ibm_svc/krb5_svc.h> header file. */
+/* #undef HAVE_IBM_SVC_KRB5_SVC_H */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the `issetugid' function. */
+#define HAVE_ISSETUGID 1
+
+/* Define to 1 if you have the <k5profile.h> header file. */
+/* #undef HAVE_K5PROFILE_H */
+
+/* Define to enable kadmin client features. */
+#define HAVE_KADM5CLNT 1
+
+/* Define to 1 if you have the `kadm5_init_krb5_context' function. */
+#define HAVE_KADM5_INIT_KRB5_CONTEXT 1
+
+/* Define to 1 if you have the `kadm5_init_with_skey_ctx' function. */
+/* #undef HAVE_KADM5_INIT_WITH_SKEY_CTX */
+
+/* Define to 1 if you have the <kadm5/kadm5_err.h> header file. */
+#define HAVE_KADM5_KADM5_ERR_H 1
+
+/* Define to 1 if you have the <kerberosv5/com_err.h> header file. */
+/* #undef HAVE_KERBEROSV5_COM_ERR_H */
+
+/* Define to 1 if you have the <kerberosv5/krb5.h> header file. */
+/* #undef HAVE_KERBEROSV5_KRB5_H */
+
+/* Define to enable Kerberos features. */
+#define HAVE_KRB5 1
+
+/* Define to 1 if you have the `krb5_appdefault_string' function. */
+#define HAVE_KRB5_APPDEFAULT_STRING 1
+
+/* Define to 1 if you have the `krb5_cc_get_full_name' function. */
+#define HAVE_KRB5_CC_GET_FULL_NAME 1
+
+/* Define to 1 if you have the `krb5_data_free' function. */
+/* #undef HAVE_KRB5_DATA_FREE */
+
+/* Define to 1 if you have the `krb5_free_default_realm' function. */
+#define HAVE_KRB5_FREE_DEFAULT_REALM 1
+
+/* Define to 1 if you have the `krb5_free_error_message' function. */
+#define HAVE_KRB5_FREE_ERROR_MESSAGE 1
+
+/* Define to 1 if you have the `krb5_free_string' function. */
+#define HAVE_KRB5_FREE_STRING 1
+
+/* Define to 1 if you have the `krb5_get_error_message' function. */
+#define HAVE_KRB5_GET_ERROR_MESSAGE 1
+
+/* Define to 1 if you have the `krb5_get_error_string' function. */
+/* #undef HAVE_KRB5_GET_ERROR_STRING */
+
+/* Define to 1 if you have the `krb5_get_err_txt' function. */
+/* #undef HAVE_KRB5_GET_ERR_TXT */
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_alloc' function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_ALLOC 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_free' function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_FREE 1
+
+/* Define if krb5_get_init_creds_opt_free takes two arguments. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_FREE_2_ARGS 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_anonymous'
+ function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ANONYMOUS 1
+
+/* Define to 1 if you have the
+ `krb5_get_init_creds_opt_set_change_password_prompt' function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_SET_CHANGE_PASSWORD_PROMPT 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_default_flags'
+ function. */
+/* #undef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_DEFAULT_FLAGS */
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_fast_ccache_name'
+ function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_SET_FAST_CCACHE_NAME 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_out_ccache'
+ function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_SET_OUT_CCACHE 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_pa' function. */
+#define HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PA 1
+
+/* Define to 1 if you have the `krb5_get_init_creds_opt_set_pkinit' function.
+ */
+/* #undef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PKINIT */
+
+/* Define if krb5_get_init_creds_opt_set_pkinit takes 9 arguments. */
+/* #undef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_PKINIT_9_ARGS */
+
+/* Define to 1 if you have the `krb5_get_profile' function. */
+/* #undef HAVE_KRB5_GET_PROFILE */
+
+/* Define to 1 if you have the `krb5_get_prompt_types' function. */
+#define HAVE_KRB5_GET_PROMPT_TYPES 1
+
+/* Define to 1 if you have the <krb5.h> header file. */
+#define HAVE_KRB5_H 1
+
+/* Define if your Kerberos implementation is Heimdal. */
+/* #undef HAVE_KRB5_HEIMDAL */
+
+/* Define to 1 if you have the `krb5_init_secure_context' function. */
+#define HAVE_KRB5_INIT_SECURE_CONTEXT 1
+
+/* Define to 1 if you have the <krb5/krb5.h> header file. */
+#define HAVE_KRB5_KRB5_H 1
+
+/* Define if your Kerberos implementation is MIT. */
+#define HAVE_KRB5_MIT 1
+
+/* Define to 1 if you have the `krb5_principal_get_realm' function. */
+/* #undef HAVE_KRB5_PRINCIPAL_GET_REALM */
+
+/* Define to 1 if you have the `krb5_principal_set_comp_string' function. */
+/* #undef HAVE_KRB5_PRINCIPAL_SET_COMP_STRING */
+
+/* Define to 1 if the system has the type `krb5_realm'. */
+/* #undef HAVE_KRB5_REALM */
+
+/* Define to 1 if you have the `krb5_set_password' function. */
+#define HAVE_KRB5_SET_PASSWORD 1
+
+/* Define to 1 if you have the `krb5_set_trace_filename' function. */
+#define HAVE_KRB5_SET_TRACE_FILENAME 1
+
+/* Define to 1 if you have the `krb5_svc_get_msg' function. */
+/* #undef HAVE_KRB5_SVC_GET_MSG */
+
+/* Define to 1 if you have the `krb5_verify_init_creds_opt_init' function. */
+#define HAVE_KRB5_VERIFY_INIT_CREDS_OPT_INIT 1
+
+/* Define to 1 if you have the `krb5_xfree' function. */
+/* #undef HAVE_KRB5_XFREE */
+
+/* Define to 1 if the system has the type `long long int'. */
+#define HAVE_LONG_LONG_INT 1
+
+/* Define to 1 if you have the <minix/config.h> header file. */
+/* #undef HAVE_MINIX_CONFIG_H */
+
+/* Define to 1 if you have the `mkstemp' function. */
+#define HAVE_MKSTEMP 1
+
+/* Define to 1 if you have the `pam_getenv' function. */
+#define HAVE_PAM_GETENV 1
+
+/* Define to 1 if you have the `pam_getenvlist' function. */
+#define HAVE_PAM_GETENVLIST 1
+
+/* Define to 1 if you have the `pam_modutil_getpwnam' function. */
+/* #undef HAVE_PAM_MODUTIL_GETPWNAM */
+
+/* Define to 1 if you have the <pam/pam_appl.h> header file. */
+/* #undef HAVE_PAM_PAM_APPL_H */
+
+/* Define to 1 if you have the <pam/pam_ext.h> header file. */
+/* #undef HAVE_PAM_PAM_EXT_H */
+
+/* Define to 1 if you have the <pam/pam_modutil.h> header file. */
+/* #undef HAVE_PAM_PAM_MODUTIL_H */
+
+/* Define to 1 if you have the `pam_syslog' function. */
+/* #undef HAVE_PAM_SYSLOG */
+
+/* Define to 1 if you have the `pam_vsyslog' function. */
+/* #undef HAVE_PAM_VSYSLOG */
+
+/* Define to 1 if you have the <profile.h> header file. */
+/* #undef HAVE_PROFILE_H */
+
+/* Define to 1 if you have the `reallocarray' function. */
+#define HAVE_REALLOCARRAY 1
+
+/* Define to 1 if you have the `regcomp' function. */
+#define HAVE_REGCOMP 1
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+#define HAVE_SECURITY_PAM_APPL_H 1
+
+/* Define to 1 if you have the <security/pam_ext.h> header file. */
+/* #undef HAVE_SECURITY_PAM_EXT_H */
+
+/* Define to 1 if you have the <security/pam_modutil.h> header file. */
+/* #undef HAVE_SECURITY_PAM_MODUTIL_H */
+
+/* Define to 1 if the system has the type `ssize_t'. */
+#define HAVE_SSIZE_T 1
+
+/* Define to 1 if stdbool.h conforms to C99. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strndup' function. */
+#define HAVE_STRNDUP 1
+
+/* Define to 1 if you have the <sys/bittypes.h> header file. */
+/* #undef HAVE_SYS_BITTYPES_H */
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if the system has the type `_Bool'. */
+#define HAVE__BOOL 1
+
+/* Define to the sub-directory where libtool stores uninstalled libraries. */
+#define LT_OBJDIR ".libs/"
+
+/* The name of the PAM module, used by the pam_vsyslog replacement. */
+#define MODULE_NAME "pam_krb5"
+
+/* Name of package */
+#define PACKAGE "pam-krb5"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "eagle@eyrie.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "pam-krb5"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "pam-krb5 4.11"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "pam-krb5"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "4.11"
+
+/* Define to const if PAM uses const in pam_get_item, empty otherwise. */
+#define PAM_CONST const
+
+/* Define to const if PAM uses const in pam_strerror, empty otherwise. */
+#define PAM_STRERROR_CONST const
+
+/* Define to the full path to openssl for some tests. */
+#define PATH_OPENSSL "/usr/bin/openssl"
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 8
+
+/* Define to 1 if all of the C90 standard headers exist (not just the ones
+ required in a freestanding environment). This macro is provided for
+ backward compatibility; new code need not use it. */
+#define STDC_HEADERS 1
+
+/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# define _ALL_SOURCE 1
+#endif
+/* Enable general extensions on macOS. */
+#ifndef _DARWIN_C_SOURCE
+# define _DARWIN_C_SOURCE 1
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# define __EXTENSIONS__ 1
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# define _GNU_SOURCE 1
+#endif
+/* Enable X/Open compliant socket functions that do not require linking
+ with -lxnet on HP-UX 11.11. */
+#ifndef _HPUX_ALT_XOPEN_SOCKET_API
+# define _HPUX_ALT_XOPEN_SOCKET_API 1
+#endif
+/* Identify the host operating system as Minix.
+ This macro does not affect the system headers' behavior.
+ A future release of Autoconf may stop defining this macro. */
+#ifndef _MINIX
+/* # undef _MINIX */
+#endif
+/* Enable general extensions on NetBSD.
+ Enable NetBSD compatibility extensions on Minix. */
+#ifndef _NETBSD_SOURCE
+# define _NETBSD_SOURCE 1
+#endif
+/* Enable OpenBSD compatibility extensions on NetBSD.
+ Oddly enough, this does nothing on OpenBSD. */
+#ifndef _OPENBSD_SOURCE
+# define _OPENBSD_SOURCE 1
+#endif
+/* Define to 1 if needed for POSIX-compatible behavior. */
+#ifndef _POSIX_SOURCE
+/* # undef _POSIX_SOURCE */
+#endif
+/* Define to 2 if needed for POSIX-compatible behavior. */
+#ifndef _POSIX_1_SOURCE
+/* # undef _POSIX_1_SOURCE */
+#endif
+/* Enable POSIX-compatible threading on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# define _POSIX_PTHREAD_SEMANTICS 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */
+#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__
+# define __STDC_WANT_IEC_60559_ATTRIBS_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */
+#ifndef __STDC_WANT_IEC_60559_BFP_EXT__
+# define __STDC_WANT_IEC_60559_BFP_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */
+#ifndef __STDC_WANT_IEC_60559_DFP_EXT__
+# define __STDC_WANT_IEC_60559_DFP_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */
+#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__
+# define __STDC_WANT_IEC_60559_FUNCS_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */
+#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__
+# define __STDC_WANT_IEC_60559_TYPES_EXT__ 1
+#endif
+/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */
+#ifndef __STDC_WANT_LIB_EXT2__
+# define __STDC_WANT_LIB_EXT2__ 1
+#endif
+/* Enable extensions specified by ISO/IEC 24747:2009. */
+#ifndef __STDC_WANT_MATH_SPEC_FUNCS__
+# define __STDC_WANT_MATH_SPEC_FUNCS__ 1
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# define _TANDEM_SOURCE 1
+#endif
+/* Enable X/Open extensions. Define to 500 only if necessary
+ to make mbstate_t available. */
+#ifndef _XOPEN_SOURCE
+/* # undef _XOPEN_SOURCE */
+#endif
+
+
+/* Version number of package */
+#define VERSION "4.11"
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
diff --git a/lib/libpam/modules/pam_krb5/pam-krb5.8 b/lib/libpam/modules/pam_krb5/pam-krb5.8
new file mode 100644
index 000000000000..3413748c7850
--- /dev/null
+++ b/lib/libpam/modules/pam_krb5/pam-krb5.8
@@ -0,0 +1,1025 @@
+.\" -*- mode: troff; coding: utf-8 -*-
+.\" Automatically generated by Pod::Man 5.0102 (Pod::Simple 3.45)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>.
+.ie n \{\
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is >0, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{\
+. if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{\
+. nr % 0
+. nr F 2
+. \}
+. \}
+.\}
+.rr rF
+.\" ========================================================================
+.\"
+.IX Title "PAM_KRB5 1"
+.TH PAM_KRB5 1 2025-06-05 "perl v5.40.2" "User Contributed Perl Documentation"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH NAME
+pam_krb5 \- Kerberos PAM module
+.SH SYNOPSIS
+.IX Header "SYNOPSIS"
+.Vb 4
+\& auth sufficient pam_krb5.so minimum_uid=1000
+\& session required pam_krb5.so minimum_uid=1000
+\& account required pam_krb5.so minimum_uid=1000
+\& password sufficient pam_krb5.so minimum_uid=1000
+.Ve
+.SH DESCRIPTION
+.IX Header "DESCRIPTION"
+The Kerberos service module for PAM, typically installed at
+\&\fI/lib/security/pam_krb5.so\fR, provides functionality for the four PAM
+operations: authentication, account management, session management, and
+password management. \fIpam_krb5.so\fR is a shared object that is
+dynamically loaded by the PAM subsystem as necessary, based on the system
+PAM configuration. PAM is a system for plugging in external
+authentication and session management modules so that each application
+doesn't have to know the best way to check user authentication or create a
+user session on that system. For details on how to configure PAM on your
+system, see the PAM man page, often \fBpam\fR\|(7).
+.PP
+Here are the actions of this module when called from each group:
+.IP auth 4
+.IX Item "auth"
+Provides implementations of \fBpam_authenticate()\fR and \fBpam_setcred()\fR. The
+former takes the username from the PAM session, prompts for the user's
+password (unless configured to use an already-entered password), and then
+performs a Kerberos initial authentication, storing the obtained
+credentials (if successful) in a temporary ticket cache. The latter,
+depending on the flags it is called with, either takes the contents of the
+temporary ticket cache and writes it out to a persistent ticket cache
+owned by the user or uses the temporary ticket cache to refresh an
+existing user ticket cache.
+.Sp
+Passwords as long or longer than PAM_MAX_RESP_SIZE octets (normally 512
+octets) will be rejected, since excessively long passwords can be used as
+a denial of service attack.
+.Sp
+After doing the initial authentication, the Kerberos PAM module will
+attempt to obtain tickets for a key in the local system keytab and then
+verify those tickets. Unless this step is performed, the authentication
+is vulnerable to KDC spoofing, but it requires that the system have a
+local key and that the PAM module be running as a user that can read the
+keytab file (normally \fI/etc/krb5.keytab\fR. You can point the Kerberos PAM
+module at a different keytab with the \fIkeytab\fR option. If that keytab
+cannot be read or if no keys are found in it, the default (potentially
+insecure) behavior is to skip this check. If you want to instead fail
+authentication if the obtained tickets cannot be checked, set
+\&\f(CW\*(C`verify_ap_req_nofail\*(C'\fR to true in the [libdefaults] section of
+\&\fI/etc/krb5.conf\fR. Note that this will affect applications other than
+this PAM module.
+.Sp
+By default, whenever the user is authenticated, a basic authorization
+check will also be done using \fBkrb5_kuserok()\fR. The default behavior of
+this function is to check the user's account for a \fI.k5login\fR file and,
+if one is present, ensure that the user's principal is listed in that
+file. If \fI.k5login\fR is not present, the default check is to ensure that
+the user's principal is in the default local realm and the user portion of
+the principal matches the account name (this can be changed by configuring
+a custom aname to localname mapping in \fIkrb5.conf\fR; see the Kerberos
+documentation for details). This can be customized with several
+configuration options; see below.
+.Sp
+If the username provided to PAM contains an \f(CW\*(C`@\*(C'\fR and Kerberos can,
+treating the username as a principal, map it to a local account name,
+\&\fBpam_authenticate()\fR will change the PAM user to that local account name.
+This allows users to log in with their Kerberos principal and let Kerberos
+do the mapping to an account. This can be disabled with the
+\&\fIno_update_user\fR option. Be aware, however, that this facility cannot be
+used with OpenSSH. OpenSSH will reject usernames that don't match local
+accounts before this remapping can be done and will pass an invalid
+password to the PAM module. Also be aware that several other common PAM
+modules, such as pam_securetty, expect to be able to look up the user with
+\&\fBgetpwnam()\fR and cannot be called before pam_krb5 when using this feature.
+.Sp
+When \fBpam_setcred()\fR is called to initialize a new ticket cache, the
+environment variable KRB5CCNAME is set to the path to that ticket cache.
+By default, the cache will be named \fI/tmp/krb5cc_UID_RANDOM\fR where UID is
+the user's UID and RANDOM is six randomly-chosen letters. This can be
+configured with the \fIccache\fR and \fIccache_dir\fR options.
+.Sp
+pam\-krb5 does not use the default ticket cache location or
+\&\fIdefault_cc_name\fR in the \f(CW\*(C`[libdefaults]\*(C'\fR section of \fIkrb5.conf\fR. The
+default cache location would share a cache for all sessions of the same
+user, which causes confusing behavior when the user logs out of one of
+multiple sessions.
+.Sp
+If \fBpam_setcred()\fR initializes a new ticket cache, it will also set up that
+ticket cache so that it will be deleted when the PAM session is closed.
+Normally, the calling program (\fBlogin\fR, \fBsshd\fR, etc.) will run the
+user's shell as a sub-process, wait for it to exit, and then close the PAM
+session, thereby cleaning up the user's session.
+.IP session 4
+.IX Item "session"
+Provides implementations of \fBpam_open_session()\fR, which is equivalent to
+calling \fBpam_setcred()\fR with the PAM_ESTABLISH_CRED flag, and
+\&\fBpam_close_session()\fR, which destroys the ticket cache created by
+\&\fBpam_setcred()\fR.
+.IP account 4
+.IX Item "account"
+Provides an implementation of \fBpam_acct_mgmt()\fR. All it does is do the same
+authorization check as performed by the \fBpam_authenticate()\fR implementation
+described above.
+.IP password 4
+.IX Item "password"
+Provides an implementation of \fBpam_chauthtok()\fR, which implements password
+changes. The user is prompted for their existing password (unless
+configured to use an already entered one) and the PAM module then obtains
+credentials for the special Kerberos principal \f(CW\*(C`kadmin/changepw\*(C'\fR. It
+then prompts the user for a new password, twice to ensure that the user
+entered it properly (again, unless configured to use an already entered
+password), and then does a Kerberos password change.
+.Sp
+Passwords as long or longer than PAM_MAX_RESP_SIZE octets (normally 512
+octets) will be rejected, since excessively long passwords can be used as
+a denial of service attack.
+.Sp
+Unlike the normal Unix password module, this module will allow any user to
+change any other user's password if they know the old password. Also,
+unlike the normal Unix password module, root will always be prompted for
+the old password, since root has no special status in Kerberos. (To
+change passwords in Kerberos without knowing the old password, use
+\&\fBkadmin\fR\|(8) instead.)
+.PP
+Both the account and session management calls of the Kerberos PAM module
+will return PAM_IGNORE if called in the context of a PAM session for a
+user who did not authenticate with Kerberos (a return code of \f(CW\*(C`ignore\*(C'\fR in
+the Linux PAM configuration language).
+.PP
+Note that this module assumes the network is available in order to do a
+Kerberos authentication. If the network is not available, some Kerberos
+libraries have timeouts longer than the timeout imposed by the login
+process. This means that using this module incautiously can make it
+impossible to log on to console as root. For this reason, you should
+always use the \fIignore_root\fR or \fIminimum_uid\fR options, list a local
+authentication module such as \fBpam_unix\fR first with a control field of
+\&\f(CW\*(C`sufficient\*(C'\fR so that the Kerberos PAM module will be skipped if local
+password authentication was successful.
+.PP
+This is not the same PAM module as the Kerberos PAM module available from
+Sourceforge, or the one included on Red Hat systems. It supports many of
+the same options, has some additional options, and doesn't support some of
+the options those modules do.
+.SH CONFIGURATION
+.IX Header "CONFIGURATION"
+The Kerberos PAM module takes many options, not all of which are relevant
+to every PAM group; options that are not relevant will be silently
+ignored. Any of these options can be set in the PAM configuration as
+arguments listed after \f(CW\*(C`pam_krb5.so\*(C'\fR. Some of the options can also be
+set in the system \fIkrb5.conf\fR file; if this is possible, it will be noted
+below in the option description.
+.PP
+To set a boolean option in the PAM configuration file, just give the name
+of the option in the arguments. To set an option that takes an argument,
+follow the option name with an equal sign (=) and the value, with no
+separating whitespace. Whitespace in option arguments is not supported in
+the PAM configuration.
+.PP
+To set an option for the PAM module in the system \fIkrb5.conf\fR file, put
+that option in the \f(CW\*(C`[appdefaults]\*(C'\fR section. All options must be followed
+by an equal sign (=) and a value, so for boolean options add \f(CW\*(C`= true\*(C'\fR.
+The Kerberos PAM module will look for options either at the top level of
+the \f(CW\*(C`[appdefaults]\*(C'\fR section or in a subsection named \f(CW\*(C`pam\*(C'\fR, inside or
+outside a section for the realm. For example, the following fragment of a
+\&\fIkrb5.conf\fR file would set \fIforwardable\fR to true, \fIminimum_uid\fR to
+1000, and set \fIignore_k5login\fR only if the realm is EXAMPLE.COM.
+.PP
+.Vb 8
+\& [appdefaults]
+\& forwardable = true
+\& pam = {
+\& minimum_uid = 1000
+\& EXAMPLE.COM = {
+\& ignore_k5login = true
+\& }
+\& }
+.Ve
+.PP
+For more information on the syntax of \fIkrb5.conf\fR, see \fBkrb5.conf\fR\|(5).
+Note that options that depend on the realm will be set only on the basis
+of the default realm, either as configured in \fBkrb5.conf\fR\|(5) or as set by
+the \fIrealm\fR option described below. If the user authenticates to an
+account qualified with a realm, that realm will not be used when
+determining which options will apply.
+.PP
+There is no difference to the PAM module whether options are specified at
+the top level or in a \f(CW\*(C`pam\*(C'\fR section; the \f(CW\*(C`pam\*(C'\fR section is supported in
+case there are options that should be set for the PAM module but not for
+other applications.
+.PP
+If the same option is set in \fIkrb5.conf\fR and in the PAM configuration,
+the latter takes precedent. Note, however, that due to the configuration
+syntax, there's no way to turn off a boolean option in the PAM
+configuration that was turned on in \fIkrb5.conf\fR.
+.PP
+The start of each option description is annotated with the version of
+pam\-krb5 in which that option was added with the current meaning.
+.SS Authorization
+.IX Subsection "Authorization"
+.IP alt_auth_map=<format> 4
+.IX Item "alt_auth_map=<format>"
+[3.12] This functions similarly to the \fIsearch_k5login\fR option. The
+<format> argument is used as the authentication Kerberos principal, with
+any \f(CW%s\fR in <format> replaced with the username. If the username
+contains an \f(CW\*(C`@\*(C'\fR, only the part of the username before the realm is used
+to replace \f(CW%s\fR. If <format> contains a realm, it will be used;
+otherwise, the realm of the username (if any) will be appended to the
+result. There is no quote removal.
+.Sp
+If this option is present, the default behavior is to try this alternate
+principal first and then fall back to the standard behavior if it fails.
+The primary usage is to allow alternative principals to be used for
+authentication in programs like \fBsudo\fR. Most examples will look like:
+.Sp
+.Vb 1
+\& alt_auth_map=%s/root
+.Ve
+.Sp
+which attempts authentication as the root instance of the username first
+and then falls back to the regular username (but see \fIforce_alt_auth\fR and
+\&\fIonly_alt_auth\fR).
+.Sp
+This option also allows a cheap way to attempt authentication in an
+alternative realm first and then fall back to the primary realm. A
+setting like:
+.Sp
+.Vb 1
+\& alt_auth_map=%s@EXAMPLE.COM
+.Ve
+.Sp
+will attempt authentication in the EXAMPLE.COM realm first and then fall
+back on the local default realm. This is more convenient than running the
+module multiple times with multiple default realms set with \fIrealm\fR, but
+it is very limited: only two realms can be tried, and the alternate realm
+is always tried first.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR, although
+normally it doesn't make sense to do that; normally it is used in the PAM
+options of configuration for specific programs. It is only applicable to
+the auth and account groups. If this option is set for the auth group, be
+sure to set it for the account group as well or account authorization may
+fail.
+.IP force_alt_auth 4
+.IX Item "force_alt_auth"
+[3.12] This option is used with \fIalt_auth_map\fR and forces authentication
+as the mapped principal if that principal exists in the KDC. Only if the
+KDC returns principal unknown does the Kerberos PAM module fall back to
+normal authentication. This can be used to force authentication with an
+alternate instance. If \fIalt_auth_map\fR is not set, it has no effect.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP ignore_k5login 4
+.IX Item "ignore_k5login"
+[2.0] Never look for a \fI.k5login\fR file in the user's home directory.
+Instead, only check that the Kerberos principal maps to the local account
+name. The default check is to ensure the realm matches the local realm
+and the user portion of the principal matches the local account name, but
+this can be customized by setting up an aname to localname mapping in
+\&\fIkrb5.conf\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and account groups.
+.IP ignore_root 4
+.IX Item "ignore_root"
+[1.1] Do not do anything if the username is \f(CW\*(C`root\*(C'\fR. The authentication
+and password calls will silently fail (allowing that status to be ignored
+via a control of \f(CW\*(C`optional\*(C'\fR or \f(CW\*(C`sufficient\*(C'\fR), and the account and
+session calls (including pam_setcred) will return PAM_IGNORE, telling the
+PAM library to proceed as if they weren't mentioned in the PAM
+configuration. This option is supported and will remain, but normally you
+want to use \fIminimum_uid\fR instead.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR.
+.IP minimum_uid=<uid> 4
+.IX Item "minimum_uid=<uid>"
+[2.0] Do not do anything if the authenticated account name corresponds to
+a local account and that local account has a UID lower than <uid>. If
+both of those conditions are true, the authentication and password calls
+will silently fail (allowing that status to be ignored via a control of
+\&\f(CW\*(C`optional\*(C'\fR or \f(CW\*(C`sufficient\*(C'\fR), and the account and session calls
+(including pam_setcred) will return PAM_IGNORE, telling the PAM library to
+proceed as if they weren't mentioned in the PAM configuration.
+.Sp
+Using this option is highly recommended if you don't need to use Kerberos
+to authenticate password logins to the root account (which isn't
+recommended since Kerberos requires a network connection). It provides
+some defense in depth against user principals that happen to match a
+system account incorrectly authenticating as that system account.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR.
+.IP only_alt_auth 4
+.IX Item "only_alt_auth"
+[3.12] This option is used with \fIalt_auth_map\fR and forces the use of the
+mapped principal for authentication. It disables fallback to normal
+authentication in all cases and overrides \fIsearch_k5login\fR and
+\&\fIforce_alt_auth\fR. If \fIalt_auth_map\fR is not set, it has no effect and
+the standard authentication behavior is used.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP search_k5login 4
+.IX Item "search_k5login"
+[2.0] Normally, the Kerberos implementation of pam_authenticate attempts
+to obtain tickets for the authenticating username in the local realm. If
+this option is set and the local user has a \fI.k5login\fR file in their home
+directory, the module will instead open and read that \fI.k5login\fR file,
+attempting to use the supplied password to authenticate as each principal
+listed there in turn. If any of those authentications succeed, the user
+will be successfully authenticated; otherwise, authentication will fail.
+This option is useful for allowing password authentication (via console or
+\&\fBsshd\fR without GSS-API support) to shared accounts. If there is no
+\&\fI.k5login\fR file, the behavior is the same as normal. Using this option
+requires that the user's \fI.k5login\fR file be readable at the time of
+authentication.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.SS "Kerberos Behavior"
+.IX Subsection "Kerberos Behavior"
+.IP anon_fast 4
+.IX Item "anon_fast"
+[4.6] Attempt to use Flexible Authentication Secure Tunneling (FAST) by
+first authenticating as the anonymous user (WELLKNOWN/ANONYMOUS) and using
+its credentials as the FAST armor. This requires anonymous PKINIT be
+enabled for the local realm, that PKINIT be configured on the local
+system, and that the Kerberos library support FAST and anonymous PKINIT.
+.Sp
+FAST is a mechanism to protect Kerberos against password guessing attacks
+and provide other security improvements. To work, FAST requires that a
+ticket be obtained with a strong key to protect exchanges with potentially
+weaker user passwords. This option uses anonymous authentication to
+obtain that key and then uses it to protect the subsequent authentication.
+.Sp
+If anonymous PKINIT is not available or fails, FAST will not be used and
+the authentication will proceed as normal.
+.Sp
+To instead use an existing ticket cache for the FAST credentials, use
+\&\fIfast_ccache\fR instead of this option. If both \fIfast_ccache\fR and
+\&\fIanon_fast\fR are set, the ticket cache named by \fIfast_ccache\fR will be
+tried first, and the Kerberos PAM module will fall back on attempting
+anonymous PKINIT if that cache could not be used.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.Sp
+The operation is the same as if using the \fIfast_ccache\fR option, but the
+cache is created and destroyed automatically. If both \fIfast_ccache\fR and
+\&\fIanon_fast\fR options are used, the \fIfast_ccache\fR takes precedent and no
+anonymous authentication is done.
+.IP fast_ccache=<ccache_name> 4
+.IX Item "fast_ccache=<ccache_name>"
+[4.3] The same as \fIanon_fast\fR, but use an existing Kerberos ticket cache
+rather than anonymous PKINIT. This allows use of FAST with a realm that
+doesn't support PKINIT or doesn't support anonymous authentication.
+.Sp
+<ccache_name> should be a credential cache containing a ticket obtained
+using a strong key, such as the randomized key for the host principal of
+the local system. If <ccache_name> names a ticket cache that is readable
+by the authenticating process and has tickets then FAST will be attempted.
+The easiest way to use this option is to use a program like \fBk5start\fR to
+maintain a ticket cache using the host's keytab. This ticket cache should
+normally only be readable by root, so this option will not be able to
+protect authentications done as non-root users (such as screensavers).
+.Sp
+If no credentials are present in the ticket cache, or if the ticket cache
+does not exist or is not readable, FAST will not used and authentication
+will proceed as normal. However, if the credentials in that ticket cache
+are expired, authentication will fail if the KDC supports FAST.
+.Sp
+To use anonymous PKINIT to protect the FAST exchange, use the \fIanon_fast\fR
+option instead. \fIanon_fast\fR is easier to configure, since no existing
+ticket cache is required, but requires PKINIT be available and configured
+and that the local realm support anonymous authentication. If both
+\&\fIfast_ccache\fR and \fIanon_fast\fR are set, the ticket cache named by
+\&\fIfast_ccache\fR will be tried first, and the Kerberos PAM module will fall
+back on attempting anonymous PKINIT if that cache could not be used.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP forwardable 4
+.IX Item "forwardable"
+[1.0] Obtain forwardable tickets. If set (to either true or false,
+although it can only be set to false in \fIkrb5.conf\fR), this overrides the
+Kerberos library default set in the [libdefaults] section of \fIkrb5.conf\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP keytab=<path> 4
+.IX Item "keytab=<path>"
+[3.0] Specifies the keytab to use when validating the user's credentials.
+The default is the default system keytab (normally \fI/etc/krb5.keytab\fR),
+which is usually only readable by root. Applications not running as root
+that use this PAM module for authentication may wish to point it to
+another keytab the application can read. The first principal found in the
+keytab will be used as the principal for credential verification.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP realm=<realm> 4
+.IX Item "realm=<realm>"
+[2.2] Set the default Kerberos realm and obtain credentials in that realm,
+rather than in the normal default realm for this system. If this option
+is used, it should be set for all groups being used for consistent
+results. This setting will affect authorization decisions since it
+changes the default realm. This setting will also change the service
+principal used to verify the obtained credentials to be in the specified
+realm.
+.Sp
+If you only want to set the realm assumed for user principals without
+changing the realm for authorization decisions or the service principal
+used to verify credentials, see the \fIuser_realm\fR option.
+.IP renew_lifetime=<lifetime> 4
+.IX Item "renew_lifetime=<lifetime>"
+[2.0] Obtain renewable tickets with a maximum renewable lifetime of
+<lifetime>. <lifetime> should be a Kerberos lifetime string such as
+\&\f(CW\*(C`2d4h10m\*(C'\fR or a time in minutes. If set, this overrides the Kerberos
+library default set in the [libdefaults] section of \fIkrb5.conf\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP ticket_lifetime=<lifetime> 4
+.IX Item "ticket_lifetime=<lifetime>"
+[3.0] Obtain tickets with a maximum lifetime of <lifetime>. <lifetime>
+should be a Kerberos lifetime string such as \f(CW\*(C`2d4h10m\*(C'\fR or a time in
+minutes. If set, this overrides the Kerberos library default set in the
+[libdefaults] section of \fIkrb5.conf\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP user_realm 4
+.IX Item "user_realm"
+[4.6] Obtain credentials in the specified realm rather than in the default
+realm for this system. If this option is used, it should be set for all
+groups being used for consistent results (although the account group
+currently doesn't care about realm). This will not change authorization
+decisions. If the obtained credentials are supposed to allow access to a
+shell account, the user will need an appropriate \fI.k5login\fR file entry or
+the system will have to have a custom aname_to_localname mapping.
+.SS "PAM Behavior"
+.IX Subsection "PAM Behavior"
+.IP clear_on_fail 4
+.IX Item "clear_on_fail"
+[3.9] When changing passwords, PAM first does a preliminary check through
+the complete password stack, and then calls each module again to do the
+password change. After that preliminary check, the order of module
+invocation is fixed. This means that even if the Kerberos password change
+fails (or if one of the other password changes in the stack fails), other
+password PAM modules in the stack will still be called even if the failing
+module is marked required or requisite. When using multiple password PAM
+modules to synchronize passwords between multiple systems when they
+change, this behavior can cause unwanted differences between the
+environments.
+.Sp
+Setting this option provides a way to work around this behavior. If this
+option is set and a Kerberos password change is attempted and fails (due
+to network errors or password strength checking on the KDC, for example),
+this module will clear the stored password in the PAM stack. This will
+force any subsequent modules that have \fIuse_authtok\fR set to fail so that
+those environments won't get out of sync with the password in Kerberos.
+The Kerberos PAM module will not meddle with the stored password if it
+skips the user due to configuration such as minimum_uid.
+.Sp
+Unfortunately, setting this option interferes with other desirable PAM
+configurations, such as attempting to change the password in Kerberos
+first and falling back on the local Unix password database if that fails.
+It therefore isn't the default. Turn it on (and list pam_krb5 first after
+pam_cracklib if used) when synchronizing passwords between multiple
+environments.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the password group.
+.IP debug 4
+.IX Item "debug"
+[1.0] Log more verbose trace and debugging information to syslog at
+LOG_DEBUG priority, including entry and exit from each of the external PAM
+interfaces (except pam_close_session).
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR.
+.IP defer_pwchange 4
+.IX Item "defer_pwchange"
+[3.11] By default, pam\-krb5 lets the Kerberos library handle prompting for
+a password change if an account's password is expired during the auth
+group. If this fails, \fBpam_authenticate()\fR returns an error.
+.Sp
+According to the PAM standard, this is not the correct way to handle
+expired passwords. Instead, \fBpam_authenticate()\fR should return success
+without attempting a password change, and then \fBpam_acct_mgmt()\fR should
+return PAM_NEW_AUTHTOK_REQD, at which point the calling application is
+responsible for either rejecting the authentication or calling
+\&\fBpam_chauthtok()\fR. However, following the standard requires that all
+applications call \fBpam_acct_mgmt()\fR and check its return status; otherwise,
+expired accounts may be able to successfully authenticate. Many
+applications do not do this.
+.Sp
+If this option is set, pam\-krb5 uses the fully correct PAM mechanism for
+handling expired accounts instead of failing in \fBpam_authenticate()\fR. Due
+to the security risk of widespread broken applications, be very careful
+about enabling this option. It should normally only be turned on to solve
+a specific problem (such as using Solaris Kerberos libraries that don't
+support prompting for password changes during authentication), and then
+only for specific applications known to call \fBpam_acct_mgmt()\fR and check its
+return status properly.
+.Sp
+This option is only supported when pam\-krb5 is built with MIT Kerberos.
+If built against Heimdal, this option does nothing and normal expired
+password change handling still happens. (Heimdal is missing the required
+API to implement this option, at least as of version 1.6.)
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP fail_pwchange 4
+.IX Item "fail_pwchange"
+[4.2] By default, pam\-krb5 lets the Kerberos library handle prompting for
+a password change if an account's password is expired during the auth
+group. If this option is set, expired passwords are instead treated as an
+authentication failure identical to an incorrect password. Also see
+\&\fIdefer_pwchange\fR and \fIforce_pwchange\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP force_pwchange 4
+.IX Item "force_pwchange"
+[3.11] If this option is set and authentication fails with a Kerberos
+error indicating the user's password is expired, attempt to immediately
+change their password during the authenticate step. Under normal
+circumstances, this is unnecessary. Most Kerberos libraries will do this
+for you, and setting this option will prompt the user twice to change
+their password if the first attempt (done by the Kerberos library) fails.
+However, some system Kerberos libraries (such as Solaris's) have password
+change prompting disabled in the Kerberos library; on those systems, you
+can set this option to simulate the normal library behavior.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP no_update_user 4
+.IX Item "no_update_user"
+[4.7] Normally, if pam\-krb5 is able to canonicalize the principal to a
+local name using \fBkrb5_aname_to_localname()\fR or similar calls, it changes
+the PAM_USER variable for this PAM session to the canonicalized local
+name. Setting this option disables this behavior and leaves PAM_USER set
+to the initial authentication identity.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth group.
+.IP silent 4
+.IX Item "silent"
+[1.0] Don't show messages and errors from Kerberos, such as warnings of
+expiring passwords, to the user via the prompter. This is equivalent to
+the behavior when the application passes in PAM_SILENT, but can be set in
+the PAM configuration.
+.Sp
+This option is only applicable to the auth and password groups.
+.IP trace=<log\-file> 4
+.IX Item "trace=<log-file>"
+[4.6] Enables Kerberos library trace logging to the specified log file if
+it is supported by the Kerberos library. This is intended for temporary
+debugging. The specified file will be appended to without further
+security checks, so do not specify a file in a publicly writable directory
+like \fI/tmp\fR.
+.SS PKINIT
+.IX Subsection "PKINIT"
+.IP pkinit_anchors=<anchors> 4
+.IX Item "pkinit_anchors=<anchors>"
+[3.0] When doing PKINIT authentication, use <anchors> as the client trust
+anchors. This is normally a reference to a file containing the trusted
+certificate authorities. This option is only used if \fItry_pkinit\fR or
+\&\fIuse_pkinit\fR are set.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP pkinit_prompt 4
+.IX Item "pkinit_prompt"
+[3.0] Before attempting PKINIT authentication, prompt the user to insert a
+smart card. You may want to set this option for programs such as
+\&\fBgnome-screensaver\fR that call PAM as soon as the mouse is touched and
+don't give the user an opportunity to enter the smart card first. Any
+information entered at the first prompt is ignored. If \fItry_pkinit\fR is
+set, a user who wishes to use a password instead can just press Enter and
+then enter their password as normal. This option is only used if
+\&\fItry_pkinit\fR or \fIuse_pkinit\fR are set.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP pkinit_user=<userid> 4
+.IX Item "pkinit_user=<userid>"
+[3.0] When doing PKINIT authentication, use <userid> as the user ID. The
+value of this string is highly dependent on the type of PKINIT
+implementation you're using, but will generally be something like:
+.Sp
+.Vb 1
+\& PKCS11:/usr/lib/pkcs11/lib/soft\-pkcs11.so
+.Ve
+.Sp
+to specify the module to use with a smart card. It may also point to a
+user certificate or to other types of user IDs. See the Kerberos library
+documentation for more details. This option is only used if \fItry_pkinit\fR
+or \fIuse_pkinit\fR are set.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP preauth_opt=<option> 4
+.IX Item "preauth_opt=<option>"
+[3.3] Sets a preauth option (currently only applicable when built with MIT
+Kerberos). <option> is either a key/value pair with the key separated
+from the value by \f(CW\*(C`=\*(C'\fR or a boolean option (in which case it's turned on).
+In \fIkrb5.conf\fR, multiple options should be separated by whitespace. In
+the PAM configuration, this option can be given multiple times to set
+multiple options. In either case, <option> may not contain whitespace.
+.Sp
+The primary use of this option, at least in the near future, will be to
+set options for the MIT Kerberos PKINIT support. For the full list of
+possible options, see the PKINIT plugin documentation. At the time of
+this writing, \f(CW\*(C`X509_user_identity\*(C'\fR is equivalent to \fIpkinit_user\fR and
+\&\f(CW\*(C`X509_anchors\*(C'\fR is equivalent to \fIpkinit_anchors\fR. \f(CW\*(C`flag_DSA_PROTOCOL\*(C'\fR
+can only be set via this option.
+.Sp
+Any settings made with this option are applied after the \fIpkinit_anchors\fR
+and \fIpkinit_user\fR options, so if an equivalent setting is made via
+\&\fIpreauth_opt\fR, it will probably override the other setting.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups. Note that there is no way to
+remove a setting made in \fIkrb5.conf\fR using the PAM configuration, but
+options set in the PAM configuration are applied after options set in
+\&\fIkrb5.conf\fR and therefore may override earlier settings.
+.IP try_pkinit 4
+.IX Item "try_pkinit"
+[3.0] Attempt PKINIT authentication before trying a regular password. You
+will probably also need to set the \fIpkinit_user\fR configuration option.
+If PKINIT fails, the PAM module will fall back on regular password
+authentication. This option is currently only supported if pam\-krb5 was
+built against Heimdal 0.8rc1 or later or MIT Kerberos 1.6.3 or later.
+.Sp
+If this option is set and pam\-krb5 is built against MIT Kerberos, and
+PKINIT fails and the module falls back to password authentication, the
+user's password will not be stored in the PAM stack for subsequent
+modules. This is a bug in the interaction between the module and MIT
+Kerberos that requires some reworking of the PKINIT authentication method
+to fix.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP use_pkinit 4
+.IX Item "use_pkinit"
+[3.0, 4.9 for MIT Kerberos] Require PKINIT authentication. You will
+probably also need to set the \fIpkinit_user\fR configuration option. If
+PKINIT fails, authentication will fail. This option is only supported if
+pam\-krb5 was built against Heimdal 0.8rc1 or later or MIT Kerberos 1.12 or
+later.
+.Sp
+Be aware that, with MIT Kerberos, this option is implemented by using a
+responder without a prompter, and thus any informational messages from the
+Kerberos libraries or KDC during authentication will not be displayed.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.SS Prompting
+.IX Subsection "Prompting"
+.IP banner=<banner> 4
+.IX Item "banner=<banner>"
+[3.0] By default, the prompts when a user changes their password are:
+.Sp
+.Vb 3
+\& Current Kerberos password:
+\& Enter new Kerberos password:
+\& Retype new Kerberos password:
+.Ve
+.Sp
+The string "Kerberos" is inserted so that users aren't confused about
+which password they're changing. Setting this option replaces the word
+"Kerberos" with whatever this option is set to. Setting this option to
+the empty string removes the word before "password:" entirely.
+.Sp
+If set in the PAM configuration, <banner> may not contain whitespace. If
+you want a value containing whitespace, set it in \fIkrb5.conf\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the password group.
+.IP expose_account 4
+.IX Item "expose_account"
+[3.0] By default, the Kerberos PAM module password prompt is simply
+"Password:". This avoids leaking any information about the system realm
+or account to principal conversions. If this option is set, the string
+"for <principal>" is added before the colon, where <principal> is the
+user's principal. This string is also added before the colon on prompts
+when changing the user's password.
+.Sp
+Enabling this option with ChallengeResponseAuthentication enabled in
+OpenSSH may cause problems for some ssh clients that only recognize
+"Password:" as a prompt. This option is automatically disabled if
+\&\fIsearch_k5login\fR is enabled since the principal displayed would be
+inaccurate.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and password groups.
+.IP force_first_pass 4
+.IX Item "force_first_pass"
+[4.0] Use the password obtained by a previous authentication or password
+module to authenticate the user without prompting the user again. If no
+previous module obtained the user's password, fail without prompting the
+user. Also see \fItry_first_pass\fR and \fIuse_first_pass\fR for weaker
+versions of this option.
+.Sp
+This option is only applicable to the auth and password groups. For the
+password group, it applies only to the old password. See \fIuse_authtok\fR
+for a similar setting for the new password.
+.IP no_prompt 4
+.IX Item "no_prompt"
+[4.6] Never prompt for the current password. Instead, pass in a NULL
+password to the Kerberos library and let the Kerberos library do the
+prompting. This may be needed if, for example, the Kerberos library is
+configured to use other authentication mechanisms than passwords and needs
+full control over the prompting process.
+.Sp
+The major disadvantage of this option is that it means the PAM module will
+never see the user's password and therefore cannot save it in the PAM
+module data for any subsequent modules. In other words, this option
+cannot be used if another module is in the stack behind the Kerberos PAM
+module and wants to use \fIuse_first_pass\fR. The Kerberos library also
+usually includes the principal in the prompt, and therefore this option
+implies behavior similar to \fIexpose_account\fR. Similar to
+\&\fIexpose_account\fR, this can cause problems with OpenSSH if
+ChallengeResponseAuthentication is enabled, since clients may not
+recognize password prompts other than "Password:".
+.Sp
+Using this option with \fIsearch_k5login\fR would result in a password prompt
+for every principal listed in the user's \fI.k5login\fR file. This is
+probably not desired behavior, although it's not prohibited by the module.
+.Sp
+This option is only applicable to the auth and password groups. For the
+password group, it applies only to the authentication process; the user
+will still be prompted for a new password.
+.IP prompt_principal 4
+.IX Item "prompt_principal"
+[3.6] Before prompting for the user's password (or using the previously
+entered password, if \fItry_first_pass\fR, \fIuse_first_pass\fR, or
+\&\fIforce_first_pass\fR are set), prompt the user for the Kerberos principal
+to use for authentication. This allows the user to authenticate with a
+different principal than the one corresponding to the local username,
+provided that either a \fI.k5login\fR file or local Kerberos principal to
+account mapping authorize that principal to access the local account.
+.Sp
+Be cautious when using this configuration option and don't use it with
+OpenSSH PasswordAuthentication, only ChallengeResponseAuthentication.
+Some PAM-enabled applications expect PAM modules to only prompt for
+passwords and may even blindly give the password to the first prompt, no
+matter what it is. Such applications, in combination with this option,
+may expose the user's password in log messages and Kerberos requests.
+.IP try_first_pass 4
+.IX Item "try_first_pass"
+[1.0] If the authentication module isn't the first on the stack, and a
+previous module obtained the user's password, use that password to
+authenticate the user without prompting them again. If that
+authentication fails, fall back on prompting the user for their password.
+This option has no effect if the authentication module is first in the
+stack or if no previous module obtained the user's password. Also see
+\&\fIuse_first_pass\fR and \fIforce_first_pass\fR for stronger versions of this
+option.
+.Sp
+This option is only applicable to the auth and password groups. For the
+password group, it applies only to the old password.
+.IP use_authtok 4
+.IX Item "use_authtok"
+[4.0] Use the new password obtained by a previous password module when
+changing passwords rather than prompting for the new password. If the new
+password isn't available, fail. This can be used to require passwords be
+checked by another, prior module, such as \fBpam_cracklib\fR.
+.Sp
+This option is only applicable to the password group.
+.IP use_first_pass 4
+.IX Item "use_first_pass"
+[1.0] Use the password obtained by a previous authentication module to
+authenticate the user without prompting the user again. If no previous
+module obtained the user's password for either an authentication or
+password change, fall back on prompting the user. If a previous module
+did obtain the user's password but authentication with that password
+fails, fail without further prompting the user. Also see
+\&\fItry_first_pass\fR and \fIforce_first_pass\fR for other versions of this
+option.
+.Sp
+This option is only applicable to the auth and password groups. For the
+password group, it applies only to the old password. See \fIuse_authtok\fR
+for a similar setting for the new password.
+.SS "Ticket Caches"
+.IX Subsection "Ticket Caches"
+.IP ccache=<pattern> 4
+.IX Item "ccache=<pattern>"
+[2.0] Use <pattern> as the pattern for creating credential cache names.
+<pattern> must be in the form <type>:<residual> where <type> and the
+following colon are optional if a file cache should be used. The special
+token \f(CW%u\fR, anywhere in <pattern>, is replaced with the user's numeric
+UID. The special token \f(CW%p\fR, anywhere in <pattern>, is replaced with the
+current process ID.
+.Sp
+If <pattern> ends in the literal string \f(CW\*(C`XXXXXX\*(C'\fR (six X's), that string
+will be replaced by randomly generated characters and the ticket cache
+will be created using \fBmkstemp\fR\|(3). This is strongly recommended if
+<pattern> points to a world-writable directory.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and session groups.
+.IP ccache_dir=<directory> 4
+.IX Item "ccache_dir=<directory>"
+[1.2] Store both the temporary ticket cache used during authentication and
+user ticket caches in <directory> instead of in \fI/tmp\fR. The algorithm
+for generating the ticket cache name is otherwise unchanged. <directory>
+may be prefixed with \f(CW\*(C`FILE:\*(C'\fR to make the cache type unambiguous (and this
+may be required on systems that use a cache type other than file as the
+default).
+.Sp
+Be aware that pam_krb5 creates and stores a temporary ticket cache file
+owned by root during the login process. If you set \fIccache\fR above to
+avoid using the system \fI/tmp\fR directory for user ticket caches, you may
+also want to set \fIccache_dir\fR to move those temporary caches to some
+other location. This will allow pam_krb5 to continue working even if the
+system \fI/tmp\fR directory is full.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and session groups.
+.IP no_ccache 4
+.IX Item "no_ccache"
+[1.0] Do not create a ticket cache after authentication. This option
+shouldn't be set in general, but is useful as part of the PAM
+configuration for a particular service that uses PAM for authentication
+but isn't creating user sessions and doesn't want the overhead of ever
+writing the user credentials to disk. When using this option, the
+application should only call \fBpam_authenticate()\fR; other functions like
+\&\fBpam_setcred()\fR, \fBpam_start_session()\fR, and \fBpam_acct_mgmt()\fR don't make sense
+with this option. Don't use this option if the application needs PAM
+account and session management calls.
+.Sp
+This option is only applicable to the auth group.
+.IP retain_after_close 4
+.IX Item "retain_after_close"
+[2.3] Normally, the user's ticket cache is destroyed when either \fBpam_end()\fR
+or \fBpam_close_session()\fR is called by the authenticating application so that
+ticket caches aren't left behind after the user logs out. In some cases,
+however, this isn't desirable. (On Solaris 8, for instance, the default
+behavior means login will destroy the ticket cache before running the
+user's shell.) If this option is set, the PAM module will never destroy
+the user's ticket cache. If you set this, you may want to call
+\&\fBkdestroy\fR in the shell's logout configuration or run a temporary file
+removal program to avoid accumulating hundreds of ticket caches in
+\&\fI/tmp\fR.
+.Sp
+This option can be set in \f(CW\*(C`[appdefaults]\*(C'\fR in \fIkrb5.conf\fR and is only
+applicable to the auth and session groups.
+.SH ENVIRONMENT
+.IX Header "ENVIRONMENT"
+.IP KRB5CCNAME 4
+.IX Item "KRB5CCNAME"
+Set by \fBpam_setcred()\fR with the PAM_ESTABLISH_CRED option, and therefore
+also by \fBpam_open_session()\fR, to point to the new credential cache for the
+user. See the \fIccache\fR and \fIccache_dir\fR options. By default, the cache
+name will be prefixed with \f(CW\*(C`FILE:\*(C'\fR to make the cache type unambiguous.
+.IP PAM_KRB5CCNAME 4
+.IX Item "PAM_KRB5CCNAME"
+Set by \fBpam_authenticate()\fR to point to the temporary ticket cache used for
+authentication (unless the \fIno_ccache\fR option was given). \fBpam_setcred()\fR
+then uses that environment variable to locate the temporary cache even if
+it was not called in the same PAM session as \fBpam_authenticate()\fR (a problem
+with \fBsshd\fR running in some modes). This environment variable is only
+used internal to the PAM module.
+.SH FILES
+.IX Header "FILES"
+.IP \fI/tmp/krb5cc_UID_RANDOM\fR 4
+.IX Item "/tmp/krb5cc_UID_RANDOM"
+The default credential cache name. UID is the decimal UID of the local
+user and RANDOM is a random six-character string. The pattern may be
+changed with the \fIccache\fR option and the directory with the \fIccache_dir\fR
+option.
+.IP \fI/tmp/krb5cc_pam_RANDOM\fR 4
+.IX Item "/tmp/krb5cc_pam_RANDOM"
+The credential cache name used for the temporary credential cache created
+by \fBpam_authenticate()\fR. This cache is removed again when the PAM session
+is ended or when \fBpam_setcred()\fR is called and will normally not be
+user-visible. RANDOM is a random six-character string.
+.IP \fI~/.k5login\fR 4
+.IX Item "~/.k5login"
+File containing Kerberos principals that are allowed access to that
+account.
+.SH BUGS
+.IX Header "BUGS"
+If \fItry_pkinit\fR is set and pam\-krb5 is built with MIT Kerberos, the
+user's password is not saved in the PAM data if PKINIT fails and the
+module falls back to password authentication.
+.SH CAVEATS
+.IX Header "CAVEATS"
+Be sure to list this module in the session group as well as the auth group
+when using it for interactive logins. Otherwise, some applications (such
+as OpenSSH) will not set up the user's ticket cache correctly.
+.PP
+The Kerberos library, via pam\-krb5, will prompt the user to change their
+password if their password is expired, but when using OpenSSH, this will
+only work when ChallengeResponseAuthentication is enabled. Unless this
+option is enabled, OpenSSH doesn't pass PAM messages to the user and can
+only respond to a simple password prompt.
+.PP
+If you are using MIT Kerberos, be aware that users whose passwords are
+expired will not be prompted to change their password unless the KDC
+configuration for your realm in [realms] in krb5.conf contains a
+master_kdc setting or, if using DNS SRV records, you have a DNS entry for
+_kerberos\-master as well as _kerberos.
+.PP
+\&\fBpam_authenticate()\fR returns failure when called for an ignored account,
+requiring the system administrator to use \f(CW\*(C`optional\*(C'\fR or \f(CW\*(C`sufficient\*(C'\fR to
+ignore the module and move on to the next module. It's arguably more
+correct to return PAM_IGNORE, which causes the module to be ignored as if
+it weren't in the configuration, but this increases the risk of
+inadvertent security holes when listing pam\-krb5 as the only
+authentication module.
+.PP
+This module treats the empty password as an authentication failure
+rather than attempting to use that password to avoid unwanted prompting
+behavior in the Kerberos libraries. If you have a Kerberos principal that
+intentionally has an empty password, it won't work with this module.
+.PP
+This module will not refresh an existing ticket cache if called with an
+effective UID or GID different than the real UID or GID, since refreshing
+an existing ticket cache requires trusting the KRB5CCNAME environment
+variable and the environment should not be trusted in a setuid context.
+.PP
+Old versions of OpenSSH are known to call pam_authenticate followed by
+pam_setcred(PAM_REINITIALIZE_CRED) without first calling pam_open_session,
+thereby requesting that an existing ticket cache be renewed (similar to
+what a screensaver would want) rather than requesting a new ticket cache
+be created. Since this behavior is indistinguishable at the PAM level
+from a screensaver, pam\-krb5 when used with these old versions of OpenSSH
+will refresh the ticket cache of the OpenSSH daemon rather than setting up
+a new ticket cache for the user. The resulting ticket cache will have the
+correct permissions, but will not be named correctly or referenced in the
+user's environment and will be overwritten by the next user login. The
+best solution to this problem is to upgrade OpenSSH. I'm not sure exactly
+when this problem was fixed, but at the very least OpenSSH 4.3 and later
+do not exhibit it.
+.SH AUTHOR
+.IX Header "AUTHOR"
+pam\-krb5 was originally written by Frank Cusack. Andres Salomon made
+extensive modifications, and then Russ Allbery <eagle@eyrie.org> adopted
+it and made even more extensive modifications. Russ Allbery currently
+maintains the module.
+.SH "COPYRIGHT AND LICENSE"
+.IX Header "COPYRIGHT AND LICENSE"
+Copyright 2005\-2010, 2014, 2020 Russ Allbery <eagle@eyrie.org>
+.PP
+Copyright 2008\-2014 The Board of Trustees of the Leland Stanford Junior
+University
+.PP
+Copying and distribution of this file, with or without modification, are
+permitted in any medium without royalty provided the copyright notice and
+this notice are preserved. This file is offered as-is, without any
+warranty.
+.PP
+SPDX-License-Identifier: FSFAP
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\fBkadmin\fR\|(8), \fBkdestroy\fR\|(1), \fBkrb5.conf\fR\|(5), \fBpam\fR\|(7), \fBpasswd\fR\|(1), \fBsyslog\fR\|(3)
+.PP
+The current version of this module is available from its web page at
+<https://www.eyrie.org/~eagle/software/pam\-krb5/>.
diff --git a/lib/libpam/modules/pam_krb5/pam_krb5.c b/lib/libpam/modules/pam_krb5/pam_krb5.c
index 5f448165b20a..e13c1b794d5b 100644
--- a/lib/libpam/modules/pam_krb5/pam_krb5.c
+++ b/lib/libpam/modules/pam_krb5/pam_krb5.c
@@ -60,6 +60,10 @@
#include <krb5.h>
#include <com_err.h>
+#ifdef MK_MITKRB5
+/* For MIT KRB5 only. */
+#include <k5-int.h>
+#endif
#define PAM_SM_AUTH
#define PAM_SM_ACCOUNT
diff --git a/lib/libpam/modules/pam_ksu/Makefile b/lib/libpam/modules/pam_ksu/Makefile
index c5fd72d9db7d..953ca23d1416 100644
--- a/lib/libpam/modules/pam_ksu/Makefile
+++ b/lib/libpam/modules/pam_ksu/Makefile
@@ -25,10 +25,21 @@
PACKAGE= kerberos
+.include <src.opts.mk>
+
LIB= pam_ksu
SRCS= pam_ksu.c
MAN= pam_ksu.8
+WARNS?= 3
LIBADD+= krb5
+.if ${MK_MITKRB5} != "no"
+WARNS= 2
+CFLAGS+= -I${SRCTOP}/crypto/krb5/src/include
+CFLAGS+= -I${SRCTOP}/krb5/include
+CFLAGS+= -include ${SRCTOP}/crypto/krb5/src/include/k5-int.h
+CFLAGS+= -DMK_MITKRB5=yes
+.endif
+
.include <bsd.lib.mk>
diff --git a/lib/libpam/modules/pam_ksu/pam_ksu.c b/lib/libpam/modules/pam_ksu/pam_ksu.c
index 47362c835c12..002613188d8c 100644
--- a/lib/libpam/modules/pam_ksu/pam_ksu.c
+++ b/lib/libpam/modules/pam_ksu/pam_ksu.c
@@ -48,6 +48,62 @@ static long get_su_principal(krb5_context, const char *, const char *,
static int auth_krb5(pam_handle_t *, krb5_context, const char *,
krb5_principal);
+#ifdef MK_MITKRB5
+/* For MIT KRB5 only. */
+
+/*
+ * XXX This entire module will need to be rewritten when heimdal
+ * XXX compatidibility is no longer needed.
+ */
+#define KRB5_DEFAULT_CCFILE_ROOT "/tmp/krb5cc_"
+#define KRB5_DEFAULT_CCROOT "FILE:" KRB5_DEFAULT_CCFILE_ROOT
+
+/*
+ * XXX We will replace krb5_build_principal_va() with
+ * XXX krb5_build_principal_alloc_va() when Heimdal is finally
+ * XXX removed.
+ */
+krb5_error_code KRB5_CALLCONV
+krb5_build_principal_va(krb5_context context,
+ krb5_principal princ,
+ unsigned int rlen,
+ const char *realm,
+ va_list ap);
+typedef char *heim_general_string;
+typedef heim_general_string Realm;
+typedef Realm krb5_realm;
+typedef const char *krb5_const_realm;
+
+static krb5_error_code
+krb5_make_principal(krb5_context context, krb5_principal principal,
+ krb5_const_realm realm, ...)
+{
+ krb5_realm temp_realm = NULL;
+ krb5_error_code rc;
+ va_list ap;
+
+ if (realm == NULL) {
+ if ((rc = krb5_get_default_realm(context, &temp_realm)))
+ return (rc);
+ realm=temp_realm;
+ }
+ va_start(ap, realm);
+ /*
+ * XXX Ideally we should be using krb5_build_principal_alloc_va()
+ * XXX here because krb5_build_principal_va() is deprecated. But,
+ * XXX this would require changes elsewhere in the calling code
+ * XXX to call krb5_free_principal() elsewhere to free the
+ * XXX principal. We can do that after Heimdal is removed from
+ * XXX our tree.
+ */
+ rc = krb5_build_principal_va(context, principal, strlen(realm), realm, ap);
+ va_end(ap);
+ if (temp_realm)
+ free(temp_realm);
+ return (rc);
+}
+#endif
+
PAM_EXTERN int
pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
int argc __unused, const char *argv[] __unused)
@@ -217,7 +273,13 @@ get_su_principal(krb5_context context, const char *target_user, const char *curr
if (rv != 0)
return (errno);
if (default_principal == NULL) {
+#ifdef MK_MITKRB5
+ /* For MIT KRB5. */
+ rv = krb5_make_principal(context, default_principal, NULL, current_user, NULL);
+#else
+ /* For Heimdal. */
rv = krb5_make_principal(context, &default_principal, NULL, current_user, NULL);
+#endif
if (rv != 0) {
PAM_LOG("Could not determine default principal name.");
return (rv);
diff --git a/lib/libpam/modules/pam_xdg/pam_xdg.8 b/lib/libpam/modules/pam_xdg/pam_xdg.8
index 9b97d3626531..9b335751a9fb 100644
--- a/lib/libpam/modules/pam_xdg/pam_xdg.8
+++ b/lib/libpam/modules/pam_xdg/pam_xdg.8
@@ -22,7 +22,7 @@
.\" * 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.
-.Dd August 22, 2024
+.Dd May 20, 2025
.Dt PAM_XDG 8
.Os
.Sh NAME
@@ -35,17 +35,26 @@
.Pa pam_xdg
.Op Ar arguments
.Sh DESCRIPTION
-The xdg service module for PAM sets up the runtime directory according
-to the XDG specifications.
+The xdg service module for PAM creates the runtime files base directory
+according to the Cross Desktop Group Base Directory Specification.
.Pp
By default the directory is created under
-.Pa /var/run/xdg/<username> .
+.Pa /var/run/xdg/ Ns $ Ns Ev USER .
.Pp
The following option may be passed to the authentication module:
-.Bl -tag -width ".Cm runtime_dir_prefix"
+.Bl -tag -width "runtime_dir_prefix=directory"
.It Cm runtime_dir_prefix Ns = Ns Ar directory
Use an alternate base directory
.El
+.Sh ENVIRONMENT
+.Bl -tag -width indent
+.It Ev XDG_RUNTIME_DIR
+The location of the runtime files base directory created by this module.
+Note that the module does not set this environment variable.
+.El
+.Sh STANDARDS
+The directory created by this module conforms to the
+.Lk https://specifications.freedesktop.org/basedir-spec XDG Base Directory Specification .
.Sh SEE ALSO
.Xr pam 3 ,
.Xr pam.conf 5
diff --git a/lib/libpam/pam.d/Makefile b/lib/libpam/pam.d/Makefile
index 5dccf590ee4e..a58c37b6c223 100644
--- a/lib/libpam/pam.d/Makefile
+++ b/lib/libpam/pam.d/Makefile
@@ -22,18 +22,15 @@ CRONPACKAGE= cron
.if ${MK_AT} != "no"
CONFGROUPS+= AT
-AT+= atrun
+AT+= atrun
ATPACKAGE+= at
.endif
.if ${MK_FTP} != "no"
CONFGROUPS+= FTP
-FTP+= ftpd
-FTPPACKAGE= ftp
-
-LINKMODE= ${CONFMODE}
-afterinstallconfig:
- ${INSTALL_LINK} ${TAG_ARGS} ${DESTDIR}${CONFDIR}/ftpd ${DESTDIR}${CONFDIR}/ftp
+FTP+= ftp ftpd
+# Do not put these in the ftp package, since ports also use them.
+FTPPACKAGE= runtime
.endif
.include <bsd.prog.mk>
diff --git a/lib/libpam/pam.d/ftp b/lib/libpam/pam.d/ftp
new file mode 100644
index 000000000000..1c255441dca6
--- /dev/null
+++ b/lib/libpam/pam.d/ftp
@@ -0,0 +1,13 @@
+#
+# PAM configuration for the "ftp" service. This is not used by the FreeBSD
+# ftpd(8), but is provided for compatibility with FTP servers from ports.
+#
+
+# auth
+auth include ftpd
+
+# account
+account include ftpd
+
+# session
+session include ftpd
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index e1cae22e2f3e..e4123fe02211 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -396,7 +396,7 @@ SNL_DECLARE_PARSER(getstatus_parser, struct genlmsghdr, snl_f_p_empty, ap_getsta
#undef _OUT
struct pfctl_status *
-pfctl_get_status_h(struct pfctl_handle *h __unused)
+pfctl_get_status_h(struct pfctl_handle *h)
{
struct pfctl_status *status;
struct snl_errmsg_data e = {};
@@ -1209,6 +1209,19 @@ snl_add_msg_attr_uid(struct snl_writer *nw, uint32_t type, const struct pf_rule_
}
static void
+snl_add_msg_attr_threshold(struct snl_writer *nw, uint32_t type, const struct pfctl_threshold *th)
+{
+ int off;
+
+ off = snl_add_msg_attr_nested(nw, type);
+
+ snl_add_msg_attr_u32(nw, PF_TH_LIMIT, th->limit);
+ snl_add_msg_attr_u32(nw, PF_TH_SECONDS, th->seconds);
+
+ snl_end_attr_nested(nw, off);
+}
+
+static void
snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfctl_rule *r)
{
int off;
@@ -1228,6 +1241,7 @@ snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfct
snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_RDR, &r->rdr);
snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_NAT, &r->nat);
snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_RT, &r->route);
+ snl_add_msg_attr_threshold(nw, PF_RT_PKTRATE, &r->pktrate);
snl_add_msg_attr_u32(nw, PF_RT_OS_FINGERPRINT, r->os_fingerprint);
snl_add_msg_attr_u32(nw, PF_RT_RTABLEID, r->rtableid);
snl_add_msg_attr_timeouts(nw, PF_RT_TIMEOUT, r->timeout);
@@ -1237,6 +1251,7 @@ snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfct
snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN, r->max_src_conn);
snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, r->max_src_conn_rate.limit);
snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, r->max_src_conn_rate.seconds);
+ snl_add_msg_attr_u16(nw, PF_RT_MAX_PKT_SIZE, r->max_pkt_size);
snl_add_msg_attr_u16(nw, PF_RT_DNPIPE, r->dnpipe);
snl_add_msg_attr_u16(nw, PF_RT_DNRPIPE, r->dnrpipe);
@@ -1581,6 +1596,15 @@ static const struct snl_attr_parser ap_rule_uid[] = {
SNL_DECLARE_ATTR_PARSER(rule_uid_parser, ap_rule_uid);
#undef _OUT
+#define _OUT(_field) offsetof(struct pfctl_threshold, _field)
+static const struct snl_attr_parser ap_pfctl_threshold[] = {
+ { .type = PF_TH_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
+ { .type = PF_TH_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 },
+ { .type = PF_TH_COUNT, .off = _OUT(count), .cb = snl_attr_get_uint32 },
+};
+SNL_DECLARE_ATTR_PARSER(pfctl_threshold_parser, ap_pfctl_threshold);
+#undef _OUT
+
struct pfctl_nl_get_rule {
struct pfctl_rule r;
char anchor_call[MAXPATHLEN];
@@ -1668,6 +1692,8 @@ static struct snl_attr_parser ap_getrule[] = {
{ .type = PF_RT_SRC_NODES_LIMIT, .off = _OUT(r.src_nodes_type[PF_SN_LIMIT]), .cb = snl_attr_get_uint64 },
{ .type = PF_RT_SRC_NODES_NAT, .off = _OUT(r.src_nodes_type[PF_SN_NAT]), .cb = snl_attr_get_uint64 },
{ .type = PF_RT_SRC_NODES_ROUTE, .off = _OUT(r.src_nodes_type[PF_SN_ROUTE]), .cb = snl_attr_get_uint64 },
+ { .type = PF_RT_PKTRATE, .off = _OUT(r.pktrate), .arg = &pfctl_threshold_parser, .cb = snl_attr_get_nested },
+ { .type = PF_RT_MAX_PKT_SIZE, .off =_OUT(r.max_pkt_size), .cb = snl_attr_get_uint16 },
};
#undef _OUT
SNL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, snl_f_p_empty, ap_getrule);
@@ -2271,6 +2297,9 @@ pfctl_set_syncookies(int dev, const struct pfctl_syncookies *s)
if (ret != 0)
return (ret);
+ if (state_limit == 0)
+ state_limit = INT_MAX;
+
lim = state_limit;
hi = lim * s->highwater / 100;
lo = lim * s->lowwater / 100;
@@ -2311,6 +2340,9 @@ pfctl_get_syncookies(int dev, struct pfctl_syncookies *s)
if (ret != 0)
return (ret);
+ if (state_limit == 0)
+ state_limit = INT_MAX;
+
bzero(s, sizeof(*s));
nvl = nvlist_create(0);
@@ -2995,16 +3027,6 @@ pfctl_get_ruleset(struct pfctl_handle *h, const char *path, uint32_t nr, struct
return (e.error);
}
-#define _OUT(_field) offsetof(struct pfctl_threshold, _field)
-static const struct snl_attr_parser ap_pfctl_threshold[] = {
- { .type = PF_TH_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
- { .type = PF_TH_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 },
- { .type = PF_TH_COUNT, .off = _OUT(count), .cb = snl_attr_get_uint32 },
- { .type = PF_TH_LAST, .off = _OUT(last), .cb = snl_attr_get_uint32 },
-};
-SNL_DECLARE_ATTR_PARSER(pfctl_threshold_parser, ap_pfctl_threshold);
-#undef _OUT
-
#define _OUT(_field) offsetof(struct pfctl_src_node, _field)
static struct snl_attr_parser ap_srcnode[] = {
{ .type = PF_SN_ADDR, .off = _OUT(addr), .cb = snl_attr_get_in6_addr },
@@ -3054,6 +3076,7 @@ pfctl_get_srcnodes(struct pfctl_handle *h, pfctl_get_srcnode_fn fn, void *arg)
return (ENXIO);
while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ bzero(&sn, sizeof(sn));
if (!snl_parse_nlmsg(&h->ss, hdr, &srcnode_parser, &sn))
continue;
@@ -3279,3 +3302,90 @@ pfctl_get_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
return (e.error);
}
+static struct snl_attr_parser ap_tstats_clr[] = {
+ { .type = PF_TS_NZERO, .off = 0, .cb = snl_attr_get_uint64 },
+};
+SNL_DECLARE_PARSER(tstats_clr_parser, struct genlmsghdr, snl_f_p_empty, ap_tstats_clr);
+
+int
+pfctl_clear_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
+ int *nzero, int flags)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint64_t zero;
+ uint32_t seq_id;
+ int family_id;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_CLR_TSTATS);
+
+ snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
+ snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
+ snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
+ snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+
+ seq_id = hdr->nlmsg_seq;
+
+ if (!snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ if (!snl_parse_nlmsg(&h->ss, hdr, &tstats_clr_parser, &zero))
+ continue;
+ if (nzero)
+ *nzero = (uint32_t)zero;
+ }
+
+ return (e.error);
+}
+
+int
+pfctl_clear_addrs(struct pfctl_handle *h, const struct pfr_table *filter,
+ int *ndel, int flags)
+{
+ struct snl_writer nw;
+ struct snl_errmsg_data e = {};
+ struct nlmsghdr *hdr;
+ uint64_t del;
+ uint32_t seq_id;
+ int family_id;
+
+ family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
+ if (family_id == 0)
+ return (ENOTSUP);
+
+ snl_init_writer(&h->ss, &nw);
+ hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_CLR_ADDRS);
+
+ snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
+ snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
+ snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
+ snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
+
+ if ((hdr = snl_finalize_msg(&nw)) == NULL)
+ return (ENXIO);
+
+ seq_id = hdr->nlmsg_seq;
+
+ if (!snl_send_message(&h->ss, hdr))
+ return (ENXIO);
+
+ while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
+ if (!snl_parse_nlmsg(&h->ss, hdr, &tstats_clr_parser, &del))
+ continue;
+ if (ndel)
+ *ndel = (uint32_t)del;
+ }
+
+ return (e.error);
+}
+
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index c1c1da66746b..98a80758ca74 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -159,6 +159,13 @@ struct pfctl_rules_info {
uint32_t ticket;
};
+struct pfctl_threshold {
+ uint32_t limit;
+ uint32_t seconds;
+ uint32_t count;
+ uint32_t last;
+};
+
struct pfctl_rule {
struct pf_rule_addr src;
struct pf_rule_addr dst;
@@ -181,6 +188,7 @@ struct pfctl_rule {
struct pfctl_pool rdr;
};
struct pfctl_pool route;
+ struct pfctl_threshold pktrate;
uint64_t evaluations;
uint64_t packets[2];
@@ -203,6 +211,7 @@ struct pfctl_rule {
uint32_t limit;
uint32_t seconds;
} max_src_conn_rate;
+ uint16_t max_pkt_size;
uint32_t qid;
uint32_t pqid;
uint16_t dnpipe;
@@ -396,13 +405,6 @@ struct pfctl_syncookies {
uint32_t halfopen_states;
};
-struct pfctl_threshold {
- uint32_t limit;
- uint32_t seconds;
- uint32_t count;
- uint32_t last;
-};
-
struct pfctl_src_node {
struct pf_addr addr;
struct pf_addr raddr;
@@ -554,5 +556,9 @@ int pfctl_del_table(struct pfctl_handle *h, struct pfr_table *table,
typedef int (*pfctl_get_tstats_fn)(const struct pfr_tstats *t, void *arg);
int pfctl_get_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
pfctl_get_tstats_fn fn, void *arg);
+int pfctl_clear_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
+ int *nzero, int flags);
+int pfctl_clear_addrs(struct pfctl_handle *h, const struct pfr_table *filter,
+ int *ndel, int flags);
#endif
diff --git a/lib/libpmcstat/libpmcstat_image.c b/lib/libpmcstat/libpmcstat_image.c
index 414ba133590b..69274dca31e8 100644
--- a/lib/libpmcstat/libpmcstat_image.c
+++ b/lib/libpmcstat/libpmcstat_image.c
@@ -193,6 +193,14 @@ pmcstat_image_link(struct pmcstat_process *pp, struct pmcstat_image *image,
assert(image->pi_type != PMCSTAT_IMAGE_UNKNOWN &&
image->pi_type != PMCSTAT_IMAGE_INDETERMINABLE);
+ /*
+ * It's possible to have images with nothing of value in .text
+ * legitimately. We shouldn't have any samples from this image, so
+ * don't bother with a map entry either.
+ */
+ if (image->pi_start == 0 && image->pi_end == 0)
+ return;
+
if ((pcmnew = malloc(sizeof(*pcmnew))) == NULL)
err(EX_OSERR, "ERROR: Cannot create a map entry");
diff --git a/lib/libproc/libproc.h b/lib/libproc/libproc.h
index 38a4faff94d5..a77bdbb35b59 100644
--- a/lib/libproc/libproc.h
+++ b/lib/libproc/libproc.h
@@ -105,8 +105,6 @@ typedef enum {
REG_RVAL2
} proc_reg_t;
-#define SIG2STR_MAX 8
-
typedef struct lwpstatus {
int pr_why;
#define PR_REQUESTED 1 /* not implemented */
diff --git a/lib/libproc/proc_util.c b/lib/libproc/proc_util.c
index bea50fb01098..a062b9a1f461 100644
--- a/lib/libproc/proc_util.c
+++ b/lib/libproc/proc_util.c
@@ -37,6 +37,7 @@
#include <err.h>
#include <errno.h>
#include <signal.h>
+#include <stdio.h>
#include <string.h>
#include <unistd.h>
@@ -180,8 +181,12 @@ proc_getwstat(struct proc_handle *phdl)
char *
proc_signame(int sig, char *name, size_t namesz)
{
+ char buf[SIG2STR_MAX];
- strlcpy(name, strsignal(sig), namesz);
+ if (sig2str(sig, buf) == 0)
+ (void)snprintf(name, namesz, "SIG%s", buf);
+ else
+ (void)snprintf(name, namesz, "SIG#%d", sig);
return (name);
}
diff --git a/lib/libprocstat/Makefile b/lib/libprocstat/Makefile
index 229adc6015f7..e20518910ba3 100644
--- a/lib/libprocstat/Makefile
+++ b/lib/libprocstat/Makefile
@@ -52,18 +52,23 @@ MLINKS+=libprocstat.3 procstat_close.3 \
libprocstat.3 procstat_open_kvm.3 \
libprocstat.3 procstat_open_sysctl.3
-# XXX This is a hack.
.if ${MK_CDDL} != "no"
CFLAGS+= -DLIBPROCSTAT_ZFS
SRCS+= zfs.c
-OBJS+= zfs/zfs_defs.o
-SUBDIR= zfs
-zfs/zfs_defs.o: .PHONY
- @cd ${.CURDIR}/zfs && ${MAKE} zfs_defs.o
-zfs/zfs_defs.pico: .PHONY
- @cd ${.CURDIR}/zfs && ${MAKE} zfs_defs.pico
-zfs/zfs_defs.pieo: .PHONY
- @cd ${.CURDIR}/zfs && ${MAKE} zfs_defs.pieo
+ZFSTOP= ${SRCTOP}/sys/contrib/openzfs
+CFLAGS.zfs.c+= -DIN_BASE
+CFLAGS.zfs.c+= -DHAVE_ISSETUGID
+CFLAGS.zfs.c+= -DZFS_DEBUG
+CFLAGS.zfs.c+= -I${ZFSTOP}/include
+CFLAGS.zfs.c+= -I${ZFSTOP}/lib/libspl/include
+CFLAGS.zfs.c+= -I${ZFSTOP}/lib/libspl/include/os/freebsd
+CFLAGS.zfs.c+= -I${ZFSTOP}/include/os/freebsd/zfs
+CFLAGS.zfs.c+= -I${ZFSTOP}/module/icp/include
+CFLAGS.zfs.c+= -I${SRCTOP}/sys
+CFLAGS.zfs.c+= -I${SRCTOP}/sys/modules/zfs
+CFLAGS.zfs.c+= -include ${ZFSTOP}/include/os/freebsd/spl/sys/ccompile.h
+CFLAGS.zfs.c+= -include ${SRCTOP}/sys/modules/zfs/zfs_config.h
+CFLAGS.zfs.c+= -Wno-cast-qual
.endif
.include <bsd.lib.mk>
diff --git a/lib/libprocstat/cd9660.c b/lib/libprocstat/cd9660.c
index de1140145527..ec37f49df0f6 100644
--- a/lib/libprocstat/cd9660.c
+++ b/lib/libprocstat/cd9660.c
@@ -52,9 +52,8 @@
#include <err.h>
-#define _KERNEL
+#define _WANT_ISO_MNT
#include <isofs/cd9660/iso.h>
-#undef _KERNEL
#include <isofs/cd9660/cd9660_node.h>
#include <kvm.h>
diff --git a/lib/libprocstat/libprocstat.c b/lib/libprocstat/libprocstat.c
index 29f464ef6414..eb8137f6c76f 100644
--- a/lib/libprocstat/libprocstat.c
+++ b/lib/libprocstat/libprocstat.c
@@ -625,6 +625,10 @@ procstat_getfiles_kvm(struct procstat *procstat, struct kinfo_proc *kp, int mmap
type = PS_FST_TYPE_EVENTFD;
data = file.f_data;
break;
+ case DTYPE_INOTIFY:
+ type = PS_FST_TYPE_INOTIFY;
+ data = file.f_data;
+ break;
default:
continue;
}
@@ -717,6 +721,7 @@ kinfo_type2fst(int kftype)
{ KF_TYPE_SOCKET, PS_FST_TYPE_SOCKET },
{ KF_TYPE_VNODE, PS_FST_TYPE_VNODE },
{ KF_TYPE_EVENTFD, PS_FST_TYPE_EVENTFD },
+ { KF_TYPE_INOTIFY, PS_FST_TYPE_INOTIFY },
{ KF_TYPE_UNKNOWN, PS_FST_TYPE_UNKNOWN }
};
#define NKFTYPES (sizeof(kftypes2fst) / sizeof(*kftypes2fst))
diff --git a/lib/libprocstat/libprocstat.h b/lib/libprocstat/libprocstat.h
index 0e9a4214414c..548747f90171 100644
--- a/lib/libprocstat/libprocstat.h
+++ b/lib/libprocstat/libprocstat.h
@@ -71,6 +71,7 @@
#define PS_FST_TYPE_PROCDESC 13
#define PS_FST_TYPE_DEV 14
#define PS_FST_TYPE_EVENTFD 15
+#define PS_FST_TYPE_INOTIFY 16
/*
* Special descriptor numbers.
diff --git a/lib/libprocstat/msdosfs.c b/lib/libprocstat/msdosfs.c
index bb1ad65e6b1a..01345bb8d334 100644
--- a/lib/libprocstat/msdosfs.c
+++ b/lib/libprocstat/msdosfs.c
@@ -44,17 +44,15 @@
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/vnode.h>
+#include <sys/mount.h>
#include <netinet/in.h>
-#define _KERNEL
-#include <sys/mount.h>
+#define _WANT_MSDOSFS_INTERNALS
#include <fs/msdosfs/bpb.h>
#include <fs/msdosfs/msdosfsmount.h>
-#undef _KERNEL
-
-#include <fs/msdosfs/denode.h>
#include <fs/msdosfs/direntry.h>
+#include <fs/msdosfs/denode.h>
#include <fs/msdosfs/fat.h>
#include <err.h>
@@ -62,13 +60,6 @@
#include <stdio.h>
#include <stdlib.h>
-/*
- * XXX -
- * VTODE is defined in denode.h only if _KERNEL is defined, but that leads to
- * header explosion
- */
-#define VTODE(vp) ((struct denode *)getvnodedata(vp))
-
#include "libprocstat.h"
#include "common_kvm.h"
diff --git a/lib/libprocstat/smbfs.c b/lib/libprocstat/smbfs.c
index 136cceacb471..cbd32cf8f597 100644
--- a/lib/libprocstat/smbfs.c
+++ b/lib/libprocstat/smbfs.c
@@ -32,9 +32,8 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/vnode.h>
-#define _KERNEL
+#define _WANT_MOUNT
#include <sys/mount.h>
-#undef _KERNEL
#include <netinet/in.h>
diff --git a/lib/libprocstat/udf.c b/lib/libprocstat/udf.c
index 9a110950f8b0..3298af6dec5f 100644
--- a/lib/libprocstat/udf.c
+++ b/lib/libprocstat/udf.c
@@ -32,9 +32,7 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/vnode.h>
-#define _KERNEL
#include <sys/mount.h>
-#undef _KERNEL
#include <netinet/in.h>
diff --git a/lib/libprocstat/zfs.c b/lib/libprocstat/zfs.c
index 665b1e5abe24..6dc23d7573fd 100644
--- a/lib/libprocstat/zfs.c
+++ b/lib/libprocstat/zfs.c
@@ -26,39 +26,36 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h> /* __RENAME */
-
-#include <stdbool.h>
-
#include <sys/param.h>
-#define _KERNEL
+#define _WANT_MOUNT
#include <sys/mount.h>
-#undef _KERNEL
#include <sys/queue.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/time.h>
#include <sys/vnode.h>
+#define _WANT_ZNODE
+#include <sys/zfs_context.h>
+#include <sys/zfs_znode.h>
#include <netinet/in.h>
#include <err.h>
#include <kvm.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#define ZFS
#include "libprocstat.h"
#include "common_kvm.h"
-#include "zfs_defs.h"
int
zfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
{
struct mount mount, *mountptr;
- void *znodeptr;
- char *dataptr;
+ znode_t *kznodeptr, *znode;
size_t len;
int size;
@@ -67,27 +64,30 @@ zfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
warnx("error getting sysctl");
return (1);
}
- dataptr = malloc(size);
- if (dataptr == NULL) {
+ znode = malloc(size);
+ if (znode == NULL) {
warnx("error allocating memory for znode storage");
return (1);
}
- if ((size_t)size < offsetof_z_id + sizeof(uint64_t) ||
- (size_t)size < offsetof_z_mode + sizeof(mode_t) ||
- (size_t)size < offsetof_z_size + sizeof(uint64_t)) {
+ if ((size_t)size != sizeof(znode_t))
+ warnx("znode_t size mismatch, data could be wrong");
+
+ if ((size_t)size < offsetof(znode_t, z_id) + sizeof(znode->z_id) ||
+ (size_t)size < offsetof(znode_t, z_mode) + sizeof(znode->z_mode) ||
+ (size_t)size < offsetof(znode_t, z_size) + sizeof(znode->z_size)) {
warnx("znode_t size is too small");
goto bad;
}
- if ((size_t)size != sizeof_znode_t)
- warnx("znode_t size mismatch, data could be wrong");
-
- /* Since we have problems including vnode.h, we'll use the wrappers. */
- znodeptr = getvnodedata(vp);
- if (!kvm_read_all(kd, (unsigned long)znodeptr, dataptr,
- (size_t)size)) {
- warnx("can't read znode at %p", (void *)znodeptr);
+ /*
+ * OpenZFS's libspl provides a dummy sys/vnode.h that shadows ours so
+ * struct vnode is an incomplete type. Use the wrapper until that is
+ * resolved.
+ */
+ kznodeptr = getvnodedata(vp);
+ if (!kvm_read_all(kd, (unsigned long)kznodeptr, znode, (size_t)size)) {
+ warnx("can't read znode at %p", (void *)kznodeptr);
goto bad;
}
@@ -103,12 +103,10 @@ zfs_filestat(kvm_t *kd, struct vnode *vp, struct vnstat *vn)
* under .zfs/.
*/
vn->vn_fsid = mount.mnt_stat.f_fsid.val[0];
- vn->vn_fileid = *(uint64_t *)(void *)(dataptr + offsetof_z_id);
- vn->vn_mode = *(mode_t *)(void *)(dataptr + offsetof_z_mode);
- vn->vn_size = *(uint64_t *)(void *)(dataptr + offsetof_z_size);
- free(dataptr);
+ vn->vn_fileid = znode->z_id;
+ vn->vn_mode = znode->z_mode;
+ vn->vn_size = znode->z_size;
return (0);
bad:
- free(dataptr);
return (1);
}
diff --git a/lib/libprocstat/zfs/Makefile b/lib/libprocstat/zfs/Makefile
deleted file mode 100644
index 5e1ebd44d1d3..000000000000
--- a/lib/libprocstat/zfs/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-.PATH: ${.CURDIR:H}
-
-SRCS= zfs_defs.c
-OBJS= zfs_defs.o
-WARNS?= 1
-
-FORTIFY_SOURCE= 0
-
-# We fake a kernel compilation environment in order to get the definition for
-# 'zpool_t'.
-CFLAGS+= -DIN_BASE -D__KERNEL__ -D_KERNEL -UKLD_TIED -DKLD_MODULE
-CFLAGS+= -DHAVE_ISSETUGID -D_SYS_VMEM_H_
-
-CFLAGS+= -fno-builtin -nostdlib
-
-CFLAGS+= -I${.CURDIR}
-CFLAGS+= -I${SRCTOP}/sys/contrib/openzfs/include
-CFLAGS+= -I${SRCTOP}/sys/contrib/openzfs/include/os/freebsd/spl
-CFLAGS+= -I${SRCTOP}/sys/contrib/openzfs/include/os/freebsd/zfs
-CFLAGS+= -I${SRCTOP}/sys/contrib/openzfs/include/os/freebsd
-CFLAGS+= -I${SRCTOP}/sys/contrib/ck/include
-CFLAGS+= -I${SRCTOP}/sys/contrib/openzfs/module/icp/include
-CFLAGS+= -I${SRCTOP}/sys -I. -I..
-
-CFLAGS+= -include ${SRCTOP}/sys/contrib/openzfs/include/os/freebsd/spl/sys/ccompile.h
-
-all: ${OBJS}
-CLEANFILES= ${OBJS}
-
-.include <bsd.lib.mk>
diff --git a/lib/libprocstat/zfs/Makefile.depend b/lib/libprocstat/zfs/Makefile.depend
deleted file mode 100644
index 993ab0638f4a..000000000000
--- a/lib/libprocstat/zfs/Makefile.depend
+++ /dev/null
@@ -1,11 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DIRDEPS = \
- include \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/lib/libprocstat/zfs_defs.c b/lib/libprocstat/zfs_defs.c
deleted file mode 100644
index 7f935c827118..000000000000
--- a/lib/libprocstat/zfs_defs.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2020 Andriy Gapon <avg@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.
- * 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 REGENTS 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 REGENTS 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.
- */
-
-#include <sys/types.h>
-/*
- * Prevent some headers from getting included and fake some types
- * in order to allow this file to compile without bringing in
- * too many kernel build dependencies.
- */
-#define _OPENSOLARIS_SYS_PATHNAME_H_
-#define _OPENSOLARIS_SYS_POLICY_H_
-#define _VNODE_PAGER_
-
-
-enum vtype { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VSOCK, VFIFO, VBAD,
- VMARKER };
-
-/*
- * Vnode attributes. A field value of VNOVAL represents a field whose value
- * is unavailable (getattr) or which is not to be changed (setattr).
- */
-struct vattr {
- enum vtype va_type; /* vnode type (for create) */
- u_short va_mode; /* files access mode and type */
- u_short va_padding0;
- uid_t va_uid; /* owner user id */
- gid_t va_gid; /* owner group id */
- nlink_t va_nlink; /* number of references to file */
- dev_t va_fsid; /* filesystem id */
- ino_t va_fileid; /* file id */
- u_quad_t va_size; /* file size in bytes */
- long va_blocksize; /* blocksize preferred for i/o */
- struct timespec va_atime; /* time of last access */
- struct timespec va_mtime; /* time of last modification */
- struct timespec va_ctime; /* time file changed */
- struct timespec va_birthtime; /* time file created */
- u_long va_gen; /* generation number of file */
- u_long va_flags; /* flags defined for file */
- dev_t va_rdev; /* device the special file represents */
- u_quad_t va_bytes; /* bytes of disk space held by file */
- u_quad_t va_filerev; /* file modification number */
- u_int va_vaflags; /* operations flags, see below */
- long va_spare; /* remain quad aligned */
-};
-
-#define _WANT_MOUNT
-#include <sys/zfs_context.h>
-#include <sys/zfs_znode.h>
-
-size_t sizeof_znode_t = sizeof(znode_t);
-size_t offsetof_z_id = offsetof(znode_t, z_id);
-size_t offsetof_z_size = offsetof(znode_t, z_size);
-size_t offsetof_z_mode = offsetof(znode_t, z_mode);
-
-/* Keep pcpu.h satisfied. */
-uintptr_t *__start_set_pcpu;
-uintptr_t *__stop_set_pcpu;
diff --git a/lib/libprocstat/zfs_defs.h b/lib/libprocstat/zfs_defs.h
deleted file mode 100644
index de17efba5630..000000000000
--- a/lib/libprocstat/zfs_defs.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2020 Andriy Gapon <avg@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.
- * 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef _LIBPROCSTAT_ZFS_DEFS_H
-#define _LIBPROCSTAT_ZFS_DEFS_H
-
-extern size_t sizeof_znode_t;
-extern size_t offsetof_z_id;
-extern size_t offsetof_z_size;
-extern size_t offsetof_z_mode;
-
-#endif /* _LIBPROCSTAT_ZFS_DEFS_H */
diff --git a/lib/libsecureboot/local.trust.mk b/lib/libsecureboot/local.trust.mk
index b009139a2f68..f2da3d3ac452 100644
--- a/lib/libsecureboot/local.trust.mk
+++ b/lib/libsecureboot/local.trust.mk
@@ -84,7 +84,7 @@ VE_SIGNATURE_LIST?= RSA
# you need to provide t*.pem or t*.asc files for each trust anchor
# below assumes they are named ta_${ext}.pem eg ta_esig.pem for ECDSA
.if empty(TRUST_ANCHORS)
-TRUST_ANCHORS!= cd ${.CURDIR} && 'ls' -1 *.pem t*.asc 2> /dev/null
+TRUST_ANCHORS!= cd ${.CURDIR} && 'ls' -1 *.pem t*.asc 2> /dev/null || echo
.endif
.if empty(TRUST_ANCHORS) && ${MK_LOADER_EFI_SECUREBOOT} != "yes"
.error Need TRUST_ANCHORS see ${.PARSEDIR}/README.rst
diff --git a/lib/libsys/Makefile.sys b/lib/libsys/Makefile.sys
index 491c765e9416..3eb4bf85153d 100644
--- a/lib/libsys/Makefile.sys
+++ b/lib/libsys/Makefile.sys
@@ -224,6 +224,7 @@ MAN+= abort2.2 \
getsockopt.2 \
gettimeofday.2 \
getuid.2 \
+ inotify.2 \
intro.2 \
ioctl.2 \
issetugid.2 \
@@ -448,6 +449,11 @@ MLINKS+=getrlimit.2 setrlimit.2
MLINKS+=getsockopt.2 setsockopt.2
MLINKS+=gettimeofday.2 settimeofday.2
MLINKS+=getuid.2 geteuid.2
+MLINKS+=inotify.2 inotify_init.2 \
+ inotify.2 inotify_init1.2 \
+ inotify.2 inotify_add_watch.2 \
+ inotify.2 inotify_add_watch_at.2 \
+ inotify.2 inotify_rm_watch.2
MLINKS+=intro.2 errno.2
MLINKS+=jail.2 jail_attach.2 \
jail.2 jail_get.2 \
diff --git a/lib/libsys/Symbol.sys.map b/lib/libsys/Symbol.sys.map
index 225eca2fc0de..45e0160100af 100644
--- a/lib/libsys/Symbol.sys.map
+++ b/lib/libsys/Symbol.sys.map
@@ -378,8 +378,11 @@ FBSD_1.7 {
};
FBSD_1.8 {
+ exterrctl;
fchroot;
getrlimitusage;
+ inotify_add_watch_at;
+ inotify_rm_watch;
kcmp;
setcred;
};
diff --git a/lib/libsys/_libsys.h b/lib/libsys/_libsys.h
index d06017edf6d9..1799906eb885 100644
--- a/lib/libsys/_libsys.h
+++ b/lib/libsys/_libsys.h
@@ -465,6 +465,9 @@ typedef int (__sys_kcmp_t)(pid_t, pid_t, int, uintptr_t, uintptr_t);
typedef int (__sys_getrlimitusage_t)(u_int, int, rlim_t *);
typedef int (__sys_fchroot_t)(int);
typedef int (__sys_setcred_t)(u_int, const struct setcred *, size_t);
+typedef int (__sys_exterrctl_t)(u_int, u_int, void *);
+typedef int (__sys_inotify_add_watch_at_t)(int, int, const char *, uint32_t);
+typedef int (__sys_inotify_rm_watch_t)(int, int);
void __sys_exit(int rval);
int __sys_fork(void);
@@ -866,6 +869,9 @@ int __sys_kcmp(pid_t pid1, pid_t pid2, int type, uintptr_t idx1, uintptr_t idx2)
int __sys_getrlimitusage(u_int which, int flags, rlim_t * res);
int __sys_fchroot(int fd);
int __sys_setcred(u_int flags, const struct setcred * wcred, size_t size);
+int __sys_exterrctl(u_int op, u_int flags, void * ptr);
+int __sys_inotify_add_watch_at(int fd, int dfd, const char * path, uint32_t mask);
+int __sys_inotify_rm_watch(int fd, int wd);
__END_DECLS
#endif /* __LIBSYS_H_ */
diff --git a/lib/libsys/_umtx_op.2 b/lib/libsys/_umtx_op.2
index 974850fb8425..c590f8e8e0c8 100644
--- a/lib/libsys/_umtx_op.2
+++ b/lib/libsys/_umtx_op.2
@@ -210,6 +210,8 @@ Valid clock identifiers are a subset of those for
.It
.Dv CLOCK_SECOND
.It
+.Dv CLOCK_TAI
+.It
.Dv CLOCK_UPTIME
.It
.Dv CLOCK_UPTIME_FAST
diff --git a/lib/libsys/accept.2 b/lib/libsys/accept.2
index 53926b3153d2..2da2af066a5b 100644
--- a/lib/libsys/accept.2
+++ b/lib/libsys/accept.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd October 9, 2014
+.Dd May 17, 2025
.Dt ACCEPT 2
.Os
.Sh NAME
@@ -85,6 +85,13 @@ and the close-on-exec flag on the new file descriptor can be set via the
flag in the
.Fa flags
argument.
+Similarly, the
+.Dv O_CLOFORK
+property can be set via the
+.Dv SOCK_CLOFORK
+flag in the
+.Fa flags
+argument.
.Pp
If no pending connections are
present on the queue, and the original socket
@@ -234,3 +241,8 @@ The
.Fn accept4
system call appeared in
.Fx 10.0 .
+.Pp
+The
+.Dv SOCK_CLOFORK
+flag appeared in
+.Fx 15.0 .
diff --git a/lib/libsys/aio_read.2 b/lib/libsys/aio_read.2
index 3a9601754c06..45779fff94c4 100644
--- a/lib/libsys/aio_read.2
+++ b/lib/libsys/aio_read.2
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 1, 2024
+.Dd March 27, 2025
.Dt AIO_READ 2
.Os
.Sh NAME
@@ -263,7 +263,9 @@ The
.Fn aio_read2
and
.Fn aio_readv
-system calls are FreeBSD extensions,
+system calls are
+.Fx
+extensions,
and should not be used in portable code.
.Sh HISTORY
The
diff --git a/lib/libsys/aio_waitcomplete.2 b/lib/libsys/aio_waitcomplete.2
index 1f20eca942ab..e7f993e0b796 100644
--- a/lib/libsys/aio_waitcomplete.2
+++ b/lib/libsys/aio_waitcomplete.2
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 21, 2016
+.Dd March 27, 2025
.Dt AIO_WAITCOMPLETE 2
.Os
.Sh NAME
@@ -91,8 +91,6 @@ The
.Fn aio_waitcomplete
system call fails if:
.Bl -tag -width Er
-.It Bq Er EINVAL
-The specified time limit is invalid.
.It Bq Er EAGAIN
The process has not yet called
.Fn aio_read
@@ -101,6 +99,8 @@ or
.It Bq Er EINTR
A signal was delivered before the timeout expired and before any
asynchronous I/O requests completed.
+.It Bq Er EINVAL
+The specified time limit is invalid.
.It Bq Er EWOULDBLOCK
.It Bq Er EINPROGRESS
The specified time limit expired before any asynchronous I/O requests
diff --git a/lib/libsys/aio_write.2 b/lib/libsys/aio_write.2
index f59406b8ab36..107e347ac335 100644
--- a/lib/libsys/aio_write.2
+++ b/lib/libsys/aio_write.2
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 1, 2024
+.Dd March 27, 2025
.Dt AIO_WRITE 2
.Os
.Sh NAME
@@ -265,7 +265,9 @@ The
.Fn aio_write2
and
.Fn aio_writev
-system calls are FreeBSD extensions,
+system calls are
+.Fx
+extensions,
and should not be used in portable code.
.Sh HISTORY
The
diff --git a/lib/libsys/amd64/Makefile.sys b/lib/libsys/amd64/Makefile.sys
index 09947d998480..8134bdc422a6 100644
--- a/lib/libsys/amd64/Makefile.sys
+++ b/lib/libsys/amd64/Makefile.sys
@@ -3,6 +3,7 @@ SRCS+= \
amd64_get_gsbase.c \
amd64_set_fsbase.c \
amd64_set_gsbase.c \
+ amd64_set_tlsbase.c \
rfork_thread.S
MDASM= vfork.S cerror.S getcontext.S
diff --git a/lib/libsys/amd64/Symbol.sys.map b/lib/libsys/amd64/Symbol.sys.map
index 5f463c85f872..11e0507b6613 100644
--- a/lib/libsys/amd64/Symbol.sys.map
+++ b/lib/libsys/amd64/Symbol.sys.map
@@ -13,6 +13,10 @@ FBSD_1.6 {
x86_pkru_unprotect_range;
};
+FBSD_1.8 {
+ amd64_set_tlsbase;
+};
+
FBSDprivate_1.0 {
_vfork;
};
diff --git a/lib/libc/aarch64/static_tls.h b/lib/libsys/amd64/amd64_set_tlsbase.c
index 2bb717eb75ce..a28441fbfc5d 100644
--- a/lib/libc/aarch64/static_tls.h
+++ b/lib/libsys/amd64/amd64_set_tlsbase.c
@@ -1,9 +1,10 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
- * Copyright (c) 2019 The FreeBSD Foundation
+ * Copyright (c) 2025 The FreeBSD Foundation
+ * All rights reserved.
*
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
+ * This software was developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
@@ -18,7 +19,7 @@
* 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
+ * 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)
@@ -28,17 +29,23 @@
* SUCH DAMAGE.
*/
-#ifndef _LIBC_AARCH64_STATIC_TLS_H
-#define _LIBC_AARCH64_STATIC_TLS_H
+#define _WANT_P_OSREL
+#include <sys/param.h>
+#include <machine/cpufunc.h>
+#include <machine/specialreg.h>
+#include <machine/sysarch.h>
+#include <x86/ifunc.h>
+#include "libc_private.h"
-static __inline uintptr_t
-_libc_get_static_tls_base(size_t offset)
+static int
+amd64_set_tlsbase_syscall(void *addr)
{
- uintptr_t tlsbase;
-
- __asm __volatile("mrs %x0, tpidr_el0" : "=r" (tlsbase));
- tlsbase += offset;
- return (tlsbase);
+ return (sysarch(AMD64_SET_TLSBASE, &addr));
}
-#endif
+DEFINE_UIFUNC(, int, amd64_set_tlsbase, (void *))
+{
+ if (__getosreldate() >= P_OSREL_TLSBASE)
+ return (amd64_set_tlsbase_syscall);
+ return (amd64_set_fsbase);
+}
diff --git a/lib/libsys/auxv.3 b/lib/libsys/auxv.3
index 10ec10e8755c..b3b741937ac7 100644
--- a/lib/libsys/auxv.3
+++ b/lib/libsys/auxv.3
@@ -22,7 +22,7 @@
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd September 16, 2022
+.Dd June 24, 2025
.Dt ELF_AUX_INFO 3
.Os
.Sh NAME
@@ -59,6 +59,12 @@ CPU / hardware feature flags
.It AT_HWCAP2
CPU / hardware feature flags
.Dv (sizeof(u_long)).
+.It AT_HWCAP3
+CPU / hardware feature flags
+.Dv (sizeof(u_long)).
+.It AT_HWCAP4
+CPU / hardware feature flags
+.Dv (sizeof(u_long)).
.It AT_NCPUS
Number of CPUs
.Dv (sizeof(int)).
diff --git a/lib/libsys/auxv.c b/lib/libsys/auxv.c
index 1a4fd352950e..80702c66ba22 100644
--- a/lib/libsys/auxv.c
+++ b/lib/libsys/auxv.c
@@ -69,10 +69,10 @@ __init_elf_aux_vector(void)
static int aux_once;
static int pagesize, osreldate, canary_len, ncpus, pagesizes_len, bsdflags;
-static int hwcap_present, hwcap2_present;
+static int hwcap_present, hwcap2_present, hwcap3_present, hwcap4_present;
static char *canary, *pagesizes, *execpath;
static void *ps_strings, *timekeep;
-static u_long hwcap, hwcap2;
+static u_long hwcap, hwcap2, hwcap3, hwcap4;
static void *fxrng_seed_version;
static u_long usrstackbase, usrstacklim;
@@ -123,6 +123,16 @@ init_aux(void)
hwcap2 = (u_long)(aux->a_un.a_val);
break;
+ case AT_HWCAP3:
+ hwcap3_present = 1;
+ hwcap3 = (u_long)(aux->a_un.a_val);
+ break;
+
+ case AT_HWCAP4:
+ hwcap4_present = 1;
+ hwcap4 = (u_long)(aux->a_un.a_val);
+ break;
+
case AT_PAGESIZES:
pagesizes = (char *)(aux->a_un.a_ptr);
break;
@@ -318,6 +328,20 @@ _elf_aux_info(int aux, void *buf, int buflen)
} else
res = ENOENT;
break;
+ case AT_HWCAP3:
+ if (hwcap3_present && buflen == sizeof(u_long)) {
+ *(u_long *)buf = hwcap3;
+ res = 0;
+ } else
+ res = ENOENT;
+ break;
+ case AT_HWCAP4:
+ if (hwcap4_present && buflen == sizeof(u_long)) {
+ *(u_long *)buf = hwcap4;
+ res = 0;
+ } else
+ res = ENOENT;
+ break;
case AT_PAGESIZES:
if (pagesizes != NULL && pagesizes_len >= buflen) {
memcpy(buf, pagesizes, buflen);
diff --git a/lib/libsys/clock_gettime.2 b/lib/libsys/clock_gettime.2
index fcdc5be498f2..89551d0f720b 100644
--- a/lib/libsys/clock_gettime.2
+++ b/lib/libsys/clock_gettime.2
@@ -27,7 +27,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 28, 2024
+.Dd August 10, 2024
.Dt CLOCK_GETTIME 2
.Os
.Sh NAME
@@ -99,11 +99,24 @@ query, using an in-kernel cached value of the current second.
Returns the execution time of the calling process.
.It Dv CLOCK_THREAD_CPUTIME_ID
Returns the execution time of the calling thread.
+.It Dv CLOCK_TAI
+Increments in SI seconds like a wall clock.
+It uses a 1970 epoch and implements the TAI timescale.
+Similar to
+.Dv CLOCK_REALTIME ,
+but without leap seconds.
+It will increase monotonically during a leap second.
+Will return
+.Er EINVAL
+if the current offset between TAI and UTC is not known,
+which may be the case early in boot before NTP or other time daemon has
+synchronized.
.El
.Pp
The clock IDs
.Dv CLOCK_BOOTTIME ,
.Dv CLOCK_REALTIME ,
+.Dv CLOCK_TAI ,
.Dv CLOCK_MONOTONIC ,
and
.Dv CLOCK_UPTIME
@@ -202,7 +215,8 @@ The clock IDs
.Dv CLOCK_MONOTONIC_PRECISE ,
.Dv CLOCK_REALTIME_FAST ,
.Dv CLOCK_REALTIME_PRECISE ,
-.Dv CLOCK_SECOND
+.Dv CLOCK_SECOND ,
+.Dv CLOCK_TAI ,
.Dv CLOCK_UPTIME ,
.Dv CLOCK_UPTIME_FAST ,
and
diff --git a/lib/libsys/closefrom.2 b/lib/libsys/closefrom.2
index aaa4c55607ac..1885a6fdeaa8 100644
--- a/lib/libsys/closefrom.2
+++ b/lib/libsys/closefrom.2
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 3, 2022
+.Dd May 17, 2025
.Dt CLOSEFROM 2
.Os
.Sh NAME
@@ -59,6 +59,8 @@ Supported
.Bl -tag -width ".Dv CLOSE_RANGE_CLOEXEC"
.It Dv CLOSE_RANGE_CLOEXEC
Set the close-on-exec flag on descriptors in the range instead of closing them.
+.It Dv CLOSE_RANGE_CLOFORK
+Set the close-on-fork flag on descriptors in the range instead of closing them.
.El
.Sh RETURN VALUES
Upon successful completion,
@@ -90,3 +92,8 @@ The
.Fn closefrom
function first appeared in
.Fx 8.0 .
+.Pp
+The
+.Dv CLOSE_RANGE_CLOFORK
+flag appeared in
+.Fx 15.0 .
diff --git a/lib/libsys/execve.2 b/lib/libsys/execve.2
index 5a35980e9555..dc85b9321e48 100644
--- a/lib/libsys/execve.2
+++ b/lib/libsys/execve.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 26, 2022
+.Dd July 02, 2025
.Dt EXECVE 2
.Os
.Sh NAME
@@ -127,7 +127,10 @@ flag is set (see
and
.Xr fcntl 2 ) .
Descriptors that remain open are unaffected by
-.Fn execve .
+.Fn execve ,
+except those with the close-on-fork flag
+.Dv FD_CLOFORK
+which is cleared from all file descriptors.
If any of the standard descriptors (0, 1, and/or 2) are closed at the
time
.Fn execve
diff --git a/lib/libsys/fcntl.2 b/lib/libsys/fcntl.2
index b5d4abe35aeb..d67c38cfbc6c 100644
--- a/lib/libsys/fcntl.2
+++ b/lib/libsys/fcntl.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 7, 2021
+.Dd June 24, 2025
.Dt FCNTL 2
.Os
.Sh NAME
@@ -80,6 +80,18 @@ associated with the new file descriptor is cleared, so the file descriptor is
to remain open across
.Xr execve 2
system calls.
+.It
+The fork-on-exec flag
+.Dv FD_CLOFORK
+associated with the new file descriptor is cleared, so the file descriptor is
+to remain open across
+.Xr fork 2
+system calls.
+.It
+The
+.Dv FD_RESOLVE_BENEATH
+flag, described below, will be set if it was set on the original
+descriptor.
.El
.It Dv F_DUPFD_CLOEXEC
Like
@@ -90,6 +102,15 @@ flag associated with the new file descriptor is set, so the file descriptor
is closed when
.Xr execve 2
system call executes.
+.It Dv F_DUPFD_CLOFORK
+Like
+.Dv F_DUPFD ,
+but the
+.Dv FD_CLOFORK
+flag associated with the new file descriptor is set, so the file descriptor
+is closed when
+.Xr fork 2
+system call executes.
.It Dv F_DUP2FD
It is functionally equivalent to
.Bd -literal -offset indent
@@ -112,30 +133,58 @@ Use
.Fn dup2
instead of
.Dv F_DUP2FD .
+.It Dv F_DUP3FD
+Used to implement the
+.Fn dup3
+call.
+Do not use it.
.It Dv F_GETFD
-Get the close-on-exec flag associated with the file descriptor
-.Fa fd
-as
-.Dv FD_CLOEXEC .
-If the returned value ANDed with
-.Dv FD_CLOEXEC
-is 0,
-the file will remain open across
-.Fn exec ,
-otherwise the file will be closed upon execution of
+Get the flags associated with the file descriptor
+.Fa fd .
+The following flags are defined:
+.Bl -tag -width FD_RESOLVE_BENEATH
+.It Dv FD_CLOEXEC
+The file will be closed upon execution of
.Fn exec
.Fa ( arg
is ignored).
+Otherwise, the file descriptor will remain open.
+.It Dv FD_CLOFORK
+The file will be closed upon execution of the
+.Fn fork
+family of system calls.
+.It Dv FD_RESOLVE_BENEATH
+All path name lookups relative to that file descriptor
+will behave as if the lookup had
+.Dv O_RESOLVE_BENEATH
+or
+.Dv AT_RESOLVE_BENEATH
+semantics.
+It is not permitted to call
+.Xr fchdir 2
+or
+.Xr fchroot 2
+on such a file descriptor.
+The
+.Dv FD_RESOLVE_BENEATH
+flag is sticky, meaning that it is preserved by
+.Xr dup 2
+and similar operations, and opening a directory with
+.Xr openat 2
+where the directory descriptor has the flag set causes the new directory
+descriptor to also have the flag set.
+.El
.It Dv F_SETFD
-Set the close-on-exec flag associated with
-.Fa fd
-to
-.Fa arg ,
-where
-.Fa arg
-is either 0 or
+Set flags associated with
+.Fa fd .
+The available flags are
.Dv FD_CLOEXEC ,
-as described above.
+.Dv FD_CLOFORK
+and
+.Dv FD_RESOLVE_BENEATH .
+The
+.Dv FD_RESOLVE_BENEATH
+flag cannot be cleared once set.
.It Dv F_GETFL
Get descriptor status flags, as described below
.Fa ( arg
@@ -528,7 +577,7 @@ A new file descriptor.
A file descriptor equal to
.Fa arg .
.It Dv F_GETFD
-Value of flag (only the low-order bit is defined).
+Value of flags.
.It Dv F_GETFL
Value of flags.
.It Dv F_GETOWN
@@ -762,8 +811,10 @@ for the reasons as stated in
.Sh STANDARDS
The
.Dv F_DUP2FD
-constant is non portable.
-It is provided for compatibility with AIX and Solaris.
+and
+.Dv F_DUP3FD
+constants are not portable.
+They are provided for compatibility with AIX and Solaris.
.Pp
Per
.St -susv4 ,
@@ -788,3 +839,10 @@ The
.Dv F_DUP2FD
constant first appeared in
.Fx 7.1 .
+.Pp
+The
+.Dv F_DUPFD_CLOFORK
+and
+.Dv F_DUP3FD
+flags appeared in
+.Fx 15.0 .
diff --git a/lib/libsys/fhopen.2 b/lib/libsys/fhopen.2
index 5bd1e9f8d90b..aba53f1dd907 100644
--- a/lib/libsys/fhopen.2
+++ b/lib/libsys/fhopen.2
@@ -31,7 +31,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd June 29, 1999
+.Dd April 6, 2025
.Dt FHOPEN 2
.Os
.Sh NAME
@@ -75,6 +75,10 @@ together the flags used for the
system call.
All said flags are valid except for
.Dv O_CREAT .
+If the file handle refers to a named attribute or named attribute
+directory, the
+.Dv O_NAMEDATTR
+flag must be specified.
.Pp
The
.Fn fhstat
@@ -116,6 +120,16 @@ Calling
with
.Dv O_CREAT
set.
+.It Bq Er ENOATTR
+The file handle does not refer to a named attribute or named attribute
+directory although the
+.Dv O_NAMEDATTR
+flag was specified.
+.It Bq Er ENOATTR
+The file handle refers to a named attribute or named attribute directory
+although the
+.Dv O_NAMEDATTR
+flag was not specified.
.It Bq Er ESTALE
The file handle
.Fa fhp
@@ -125,7 +139,8 @@ is no longer valid.
.Xr fstat 2 ,
.Xr fstatfs 2 ,
.Xr getfh 2 ,
-.Xr open 2
+.Xr open 2 ,
+.Xr named_attribute 9
.Sh HISTORY
The
.Fn fhopen ,
diff --git a/lib/libsys/fork.2 b/lib/libsys/fork.2
index 7d548a42890d..e59b208a9ff5 100644
--- a/lib/libsys/fork.2
+++ b/lib/libsys/fork.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 5, 2021
+.Dd May 17, 2024
.Dt FORK 2
.Os
.Sh NAME
@@ -68,6 +68,16 @@ by the parent.
This descriptor copying is also used by the shell to
establish standard input and output for newly created processes
as well as to set up pipes.
+Any file descriptors that were marked with the close-on-fork flag,
+.Dv FD_CLOFORK
+.Po see
+.Fn fcntl 2
+and
+.Dv O_CLOFORK
+in
+.Fn open 2
+.Pc ,
+will not be present in the child process, but remain open in the parent.
.It
The child process' resource utilizations
are set to 0; see
diff --git a/lib/libsys/getdirentries.2 b/lib/libsys/getdirentries.2
index 0e5840ce25cd..202ae133f548 100644
--- a/lib/libsys/getdirentries.2
+++ b/lib/libsys/getdirentries.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd September 5, 2023
+.Dd July 8, 2025
.Dt GETDIRENTRIES 2
.Os
.Sh NAME
@@ -178,9 +178,7 @@ or non-NULL
.Fa basep
point outside the allocated address space.
.It Bq Er EINVAL
-The file referenced by
-.Fa fd
-is not a directory, or
+The value of
.Fa nbytes
is too small for returning a directory entry or block of entries,
or the current position pointer is invalid.
@@ -192,6 +190,10 @@ error occurred while reading from or writing to the file system.
Corrupted data was detected while reading from the file system.
.It Bq Er ENOENT
Directory unlinked but still open.
+.It Bq Er ENOTDIR
+The file referenced by
+.Fa fd
+is not a directory.
.El
.Sh SEE ALSO
.Xr lseek 2 ,
diff --git a/lib/libsys/getsockopt.2 b/lib/libsys/getsockopt.2
index 619540b53fae..8839b61597a2 100644
--- a/lib/libsys/getsockopt.2
+++ b/lib/libsys/getsockopt.2
@@ -679,7 +679,7 @@ The
option originated in
.Ox 4.9
and first appeared in
-.Fx 15.0 .
+.Fx 14.3 .
The
.Fx
implementation aims to be source-compatible.
diff --git a/lib/libsys/inotify.2 b/lib/libsys/inotify.2
new file mode 100644
index 000000000000..f94509d6f59e
--- /dev/null
+++ b/lib/libsys/inotify.2
@@ -0,0 +1,379 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2025 Klara, Inc.
+.\"
+.Dd May 19, 2025
+.Dt INOTIFY 2
+.Os
+.Sh NAME
+.Nm inotify_init ,
+.Nm inotify_init1 ,
+.Nm inotify_add_watch ,
+.Nm inotify_add_watch_at ,
+.Nm inotify_rm_watch
+.Nd monitor file system events
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In sys/inotify.h
+.Ft int
+.Fo inotify_init
+.Fc
+.Ft int
+.Fo inotify_init1
+.Fa "int flags"
+.Fc
+.Ft int
+.Fo inotify_add_watch
+.Fa "int fd"
+.Fa "const char *pathname"
+.Fa "uint32_t mask"
+.Fc
+.Ft int
+.Fo inotify_add_watch_at
+.Fa "int fd"
+.Fa "int dfd"
+.Fa "const char *pathname"
+.Fa "uint32_t mask"
+.Fc
+.Ft int
+.Fo inotify_rm_watch
+.Fa "int fd"
+.Fa "uint32_t wd"
+.Fc
+.Bd -literal
+struct inotify_event {
+ int wd; /* Watch descriptor */
+ uint32_t mask; /* Event and flags */
+ uint32_t cookie; /* Unique ID which links rename events */
+ uint32_t len; /* Name field size, including nul bytes */
+ char name[0]; /* Filename (nul-terminated) */
+};
+.Ed
+.Sh DESCRIPTION
+The inotify system calls provide an interface to monitor file system events.
+They aim to be compatible with the Linux inotify interface.
+The provided functionality is similar to the
+.Dv EVFILT_VNODE
+filter of the
+.Xr kevent 2
+system call, but further allows monitoring of a directory without needing to
+open each object in that directory.
+This avoids races and reduces the number of file descriptors needed to monitor
+a large file hierarchy.
+.Pp
+inotify allows one or more file system objects, generally files or directories,
+to be watched for events, such as file open or close.
+Watched objects are associated with a file descriptor returned
+by
+.Fn inotify_init
+or
+.Fn inotify_init1 .
+When an event occurs, a record describing the event becomes available for
+reading from the inotify file descriptor.
+Each inotify descriptor thus refers to a queue of events waiting to be read.
+inotify descriptors are inherited across
+.Xr fork 2
+calls and may be passed to other processes via
+.Xr unix 4
+sockets.
+.Pp
+The
+.Fn inotify_init1
+system call accepts two flags.
+The
+.Dv IN_NONBLOCK
+flag causes the inotify descriptor to be opened in non-blocking mode, such that
+.Xr read 2
+calls will not block if no records are available to consume, and will instead
+return
+.Er EWOULDBLOCK .
+The
+.Dv IN_CLOEXEC
+flag causes the inotify descriptor to be closed automatically when
+.Xr execve 2
+is called.
+.Pp
+To watch a file or directory, the
+.Fn inotify_add_watch
+or
+.Fn inotify_add_watch_at
+system calls must be used.
+They take a path and a mask of events to watch for, and return a
+.Dq watch descriptor ,
+a non-negative integer which uniquely identifies the watched object within the
+inotify descriptor.
+.Pp
+The
+.Fn inotify_rm_watch
+system call removes a watch from an inotify descriptor.
+.Pp
+When watching a directory, objects within the directory are monitored for events
+as well as the directory itself.
+A record describing an inotify event consists of a
+.Dq struct inotify_event
+followed by the name of the object in the directory being watched.
+If the watched object itself generates an event, no name is present.
+Extra nul bytes may follow the file name in order to provide alignment for a
+subsequent record.
+.Pp
+The following events are defined:
+.Bl -tag -width IN_CLOSE_NOWRITE
+.It Dv IN_ACCESS
+A file's contents were accessed, e.g., by
+.Xr read 2
+.Xr copy_file_range 2 ,
+.Xr sendfile 2 ,
+or
+.Xr getdirentries 2 .
+.It Dv IN_ATTRIB
+A file's metadata was changed, e.g., by
+.Xr chmod 2
+or
+.Xr unlink 2 .
+.It Dv IN_CLOSE_WRITE
+A file that was previously opened for writing was closed.
+.It Dv IN_CLOSE_NOWRITE
+A file that was previously opened read-only was closed.
+.It Dv IN_CREATE
+A file within a watched directory was created, e.g., by
+.Xr open 2 ,
+.Xr mkdir 2 ,
+.Xr symlink 2 ,
+.Xr mknod 2 ,
+or
+.Xr bind 2 .
+.It Dv IN_DELETE
+A file or directory within a watched directory was removed.
+.It Dv IN_DELETE_SELF
+The watched file or directory itself was deleted.
+This event is generated only when the link count of the file drops
+to zero.
+.It Dv IN_MODIFY
+A file's contents were modified, e.g., by
+.Xr write 2
+or
+.Xr copy_file_range 2 .
+.It Dv IN_MOVE_SELF
+The watched file or directory itself was renamed.
+.It Dv IN_MOVED_FROM
+A file or directory was moved from a watched directory.
+.It Dv IN_MOVED_TO
+A file or directory was moved into a watched directory.
+A
+.Xr rename 2
+call thus may generate two events, one for the old name and one for the new
+name.
+These are linked together by the
+.Ar cookie
+field in the inotify record, which can be compared to link the two records
+to the same event.
+.It Dv IN_OPEN
+A file was opened.
+.El
+.Pp
+Some additional flags may be set in inotify event records:
+.Bl -tag -width IN_Q_OVERFLOW
+.It Dv IN_IGNORED
+When a watch is removed from a file, for example because it was created with the
+.Dv IN_ONESHOT
+flag, the file was deleted, or the watch was explicitly removed with
+.Xr inotify_rm_watch 2 ,
+an event with this mask is generated to indicate that the watch will not
+generate any more events.
+Once this event is generated, the watch is automatically removed, and in
+particular should not be removed manually with
+.Xr inotify_rm_watch 2 .
+.It Dv IN_ISDIR
+When the subject of an event is a directory, this flag is set in the
+.Ar mask
+.It Dv IN_Q_OVERFLOW
+One or more events were dropped, for example because of a kernel memory allocation
+failure or because the event queue size hit a limit.
+.It Dv IN_UNMOUNT
+The filesystem containing the watched object was unmounted.
+.El
+.Pp
+A number of flags may also be specified in the
+.Ar mask
+given to
+.Fn inotify_add_watch
+and
+.Fn inotify_add_watch_at :
+.Bl -tag -width IN_DONT_FOLLOW
+.It Dv IN_DONT_FOLLOW
+If
+.Ar pathname
+is a symbolic link, do not follow it.
+.It Dv IN_EXCL_UNLINK
+This currently has no effect, see the
+.Sx BUGS
+section.
+.In Dv IN_MASK_ADD
+When adding a watch to an object, and that object is already watched by the
+same inotify descriptor, by default the mask of the existing watch is
+overwritten.
+When
+.Dv IN_MASK_ADD
+is specified, the mask of the existing watch is instead logically ORed with
+the new mask.
+.In Dv IN_MASK_CREATE
+When
+.Fn inotify_add watch
+is used to add a watch to an object,
+.Dv IN_MASK_CREATE
+is specified, and that object is already watched by the same inotify descriptor,
+return an error instead of updating the existing watch.
+.In Dv IN_ONESHOT
+Monitor the object for a single event, after which the watch is automatically
+removed.
+As part of removal, a
+.Dv IN_IGNORED
+event is generated.
+.In Dv IN_ONLYDIR
+When creating a watch, fail with
+.Er ENOTDIR
+if the path does not refer to a directory.
+.El
+.Sh SYSCTL VARIABLES
+The following variables are available as both
+.Xr sysctl 8
+variables and
+.Xr loader 8
+tunables:
+.Bl -tag -width 15
+.It Va vfs.inotify.max_events
+The maximum number of inotify records that can be queued for a single
+inotify descriptor.
+Records in excess of this limit are discarded, and a single event with
+mask equal to
+.Dv IN_Q_OVERFLOW
+will be present in the queue.
+.It Va vfs.inotify.max_user_instances
+The maximum number of inotify descriptors that can be created by a single
+user.
+.It Va vfs.inotify.max_user_watches
+The maximum number of inotify watches per user.
+.El
+.Sh EXAMPLES
+See the example program in
+.Pa /usr/share/examples/inotify/inotify.c .
+.Sh ERRORS
+The
+.Fn inotify_init
+and
+.Fn inotify_init1
+functions will fail if:
+.Bl -tag -width Er
+.It Bq Er ENFILE
+The system limit on the total number of open files has been reached.
+.It Bq Er EMFILE
+A per-process limit on the number of open files has been reached.
+.It Bq Er EMFILE
+The system limit on the number of inotify descriptors has been reached.
+.It Bq Er EINVAL
+An unrecognized flag was passed to
+.Fn inotify_init1 .
+.El
+.Pp
+The
+.Fn inotify_add_watch
+and
+.Fn inotify_add_watch_at
+system calls will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Ar fd
+parameter is not a valid file descriptor.
+.It Bq Er EINVAL
+The
+.Ar fd
+parameter is not an inotify descriptor.
+.It Bq Er EINVAL
+The
+.Ar mask
+parameter does not specify an event, or
+the
+.Dv IN_MASK_CREATE
+and
+.Dv IN_MASK_ADD
+flags are both set, or an unrecognized flag was passed.
+.It Bq Er ENOTDIR
+The
+.Ar pathname
+parameter refers to a file that is not a directory, and the
+.Dv IN_ONLYDIR
+flag was specified.
+.It Bq Er ENOSPC
+The per-user limit on the total number of inotify watches has been reached.
+.It Bq Er ECAPMODE
+The process is in capability mode and
+.Fn inotify_add_watch
+was called, or
+.Fn inotify_add_watch_at
+was called with
+.Dv AT_FDCWD
+as the directory file descriptor
+.Ar dfd .
+.It Bq Er ENOTCAPABLE
+The process is in capability mode and
+.Ar pathname
+contains a
+.Dq ..
+component leading to a directory outside the directory hierarchy specified
+by
+.Ar dfd .
+.El
+.Pp
+The
+.Fn inotify_rm_watch
+system call will fail if:
+.Bl -tag -width Er
+.It Bq Er EBADF
+The
+.Ar fd
+parameter is not a valid file descriptor.
+.It Bq Er EINVAL
+The
+.Ar fd
+parameter is not an inotify descriptor.
+.It Bq Er EINVAL
+The
+.Ar wd
+parameter is not a valid watch descriptor.
+.El
+.Sh SEE ALSO
+.Xr kevent 2 ,
+.Xr capsicum 4
+.Sh STANDARDS
+The
+.Nm
+interface originates from Linux and is non-standard.
+This implementation aims to be compatible with that of Linux and is based
+on the documentation available at
+.Pa https://man7.org/linux/man-pages/man7/inotify.7.html .
+.Sh HISTORY
+The inotify system calls first appeared in
+.Fx 15.0 .
+.Sh BUGS
+If a file in a watched directory has multiple hard links,
+an access via any hard link for that file will generate an event, even
+if the accessed link belongs to an unwatched directory.
+This is not the case for the Linux implementation, where only accesses
+via the hard link in the watched directory will generate an event.
+.Pp
+If a watched directory contains multiple hard links of a file, an event
+on one of the hard links will generate an inotify record for each link
+in the directory.
+.Pp
+When a file is unlinked, no more events will be generated for that file,
+even if it continues to be accessed.
+By default, the Linux implementation will continue to generate events in
+this case.
+Thus, the
+.Fx
+implementation behaves as though
+.Dv IN_EXCL_UNLINK
+is always set.
diff --git a/lib/libsys/nanosleep.2 b/lib/libsys/nanosleep.2
index 8a4931e51413..290565dbd6e1 100644
--- a/lib/libsys/nanosleep.2
+++ b/lib/libsys/nanosleep.2
@@ -27,7 +27,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 3, 2022
+.Dd May 3, 2025
.Dt NANOSLEEP 2
.Os
.Sh NAME
@@ -87,14 +87,6 @@ If, at the time of the call, the time value specified by
is less than or equal to the time value of the specified clock, then
.Fn clock_nanosleep
returns immediately and the calling thread is not suspended.
-.Pp
-The suspension time may be longer than requested due to the
-scheduling of other activity by the system.
-It is also subject to the allowed time interval deviation
-specified by the
-.Va kern.timecounter.alloweddeviation
-.Xr sysctl 8
-variable.
An unmasked signal will terminate the sleep early, regardless of the
.Dv SA_RESTART
value on the interrupting signal.
@@ -124,6 +116,8 @@ CLOCK_REALTIME_PRECISE
.It
CLOCK_SECOND
.It
+CLOCK_TAI
+.It
CLOCK_UPTIME
.It
CLOCK_UPTIME_FAST
@@ -131,6 +125,32 @@ CLOCK_UPTIME_FAST
CLOCK_UPTIME_PRECISE
.El
.Pp
+The suspension time may be longer than requested due to the
+scheduling of other activity by the system.
+The clocks with the
+.Dv _FAST
+suffix and the
+.Dv CLOCK_SECOND
+are subject to the allowed time interval deviation specified by the
+.Va kern.timecounter.alloweddeviation
+.Xr sysctl 8
+variable.
+The clocks with the
+.Dv _PRECISE
+suffix are always as precise as possible.
+The
+.Dv CLOCK_MONOTONIC ,
+.Dv CLOCK_REALTIME
+and
+.Dv CLOCK_UPTIME
+are precise by default.
+Setting the
+.Va kern.timecounter.nanosleep_precise
+.Xr sysctl 8
+to a false value would make those clocks to behave like the
+.Dv _FAST
+clocks.
+.Pp
The
.Fn nanosleep
function behaves like
@@ -217,3 +237,19 @@ and was ported to
.Ox 2.1
and
.Fx 3.0 .
+The
+.Fn clock_nanosleep
+system call has been available since
+.Fx 11.1 .
+.Pp
+In
+.Fx 15.0
+the default behavior of
+.Fn clock_nanosleep
+with
+.Dv CLOCK_MONOTONIC ,
+.Dv CLOCK_REALTIME ,
+.Dv CLOCK_UPTIME
+clocks and
+.Fn nanosleep
+has been switched to use precise clock.
diff --git a/lib/libsys/open.2 b/lib/libsys/open.2
index d8540637b690..a0e905a8f375 100644
--- a/lib/libsys/open.2
+++ b/lib/libsys/open.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 28, 2025
+.Dd May 17, 2025
.Dt OPEN 2
.Os
.Sh NAME
@@ -195,6 +195,9 @@ error if file is not a directory
.It Dv O_CLOEXEC
automatically close file on
.Xr execve 2
+.It Dv O_CLOFORK
+automatically close file on any child process created with
+.Fn fork 2
.It Dv O_VERIFY
verify the contents of the file with
.Xr mac_veriexec 4
@@ -210,6 +213,8 @@ record only the target path in the opened descriptor
open file referenced by
.Fa fd
if path is empty
+.It Dv O_NAMEDATTR
+open a named attribute or named attribute directory
.El
.Pp
Exactly one of the flags
@@ -358,6 +363,27 @@ may be used to set
.Dv FD_CLOEXEC
flag for the newly returned file descriptor.
.Pp
+.Dv O_CLOFORK
+may be used to set
+.Dv FD_CLOFORK
+flag for the newly returned file descriptor.
+The file will be closed on any child process created with
+.Fn fork 2 ,
+.Fn vfork 2
+or
+.Fn rfork 2
+with the
+.Dv RFFDG
+flag, remaining open in the parent.
+Both the
+.Dv O_CLOEXEC
+and
+.Dv O_CLOFORK
+flags can be modified with the
+.Dv F_SETFD
+.Fn fcntl 2
+command.
+.Pp
.Dv O_VERIFY
may be used to indicate to the kernel that the contents of the file should
be verified before allowing the open to proceed.
@@ -464,6 +490,13 @@ flag for
.Xr fstatat 2
and related syscalls.
.Pp
+Conversely, a file descriptor
+.Dv fd
+referencing a filesystem file can be converted to the
+.Dv O_PATH
+type of descriptor by using the following call
+.Dl opath_fd = openat(fd, \[dq]\[dq], O_EMPTY_PATH | O_PATH);
+.Pp
If successful,
.Fn open
returns a non-negative integer, termed a file descriptor.
@@ -499,6 +532,42 @@ and the description of the
.Dv O_CLOEXEC
flag.
.Pp
+When the
+.Dv O_NAMEDATTR
+flag is specified for an
+.Fn openat
+where the
+.Fa fd
+argument is for a file object,
+a named attribute for the file object
+is opened and not the file object itself.
+If the
+.Dv O_CREAT
+flag has been specified as well, the named attribute will be
+created if it does not exist.
+When the
+.Dv O_NAMEDATTR
+flag is specified for a
+.Fn open ,
+a named attribute for the current working directory is opened and
+not the current working directory.
+The
+.Fa path
+argument for this
+.Fn openat
+or
+.Fn open
+must be a single component name with no embedded
+.Ql / .
+If the
+.Fa path
+argument is
+.Ql .\&
+then the named attribute directory for the file object is opened.
+(See
+.Xr named_attribute 7
+for more information.)
+.Pp
The system imposes a limit on the number of file descriptors
open simultaneously by one process.
The
@@ -730,6 +799,10 @@ contains a ".." component, the
.Dv vfs.lookup_cap_dotdot
.Xr sysctl 3
is set, and the process is in capability mode.
+.It Bq Er ENOATTR
+.Dv O_NAMEDATTR
+has been specified and the file object is not a named attribute
+directory or named attribute.
.El
.Sh SEE ALSO
.Xr chmod 2 ,
@@ -745,7 +818,8 @@ is set, and the process is in capability mode.
.Xr umask 2 ,
.Xr write 2 ,
.Xr fopen 3 ,
-.Xr capsicum 4
+.Xr capsicum 4 ,
+.Xr named_attribute 7
.Sh STANDARDS
These functions are specified by
.St -p1003.1-2008 .
@@ -794,6 +868,11 @@ function was introduced in
.Fx 8.0 .
.Dv O_DSYNC
appeared in 13.0.
+.Dv O_NAMEDATTR
+appeared in 15.0.
+.Dv O_CLOFORK
+appeared in
+.Fx 15.0 .
.Sh BUGS
The
.Fa mode
diff --git a/lib/libsys/pathconf.2 b/lib/libsys/pathconf.2
index 786753f2d02a..79ac8310000d 100644
--- a/lib/libsys/pathconf.2
+++ b/lib/libsys/pathconf.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 6, 2021
+.Dd July 5, 2025
.Dt PATHCONF 2
.Os
.Sh NAME
@@ -175,6 +175,18 @@ hole size but still reports holes.
Return 1 if a file system supports hole-punching (see
.Xr fspacectl 2 ) ,
otherwise 0.
+.It Li _PC_NAMEDATTR_ENABLED
+Return 1 if named attributes are enabled for the file system, otherwise 0.
+.It Li _PC_HAS_NAMEDATTR
+Return 1 if one or more named attributes exist for the file, otherwise 0.
+.It Li _PC_HAS_HIDDENSYSTEM
+Return 1 if both
+.Dv UF_HIDDEN
+and
+.Dv UF_SYSTEM
+flags can be set by
+.Xr chflags 2 ,
+otherwise 0.
.El
.Sh RETURN VALUES
If the call to
@@ -251,6 +263,7 @@ An I/O error occurred while reading from or writing to the file system.
Corrupted data was detected while reading from the file system.
.El
.Sh SEE ALSO
+.Xr chflags 2 ,
.Xr lseek 2 ,
.Xr sysctl 3
.Sh HISTORY
diff --git a/lib/libsys/pipe.2 b/lib/libsys/pipe.2
index 9531c9717395..37d6eba420de 100644
--- a/lib/libsys/pipe.2
+++ b/lib/libsys/pipe.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 1, 2017
+.Dd May 17, 2025
.Dt PIPE 2
.Os
.Sh NAME
@@ -64,6 +64,8 @@ list, defined in
.Bl -tag -width ".Dv O_NONBLOCK"
.It Dv O_CLOEXEC
Set the close-on-exec flag for the new file descriptors.
+.It Dv O_CLOFORK
+Set the close-on-fork flag for the new file descriptors.
.It Dv O_NONBLOCK
Set the non-blocking flag for the ends of the pipe.
.El
@@ -173,3 +175,8 @@ function became a wrapper around
.Fn pipe2
in
.Fx 11.0 .
+.Pp
+The
+.Dv O_CLOFORK
+flag appeared in
+.Fx 15.0 .
diff --git a/lib/libsys/procctl.2 b/lib/libsys/procctl.2
index 75804ba243f1..dfb7931de265 100644
--- a/lib/libsys/procctl.2
+++ b/lib/libsys/procctl.2
@@ -27,7 +27,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 14, 2024
+.Dd April 21, 2025
.Dt PROCCTL 2
.Os
.Sh NAME
@@ -133,17 +133,17 @@ dump.
The
.Va arg
parameter must point to an integer variable holding one of the following values:
-.Bl -tag -width PROC_LOGSIGEXIT_FORCE_DISABLE
-.It Dv PROC_LOGSIGEXIT_FORCE_ENABLE
+.Bl -tag -width PROC_LOGSIGEXIT_CTL_FORCE_DISABLE
+.It Dv PROC_LOGSIGEXIT_CTL_FORCE_ENABLE
Enables logging of exits due to signals that would normally cause a core dump.
Logging is done via
.Xr log 9
with a log level of
.Dv LOG_INFO .
-.It Dv PROC_LOGSIGEXIT_FORCE_DISABLE
+.It Dv PROC_LOGSIGEXIT_CTL_FORCE_DISABLE
Disables the logging of exits due to signals that would normally cause a core
dump.
-.It Dv PROC_LOGSIGEXIT_NOFORCE
+.It Dv PROC_LOGSIGEXIT_CTL_NOFORCE
The logging behavior is delegated to the
.Xr sysctl 3
MIB variable
@@ -155,10 +155,10 @@ The
.Va arg
parameter must point to an integer variable, where one of the following values
is written:
-.Bl -tag -width PROC_LOGSIGEXIT_FORCE_DISABLE
-.It Dv PROC_LOGSIGEXIT_FORCE_ENABLE
-.It Dv PROC_LOGSIGEXIT_FORCE_DISABLE
-.It Dv PROC_LOGSIGEXIT_NOFORCE
+.Bl -tag -width PROC_LOGSIGEXIT_CTL_FORCE_DISABLE
+.It Dv PROC_LOGSIGEXIT_CTL_FORCE_ENABLE
+.It Dv PROC_LOGSIGEXIT_CTL_FORCE_DISABLE
+.It Dv PROC_LOGSIGEXIT_CTL_NOFORCE
.El
.It Dv PROC_PROTMAX_CTL
Controls the maximum protection used for
diff --git a/lib/libsys/ptrace.2 b/lib/libsys/ptrace.2
index 9b789a0e45b3..7aa24a3f820b 100644
--- a/lib/libsys/ptrace.2
+++ b/lib/libsys/ptrace.2
@@ -1,7 +1,7 @@
.\" $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
.\"
.\" This file is in the public domain.
-.Dd August 18, 2023
+.Dd June 19, 2025
.Dt PTRACE 2
.Os
.Sh NAME
@@ -473,6 +473,16 @@ This request is like PT_CONTINUE, except that it does not allow
specifying an alternate place to continue execution, and after it
succeeds, the traced process is no longer traced and continues
execution normally.
+.Pp
+The parent of the traced process will be sent a
+.Dv SIGCHLD
+to indicate that the process has continued from a stopped state regardless of
+whether the process was in a stopped state prior to the corresponding
+.Dv PT_ATTACH
+request.
+A
+.Xr wait 2
+for the traced process would indicate that it had been continued.
.It Dv PT_GETREGS
This request reads the traced process's machine registers into the
.Do
diff --git a/lib/libsys/recv.2 b/lib/libsys/recv.2
index f3ee60b75663..b78cd70b8a1d 100644
--- a/lib/libsys/recv.2
+++ b/lib/libsys/recv.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 30, 2022
+.Dd May 17, 2025
.Dt RECV 2
.Os
.Sh NAME
@@ -164,6 +164,7 @@ one or more of the values:
.It Dv MSG_WAITALL Ta wait for full request or error
.It Dv MSG_DONTWAIT Ta do not block
.It Dv MSG_CMSG_CLOEXEC Ta set received fds close-on-exec
+.It Dv MSG_CMSG_CLOFORK Ta set received fds close-on-fork
.It Dv MSG_WAITFORONE Ta do not block after receiving the first message
(only for
.Fn recvmmsg
diff --git a/lib/libsys/sendfile.2 b/lib/libsys/sendfile.2
index 07a563d5ef82..6000e3e9828f 100644
--- a/lib/libsys/sendfile.2
+++ b/lib/libsys/sendfile.2
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 30, 2020
+.Dd June 24, 2025
.Dt SENDFILE 2
.Os
.Sh NAME
@@ -147,12 +147,6 @@ in a different context.
.It Dv SF_NOCACHE
The data sent to socket will not be cached by the virtual memory system,
and will be freed directly to the pool of free pages.
-.It Dv SF_SYNC
-.Nm
-sleeps until the network stack no longer references the VM pages
-of the file, making subsequent modifications to it safe.
-Please note that this is not a guarantee that the data has actually
-been sent.
.It Dv SF_USER_READAHEAD
.Nm
has some internal heuristics to do readahead when sending data.
diff --git a/lib/libsys/setcred.2 b/lib/libsys/setcred.2
index a1b819d24c52..86f61ddfdb30 100644
--- a/lib/libsys/setcred.2
+++ b/lib/libsys/setcred.2
@@ -248,7 +248,7 @@ does not.
The
.Fn setcred
system call appeared in
-.Fx 15.0 .
+.Fx 14.3 .
.Pp
Traditionally in UNIX, all credential changes beyond shuffles of effective, real
and saved IDs have been done by setuid binaries that successively call multiple
diff --git a/lib/libsys/socket.2 b/lib/libsys/socket.2
index a383cbcc4d80..b211611c6354 100644
--- a/lib/libsys/socket.2
+++ b/lib/libsys/socket.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 15, 2023
+.Dd May 17, 2025
.Dt SOCKET 2
.Os
.Sh NAME
@@ -121,6 +121,7 @@ argument:
.Pp
.Bd -literal -offset indent -compact
SOCK_CLOEXEC Set close-on-exec on the new descriptor,
+SOCK_CLOFORK Set close-on-fork on the new descriptor,
SOCK_NONBLOCK Set non-blocking mode on the new socket
.Ed
.Pp
@@ -331,7 +332,10 @@ argument of
.Fn socket .
The
.Dv SOCK_CLOEXEC
-flag is expected to conform to the next revision of the
+and
+.Dv SOCK_CLOFORK
+flags are expected to conform to
+.St -p1003.1-2024 .
.Tn POSIX
standard.
The
@@ -347,3 +351,8 @@ The
.Fn socket
system call appeared in
.Bx 4.2 .
+.Pp
+The
+.Dv SOCK_CLOFORK
+flag appeared in
+.Fx 15.0 .
diff --git a/lib/libsys/socketpair.2 b/lib/libsys/socketpair.2
index 5874a0791f4d..60dec74f9cc2 100644
--- a/lib/libsys/socketpair.2
+++ b/lib/libsys/socketpair.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 10, 2018
+.Dd May 17, 2025
.Dt SOCKETPAIR 2
.Os
.Sh NAME
@@ -56,7 +56,8 @@ and
The two sockets are indistinguishable.
.Pp
The
-.Dv SOCK_CLOEXEC
+.Dv SOCK_CLOEXEC ,
+.Dv SOCK_CLOFORK
and
.Dv SOCK_NONBLOCK
flags in the
diff --git a/lib/libsys/statfs.2 b/lib/libsys/statfs.2
index b411b3b6ff46..49e8b5120558 100644
--- a/lib/libsys/statfs.2
+++ b/lib/libsys/statfs.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 29, 2023
+.Dd April 7, 2025
.Dt STATFS 2
.Os
.Sh NAME
@@ -125,6 +125,9 @@ The file system resides locally.
Mandatory Access Control (MAC) support for individual objects
(see
.Xr mac 4 ) .
+.It Dv MNT_NAMEDATTR
+The file system supports named attributes as described in
+.Xr named_attribute 9 .
.It Dv MNT_NFS4ACLS
ACLs in NFSv4 variant are supported.
.It Dv MNT_NOATIME
@@ -260,7 +263,8 @@ each file or directory name or disk label
.Pc .
.Sh SEE ALSO
.Xr fhstatfs 2 ,
-.Xr getfsstat 2
+.Xr getfsstat 2 ,
+.Xr named_attribute 9
.Sh HISTORY
The
.Fn statfs
diff --git a/lib/libsys/symlink.2 b/lib/libsys/symlink.2
index 6892586f69f2..b5d878aaae50 100644
--- a/lib/libsys/symlink.2
+++ b/lib/libsys/symlink.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 30, 2020
+.Dd April 15, 2025
.Dt SYMLINK 2
.Os
.Sh NAME
@@ -92,6 +92,10 @@ or the entire length of either path name exceeded 1023 characters.
A component of the
.Fa name2
path prefix does not exist.
+.It Bq Er EOPNOTSUPP
+The file system containing the file named by
+.Fa name2
+does not support symbolic links.
.It Bq Er EACCES
A component of the
.Fa name2
diff --git a/lib/libsys/syscalls.map b/lib/libsys/syscalls.map
index 474df2cd8b1c..69fce2ea7c63 100644
--- a/lib/libsys/syscalls.map
+++ b/lib/libsys/syscalls.map
@@ -807,4 +807,10 @@ FBSDprivate_1.0 {
__sys_fchroot;
_setcred;
__sys_setcred;
+ _exterrctl;
+ __sys_exterrctl;
+ _inotify_add_watch_at;
+ __sys_inotify_add_watch_at;
+ _inotify_rm_watch;
+ __sys_inotify_rm_watch;
};
diff --git a/lib/libsys/thr_new.2 b/lib/libsys/thr_new.2
index c0bcc8bbc7c2..a04327723c34 100644
--- a/lib/libsys/thr_new.2
+++ b/lib/libsys/thr_new.2
@@ -133,6 +133,15 @@ The flag is not currently implemented.
.It Dv THR_SYSTEM_SCOPE
Create the system scope thread.
The flag is not currently implemented.
+.It Dv THR_C_RUNTIME
+Indicate that the new thread is created by the C language runtime.
+It has architecture-specific meaning.
+.Pp
+On amd64, the flag requests that the specified
+.Fa tls_base
+was loaded into the
+.Va %fsbase
+register before calling a signal handler.
.El
.It Va rtp
Real-time scheduling priority for the new thread.
diff --git a/lib/libsys/timer_create.2 b/lib/libsys/timer_create.2
index e8489b390845..8f6ff2e27c51 100644
--- a/lib/libsys/timer_create.2
+++ b/lib/libsys/timer_create.2
@@ -126,7 +126,8 @@ the value of the timer ID.
This implementation supports a
.Fa clock_id
of
-.Dv CLOCK_REALTIME
+.Dv CLOCK_REALTIME ,
+.Dv CLOCK_TAI ,
or
.Dv CLOCK_MONOTONIC .
.Pp
diff --git a/lib/libsys/wait.2 b/lib/libsys/wait.2
index 3c649f3dfa77..eeddf77aeac7 100644
--- a/lib/libsys/wait.2
+++ b/lib/libsys/wait.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 27, 2024
+.Dd June 19, 2025
.Dt WAIT 2
.Os
.Sh NAME
@@ -273,6 +273,10 @@ Report the status of selected processes that
have continued from a job control stop by receiving a
.Dv SIGCONT
signal.
+.Xr ptrace 2
+can also cause a process to be continued, when a
+.Dv PT_DETACH
+request is issued to detach the debugger.
.It Dv WNOHANG
Do not block when
there are no processes wishing to report status.
@@ -450,7 +454,7 @@ value:
.Bl -tag -width Ds
.It Fn WIFCONTINUED status
True if the process has not terminated, and
-has continued after a job control stop.
+has continued after a job control stop or detach of a debugger.
This macro can be true only if the wait call specified the
.Dv WCONTINUED
option.
diff --git a/lib/libsys/write.2 b/lib/libsys/write.2
index 5fea75150e3b..d2ff41ceead9 100644
--- a/lib/libsys/write.2
+++ b/lib/libsys/write.2
@@ -185,13 +185,6 @@ A signal interrupted the write before it could be completed.
.It Bq Er EAGAIN
The file was marked for non-blocking I/O,
and no data could be written immediately.
-.It Bq Er EROFS
-An attempt was made to write over a disk label area at the beginning
-of a slice.
-Use
-.Xr disklabel 8
-.Fl W
-to enable writing on the disk label area.
.It Bq Er EINVAL
The value
.Fa nbytes
@@ -202,6 +195,9 @@ is greater than
if the sysctl
.Va debug.iosize_max_clamp
is non-zero).
+.It Bq Er EINVAL
+The file descriptor refers to a raw device, and the write
+offset or size is not a multiple of the device's block size.
.It Bq Er EINTEGRITY
The backing store for
.Fa fd
diff --git a/lib/libsysdecode/Makefile b/lib/libsysdecode/Makefile
index b01877bb8bb8..ca020552a6e9 100644
--- a/lib/libsysdecode/Makefile
+++ b/lib/libsysdecode/Makefile
@@ -84,6 +84,7 @@ MLINKS+=sysdecode_mask.3 sysdecode_accessmode.3 \
sysdecode_mask.3 sysdecode_fileflags.3 \
sysdecode_mask.3 sysdecode_filemode.3 \
sysdecode_mask.3 sysdecode_flock_operation.3 \
+ sysdecode_mask.3 sysdecode_inotifyflags.3 \
sysdecode_mask.3 sysdecode_mlockall_flags.3 \
sysdecode_mask.3 sysdecode_mmap_flags.3 \
sysdecode_mask.3 sysdecode_mmap_prot.3 \
diff --git a/lib/libsysdecode/flags.c b/lib/libsysdecode/flags.c
index 32829d35dbe0..f8e26e6a9dae 100644
--- a/lib/libsysdecode/flags.c
+++ b/lib/libsysdecode/flags.c
@@ -23,7 +23,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#define L2CAP_SOCKET_CHECKED
#include <sys/types.h>
@@ -31,6 +30,7 @@
#include <sys/capsicum.h>
#include <sys/event.h>
#include <sys/extattr.h>
+#include <sys/inotify.h>
#include <sys/linker.h>
#include <sys/mman.h>
#include <sys/mount.h>
@@ -196,7 +196,7 @@ sysdecode_vmprot(FILE *fp, int type, int *rem)
}
static struct name_table sockflags[] = {
- X(SOCK_CLOEXEC) X(SOCK_NONBLOCK) XEND
+ X(SOCK_CLOEXEC) X(SOCK_CLOFORK) X(SOCK_NONBLOCK) XEND
};
bool
@@ -206,16 +206,17 @@ sysdecode_socket_type(FILE *fp, int type, int *rem)
uintmax_t val;
bool printed;
- str = lookup_value(socktype, type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK));
+ str = lookup_value(socktype,
+ type & ~(SOCK_CLOEXEC | SOCK_CLOFORK | SOCK_NONBLOCK));
if (str != NULL) {
fputs(str, fp);
*rem = 0;
printed = true;
} else {
- *rem = type & ~(SOCK_CLOEXEC | SOCK_NONBLOCK);
+ *rem = type & ~(SOCK_CLOEXEC | SOCK_CLOFORK | SOCK_NONBLOCK);
printed = false;
}
- val = type & (SOCK_CLOEXEC | SOCK_NONBLOCK);
+ val = type & (SOCK_CLOEXEC | SOCK_CLOFORK | SOCK_NONBLOCK);
print_mask_part(fp, sockflags, &val, &printed);
return (printed);
}
@@ -351,6 +352,13 @@ sysdecode_getrusage_who(int who)
return (lookup_value(rusage, who));
}
+bool
+sysdecode_inotifyflags(FILE *fp, int flag, int *rem)
+{
+
+ return (print_mask_int(fp, inotifyflags, flag, rem));
+}
+
static struct name_table kevent_user_ffctrl[] = {
X(NOTE_FFNOP) X(NOTE_FFAND) X(NOTE_FFOR) X(NOTE_FFCOPY)
XEND
@@ -556,7 +564,7 @@ sysdecode_nfssvc_flags(int flags)
}
static struct name_table pipe2flags[] = {
- X(O_CLOEXEC) X(O_NONBLOCK) XEND
+ X(O_CLOEXEC) X(O_CLOFORK) X(O_NONBLOCK) XEND
};
bool
@@ -866,7 +874,7 @@ sysdecode_fcntl_cmd(int cmd)
}
static struct name_table fcntl_fd_arg[] = {
- X(FD_CLOEXEC) X(0) XEND
+ X(FD_CLOEXEC) X(FD_CLOFORK) X(0) XEND
};
bool
diff --git a/lib/libsysdecode/mktables b/lib/libsysdecode/mktables
index 87ab24ddf1a5..6b4f79402660 100644
--- a/lib/libsysdecode/mktables
+++ b/lib/libsysdecode/mktables
@@ -98,6 +98,7 @@ gen_table "extattrns" "EXTATTR_NAMESPACE_[A-Z]+[[:space:]]+0x[0-9]+" "sys/
gen_table "fadvisebehav" "POSIX_FADV_[A-Z]+[[:space:]]+[0-9]+" "sys/fcntl.h"
gen_table "openflags" "O_[A-Z]+[[:space:]]+0x[0-9A-Fa-f]+" "sys/fcntl.h" "O_RDONLY|O_RDWR|O_WRONLY"
gen_table "flockops" "LOCK_[A-Z]+[[:space:]]+0x[0-9]+" "sys/fcntl.h"
+gen_table "inotifyflags" "IN_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/inotify.h" "IN_CLOEXEC|IN_NONBLOCK"
gen_table "kldsymcmd" "KLDSYM_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h"
gen_table "kldunloadfflags" "LINKER_UNLOAD_[A-Z]+[[:space:]]+[0-9]+" "sys/linker.h"
gen_table "lio_listiomodes" "LIO_(NO)?WAIT[[:space:]]+[0-9]+" "aio.h"
@@ -145,7 +146,7 @@ gen_table "sockopttcp" "TCP_[[:alnum:]_]+[[:space:]]+[0-9]+" "neti
gen_table "sockoptudp" "UDP_[[:alnum:]]+[[:space:]]+[0-9]+" "netinet/udp.h" "UDP_ENCAP_"
gen_table "sockoptudplite" "UDPLITE_[[:alnum:]_]+[[:space:]]+[0-9]+" "netinet/udplite.h"
gen_table "socktype" "SOCK_[A-Z]+[[:space:]]+[1-9]+[0-9]*" "sys/socket.h"
-gen_table "thrcreateflags" "THR_[A-Z]+[[:space:]]+0x[0-9]+" "sys/thr.h"
+gen_table "thrcreateflags" "THR_[A-Z_]+[[:space:]]+0x[0-9]+" "sys/thr.h"
gen_table "umtxop" "UMTX_OP_[[:alnum:]][[:alnum:]_]*[[:space:]]+[0-9]+" "sys/umtx.h"
gen_table "umtxopflags" "UMTX_OP__[[:alnum:]_]+[[:space:]]+[0-9]+" "sys/umtx.h"
gen_table "vmprot" "VM_PROT_[A-Z_]+[[:space:]]+\(\(vm_prot_t\)[[:space:]]+0x[0-9]+\)" "vm/vm.h"
diff --git a/lib/libsysdecode/sysdecode.h b/lib/libsysdecode/sysdecode.h
index 8dc0bbea6f0d..c95d7f71379b 100644
--- a/lib/libsysdecode/sysdecode.h
+++ b/lib/libsysdecode/sysdecode.h
@@ -61,6 +61,7 @@ const char *sysdecode_getfsstat_mode(int _mode);
const char *sysdecode_getrusage_who(int _who);
const char *sysdecode_idtype(int _idtype);
const char *sysdecode_ioctlname(unsigned long _val);
+bool sysdecode_inotifyflags(FILE *_fp, int _flags, int *_rem);
const char *sysdecode_ipproto(int _protocol);
void sysdecode_kevent_fflags(FILE *_fp, short _filter, int _fflags,
int _base);
diff --git a/lib/libsysdecode/sysdecode_fcntl_arg.3 b/lib/libsysdecode/sysdecode_fcntl_arg.3
index ee3a030a79e4..d5648ce0adc3 100644
--- a/lib/libsysdecode/sysdecode_fcntl_arg.3
+++ b/lib/libsysdecode/sysdecode_fcntl_arg.3
@@ -54,7 +54,8 @@ are determined by
.It Sy Command Ta Fa arg Sy Type Ta Sy Output Format
.It
.It Dv F_SETFD Ta Vt int Ta
-.Dq FD_CLOEXEC
+.Dq FD_CLOEXEC ,
+.Dq FD_CLOFORK
or the value of
.Fa arg
in the indicated
diff --git a/lib/libtelnet/Makefile b/lib/libtelnet/Makefile
index 69e63af4e272..6bc2f5a51de0 100644
--- a/lib/libtelnet/Makefile
+++ b/lib/libtelnet/Makefile
@@ -19,7 +19,8 @@ CFLAGS+= -DENCRYPTION -DAUTHENTICATION -DSRA
CFLAGS+= -DOPENSSL_API_COMPAT=0x10100000L
.endif
-.if ${MK_KERBEROS_SUPPORT} != "no"
+.if ${MK_KERBEROS_SUPPORT} != "no" && ${MK_MITKRB5} != "yes"
+# MIT KRB5 deprecated and removed 3DES. Therefore no telnet support.
SRCS+= kerberos5.c
CFLAGS+= -DKRB5 -DFORWARD -Dnet_write=telnet_net_write
.endif
diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile
index 19afa93f12be..c87be9475390 100644
--- a/lib/libthr/Makefile
+++ b/lib/libthr/Makefile
@@ -53,6 +53,7 @@ CFLAGS+=-D_PTHREAD_FORCED_UNWIND
.endif
LDFLAGS+=-Wl,-znodelete
+LDFLAGS+=-Wl,-zinitfirst
LDFLAGS+=-Wl,--auxiliary,libsys.so.7
VERSION_DEF=${SRCTOP}/lib/libc/Versions.def
diff --git a/lib/libthr/arch/aarch64/include/pthread_md.h b/lib/libthr/arch/aarch64/include/pthread_md.h
index 305abed55d3c..4316955f1d3d 100644
--- a/lib/libthr/arch/aarch64/include/pthread_md.h
+++ b/lib/libthr/arch/aarch64/include/pthread_md.h
@@ -54,4 +54,6 @@ _thr_resolve_machdep(void)
{
}
+#define __thr_setup_tsd(thread) _tcb_set((thread)->tcb)
+
#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/aarch64/include/pthread_tls.h b/lib/libthr/arch/aarch64/include/pthread_tls.h
deleted file mode 100644
index 4e02f8d4e03f..000000000000
--- a/lib/libthr/arch/aarch64/include/pthread_tls.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _ARCH_AARCH64_PTHREAD_TLS_H
-#define _ARCH_AARCH64_PTHREAD_TLS_H
-
-static __inline uintptr_t
-_get_static_tls_base(struct pthread *thr, size_t offset)
-{
- uintptr_t tlsbase;
-
- tlsbase = (uintptr_t)thr->tcb;
- tlsbase += offset;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libthr/arch/amd64/Makefile.inc b/lib/libthr/arch/amd64/Makefile.inc
index f8013ea914ed..fe80e1a73cc9 100644
--- a/lib/libthr/arch/amd64/Makefile.inc
+++ b/lib/libthr/arch/amd64/Makefile.inc
@@ -3,3 +3,5 @@
# the extra context switch cost. This can measurably impact
# performance when the application also does not use enough SSE.
CFLAGS+=${CFLAGS_NO_SIMD}
+
+SRCS+= thr_machdep.c
diff --git a/lib/libthr/arch/amd64/amd64/thr_machdep.c b/lib/libthr/arch/amd64/amd64/thr_machdep.c
new file mode 100644
index 000000000000..d23e1689779c
--- /dev/null
+++ b/lib/libthr/arch/amd64/amd64/thr_machdep.c
@@ -0,0 +1,48 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Konstantin Belousov
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ */
+
+#define _WANT_P_OSREL
+#include <sys/param.h>
+#include <errno.h>
+#include <machine/sysarch.h>
+
+#include "libc_private.h"
+#include "thr_private.h"
+
+void
+__thr_setup_tsd(struct pthread *thread)
+{
+ void *base;
+ int error;
+
+ if (__getosreldate() < P_OSREL_TLSBASE) {
+ amd64_set_tlsbase(thread->tcb);
+ return;
+ }
+
+ /*
+ * Make tlsbase handling more compatible with code, like Go
+ * runtime, which wants to manage fsbase itself, and which do
+ * not need assistance in setting fsbase for signal handlers.
+ *
+ * If the main thread did not used amd64_set_tlsbase(), which
+ * means that rtld/libc was not utilized, do not use
+ * amd64_set_tlsbase() either. Also do not mark new threads
+ * as using C runtime with the THR_C_RUNTIME flag.
+ */
+ error = sysarch(AMD64_GET_TLSBASE, &base);
+ if (error != 0 && errno == ESRCH) {
+ __thr_new_flags &= ~THR_C_RUNTIME;
+ amd64_set_fsbase(thread->tcb);
+ } else {
+ amd64_set_tlsbase(thread->tcb);
+ }
+}
diff --git a/lib/libthr/arch/amd64/include/pthread_md.h b/lib/libthr/arch/amd64/include/pthread_md.h
index 85517c1aee70..02b73d90f006 100644
--- a/lib/libthr/arch/amd64/include/pthread_md.h
+++ b/lib/libthr/arch/amd64/include/pthread_md.h
@@ -57,4 +57,6 @@ _thr_resolve_machdep(void)
{
}
+void __thr_setup_tsd(struct pthread *thread);
+
#endif
diff --git a/lib/libthr/arch/amd64/include/pthread_tls.h b/lib/libthr/arch/amd64/include/pthread_tls.h
deleted file mode 100644
index 2af0aeda4c85..000000000000
--- a/lib/libthr/arch/amd64/include/pthread_tls.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _ARCH_AMD64_PTHREAD_TLS_H
-#define _ARCH_AMD64_PTHREAD_TLS_H
-
-static __inline uintptr_t
-_get_static_tls_base(struct pthread *thr, size_t offset)
-{
- uintptr_t tlsbase;
-
- tlsbase = (uintptr_t)thr->tcb;
- tlsbase -= offset;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libthr/arch/arm/include/pthread_md.h b/lib/libthr/arch/arm/include/pthread_md.h
index d616868bdee4..b90568e249ee 100644
--- a/lib/libthr/arch/arm/include/pthread_md.h
+++ b/lib/libthr/arch/arm/include/pthread_md.h
@@ -48,4 +48,6 @@ _get_curthread(void)
return (NULL);
}
+#define __thr_setup_tsd(thread) _tcb_set((thread)->tcb)
+
#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/arm/include/pthread_tls.h b/lib/libthr/arch/arm/include/pthread_tls.h
deleted file mode 100644
index 27a07f69f474..000000000000
--- a/lib/libthr/arch/arm/include/pthread_tls.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _ARCH_ARM_PTHREAD_TLS_H
-#define _ARCH_ARM_PTHREAD_TLS_H
-
-static __inline uintptr_t
-_get_static_tls_base(struct pthread *thr, size_t offset)
-{
- uintptr_t tlsbase;
-
- tlsbase = (uintptr_t)thr->tcb;
- tlsbase += offset;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libthr/arch/i386/include/pthread_md.h b/lib/libthr/arch/i386/include/pthread_md.h
index 7e2c8d7330fc..43f84c3d0393 100644
--- a/lib/libthr/arch/i386/include/pthread_md.h
+++ b/lib/libthr/arch/i386/include/pthread_md.h
@@ -57,4 +57,6 @@ _thr_resolve_machdep(void)
{
}
+#define __thr_setup_tsd(thread) _tcb_set((thread)->tcb)
+
#endif
diff --git a/lib/libthr/arch/i386/include/pthread_tls.h b/lib/libthr/arch/i386/include/pthread_tls.h
deleted file mode 100644
index b2d0f2dbe845..000000000000
--- a/lib/libthr/arch/i386/include/pthread_tls.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _ARCH_I386_PTHREAD_TLS_H
-#define _ARCH_I386_PTHREAD_TLS_H
-
-static __inline uintptr_t
-_get_static_tls_base(struct pthread *thr, size_t offset)
-{
- uintptr_t tlsbase;
-
- tlsbase = (uintptr_t)thr->tcb;
- tlsbase -= offset;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libthr/arch/powerpc/include/pthread_md.h b/lib/libthr/arch/powerpc/include/pthread_md.h
index a5bc0265ed3a..291f2d9350d9 100644
--- a/lib/libthr/arch/powerpc/include/pthread_md.h
+++ b/lib/libthr/arch/powerpc/include/pthread_md.h
@@ -54,4 +54,6 @@ _thr_resolve_machdep(void)
{
}
+#define __thr_setup_tsd(thread) _tcb_set((thread)->tcb)
+
#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/powerpc/include/pthread_tls.h b/lib/libthr/arch/powerpc/include/pthread_tls.h
deleted file mode 100644
index e53164436018..000000000000
--- a/lib/libthr/arch/powerpc/include/pthread_tls.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _ARCH_POWERPC_PTHREAD_TLS_H
-#define _ARCH_POWERPC_PTHREAD_TLS_H
-
-static __inline uintptr_t
-_get_static_tls_base(struct pthread *thr, size_t offset)
-{
- uintptr_t tlsbase;
-
- tlsbase = (uintptr_t)thr->tcb;
- tlsbase += offset;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libthr/arch/riscv/include/pthread_md.h b/lib/libthr/arch/riscv/include/pthread_md.h
index baddfe3ecb22..01dcc9c02b8c 100644
--- a/lib/libthr/arch/riscv/include/pthread_md.h
+++ b/lib/libthr/arch/riscv/include/pthread_md.h
@@ -61,4 +61,6 @@ _thr_resolve_machdep(void)
{
}
+#define __thr_setup_tsd(thread) _tcb_set((thread)->tcb)
+
#endif /* _PTHREAD_MD_H_ */
diff --git a/lib/libthr/arch/riscv/include/pthread_tls.h b/lib/libthr/arch/riscv/include/pthread_tls.h
deleted file mode 100644
index 0af1ddd4cfaf..000000000000
--- a/lib/libthr/arch/riscv/include/pthread_tls.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2019 The FreeBSD Foundation
- *
- * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
- * under sponsorship from 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.
- * 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.
- */
-
-#ifndef _ARCH_RISCV_PTHREAD_TLS_H
-#define _ARCH_RISCV_PTHREAD_TLS_H
-
-static __inline uintptr_t
-_get_static_tls_base(struct pthread *thr, size_t offset)
-{
- uintptr_t tlsbase;
-
- tlsbase = (uintptr_t)thr->tcb;
- tlsbase += offset;
- return (tlsbase);
-}
-
-#endif
diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map
index f75ef4c9135e..3a5353a32dc3 100644
--- a/lib/libthr/pthread.map
+++ b/lib/libthr/pthread.map
@@ -136,7 +136,6 @@ FBSDprivate_1.0 {
__pthread_mutex_lock;
__pthread_mutex_timedlock;
__pthread_mutex_trylock;
- __pthread_distribute_static_tls;
_pthread_atfork;
_pthread_barrier_destroy;
_pthread_barrier_init;
@@ -339,5 +338,7 @@ FBSD_1.6 {
};
FBSD_1.8 {
+ pthread_signals_block_np;
+ pthread_signals_unblock_np;
pthread_sigqueue;
};
diff --git a/lib/libthr/tests/dlopen/dso/Makefile b/lib/libthr/tests/dlopen/dso/Makefile
index 0dac101f7186..74d8ada35ff1 100644
--- a/lib/libthr/tests/dlopen/dso/Makefile
+++ b/lib/libthr/tests/dlopen/dso/Makefile
@@ -1,6 +1,7 @@
TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libpthread/dlopen/dso
WARNS?= 3
+PACKAGE= tests
SHLIB= h_pthread_dlopen
SHLIB_MAJOR= 1
SHLIB_NAME= h_pthread_dlopen.so.${SHLIB_MAJOR}
diff --git a/lib/libthr/thread/thr_condattr.c b/lib/libthr/thread/thr_condattr.c
index 0dc3e52bab5e..dc56363fc084 100644
--- a/lib/libthr/thread/thr_condattr.c
+++ b/lib/libthr/thread/thr_condattr.c
@@ -94,6 +94,7 @@ _pthread_condattr_setclock(pthread_condattr_t *attr, clockid_t clock_id)
if (attr == NULL || *attr == NULL)
return (EINVAL);
if (clock_id != CLOCK_REALTIME &&
+ clock_id != CLOCK_TAI &&
clock_id != CLOCK_VIRTUAL &&
clock_id != CLOCK_PROF &&
clock_id != CLOCK_MONOTONIC) {
diff --git a/lib/libthr/thread/thr_create.c b/lib/libthr/thread/thr_create.c
index 2ae7cf0cd7b2..e56dbcfe30e1 100644
--- a/lib/libthr/thread/thr_create.c
+++ b/lib/libthr/thread/thr_create.c
@@ -27,10 +27,12 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
+#define _WANT_P_OSREL
#include "namespace.h"
#include <sys/types.h>
#include <sys/rtprio.h>
#include <sys/signalvar.h>
+#include <sys/exterrvar.h>
#include <errno.h>
#include <link.h>
#include <stdlib.h>
@@ -43,9 +45,13 @@
#include "libc_private.h"
#include "thr_private.h"
+int __getosreldate(void);
+
static int create_stack(struct pthread_attr *pattr);
static void thread_start(struct pthread *curthread);
+int __thr_new_flags = THR_C_RUNTIME;
+
__weak_reference(_pthread_create, pthread_create);
int
@@ -160,7 +166,7 @@ _pthread_create(pthread_t * __restrict thread,
param.tls_size = sizeof(struct tcb);
param.child_tid = &new_thread->tid;
param.parent_tid = &new_thread->tid;
- param.flags = 0;
+ param.flags = __thr_new_flags;
if (new_thread->attr.flags & PTHREAD_SCOPE_SYSTEM)
param.flags |= THR_SYSTEM_SCOPE;
if (new_thread->attr.sched_inherit == PTHREAD_INHERIT_SCHED)
@@ -285,6 +291,10 @@ thread_start(struct pthread *curthread)
curthread->attr.stacksize_attr;
#endif
+ curthread->uexterr.ver = UEXTERROR_VER;
+ if (__getosreldate() >= P_OSREL_EXTERRCTL)
+ exterrctl(EXTERRCTL_ENABLE, 0, &curthread->uexterr);
+
/* Run the current thread's start routine with argument: */
_pthread_exit(curthread->start_routine(curthread->arg));
diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c
index 8855491b91cb..64cf7d004070 100644
--- a/lib/libthr/thread/thr_init.c
+++ b/lib/libthr/thread/thr_init.c
@@ -33,6 +33,7 @@
* SUCH DAMAGE.
*/
+#define _WANT_P_OSREL
#include "namespace.h"
#include <sys/param.h>
#include <sys/auxv.h>
@@ -59,6 +60,7 @@
#include "libc_private.h"
#include "thr_private.h"
+int __getosreldate(void);
char *_usrstack;
struct pthread *_thr_initial;
int _libthr_debug;
@@ -352,7 +354,7 @@ _libpthread_init(struct pthread *curthread)
_thread_active_threads = 1;
/* Setup the thread specific data */
- _tcb_set(curthread->tcb);
+ __thr_setup_tsd(curthread);
if (first) {
_thr_initial = curthread;
@@ -433,6 +435,10 @@ init_main_thread(struct pthread *thread)
thread->unwind_stackend = _usrstack;
#endif
+ thread->uexterr.ver = UEXTERROR_VER;
+ if (__getosreldate() >= P_OSREL_EXTERRCTL)
+ exterrctl(EXTERRCTL_ENABLE, EXTERRCTLF_FORCE, &thread->uexterr);
+
/* Others cleared to zero by thr_alloc() */
}
diff --git a/lib/libthr/thread/thr_list.c b/lib/libthr/thread/thr_list.c
index bbc1d2899cb9..cbf16179f619 100644
--- a/lib/libthr/thread/thr_list.c
+++ b/lib/libthr/thread/thr_list.c
@@ -30,13 +30,14 @@
#include <sys/types.h>
#include <sys/queue.h>
+#include <machine/tls.h>
+
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "libc_private.h"
#include "thr_private.h"
-#include "static_tls.h"
/*#define DEBUG_THREAD_LIST */
#ifdef DEBUG_THREAD_LIST
@@ -150,11 +151,13 @@ _thr_alloc(struct pthread *curthread)
if (total_threads > MAX_THREADS)
return (NULL);
atomic_add_int(&total_threads, 1);
- thread = __thr_calloc(1, sizeof(struct pthread));
+ thread = __thr_aligned_alloc_offset(_Alignof(struct pthread),
+ sizeof(struct pthread), 0);
if (thread == NULL) {
atomic_add_int(&total_threads, -1);
return (NULL);
}
+ memset(thread, 0, sizeof(*thread));
if ((thread->sleepqueue = _sleepq_alloc()) == NULL ||
(thread->wake_addr = _thr_alloc_wake_addr()) == NULL) {
thr_destroy(curthread, thread);
@@ -360,35 +363,3 @@ _thr_find_thread(struct pthread *curthread, struct pthread *thread,
THREAD_LIST_UNLOCK(curthread);
return (ret);
}
-
-#include "pthread_tls.h"
-
-static void
-thr_distribute_static_tls(uintptr_t tlsbase, void *src, size_t len,
- size_t total_len)
-{
-
- memcpy((void *)tlsbase, src, len);
- memset((char *)tlsbase + len, 0, total_len - len);
-}
-
-void
-__pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len)
-{
- struct pthread *curthread, *thrd;
- uintptr_t tlsbase;
-
- if (!_thr_is_inited()) {
- tlsbase = _libc_get_static_tls_base(offset);
- thr_distribute_static_tls(tlsbase, src, len, total_len);
- return;
- }
- curthread = _get_curthread();
- THREAD_LIST_RDLOCK(curthread);
- TAILQ_FOREACH(thrd, &_thread_list, tle) {
- tlsbase = _get_static_tls_base(thrd, offset);
- thr_distribute_static_tls(tlsbase, src, len, total_len);
- }
- THREAD_LIST_UNLOCK(curthread);
-}
diff --git a/lib/libthr/thread/thr_malloc.c b/lib/libthr/thread/thr_malloc.c
index 9a81d6d1bd6b..48af9d1ea929 100644
--- a/lib/libthr/thread/thr_malloc.c
+++ b/lib/libthr/thread/thr_malloc.c
@@ -120,6 +120,19 @@ __thr_malloc(size_t nbytes)
}
void *
+__thr_aligned_alloc_offset(size_t align, size_t size, size_t offset)
+{
+ struct pthread *curthread;
+ void *res;
+
+ curthread = _get_curthread();
+ thr_malloc_lock(curthread);
+ res = __crt_aligned_alloc_offset(align, size, offset);
+ thr_malloc_unlock(curthread);
+ return (res);
+}
+
+void *
__thr_realloc(void *cp, size_t nbytes)
{
struct pthread *curthread;
diff --git a/lib/libthr/thread/thr_private.h b/lib/libthr/thread/thr_private.h
index 926e868293cd..d7b889930365 100644
--- a/lib/libthr/thread/thr_private.h
+++ b/lib/libthr/thread/thr_private.h
@@ -40,6 +40,7 @@
#include <sys/queue.h>
#include <sys/param.h>
#include <sys/cpuset.h>
+#include <sys/exterrvar.h>
#include <machine/atomic.h>
#include <errno.h>
#include <limits.h>
@@ -576,6 +577,8 @@ struct pthread {
/* pthread_set/get_name_np */
char *name;
+
+ struct uexterror uexterr;
};
#define THR_SHOULD_GC(thrd) \
@@ -776,6 +779,8 @@ extern struct pthread *_single_thread __hidden;
extern bool _thr_after_fork __hidden;
+extern int __thr_new_flags;
+
/*
* Function prototype definitions.
*/
@@ -981,8 +986,6 @@ void __pthread_cxa_finalize(struct dl_phdr_info *phdr_info);
void _thr_tsd_unload(struct dl_phdr_info *phdr_info) __hidden;
void _thr_sigact_unload(struct dl_phdr_info *phdr_info) __hidden;
void _thr_stack_fix_protection(struct pthread *thrd);
-void __pthread_distribute_static_tls(size_t offset, void *src, size_t len,
- size_t total_len);
int *__error_threaded(void) __hidden;
void __thr_interpose_libc(void) __hidden;
@@ -1014,6 +1017,7 @@ void __thr_pshared_destroy(void *key) __hidden;
void __thr_pshared_atfork_pre(void) __hidden;
void __thr_pshared_atfork_post(void) __hidden;
+void *__thr_aligned_alloc_offset(size_t align, size_t size, size_t offset);
void *__thr_calloc(size_t num, size_t size);
void __thr_free(void *cp);
void *__thr_malloc(size_t nbytes);
diff --git a/lib/libthr/thread/thr_rtld.c b/lib/libthr/thread/thr_rtld.c
index e5a7f86de288..3cfdfc548cf2 100644
--- a/lib/libthr/thread/thr_rtld.c
+++ b/lib/libthr/thread/thr_rtld.c
@@ -50,8 +50,11 @@ static int _thr_rtld_set_flag(int);
static void _thr_rtld_wlock_acquire(void *);
struct rtld_lock {
- struct urwlock lock;
- char _pad[CACHE_LINE_SIZE - sizeof(struct urwlock)];
+ struct urwlock lock;
+ struct pthread *wowner;
+ u_int rlocks;
+ char _pad[CACHE_LINE_SIZE - sizeof(struct urwlock) -
+ sizeof(struct pthread *) - sizeof(u_int)];
};
static struct rtld_lock lock_place[MAX_RTLD_LOCKS] __aligned(CACHE_LINE_SIZE);
@@ -116,9 +119,13 @@ _thr_rtld_rlock_acquire(void *lock)
SAVE_ERRNO();
l = (struct rtld_lock *)lock;
- THR_CRITICAL_ENTER(curthread);
- while (_thr_rwlock_rdlock(&l->lock, 0, NULL) != 0)
- ;
+ if (l->wowner == curthread) {
+ l->rlocks++;
+ } else {
+ THR_CRITICAL_ENTER(curthread);
+ while (_thr_rwlock_rdlock(&l->lock, 0, NULL) != 0)
+ ;
+ }
curthread->rdlock_count++;
RESTORE_ERRNO();
}
@@ -137,6 +144,7 @@ _thr_rtld_wlock_acquire(void *lock)
THR_CRITICAL_ENTER(curthread);
while (_thr_rwlock_wrlock(&l->lock, NULL) != 0)
;
+ l->wowner = curthread;
RESTORE_ERRNO();
}
@@ -164,6 +172,14 @@ _thr_rtld_lock_release(void *lock)
l->lock.rw_blocked_readers = 0;
l->lock.rw_blocked_writers = 0;
}
+ if ((state & URWLOCK_WRITE_OWNER) != 0) {
+ if (l->rlocks > 0) {
+ l->rlocks--;
+ return;
+ } else {
+ l->wowner = NULL;
+ }
+ }
if (_thr_rwlock_unlock(&l->lock) == 0) {
if ((state & URWLOCK_WRITE_OWNER) == 0)
curthread->rdlock_count--;
diff --git a/lib/libthr/thread/thr_sig.c b/lib/libthr/thread/thr_sig.c
index c5ee5aa8423b..2cd3de512d1c 100644
--- a/lib/libthr/thread/thr_sig.c
+++ b/lib/libthr/thread/thr_sig.c
@@ -37,6 +37,7 @@
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
+#include <pthread_np.h>
#include "un-namespace.h"
#include "libc_private.h"
@@ -163,6 +164,24 @@ _thr_signal_block_setup(struct pthread *curthread)
__sys_sigfastblock(SIGFASTBLOCK_SETPTR, &curthread->fsigblock);
}
+void
+pthread_signals_block_np(void)
+{
+ struct pthread *curthread;
+
+ curthread = _get_curthread();
+ _thr_signal_block(curthread);
+}
+
+void
+pthread_signals_unblock_np(void)
+{
+ struct pthread *curthread;
+
+ curthread = _get_curthread();
+ _thr_signal_unblock(curthread);
+}
+
int
_thr_send_sig(struct pthread *thread, int sig)
{
diff --git a/lib/libthr/thread/thr_switch_np.c b/lib/libthr/thread/thr_switch_np.c
index 80cd34c15650..59a9a4c7e1a3 100644
--- a/lib/libthr/thread/thr_switch_np.c
+++ b/lib/libthr/thread/thr_switch_np.c
@@ -40,10 +40,13 @@
#include "thr_private.h"
-
__weak_reference(_pthread_switch_add_np, pthread_switch_add_np);
__weak_reference(_pthread_switch_delete_np, pthread_switch_delete_np);
+typedef void (*pthread_switch_routine_t)(pthread_t, pthread_t);
+int _pthread_switch_add_np(pthread_switch_routine_t routine);
+int _pthread_switch_delete_np(pthread_switch_routine_t routine);
+
int
_pthread_switch_add_np(pthread_switch_routine_t routine __unused)
{
diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c
index 22f9c1f68ec2..188374a30070 100644
--- a/lib/libthr/thread/thr_syscalls.c
+++ b/lib/libthr/thread/thr_syscalls.c
@@ -66,9 +66,9 @@
*/
#include "namespace.h"
-#include <sys/types.h>
-#include <sys/mman.h>
#include <sys/param.h>
+#include <sys/exterrvar.h>
+#include <sys/mman.h>
#include <sys/select.h>
#include <sys/signalvar.h>
#include <sys/socket.h>
@@ -620,6 +620,15 @@ __thr_writev(int fd, const struct iovec *iov, int iovcnt)
return (ret);
}
+static int
+__thr_uexterr_gettext(char *buf, size_t bufsz)
+{
+ struct pthread *curthread;
+
+ curthread = _get_curthread();
+ return (__uexterr_format(&curthread->uexterr, buf, bufsz));
+}
+
void
__thr_interpose_libc(void)
{
@@ -675,6 +684,7 @@ __thr_interpose_libc(void)
SLOT(fdatasync);
SLOT(clock_nanosleep);
SLOT(pdfork);
+ SLOT(uexterr_gettext);
#undef SLOT
*(__libc_interposing_slot(
INTERPOS__pthread_mutex_init_calloc_cb)) =
diff --git a/lib/libufs/Makefile b/lib/libufs/Makefile
index 12c742e6b871..ab913f834bb3 100644
--- a/lib/libufs/Makefile
+++ b/lib/libufs/Makefile
@@ -1,4 +1,4 @@
-PACKAGE= ufs
+PACKAGE= libufs
LIB= ufs
SHLIBDIR?= /lib
SHLIB_MAJOR= 8
diff --git a/lib/libunbound/config.h b/lib/libunbound/config.h
index 17a6707c7102..a986bfc869a3 100644
--- a/lib/libunbound/config.h
+++ b/lib/libunbound/config.h
@@ -796,7 +796,7 @@
#define PACKAGE_NAME "unbound"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "unbound 1.22.0"
+#define PACKAGE_STRING "unbound 1.23.0"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "unbound"
@@ -805,7 +805,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "1.22.0"
+#define PACKAGE_VERSION "1.23.0"
/* default pidfile location */
#define PIDFILE "/var/unbound/unbound.pid"
@@ -828,7 +828,7 @@
#define ROOT_CERT_FILE "/var/unbound/icannbundle.pem"
/* version number for resource files */
-#define RSRC_PACKAGE_VERSION 1,22,0,0
+#define RSRC_PACKAGE_VERSION 1,23,0,0
/* Directory to chdir to */
#define RUN_DIR "/var/unbound"
diff --git a/lib/libusb/libusb.3 b/lib/libusb/libusb.3
index fe07e86623c8..74b85d4aa17e 100644
--- a/lib/libusb/libusb.3
+++ b/lib/libusb/libusb.3
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 26, 2023
+.Dd June 13, 2025
.Dt LIBUSB 3
.Os
.Sh NAME
@@ -106,6 +106,19 @@ Get the ASCII representation of the error given by the
argument.
This function does not return NULL.
.Pp
+.Ft int
+.Fn libusb_setlocale "const char *locale"
+Set locale for the error message when using
+.Fn libusb_strerror
+to
+.Ft locale .
+Note other
+.Nm
+implementations only support the first two bytes, that means
+.Ql en-US
+is equivalent to
+.Ql en-CA .
+.Pp
.Ft const char *
.Fn libusb_error_name "int code"
Get the ASCII representation of the error enum given by the
@@ -117,7 +130,7 @@ This function does not return NULL.
.Fn libusb_set_debug "libusb_context *ctx" "int level"
Set the debug level to
.Fa level .
-.Pp
+.Sh DEVICE HANDLING AND ENUMERATION
.Ft ssize_t
.Fn libusb_get_device_list "libusb_context *ctx" "libusb_device ***list"
Populate
@@ -220,6 +233,11 @@ Close a device handle.
Get the device contained by devh.
Returns NULL on error.
.Pp
+.Ft libusb_device *
+.Fn libusb_get_parent "libusb_device *dev"
+Get dev's parent device.
+Returns NULL if the device has no parent (i.e. is a root device).
+.Pp
.Ft int
.Fn libusb_get_configuration "libusb_device_handle *devh" "int *config"
Returns the value of the current configuration.
diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h
index 732fc9dca1e0..6fb1c19fad13 100644
--- a/lib/libusb/libusb.h
+++ b/lib/libusb/libusb.h
@@ -210,12 +210,15 @@ enum libusb_error {
LIBUSB_ERROR_OTHER = -99,
};
+#define LIBUSB_ERROR_COUNT 14
+
enum libusb_speed {
LIBUSB_SPEED_UNKNOWN = 0,
LIBUSB_SPEED_LOW = 1,
LIBUSB_SPEED_FULL = 2,
LIBUSB_SPEED_HIGH = 3,
LIBUSB_SPEED_SUPER = 4,
+ LIBUSB_SPEED_SUPER_PLUS = 5,
};
enum libusb_transfer_status {
@@ -242,17 +245,6 @@ enum libusb_log_level {
LIBUSB_LOG_LEVEL_DEBUG
};
-/* XXX */
-/* libusb_set_debug should take parameters from libusb_log_level
- * above according to
- * https://libusb.sourceforge.io/api-1.0/group__libusb__lib.html
- */
-enum libusb_debug_level {
- LIBUSB_DEBUG_NO=0,
- LIBUSB_DEBUG_FUNCTION=1,
- LIBUSB_DEBUG_TRANSFER=2,
-};
-
#define LIBUSB_HOTPLUG_MATCH_ANY -1
typedef enum {
@@ -417,7 +409,10 @@ typedef struct libusb_bos_descriptor {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wTotalLength;
- uint8_t bNumDeviceCapabilities;
+#ifndef bNumDeviceCapabilities
+#define bNumDeviceCapabilities bNumDeviceCaps
+#endif
+ uint8_t bNumDeviceCaps;
struct libusb_usb_2_0_device_capability_descriptor *usb_2_0_ext_cap;
struct libusb_ss_usb_device_capability_descriptor *ss_usb_cap;
struct libusb_bos_dev_capability_descriptor **dev_capability;
@@ -482,6 +477,7 @@ int libusb_init(libusb_context ** context);
int libusb_init_context(libusb_context **, const struct libusb_init_option [], int num_options);
void libusb_exit(struct libusb_context *ctx);
int libusb_has_capability(uint32_t capability);
+int libusb_setlocale(const char *locale);
/* Device handling and enumeration */
@@ -502,6 +498,7 @@ int libusb_open(libusb_device * dev, libusb_device_handle ** devh);
libusb_device_handle *libusb_open_device_with_vid_pid(libusb_context * ctx, uint16_t vendor_id, uint16_t product_id);
void libusb_close(libusb_device_handle * devh);
libusb_device *libusb_get_device(libusb_device_handle * devh);
+libusb_device *libusb_get_parent(libusb_device * dev);
int libusb_get_configuration(libusb_device_handle * devh, int *config);
int libusb_set_configuration(libusb_device_handle * devh, int configuration);
int libusb_claim_interface(libusb_device_handle * devh, int interface_number);
diff --git a/lib/libusb/libusb01.c b/lib/libusb/libusb01.c
index 7017016693af..f246e74353a6 100644
--- a/lib/libusb/libusb01.c
+++ b/lib/libusb/libusb01.c
@@ -130,6 +130,8 @@ usb_get_transfer_by_ep_no(usb_dev_handle * dev, uint8_t ep_no)
bufsize = 4096;
} else if (speed == LIBUSB20_SPEED_SUPER) {
bufsize = 65536;
+ } else if (speed == LIBUSB20_SPEED_SUPER_PLUS) {
+ bufsize = 131072;
} else {
bufsize = 16384;
}
diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c
index afa25eabf459..6f1ca877fc28 100644
--- a/lib/libusb/libusb10.c
+++ b/lib/libusb/libusb10.c
@@ -3,6 +3,8 @@
*
* Copyright (c) 2009 Sylvestre Gallon. All rights reserved.
* Copyright (c) 2009-2023 Hans Petter Selasky
+ * Copyright (c) 2024 Aymeric Wibo
+ * Copyright (c) 2025 ShengYi Hung
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,15 +32,18 @@
#include LIBUSB_GLOBAL_INCLUDE_FILE
#else
#include <assert.h>
+#include <ctype.h>
#include <errno.h>
#include <poll.h>
#include <pthread.h>
#include <signal.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
+#include <sys/eventfd.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/queue.h>
@@ -46,6 +51,7 @@
#endif
#define libusb_device_handle libusb20_device
+#define LIBUSB_LOG_BUFFER_SIZE 1024
#include "libusb20.h"
#include "libusb20_desc.h"
@@ -80,6 +86,52 @@ static const struct libusb_version libusb_version = {
.describe = "https://www.freebsd.org"
};
+static const struct libusb_language_context libusb_language_ctx[] = {
+ {
+ .lang_name = "en",
+ .err_strs = {
+ [-LIBUSB_SUCCESS] = "Success",
+ [-LIBUSB_ERROR_IO] = "I/O error",
+ [-LIBUSB_ERROR_INVALID_PARAM] = "Invalid parameter",
+ [-LIBUSB_ERROR_ACCESS] = "Permissions error",
+ [-LIBUSB_ERROR_NO_DEVICE] = "No device",
+ [-LIBUSB_ERROR_NOT_FOUND] = "Not found",
+ [-LIBUSB_ERROR_BUSY] = "Device busy",
+ [-LIBUSB_ERROR_TIMEOUT] = "Timeout",
+ [-LIBUSB_ERROR_OVERFLOW] = "Overflow",
+ [-LIBUSB_ERROR_PIPE] = "Pipe error",
+ [-LIBUSB_ERROR_INTERRUPTED] = "Interrupted",
+ [-LIBUSB_ERROR_NO_MEM] = "Out of memory",
+ [-LIBUSB_ERROR_NOT_SUPPORTED] ="Not supported",
+ [LIBUSB_ERROR_COUNT - 1] = "Other error",
+ [LIBUSB_ERROR_COUNT] = "Unknown error",
+ }
+ },
+ {
+ .lang_name = "zh",
+ .err_strs = {
+ [-LIBUSB_SUCCESS] = "成功",
+ [-LIBUSB_ERROR_IO] = "I/O 錯誤",
+ [-LIBUSB_ERROR_INVALID_PARAM] = "不合法的參數",
+ [-LIBUSB_ERROR_ACCESS] = "權限錯誤",
+ [-LIBUSB_ERROR_NO_DEVICE] = "裝置不存在",
+ [-LIBUSB_ERROR_NOT_FOUND] = "不存在",
+ [-LIBUSB_ERROR_BUSY] = "裝置忙碌中",
+ [-LIBUSB_ERROR_TIMEOUT] = "逾時",
+ [-LIBUSB_ERROR_OVERFLOW] = "溢位",
+ [-LIBUSB_ERROR_PIPE] = "管道錯誤",
+ [-LIBUSB_ERROR_INTERRUPTED] = "被中斷",
+ [-LIBUSB_ERROR_NO_MEM] = "記憶體不足",
+ [-LIBUSB_ERROR_NOT_SUPPORTED] ="不支援",
+ [LIBUSB_ERROR_COUNT - 1] = "其他錯誤",
+ [LIBUSB_ERROR_COUNT] = "未知錯誤",
+ }
+ },
+};
+
+static const struct libusb_language_context *default_language_context =
+ &libusb_language_ctx[0];
+
const struct libusb_version *
libusb_get_version(void)
{
@@ -118,17 +170,15 @@ libusb_set_nonblocking(int f)
void
libusb_interrupt_event_handler(libusb_context *ctx)
{
- uint8_t dummy;
int err;
if (ctx == NULL)
return;
- dummy = 0;
- err = write(ctx->ctrl_pipe[1], &dummy, sizeof(dummy));
- if (err < (int)sizeof(dummy)) {
+ err = eventfd_write(ctx->event, 1);
+ if (err < 0) {
/* ignore error, if any */
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "Waking up event loop failed!");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_ERROR, "Waking up event loop failed!");
}
}
@@ -145,7 +195,6 @@ libusb_init_context(libusb_context **context,
struct libusb_context *ctx;
pthread_condattr_t attr;
char *debug, *ep;
- int ret;
if (num_options < 0)
return (LIBUSB_ERROR_INVALID_PARAM);
@@ -234,19 +283,16 @@ libusb_init_context(libusb_context **context,
ctx->ctx_handler = NO_THREAD;
ctx->hotplug_handler = NO_THREAD;
- ret = pipe(ctx->ctrl_pipe);
- if (ret < 0) {
+ ctx->event = eventfd(0, EFD_NONBLOCK);
+ if (ctx->event < 0) {
pthread_mutex_destroy(&ctx->ctx_lock);
pthread_mutex_destroy(&ctx->hotplug_lock);
pthread_cond_destroy(&ctx->ctx_cond);
free(ctx);
return (LIBUSB_ERROR_OTHER);
}
- /* set non-blocking mode on the control pipe to avoid deadlock */
- libusb_set_nonblocking(ctx->ctrl_pipe[0]);
- libusb_set_nonblocking(ctx->ctrl_pipe[1]);
- libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->ctrl_pipe[0], POLLIN);
+ libusb10_add_pollfd(ctx, &ctx->ctx_poll, NULL, ctx->event, POLLIN);
pthread_mutex_lock(&default_context_lock);
if (usbi_default_context == NULL) {
@@ -257,7 +303,7 @@ libusb_init_context(libusb_context **context,
if (context)
*context = ctx;
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_init complete");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_INFO, "libusb_init complete");
signal(SIGPIPE, SIG_IGN);
@@ -296,8 +342,7 @@ libusb_exit(libusb_context *ctx)
/* XXX cleanup devices */
libusb10_remove_pollfd(ctx, &ctx->ctx_poll);
- close(ctx->ctrl_pipe[0]);
- close(ctx->ctrl_pipe[1]);
+ close(ctx->event);
pthread_mutex_destroy(&ctx->ctx_lock);
pthread_mutex_destroy(&ctx->hotplug_lock);
pthread_cond_destroy(&ctx->ctx_cond);
@@ -317,9 +362,9 @@ ssize_t
libusb_get_device_list(libusb_context *ctx, libusb_device ***list)
{
struct libusb20_backend *usb_backend;
- struct libusb20_device *pdev;
+ struct libusb20_device *pdev, *parent_dev;
struct libusb_device *dev;
- int i;
+ int i, j, k;
ctx = GET_CONTEXT(ctx);
@@ -371,6 +416,9 @@ libusb_get_device_list(libusb_context *ctx, libusb_device ***list)
/* set context we belong to */
dev->ctx = ctx;
+ /* assume we have no parent by default */
+ dev->parent_dev = NULL;
+
/* link together the two structures */
dev->os_priv = pdev;
pdev->privLuData = dev;
@@ -380,6 +428,25 @@ libusb_get_device_list(libusb_context *ctx, libusb_device ***list)
}
(*list)[i] = NULL;
+ /* for each device, find its parent */
+ for (j = 0; j < i; j++) {
+ pdev = (*list)[j]->os_priv;
+
+ for (k = 0; k < i; k++) {
+ if (k == j)
+ continue;
+
+ parent_dev = (*list)[k]->os_priv;
+
+ if (parent_dev->bus_number != pdev->bus_number)
+ continue;
+ if (parent_dev->device_address == pdev->parent_address) {
+ (*list)[j]->parent_dev = libusb_ref_device((*list)[k]);
+ break;
+ }
+ }
+ }
+
libusb20_be_free(usb_backend);
return (i);
}
@@ -451,6 +518,8 @@ libusb_get_device_speed(libusb_device *dev)
return (LIBUSB_SPEED_HIGH);
case LIBUSB20_SPEED_SUPER:
return (LIBUSB_SPEED_SUPER);
+ case LIBUSB20_SPEED_SUPER_PLUS:
+ return (LIBUSB_SPEED_SUPER_PLUS);
default:
break;
}
@@ -544,6 +613,7 @@ libusb_unref_device(libusb_device *dev)
CTX_UNLOCK(dev->ctx);
if (dev->refcnt == 0) {
+ libusb_unref_device(dev->parent_dev);
libusb20_dev_free(dev->os_priv);
free(dev);
}
@@ -605,7 +675,7 @@ libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id,
if (ctx == NULL)
return (NULL); /* be NULL safe */
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_open_device_with_vid_pid enter");
if ((i = libusb_get_device_list(ctx, &devs)) < 0)
return (NULL);
@@ -629,7 +699,7 @@ libusb_open_device_with_vid_pid(libusb_context *ctx, uint16_t vendor_id,
}
libusb_free_device_list(devs, 1);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_open_device_with_vid_pid leave");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_open_device_with_vid_pid leave");
return (pdev);
}
@@ -820,6 +890,12 @@ libusb_set_interface_alt_setting(struct libusb20_device *pdev,
return (err ? LIBUSB_ERROR_OTHER : 0);
}
+libusb_device *
+libusb_get_parent(libusb_device *dev)
+{
+ return (dev->parent_dev);
+}
+
static struct libusb20_transfer *
libusb10_get_transfer(struct libusb20_device *pdev,
uint8_t endpoint, uint8_t xfer_index)
@@ -1080,6 +1156,9 @@ libusb10_get_buffsize(struct libusb20_device *pdev, libusb_transfer *xfer)
case LIBUSB20_SPEED_SUPER:
ret = 65536;
break;
+ case LIBUSB20_SPEED_SUPER_PLUS:
+ ret = 131072;
+ break;
default:
ret = 16384;
break;
@@ -1507,7 +1586,7 @@ libusb_submit_transfer(struct libusb_transfer *uxfer)
dev = libusb_get_device(uxfer->dev_handle);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer enter");
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_submit_transfer enter");
sxfer = (struct libusb_super_transfer *)(
(uint8_t *)uxfer - sizeof(*sxfer));
@@ -1542,7 +1621,7 @@ libusb_submit_transfer(struct libusb_transfer *uxfer)
CTX_UNLOCK(dev->ctx);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_submit_transfer leave %d", err);
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_submit_transfer leave %d", err);
return (err);
}
@@ -1571,7 +1650,7 @@ libusb_cancel_transfer(struct libusb_transfer *uxfer)
dev = libusb_get_device(devh);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer enter");
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_cancel_transfer enter");
sxfer = (struct libusb_super_transfer *)(
(uint8_t *)uxfer - sizeof(*sxfer));
@@ -1632,7 +1711,7 @@ libusb_cancel_transfer(struct libusb_transfer *uxfer)
CTX_UNLOCK(dev->ctx);
- DPRINTF(dev->ctx, LIBUSB_DEBUG_FUNCTION, "libusb_cancel_transfer leave");
+ DPRINTF(dev->ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_cancel_transfer leave");
return (retval);
}
@@ -1697,38 +1776,26 @@ libusb_le16_to_cpu(uint16_t x)
const char *
libusb_strerror(int code)
{
- switch (code) {
- case LIBUSB_SUCCESS:
- return ("Success");
- case LIBUSB_ERROR_IO:
- return ("I/O error");
- case LIBUSB_ERROR_INVALID_PARAM:
- return ("Invalid parameter");
- case LIBUSB_ERROR_ACCESS:
- return ("Permissions error");
- case LIBUSB_ERROR_NO_DEVICE:
- return ("No device");
- case LIBUSB_ERROR_NOT_FOUND:
- return ("Not found");
- case LIBUSB_ERROR_BUSY:
- return ("Device busy");
- case LIBUSB_ERROR_TIMEOUT:
- return ("Timeout");
- case LIBUSB_ERROR_OVERFLOW:
- return ("Overflow");
- case LIBUSB_ERROR_PIPE:
- return ("Pipe error");
- case LIBUSB_ERROR_INTERRUPTED:
- return ("Interrupted");
- case LIBUSB_ERROR_NO_MEM:
- return ("Out of memory");
- case LIBUSB_ERROR_NOT_SUPPORTED:
- return ("Not supported");
- case LIBUSB_ERROR_OTHER:
- return ("Other error");
- default:
- return ("Unknown error");
- }
+ int entry = -code;
+
+ if (code == LIBUSB_ERROR_OTHER)
+ entry = LIBUSB_ERROR_COUNT - 1;
+ /*
+ * The libusb upstream considers all code out of range a
+ * LIBUSB_ERROR_OTHER. In FreeBSD, it is a special unknown error. We
+ * preserve the FreeBSD implementation as I think it make sense.
+ */
+ if (entry < 0 || entry >= LIBUSB_ERROR_COUNT)
+ entry = LIBUSB_ERROR_COUNT;
+
+ /*
+ * Fall back to English one as the translation may be unimplemented
+ * when adding new error code.
+ */
+ if (default_language_context->err_strs[entry] == NULL)
+ return (libusb_language_ctx[0].err_strs[entry]);
+
+ return (default_language_context->err_strs[entry]);
}
const char *
@@ -1782,3 +1849,58 @@ libusb_has_capability(uint32_t capability)
return (0);
}
}
+
+void
+libusb_log_va_args(struct libusb_context *ctx, enum libusb_log_level level,
+ const char *fmt, ...)
+{
+ static const char *log_prefix[5] = {
+ [LIBUSB_LOG_LEVEL_ERROR] = "LIBUSB_ERROR",
+ [LIBUSB_LOG_LEVEL_WARNING] = "LIBUSB_WARN",
+ [LIBUSB_LOG_LEVEL_INFO] = "LIBUSB_INFO",
+ [LIBUSB_LOG_LEVEL_DEBUG] = "LIBUSB_DEBUG",
+ };
+
+ char buffer[LIBUSB_LOG_BUFFER_SIZE];
+ char new_fmt[LIBUSB_LOG_BUFFER_SIZE];
+ va_list args;
+
+ ctx = GET_CONTEXT(ctx);
+
+ if (ctx->debug < level)
+ return;
+
+ va_start(args, fmt);
+
+ snprintf(new_fmt, sizeof(new_fmt), "%s: %s\n", log_prefix[level], fmt);
+ vsnprintf(buffer, sizeof(buffer), new_fmt, args);
+ fputs(buffer, stdout);
+
+ va_end(args);
+}
+
+/*
+ * Upstream code actually recognizes the first two characters to identify a
+ * language. We do so to provide API compatibility with setlocale.
+ */
+int
+libusb_setlocale(const char *locale)
+{
+ size_t idx;
+ const char *lang;
+
+ if (locale == NULL || strlen(locale) < 2 ||
+ (locale[2] != '\0' && strchr("-_.", locale[2]) == NULL))
+ return (LIBUSB_ERROR_INVALID_PARAM);
+
+ for (idx = 0; idx < nitems(libusb_language_ctx); ++idx) {
+ lang = libusb_language_ctx[idx].lang_name;
+ if (tolower(locale[0]) == lang[0] &&
+ tolower(locale[1]) == lang[1]) {
+ default_language_context = &libusb_language_ctx[idx];
+ return (LIBUSB_SUCCESS);
+ }
+ }
+
+ return (LIBUSB_ERROR_INVALID_PARAM);
+}
diff --git a/lib/libusb/libusb10.h b/lib/libusb/libusb10.h
index 3402e0377c92..eced364ef857 100644
--- a/lib/libusb/libusb10.h
+++ b/lib/libusb/libusb10.h
@@ -29,6 +29,7 @@
#define __LIBUSB10_H__
#ifndef LIBUSB_GLOBAL_INCLUDE_FILE
+#include <sys/cdefs.h>
#include <sys/queue.h>
#include <netlink/netlink.h>
#include <netlink/netlink_generic.h>
@@ -46,24 +47,11 @@
#define HOTPLUG_LOCK(ctx) pthread_mutex_lock(&(ctx)->hotplug_lock)
#define HOTPLUG_UNLOCK(ctx) pthread_mutex_unlock(&(ctx)->hotplug_lock)
-#define DPRINTF(ctx, dbg, format, ...) do { \
- switch (dbg) { \
- case LIBUSB_DEBUG_FUNCTION: \
- if ((ctx)->debug & LIBUSB_DEBUG_FUNCTION) { \
- printf("LIBUSB_FUNCTION: " \
- format "\n", ## __VA_ARGS__); \
- } \
- break; \
- case LIBUSB_DEBUG_TRANSFER: \
- if ((ctx)->debug & LIBUSB_DEBUG_TRANSFER) { \
- printf("LIBUSB_TRANSFER: " \
- format "\n", ## __VA_ARGS__); \
- } \
- break; \
- default: \
- break; \
- } \
-} while (0)
+void libusb_log_va_args(struct libusb_context *ctx, enum libusb_log_level level,
+ const char *fmt, ...) __printflike(3, 4);
+
+#define DPRINTF(ctx, dbg, format, ...) \
+ libusb_log_va_args(ctx, dbg, format, ##__VA_ARGS__)
/* internal structures */
@@ -106,7 +94,7 @@ typedef enum {
struct libusb_context {
int debug;
int debug_fixed;
- int ctrl_pipe[2];
+ int event;
int tr_done_ref;
int tr_done_gen;
usb_event_mode_t usb_event_mode;
@@ -142,6 +130,7 @@ struct libusb_device {
struct libusb_super_pollfd dev_poll;
struct libusb_context *ctx;
+ struct libusb_device *parent_dev;
TAILQ_ENTRY(libusb_device) hotplug_entry;
@@ -150,6 +139,12 @@ struct libusb_device {
struct libusb20_device *os_priv;
};
+struct libusb_language_context {
+ const char *lang_name;
+ /* All error Plus 1 UNKNOWN */
+ const char *err_strs[LIBUSB_ERROR_COUNT + 1];
+};
+
extern struct libusb_context *usbi_default_context;
void libusb10_add_pollfd(libusb_context *ctx, struct libusb_super_pollfd *pollfd, struct libusb20_device *pdev, int fd, short events);
diff --git a/lib/libusb/libusb10_desc.c b/lib/libusb/libusb10_desc.c
index 3e36009cbb3a..5f4c46740688 100644
--- a/lib/libusb/libusb10_desc.c
+++ b/lib/libusb/libusb10_desc.c
@@ -470,10 +470,11 @@ libusb_parse_bos_descriptor(const void *buf, int len,
ptr->bDescriptorType = dtype;
ptr->wTotalLength = ((const uint8_t *)buf)[2] |
(((const uint8_t *)buf)[3] << 8);
- ptr->bNumDeviceCapabilities = ((const uint8_t *)buf)[4];
+ ptr->bNumDeviceCaps = ((const uint8_t *)buf)[4];
ptr->usb_2_0_ext_cap = NULL;
ptr->ss_usb_cap = NULL;
- ptr->dev_capability = calloc(ptr->bNumDeviceCapabilities, sizeof(void *));
+ ptr->dev_capability = calloc(ptr->bNumDeviceCaps,
+ sizeof(void *));
if (ptr->dev_capability == NULL) {
free(ptr);
return (LIBUSB_ERROR_NO_MEM);
@@ -485,7 +486,7 @@ libusb_parse_bos_descriptor(const void *buf, int len,
if (dlen >= 3 &&
ptr != NULL &&
dtype == LIBUSB_DT_DEVICE_CAPABILITY) {
- if (index != ptr->bNumDeviceCapabilities) {
+ if (index != ptr->bNumDeviceCaps) {
ptr->dev_capability[index] = malloc(dlen);
if (ptr->dev_capability[index] == NULL) {
libusb_free_bos_descriptor(ptr);
@@ -542,7 +543,7 @@ libusb_parse_bos_descriptor(const void *buf, int len,
}
if (ptr != NULL) {
- ptr->bNumDeviceCapabilities = index;
+ ptr->bNumDeviceCaps = index;
return (0); /* success */
}
@@ -557,7 +558,7 @@ libusb_free_bos_descriptor(struct libusb_bos_descriptor *bos)
if (bos == NULL)
return;
- for (i = 0; i != bos->bNumDeviceCapabilities; i++)
+ for (i = 0; i != bos->bNumDeviceCaps; i++)
free(bos->dev_capability[i]);
free(bos->dev_capability);
free(bos);
diff --git a/lib/libusb/libusb10_hotplug.c b/lib/libusb/libusb10_hotplug.c
index b7573bf916ec..369539d4512e 100644
--- a/lib/libusb/libusb10_hotplug.c
+++ b/lib/libusb/libusb10_hotplug.c
@@ -73,7 +73,7 @@ netlink_init(libusb_context *ctx)
if (modfind("nlsysevent") < 0)
return (false);
if (!snl_init(&ctx->ss, NETLINK_GENERIC) || (group =
- snl_get_genl_mcast_group(&ctx->ss, "nlsysevent", "ACPI", NULL)) == 0)
+ snl_get_genl_mcast_group(&ctx->ss, "nlsysevent", "USB", NULL)) == 0)
return (false);
if (setsockopt(ctx->ss.fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group,
@@ -140,6 +140,8 @@ verify_event_validity(libusb_context *ctx)
return (valid_event);
return (invalid_event);
}
+ if (errno == EBADF)
+ return (broken_event);
return (invalid_event);
} else if (ctx->usb_event_mode == usb_event_devd) {
char buf[DEVCTL_MAXBUF];
@@ -407,6 +409,7 @@ void libusb_hotplug_deregister_callback(libusb_context *ctx,
HOTPLUG_LOCK(ctx);
TAILQ_REMOVE(&ctx->hotplug_cbh, handle, entry);
+ libusb_interrupt_event_handler(ctx);
HOTPLUG_UNLOCK(ctx);
free(handle);
diff --git a/lib/libusb/libusb10_io.c b/lib/libusb/libusb10_io.c
index 59bac60c4672..dd541b09caa6 100644
--- a/lib/libusb/libusb10_io.c
+++ b/lib/libusb/libusb10_io.c
@@ -36,6 +36,7 @@
#include <string.h>
#include <time.h>
#include <unistd.h>
+#include <sys/eventfd.h>
#include <sys/queue.h>
#include <sys/endian.h>
#endif
@@ -107,7 +108,7 @@ libusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv)
int i;
int err;
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb10_handle_events_sub enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb10_handle_events_sub enter");
nfds = 0;
i = 0;
@@ -187,10 +188,8 @@ libusb10_handle_events_sub(struct libusb_context *ctx, struct timeval *tv)
CTX_LOCK(ctx);
} else {
- uint8_t dummy;
+ eventfd_read(fds[i].fd, &(eventfd_t){0});
- while (read(fds[i].fd, &dummy, 1) == 1)
- ;
}
}
@@ -231,6 +230,7 @@ do_done:
/* Wakeup other waiters */
pthread_cond_broadcast(&ctx->ctx_cond);
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb10_handle_events_sub complete");
return (err);
}
@@ -314,7 +314,7 @@ libusb_wait_for_event(libusb_context *ctx, struct timeval *tv)
int err;
ctx = GET_CONTEXT(ctx);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_wait_for_event enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_wait_for_event enter");
if (tv == NULL) {
pthread_cond_wait(&ctx->ctx_cond,
@@ -358,7 +358,7 @@ libusb_handle_events_timeout_completed(libusb_context *ctx,
ctx = GET_CONTEXT(ctx);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_handle_events_timeout_completed enter");
libusb_lock_events(ctx);
@@ -374,7 +374,7 @@ libusb_handle_events_timeout_completed(libusb_context *ctx,
libusb_unlock_events(ctx);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_handle_events_timeout_completed exit");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_handle_events_timeout_completed exit");
return (err);
}
@@ -523,7 +523,7 @@ libusb10_do_transfer_cb(struct libusb_transfer *transfer)
ctx = libusb10_get_context_by_device_handle(transfer->dev_handle);
- DPRINTF(ctx, LIBUSB_DEBUG_TRANSFER, "sync I/O done");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "sync I/O done");
pdone = transfer->user_data;
*pdone = 1;
@@ -613,12 +613,12 @@ libusb_bulk_transfer(libusb_device_handle *devh,
ctx = libusb10_get_context_by_device_handle(devh);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_bulk_transfer enter");
ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
timeout, LIBUSB_TRANSFER_TYPE_BULK);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_bulk_transfer leave");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_bulk_transfer leave");
return (ret);
}
@@ -632,12 +632,12 @@ libusb_interrupt_transfer(libusb_device_handle *devh,
ctx = libusb10_get_context_by_device_handle(devh);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer enter");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_interrupt_transfer enter");
ret = libusb10_do_transfer(devh, endpoint, data, length, transferred,
timeout, LIBUSB_TRANSFER_TYPE_INTERRUPT);
- DPRINTF(ctx, LIBUSB_DEBUG_FUNCTION, "libusb_interrupt_transfer leave");
+ DPRINTF(ctx, LIBUSB_LOG_LEVEL_DEBUG, "libusb_interrupt_transfer leave");
return (ret);
}
diff --git a/lib/libusb/libusb20.3 b/lib/libusb/libusb20.3
index 1d07db8f32a4..7854b0f8ed7e 100644
--- a/lib/libusb/libusb20.3
+++ b/lib/libusb/libusb20.3
@@ -858,6 +858,7 @@ returns the current speed of the given USB device.
.It LIBUSB20_SPEED_HIGH
.It LIBUSB20_SPEED_VARIABLE
.It LIBUSB20_SPEED_SUPER
+.It LIBUSB20_SPEED_SUPER_PLUS
.El
.
.Pp
diff --git a/lib/libusb/libusb20.h b/lib/libusb/libusb20.h
index 7bca2f7508c7..c132c58a9f69 100644
--- a/lib/libusb/libusb20.h
+++ b/lib/libusb/libusb20.h
@@ -159,6 +159,7 @@ enum {
LIBUSB20_SPEED_HIGH,
LIBUSB20_SPEED_VARIABLE,
LIBUSB20_SPEED_SUPER,
+ LIBUSB20_SPEED_SUPER_PLUS,
};
/** \ingroup misc
diff --git a/lib/libusb/libusb20_desc.h b/lib/libusb/libusb20_desc.h
index 017148a34b1c..0f7c9294ebc8 100644
--- a/lib/libusb/libusb20_desc.h
+++ b/lib/libusb/libusb20_desc.h
@@ -298,11 +298,15 @@ LIBUSB20_MAKE_STRUCT(LIBUSB20_USB_20_DEVCAP_DESC);
LIBUSB20_MAKE_STRUCT(LIBUSB20_SS_USB_DEVCAP_DESC);
+#ifndef bNumDeviceCapabilities
+#define bNumDeviceCapabilities bNumDeviceCaps
+#endif
+
#define LIBUSB20_BOS_DESCRIPTOR(m,n) \
m(n, UINT8_T, bLength, ) \
m(n, UINT8_T, bDescriptorType, ) \
m(n, UINT16_T, wTotalLength, ) \
- m(n, UINT8_T, bNumDeviceCapabilities, ) \
+ m(n, UINT8_T, bNumDeviceCaps, ) \
LIBUSB20_MAKE_STRUCT(LIBUSB20_BOS_DESCRIPTOR);
diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile
index 8178d33b7ba8..0639745d08fc 100644
--- a/lib/libutil/Makefile
+++ b/lib/libutil/Makefile
@@ -16,9 +16,10 @@ SRCS= _secure_path.c auth.c cpuset.c expand_number.c flopen.c fparseln.c \
kinfo_getvmobject.c kld.c \
login_auth.c login_cap.c \
login_class.c login_crypt.c login_ok.c login_times.c login_tty.c \
+ mntopts.c \
pidfile.c property.c pty.c pw_scan.c pw_util.c quotafile.c \
realhostname.c stub.c trimdomain.c uucplock.c
-INCS= libutil.h login_cap.h
+INCS= libutil.h login_cap.h mntopts.h
CFLAGS+= -DNO__SCCSID
@@ -32,7 +33,8 @@ MAN+= cpuset.3 expand_number.3 flopen.3 fparseln.3 ftime.3 getlocalbase.3 \
hexdump.3 humanize_number.3 kinfo_getallproc.3 kinfo_getfile.3 \
kinfo_getproc.3 kinfo_getvmmap.3 kinfo_getvmobject.3 kld.3 \
login_auth.3 login_cap.3 \
- login_class.3 login_ok.3 login_times.3 login_tty.3 pidfile.3 \
+ login_class.3 login_ok.3 login_times.3 login_tty.3 mntopts.3 \
+ pidfile.3 \
property.3 pty.3 quotafile.3 realhostname.3 realhostname_sa.3 \
_secure_path.3 trimdomain.3 uucplock.3 pw_util.3
MAN+= login.conf.5
@@ -54,6 +56,14 @@ MLINKS+=login_times.3 in_lt.3 login_times.3 in_ltm.3 \
login_times.3 in_ltms.3 \
login_times.3 in_lts.3 \
login_times.3 parse_lt.3
+MLINKS+=mntopts.3 getmntopts.3 \
+ mntopts.3 getmntpoint.3 \
+ mntopts.3 chkdoreload.3 \
+ mntopts.3 build_iovec.3 \
+ mntopts.3 build_iovec_argf.3 \
+ mntopts.3 free_iovec.3 \
+ mntopts.3 checkpath.3 \
+ mntopts.3 rmslashes.3
MLINKS+=pidfile.3 pidfile_close.3 \
pidfile.3 pidfile_fileno.3 \
pidfile.3 pidfile_open.3 \
diff --git a/lib/libutil/kinfo_getfile.c b/lib/libutil/kinfo_getfile.c
index f1441bdf771a..345da657df81 100644
--- a/lib/libutil/kinfo_getfile.c
+++ b/lib/libutil/kinfo_getfile.c
@@ -27,6 +27,10 @@ kinfo_getfile(pid_t pid, int *cntp)
error = sysctl(mib, nitems(mib), NULL, &len, NULL, 0);
if (error)
return (NULL);
+ /*
+ * Add extra space as the table may grow between requesting the size
+ * and fetching the data.
+ */
len = len * 4 / 3;
buf = malloc(len);
if (buf == NULL)
diff --git a/lib/libutil/mntopts.3 b/lib/libutil/mntopts.3
new file mode 100644
index 000000000000..35f6d476fcec
--- /dev/null
+++ b/lib/libutil/mntopts.3
@@ -0,0 +1,377 @@
+.\" Copyright (c) 2023 Marshall Kirk McKusick
+.\" Copyright (c) 1994 The Regents of the University of California.
+.\"
+.\" 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 AUTHORS 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 AUTHORS 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.
+.\"
+.Dd April 21, 2025
+.Dt MNTOPTS 3
+.Os
+.Sh NAME
+.Nm getmntopts ,
+.Nm getmntpoint ,
+.Nm chkdoreload ,
+.Nm build_iovec ,
+.Nm build_iovec_argf ,
+.Nm free_iovec ,
+.Nm checkpath ,
+.Nm rmslashes
+.Nd "mount point operations"
+.Sh LIBRARY
+.Lb libutil
+.Sh SYNOPSIS
+.In mntopts.h
+.Ft void
+.Fo getmntopts
+.Fa "const char *options" "const struct mntopt *mopts"
+.Fa "int *flagp" "int *altflagp"
+.Fc
+.Ft struct statfs *
+.Fn getmntpoint "const char *name"
+.Ft int
+.Fo chkdoreload
+.Fa "struct statfs *mntp"
+.Fa "void (*prtmsg)(const char *fmt, ...)"
+.Fc
+.Ft void
+.Fo build_iovec
+.Fa "struct iovec **iov" "int *iovlen" "const char *name" "void *val"
+.Fa "size_t len"
+.Fc
+.Ft void
+.Fo build_iovec_argf
+.Fa "struct iovec **iov" "int *iovlen" "const char *name"
+.Fa "const char *fmt" "..."
+.Fc
+.Ft void
+.Fn free_iovec "struct iovec **iov" "int *iovlen"
+.Ft int
+.Fn checkpath "const char *path" "char *resolved"
+.Ft void
+.Fn rmslashes "char *rrpin" "char *rrpout"
+.Sh DESCRIPTION
+The
+.Nm mntopts
+functions support operations associated with a mount point.
+.Pp
+The
+.Fn getmntopts
+function takes a comma separated option list and a list
+of valid option names, and computes the bitmask
+corresponding to the requested set of options.
+.Pp
+The string
+.Fa options
+is broken down into a sequence of comma separated tokens.
+Each token is looked up in the table described by
+.Fa mopts
+and the bits in
+the word referenced by either
+.Fa flagp
+or
+.Fa altflagp
+(depending on the
+.Va m_altloc
+field of the option's table entry)
+are updated.
+The flag words are not initialized by
+.Fn getmntopts .
+The table,
+.Fa mopts ,
+has the following format:
+.Bd -literal
+struct mntopt {
+ char *m_option; /* option name */
+ int m_inverse; /* is this a negative option, e.g., "dev" */
+ int m_flag; /* bit to set, e.g., MNT_RDONLY */
+ int m_altloc; /* non-zero to use altflagp rather than flagp */
+};
+.Ed
+.Pp
+The members of this structure are:
+.Bl -tag -width m_inverse
+.It Va m_option
+the option name,
+for example
+.Dq Li suid .
+.It Va m_inverse
+tells
+.Fn getmntopts
+that the name has the inverse meaning of the
+bit.
+For example,
+.Dq Li suid
+is the string, whereas the
+mount flag is
+.Dv MNT_NOSUID .
+In this case, the sense of the string and the flag
+are inverted, so the
+.Va m_inverse
+flag should be set.
+.It Va m_flag
+the value of the bit to be set or cleared in
+the flag word when the option is recognized.
+The bit is set when the option is discovered,
+but cleared if the option name was preceded
+by the letters
+.Dq Li no .
+The
+.Va m_inverse
+flag causes these two operations to be reversed.
+.It Va m_altloc
+the bit should be set or cleared in
+.Fa altflagp
+rather than
+.Fa flagp .
+.El
+.Pp
+Each of the user visible
+.Dv MNT_
+flags has a corresponding
+.Dv MOPT_
+macro which defines an appropriate
+.Vt "struct mntopt"
+entry.
+To simplify the program interface and ensure consistency across all
+programs, a general purpose macro,
+.Dv MOPT_STDOPTS ,
+is defined which
+contains an entry for all the generic VFS options.
+In addition, the macros
+.Dv MOPT_FORCE
+and
+.Dv MOPT_UPDATE
+exist to enable the
+.Dv MNT_FORCE
+and
+.Dv MNT_UPDATE
+flags to be set.
+Finally, the table must be terminated by an entry with a
+.Dv NULL
+first element.
+.Pp
+The
+.Fn getmntpoint
+function takes the pathname of a possible mount point
+or of a device (with or without
+.Pa /dev/
+prepended to it).
+If the pathname is a directory or a file,
+.Fn getmntpoint
+checks to see if the mount point currently has a filesystem
+mounted on it.
+If the pathname is a device,
+.Fn getmntpoint
+checks to see if it is currently mounted.
+If there is an associated mount, a pointer to a
+.Vt "struct statfs"
+is returned.
+The returned result is stored in a static buffer that is over-written
+each time the
+.Fn getmntpoint
+function or the
+.Xr getmntinfo 3
+library routine is called.
+If no mount is found, NULL is returned.
+.Pp
+The
+.Fn chkdoreload
+function takes a pointer to a
+.Vt "struct statfs" .
+If the filesystem associated with the mount point is mounted read-only,
+.Fn chkdoreload
+requests the filesystem to reload all of its metadata from its backing store.
+The second parameter is the function to call to print an error message
+if the reload fails.
+If no error message is desired, a
+.Dv NULL
+can be passed as the second argument.
+The
+.Fn chkdoreload
+function returns zero on success or non-zero on failure.
+.Pp
+The
+.Fn build_iovec
+function adds a parameter to a list of parameters to be passed to the
+.Xr nmount 2
+system call.
+The parameter list is built up in
+.Va iov
+and its length is kept in
+.Va iovlen .
+Before the first call to
+.Fn build_iovec ,
+.Va iov
+should be set to
+.Dv NULL
+and
+.Va iovlen
+should be set to 0.
+The parameter name is passed in
+.Va name .
+The value of the parameter name is pointed to by
+.Va val .
+The size of the value is passed in
+.Va len .
+If the value is a string, a
+.Va len
+of -1 is passed to indicate that the length should be determined using
+.Xr strlen 3 .
+If the parameter has no value,
+.Va name
+should be
+.Dv NULL
+and
+.Va len
+should be 0.
+.Pp
+The
+.Fn build_iovec_argf
+function adds a formatted parameter to a list of parameters to be passed
+to the
+.Xr nmount 2
+system call.
+The parameter list is built up in
+.Va iov
+and its length is kept in
+.Va iovlen .
+Before the first call to
+.Fn build_iovec_argf ,
+.Va iov
+should be set to
+.Dv NULL
+and
+.Va iovlen
+should be set to 0.
+The parameter name is passed in
+.Va name .
+The value of the parameter name is described by a format string pointed to by
+.Va fmt .
+If the parameter has no value,
+.Va name
+should be
+.Dv NULL .
+.Pp
+The
+.Fn free_iovec
+function frees the memory in the
+.Va iov
+vector of the length specified in
+.Va iovlen
+that was previously allocated by the
+.Fn build_iovec
+and / or
+.Fn build_iovec_argf
+functions.
+The
+.Va iov
+is set to
+.Dv NULL
+and the
+.Va iovlen
+is set to 0 to indicate that the space has been freed.
+.Pp
+The
+.Fn checkpath
+function uses
+.Xr realpath 3
+to verify that its
+.Va path
+argument is valid and references a directory.
+The
+.Fn checkpath
+function returns zero on success or non-zero on failure.
+.Pp
+The
+.Fn rmslashes
+function removes all double slashes and trailing slashes from its
+.Va rrpin
+pathname parameter and returns the resulting pathname in its
+.Va rrpout
+parameter.
+.Sh EXAMPLES
+Most commands will use the standard option set.
+Local file systems which support the
+.Dv MNT_UPDATE
+flag, would also have an
+.Dv MOPT_UPDATE
+entry.
+This can be declared and used as follows:
+.Bd -literal
+#include <mntopts.h>
+
+struct mntopt mopts[] = {
+ MOPT_STDOPTS,
+ MOPT_UPDATE,
+ { NULL }
+};
+
+ ...
+ mntflags = mntaltflags = 0;
+ ...
+ getmntopts(options, mopts, &mntflags, &mntaltflags);
+ ...
+.Ed
+.Sh DIAGNOSTICS
+If the external integer variable
+.Va getmnt_silent
+is zero, then the
+.Fn getmntopts
+function displays an error message and exits if an
+unrecognized option is encountered.
+Otherwise unrecognized options are silently ignored.
+By default
+.Va getmnt_silent
+is zero.
+.Sh SEE ALSO
+.Xr err 3 ,
+.Xr mount 8 ,
+.Xr nmount 8
+.Sh HISTORY
+The
+.Fn getmntopts
+function appeared in
+.Bx 4.4 .
+The
+.Fn build_iovec ,
+.Fn build_iovec_argf ,
+.Fn free_iovec ,
+.Fn checkpath ,
+and
+.Fn rmslashes
+functions were added with
+.Xr nmount 8
+in
+.Fx 5.0 .
+The
+.Fn getmntpoint
+and
+.Fn chkdoreload
+functions were added in
+.Fx 13.2 .
+.Pp
+Historically, these functions were found in getmntopts.c in the sources for the
+.Xr mount 8
+program.
+As of
+.Fx 15.0
+they are part of
+.Nm libutil .
diff --git a/lib/libutil/mntopts.c b/lib/libutil/mntopts.c
new file mode 100644
index 000000000000..1d9347e3108a
--- /dev/null
+++ b/lib/libutil/mntopts.c
@@ -0,0 +1,300 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+
+#include <err.h>
+#include <errno.h>
+#include <mntopts.h>
+#include <paths.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int getmnt_silent = 0;
+
+void
+getmntopts(const char *options, const struct mntopt *m0, int *flagp,
+ int *altflagp)
+{
+ const struct mntopt *m;
+ int negative, len;
+ char *opt, *optbuf, *p;
+ int *thisflagp;
+
+ /* Copy option string, since it is about to be torn asunder... */
+ if ((optbuf = strdup(options)) == NULL)
+ err(1, NULL);
+
+ for (opt = optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
+ /* Check for "no" prefix. */
+ if (opt[0] == 'n' && opt[1] == 'o') {
+ negative = 1;
+ opt += 2;
+ } else
+ negative = 0;
+
+ /*
+ * for options with assignments in them (ie. quotas)
+ * ignore the assignment as it's handled elsewhere
+ */
+ p = strchr(opt, '=');
+ if (p != NULL)
+ *++p = '\0';
+
+ /* Scan option table. */
+ for (m = m0; m->m_option != NULL; ++m) {
+ len = strlen(m->m_option);
+ if (strncasecmp(opt, m->m_option, len) == 0)
+ if (opt[len] == '\0' || opt[len] == '=')
+ break;
+ }
+
+ /* Save flag, or fail if option is not recognized. */
+ if (m->m_option) {
+ thisflagp = m->m_altloc ? altflagp : flagp;
+ if (negative == m->m_inverse)
+ *thisflagp |= m->m_flag;
+ else
+ *thisflagp &= ~m->m_flag;
+ } else if (!getmnt_silent) {
+ errx(1, "-o %s: option not supported", opt);
+ }
+ }
+
+ free(optbuf);
+}
+
+void
+rmslashes(char *rrpin, char *rrpout)
+{
+ char *rrpoutstart;
+
+ *rrpout = *rrpin;
+ for (rrpoutstart = rrpout; *rrpin != '\0'; *rrpout++ = *rrpin++) {
+
+ /* skip all double slashes */
+ while (*rrpin == '/' && *(rrpin + 1) == '/')
+ rrpin++;
+ }
+
+ /* remove trailing slash if necessary */
+ if (rrpout - rrpoutstart > 1 && *(rrpout - 1) == '/')
+ *(rrpout - 1) = '\0';
+ else
+ *rrpout = '\0';
+}
+
+int
+checkpath(const char *path, char *resolved)
+{
+ struct stat sb;
+
+ if (realpath(path, resolved) == NULL || stat(resolved, &sb) != 0)
+ return (1);
+ if (!S_ISDIR(sb.st_mode)) {
+ errno = ENOTDIR;
+ return (1);
+ }
+ return (0);
+}
+
+int
+checkpath_allow_file(const char *path, char *resolved)
+{
+ struct stat sb;
+
+ if (realpath(path, resolved) == NULL || stat(resolved, &sb) != 0)
+ return (1);
+ if (!S_ISDIR(sb.st_mode) && !S_ISREG(sb.st_mode)) {
+ errno = ENOTDIR;
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Get the mount point information for name. Name may be mount point name
+ * or device name (with or without /dev/ preprended).
+ */
+struct statfs *
+getmntpoint(const char *name)
+{
+ struct stat devstat, mntdevstat;
+ char device[sizeof(_PATH_DEV) - 1 + MNAMELEN];
+ char *ddevname;
+ struct statfs *mntbuf, *statfsp;
+ int i, mntsize, isdev;
+ u_long len;
+
+ if (stat(name, &devstat) != 0)
+ return (NULL);
+ if (S_ISCHR(devstat.st_mode) || S_ISBLK(devstat.st_mode))
+ isdev = 1;
+ else
+ isdev = 0;
+ mntsize = getmntinfo(&mntbuf, MNT_NOWAIT);
+ for (i = 0; i < mntsize; i++) {
+ statfsp = &mntbuf[i];
+ if (isdev == 0) {
+ if (strcmp(name, statfsp->f_mntonname))
+ continue;
+ return (statfsp);
+ }
+ ddevname = statfsp->f_mntfromname;
+ if (*ddevname != '/') {
+ if ((len = strlen(_PATH_DEV) + strlen(ddevname) + 1) >
+ sizeof(statfsp->f_mntfromname) ||
+ len > sizeof(device))
+ continue;
+ strncpy(device, _PATH_DEV, len);
+ strncat(device, ddevname, len);
+ if (stat(device, &mntdevstat) == 0)
+ strncpy(statfsp->f_mntfromname, device, len);
+ }
+ if (stat(ddevname, &mntdevstat) == 0 &&
+ mntdevstat.st_rdev == devstat.st_rdev)
+ return (statfsp);
+ }
+ return (NULL);
+}
+
+/*
+ * If possible reload a mounted filesystem.
+ * When prtmsg != NULL print a warning if a reload is attempted, but fails.
+ * Return 0 on success, 1 on failure.
+ */
+int
+chkdoreload(struct statfs *mntp,
+ void (*prtmsg)(const char *, ...) __printflike(1,2))
+{
+ struct iovec *iov;
+ int iovlen, error;
+ char errmsg[255];
+
+ /*
+ * If the filesystem is not mounted it does not need to be reloaded.
+ * If it is mounted for writing, then it could not have been opened
+ * for writing by a utility, so does not need to be reloaded.
+ */
+ if (mntp == NULL || (mntp->f_flags & MNT_RDONLY) == 0)
+ return (0);
+
+ /*
+ * We modified a mounted file system. Do a mount update on
+ * it so we can continue using it as safely as possible.
+ */
+ iov = NULL;
+ iovlen = 0;
+ errmsg[0] = '\0';
+ build_iovec(&iov, &iovlen, "fstype", __DECONST(void *, "ffs"), 4);
+ build_iovec(&iov, &iovlen, "from", mntp->f_mntfromname, (size_t)-1);
+ build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, (size_t)-1);
+ build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg));
+ build_iovec(&iov, &iovlen, "update", NULL, 0);
+ build_iovec(&iov, &iovlen, "reload", NULL, 0);
+ /*
+ * XX: We need the following line until we clean up
+ * nmount parsing of root mounts and NFS root mounts.
+ */
+ build_iovec(&iov, &iovlen, "ro", NULL, 0);
+ error = nmount(iov, iovlen, mntp->f_flags);
+ free_iovec(&iov, &iovlen);
+ if (error == 0)
+ return (0);
+ if (prtmsg != NULL)
+ prtmsg("mount reload of '%s' failed: %s %s\n\n",
+ mntp->f_mntonname, strerror(errno), errmsg);
+ return (1);
+}
+
+void
+build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val,
+ size_t len)
+{
+ int i;
+
+ if (*iovlen < 0)
+ return;
+ i = *iovlen;
+ *iov = realloc(*iov, sizeof **iov * (i + 2));
+ if (*iov == NULL) {
+ *iovlen = -1;
+ return;
+ }
+ (*iov)[i].iov_base = strdup(name);
+ (*iov)[i].iov_len = strlen(name) + 1;
+ i++;
+ (*iov)[i].iov_base = val;
+ if (len == (size_t)-1) {
+ if (val != NULL)
+ len = strlen(val) + 1;
+ else
+ len = 0;
+ }
+ (*iov)[i].iov_len = (int)len;
+ *iovlen = ++i;
+}
+
+/*
+ * This function is needed for compatibility with parameters
+ * which used to use the mount_argf() command for the old mount() syscall.
+ */
+void
+build_iovec_argf(struct iovec **iov, int *iovlen, const char *name,
+ const char *fmt, ...)
+{
+ va_list ap;
+ char val[255] = { 0 };
+
+ va_start(ap, fmt);
+ vsnprintf(val, sizeof(val), fmt, ap);
+ va_end(ap);
+ build_iovec(iov, iovlen, name, strdup(val), (size_t)-1);
+}
+
+/*
+ * Free the iovec and reset to NULL with zero length. Useful for calling
+ * nmount in a loop.
+ */
+void
+free_iovec(struct iovec **iov, int *iovlen)
+{
+ int i;
+
+ for (i = 0; i < *iovlen; i += 2)
+ free((*iov)[i].iov_base);
+ free(*iov);
+}
diff --git a/lib/libutil/mntopts.h b/lib/libutil/mntopts.h
new file mode 100644
index 000000000000..0027b8ca7155
--- /dev/null
+++ b/lib/libutil/mntopts.h
@@ -0,0 +1,114 @@
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _MNTOPTS_H_
+#define _MNTOPTS_H_
+
+struct mntopt {
+ const char *m_option; /* option name */
+ int m_inverse; /* if a negative option, e.g. "atime" */
+ long long m_flag; /* bit to set, e.g. MNT_RDONLY */
+ int m_altloc; /* 1 => set bit in altflags */
+};
+
+/* User-visible MNT_ flags. */
+#define MOPT_ASYNC { "async", 0, MNT_ASYNC, 0 }
+#define MOPT_NOATIME { "atime", 1, MNT_NOATIME, 0 }
+#define MOPT_NOEXEC { "exec", 1, MNT_NOEXEC, 0 }
+#define MOPT_NOSUID { "suid", 1, MNT_NOSUID, 0 }
+#define MOPT_NOSYMFOLLOW { "symfollow", 1, MNT_NOSYMFOLLOW, 0 }
+#define MOPT_RDONLY { "rdonly", 0, MNT_RDONLY, 0 }
+#define MOPT_SYNC { "sync", 0, MNT_SYNCHRONOUS, 0 }
+#define MOPT_UNION { "union", 0, MNT_UNION, 0 }
+#define MOPT_USERQUOTA { "userquota", 0, 0, 0 }
+#define MOPT_GROUPQUOTA { "groupquota", 0, 0, 0 }
+#define MOPT_NOCLUSTERR { "clusterr", 1, MNT_NOCLUSTERR, 0 }
+#define MOPT_NOCLUSTERW { "clusterw", 1, MNT_NOCLUSTERW, 0 }
+#define MOPT_SUIDDIR { "suiddir", 0, MNT_SUIDDIR, 0 }
+#define MOPT_SNAPSHOT { "snapshot", 0, MNT_SNAPSHOT, 0 }
+#define MOPT_MULTILABEL { "multilabel", 0, MNT_MULTILABEL, 0 }
+#define MOPT_ACLS { "acls", 0, MNT_ACLS, 0 }
+#define MOPT_NFS4ACLS { "nfsv4acls", 0, MNT_NFS4ACLS, 0 }
+#define MOPT_AUTOMOUNTED { "automounted",0, MNT_AUTOMOUNTED, 0 }
+#define MOPT_UNTRUSTED { "untrusted", 0, MNT_UNTRUSTED, 0 }
+
+/* Control flags. */
+#define MOPT_FORCE { "force", 0, MNT_FORCE, 0 }
+#define MOPT_UPDATE { "update", 0, MNT_UPDATE, 0 }
+#define MOPT_RO { "ro", 0, MNT_RDONLY, 0 }
+#define MOPT_RW { "rw", 1, MNT_RDONLY, 0 }
+#define MOPT_NOCOVER { "cover", 1, MNT_NOCOVER, 0 }
+#define MOPT_EMPTYDIR { "emptydir", 0, MNT_EMPTYDIR, 0 }
+/* This is parsed by mount(8), but is ignored by specific mount_*(8)s. */
+#define MOPT_AUTO { "auto", 0, 0, 0 }
+
+/* A handy macro as terminator of MNT_ array. */
+#define MOPT_END { NULL, 0, 0, 0 }
+
+#define MOPT_FSTAB_COMPAT \
+ MOPT_RO, \
+ MOPT_RW, \
+ MOPT_AUTO
+
+/* Standard options which all mounts can understand. */
+#define MOPT_STDOPTS \
+ MOPT_USERQUOTA, \
+ MOPT_GROUPQUOTA, \
+ MOPT_FSTAB_COMPAT, \
+ MOPT_NOATIME, \
+ MOPT_NOEXEC, \
+ MOPT_SUIDDIR, /* must be before MOPT_NOSUID */ \
+ MOPT_NOSUID, \
+ MOPT_NOSYMFOLLOW, \
+ MOPT_RDONLY, \
+ MOPT_UNION, \
+ MOPT_NOCLUSTERR, \
+ MOPT_NOCLUSTERW, \
+ MOPT_MULTILABEL, \
+ MOPT_ACLS, \
+ MOPT_NFS4ACLS, \
+ MOPT_AUTOMOUNTED, \
+ MOPT_UNTRUSTED, \
+ MOPT_NOCOVER, \
+ MOPT_EMPTYDIR
+
+void getmntopts(const char *, const struct mntopt *, int *, int *);
+void rmslashes(char *, char *);
+int checkpath(const char *, char resolved_path[]);
+int checkpath_allow_file(const char *, char resolved_path[]);
+struct statfs *getmntpoint(const char *);
+int chkdoreload(struct statfs *, void (*)(const char *, ...) __printflike(1,2));
+extern int getmnt_silent;
+void build_iovec(struct iovec **iov, int *iovlen, const char *name, void *val, size_t len);
+void build_iovec_argf(struct iovec **iov, int *iovlen, const char *name, const char *fmt, ...);
+void free_iovec(struct iovec **iovec, int *iovlen);
+
+#endif /* !_MNTOPTS_H_ */
diff --git a/lib/libyaml/Makefile b/lib/libyaml/Makefile
new file mode 100644
index 000000000000..6acd34f178a9
--- /dev/null
+++ b/lib/libyaml/Makefile
@@ -0,0 +1,29 @@
+LIBYAML_DIR= ${SRCTOP}/contrib/libyaml
+
+PACKAGE=lib${LIB}
+LIB= yaml
+PRIVATELIB= true
+SHLIB_MAJOR= 1
+SRCS= api.c \
+ dumper.c \
+ emitter.c \
+ loader.c \
+ parser.c \
+ reader.c \
+ scanner.c \
+ writer.c
+
+.PATH: ${LIBYAML_DIR}/src \
+ ${LIBYAML_DIR}/include
+
+INCS= yaml.h
+
+WARNS?= 1
+CFLAGS+= -I${LIBYAML_DIR}/include \
+ -I${LIBYAML_DIR}/src \
+ -DYAML_VERSION_STRING=\"0.2.5\" \
+ -DYAML_VERSION_MAJOR=0 \
+ -DYAML_VERSION_MINOR=2 \
+ -DYAML_VERSION_PATCH=5
+
+.include <bsd.lib.mk>
diff --git a/lib/msun/aarch64/fenv.h b/lib/msun/aarch64/fenv.h
index 2148a68b053b..a435a9de5223 100644
--- a/lib/msun/aarch64/fenv.h
+++ b/lib/msun/aarch64/fenv.h
@@ -31,6 +31,7 @@
#ifndef _FENV_H_
#define _FENV_H_
+#include <sys/cdefs.h>
#include <sys/_types.h>
#ifndef __fenv_static
diff --git a/lib/msun/arm/fenv.h b/lib/msun/arm/fenv.h
index 5dded5d744fd..e8a30fcf496f 100644
--- a/lib/msun/arm/fenv.h
+++ b/lib/msun/arm/fenv.h
@@ -29,6 +29,7 @@
#ifndef _FENV_H_
#define _FENV_H_
+#include <sys/cdefs.h>
#include <sys/_types.h>
#ifndef __fenv_static
diff --git a/lib/msun/riscv/fenv.h b/lib/msun/riscv/fenv.h
index cc50f0659248..fd50463d479e 100644
--- a/lib/msun/riscv/fenv.h
+++ b/lib/msun/riscv/fenv.h
@@ -36,6 +36,7 @@
#ifndef _FENV_H_
#define _FENV_H_
+#include <sys/cdefs.h>
#include <sys/_types.h>
#ifndef __fenv_static
diff --git a/lib/msun/src/math.h b/lib/msun/src/math.h
index be7b86144738..aecc652ea08a 100644
--- a/lib/msun/src/math.h
+++ b/lib/msun/src/math.h
@@ -15,6 +15,7 @@
#ifndef _MATH_H_
#define _MATH_H_
+#include <sys/cdefs.h>
#include <sys/_types.h>
#include <machine/_limits.h>
diff --git a/lib/msun/src/s_cbrt.c b/lib/msun/src/s_cbrt.c
index 6bf84243adcd..568a36545216 100644
--- a/lib/msun/src/s_cbrt.c
+++ b/lib/msun/src/s_cbrt.c
@@ -90,7 +90,7 @@ cbrt(double x)
* the result is larger in magnitude than cbrt(x) but not much more than
* 2 23-bit ulps larger). With rounding towards zero, the error bound
* would be ~5/6 instead of ~4/6. With a maximum error of 2 23-bit ulps
- * in the rounded t, the infinite-precision error in the Newton
+ * in the rounded t, the infinite-precision error in the Halley
* approximation barely affects third digit in the final error
* 0.667; the error in the rounded t can be up to about 3 23-bit ulps
* before the final error is larger than 0.667 ulps.
@@ -99,7 +99,7 @@ cbrt(double x)
u.bits=(u.bits+0x80000000)&0xffffffffc0000000ULL;
t=u.value;
- /* one step Newton iteration to 53 bits with error < 0.667 ulps */
+ /* one step Halley iteration to 53 bits with error < 0.667 ulps */
s=t*t; /* t*t is exact */
r=x/s; /* error <= 0.5 ulps; |r| < |t| */
w=t+t; /* t+t is exact */
diff --git a/lib/msun/src/s_cbrtf.c b/lib/msun/src/s_cbrtf.c
index a225d3edb982..c69e0fa5be12 100644
--- a/lib/msun/src/s_cbrtf.c
+++ b/lib/msun/src/s_cbrtf.c
@@ -50,7 +50,7 @@ cbrtf(float x)
SET_FLOAT_WORD(t,sign|(hx/3+B1));
/*
- * First step Newton iteration (solving t*t-x/t == 0) to 16 bits. In
+ * First step Halley iteration (solving t*t-x/t == 0) to 16 bits. In
* double precision so that its terms can be arranged for efficiency
* without causing overflow or underflow.
*/
@@ -59,7 +59,7 @@ cbrtf(float x)
T=T*((double)x+x+r)/(x+r+r);
/*
- * Second step Newton iteration to 47 bits. In double precision for
+ * Second step Halley iteration to 47 bits. In double precision for
* efficiency and accuracy.
*/
r=T*T*T;
diff --git a/lib/msun/src/s_cbrtl.c b/lib/msun/src/s_cbrtl.c
index f1950e2d4cef..ff527cc5e5e7 100644
--- a/lib/msun/src/s_cbrtl.c
+++ b/lib/msun/src/s_cbrtl.c
@@ -126,7 +126,7 @@ cbrtl(long double x)
#endif
/*
- * Final step Newton iteration to 64 or 113 bits with
+ * Final step Halley iteration to 64 or 113 bits with
* error < 0.667 ulps
*/
s=t*t; /* t*t is exact */
diff --git a/lib/ncurses/ncurses/Makefile b/lib/ncurses/ncurses/Makefile
index 254f05a1e740..512a452ad6d0 100644
--- a/lib/ncurses/ncurses/Makefile
+++ b/lib/ncurses/ncurses/Makefile
@@ -8,8 +8,6 @@ SHLIBDIR?= /lib
LIB= ncursesw
SHLIB_MAJOR= 9
-NO_LINT=
-
GENSRCS= \
expanded.c \
lib_gen.c
diff --git a/lib/ncurses/tinfo/Makefile b/lib/ncurses/tinfo/Makefile
index e11d0e15245e..920bd6e5559c 100644
--- a/lib/ncurses/tinfo/Makefile
+++ b/lib/ncurses/tinfo/Makefile
@@ -8,8 +8,6 @@ SHLIBDIR?= /lib
LIB= tinfow
SHLIB_MAJOR= 9
-NO_LINT=
-
NCURSES_MAJOR!= egrep 'NCURSES_MAJOR[ ]*=' ${NCURSES_DIR}/dist.mk | sed -e 's%^[^0-9]*%%'
NCURSES_MINOR!= egrep 'NCURSES_MINOR[ ]*=' ${NCURSES_DIR}/dist.mk | sed -e 's%^[^0-9]*%%'
NCURSES_PATCH!= egrep 'NCURSES_PATCH[ ]*=' ${NCURSES_DIR}/dist.mk | sed -e 's%^[^0-9]*%%'
diff --git a/lib/ofed/libibnetdisc/Makefile b/lib/ofed/libibnetdisc/Makefile
index d3e0dd92509a..aac0bf0f5971 100644
--- a/lib/ofed/libibnetdisc/Makefile
+++ b/lib/ofed/libibnetdisc/Makefile
@@ -29,7 +29,6 @@ LIBADD= osmcomp ibmad ibumad
CFLAGS+= -DHAVE_CONFIG_H=1
CFLAGS+= -I${_spath}
CFLAGS+= -I${SYSROOT:U${DESTDIR}}/${INCLUDEDIR}/infiniband
-CXXSTD= c++11
VERSION_MAP= ${_spath}/libibnetdisc.map
.include <bsd.lib.mk>