aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/checklist.yml1
-rw-r--r--Makefile.inc124
-rw-r--r--ObsoleteFiles.inc3
-rw-r--r--UPDATING6
-rw-r--r--bin/df/df.16
-rw-r--r--bin/ps/ps.16
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/dtrace.13
-rw-r--r--contrib/bmake/ChangeLog27
-rw-r--r--contrib/bmake/FILES8
-rw-r--r--contrib/bmake/VERSION2
-rw-r--r--contrib/bmake/arch.c6
-rw-r--r--contrib/bmake/bmake.179
-rw-r--r--contrib/bmake/bmake.cat145
-rw-r--r--contrib/bmake/compat.c11
-rw-r--r--contrib/bmake/cond.c89
-rw-r--r--contrib/bmake/for.c12
-rw-r--r--contrib/bmake/job.c42
-rw-r--r--contrib/bmake/job.h4
-rw-r--r--contrib/bmake/main.c54
-rw-r--r--contrib/bmake/make.179
-rw-r--r--contrib/bmake/make.c6
-rw-r--r--contrib/bmake/make.h5
-rw-r--r--contrib/bmake/make_malloc.c7
-rw-r--r--contrib/bmake/mk/ChangeLog4
-rw-r--r--contrib/bmake/mk/prog.mk8
-rw-r--r--contrib/bmake/parse.c19
-rw-r--r--contrib/bmake/str.c9
-rw-r--r--contrib/bmake/unit-tests/Makefile7
-rw-r--r--contrib/bmake/unit-tests/char-005c-reverse-solidus.exp13
-rw-r--r--contrib/bmake/unit-tests/char-005c-reverse-solidus.mk131
-rw-r--r--contrib/bmake/unit-tests/check-expect.lua219
-rw-r--r--contrib/bmake/unit-tests/cmd-errors-jobs.exp4
-rw-r--r--contrib/bmake/unit-tests/cmd-errors-jobs.mk6
-rw-r--r--contrib/bmake/unit-tests/cmd-errors-lint.exp2
-rw-r--r--contrib/bmake/unit-tests/cmd-errors-lint.mk4
-rw-r--r--contrib/bmake/unit-tests/cmd-errors.exp2
-rw-r--r--contrib/bmake/unit-tests/cmd-errors.mk4
-rw-r--r--contrib/bmake/unit-tests/cmdline-undefined.exp20
-rw-r--r--contrib/bmake/unit-tests/cmdline-undefined.mk26
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-numeric-eq.exp4
-rwxr-xr-xcontrib/bmake/unit-tests/cond-cmp-numeric-eq.mk6
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-numeric.exp8
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-numeric.mk10
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-string.exp16
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-string.mk18
-rw-r--r--contrib/bmake/unit-tests/cond-eof.exp6
-rw-r--r--contrib/bmake/unit-tests/cond-eof.mk8
-rw-r--r--contrib/bmake/unit-tests/cond-func-defined.exp4
-rw-r--r--contrib/bmake/unit-tests/cond-func-defined.mk6
-rw-r--r--contrib/bmake/unit-tests/cond-func-make.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-func-make.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-func.exp12
-rw-r--r--contrib/bmake/unit-tests/cond-func.mk14
-rw-r--r--contrib/bmake/unit-tests/cond-late.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-late.mk16
-rw-r--r--contrib/bmake/unit-tests/cond-op-and-lint.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-op-and-lint.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-op-and.exp10
-rw-r--r--contrib/bmake/unit-tests/cond-op-and.mk12
-rw-r--r--contrib/bmake/unit-tests/cond-op-not.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-op-not.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-op-or-lint.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-op-or-lint.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-op-or.exp10
-rw-r--r--contrib/bmake/unit-tests/cond-op-or.mk12
-rw-r--r--contrib/bmake/unit-tests/cond-op-parentheses.exp8
-rw-r--r--contrib/bmake/unit-tests/cond-op-parentheses.mk10
-rw-r--r--contrib/bmake/unit-tests/cond-op.exp14
-rw-r--r--contrib/bmake/unit-tests/cond-op.mk16
-rw-r--r--contrib/bmake/unit-tests/cond-short.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-short.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-token-number.exp8
-rw-r--r--contrib/bmake/unit-tests/cond-token-number.mk10
-rw-r--r--contrib/bmake/unit-tests/cond-token-plain.exp24
-rw-r--r--contrib/bmake/unit-tests/cond-token-plain.mk50
-rw-r--r--contrib/bmake/unit-tests/cond-token-string.exp2
-rw-r--r--contrib/bmake/unit-tests/cond-token-string.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-token-var.exp6
-rw-r--r--contrib/bmake/unit-tests/cond-token-var.mk8
-rw-r--r--contrib/bmake/unit-tests/dep-op-missing.exp2
-rw-r--r--contrib/bmake/unit-tests/deptgt-begin.exp2
-rw-r--r--contrib/bmake/unit-tests/deptgt-begin.mk6
-rw-r--r--contrib/bmake/unit-tests/deptgt-path-suffix.exp2
-rw-r--r--contrib/bmake/unit-tests/deptgt-path-suffix.mk4
-rw-r--r--contrib/bmake/unit-tests/deptgt.exp6
-rw-r--r--contrib/bmake/unit-tests/deptgt.mk8
-rwxr-xr-xcontrib/bmake/unit-tests/directive-dinclude.exp2
-rwxr-xr-xcontrib/bmake/unit-tests/directive-dinclude.mk4
-rw-r--r--contrib/bmake/unit-tests/directive-export-gmake.exp2
-rw-r--r--contrib/bmake/unit-tests/directive-export-gmake.mk4
-rw-r--r--contrib/bmake/unit-tests/directive-for-errors.exp6
-rw-r--r--contrib/bmake/unit-tests/directive-for-errors.mk8
-rw-r--r--contrib/bmake/unit-tests/directive-for-escape.exp10
-rw-r--r--contrib/bmake/unit-tests/directive-for-escape.mk12
-rw-r--r--contrib/bmake/unit-tests/directive-for-lines.exp12
-rw-r--r--contrib/bmake/unit-tests/directive-for-lines.mk20
-rwxr-xr-xcontrib/bmake/unit-tests/directive-for.exp22
-rwxr-xr-xcontrib/bmake/unit-tests/directive-for.mk23
-rwxr-xr-xcontrib/bmake/unit-tests/directive-hyphen-include.exp2
-rwxr-xr-xcontrib/bmake/unit-tests/directive-hyphen-include.mk4
-rw-r--r--contrib/bmake/unit-tests/directive-if.exp2
-rw-r--r--contrib/bmake/unit-tests/directive-if.mk4
-rwxr-xr-xcontrib/bmake/unit-tests/directive-include.exp2
-rwxr-xr-xcontrib/bmake/unit-tests/directive-include.mk4
-rw-r--r--contrib/bmake/unit-tests/directive-misspellings.exp8
-rw-r--r--contrib/bmake/unit-tests/directive-misspellings.mk10
-rwxr-xr-xcontrib/bmake/unit-tests/directive-sinclude.exp2
-rwxr-xr-xcontrib/bmake/unit-tests/directive-sinclude.mk4
-rw-r--r--contrib/bmake/unit-tests/directive-unexport.exp2
-rw-r--r--contrib/bmake/unit-tests/directive-unexport.mk3
-rw-r--r--contrib/bmake/unit-tests/directive-warning.exp6
-rw-r--r--contrib/bmake/unit-tests/directive-warning.mk5
-rw-r--r--contrib/bmake/unit-tests/directive.exp4
-rw-r--r--contrib/bmake/unit-tests/directive.mk6
-rw-r--r--contrib/bmake/unit-tests/moderrs.exp14
-rw-r--r--contrib/bmake/unit-tests/moderrs.mk16
-rw-r--r--contrib/bmake/unit-tests/opt-debug-file.exp6
-rw-r--r--contrib/bmake/unit-tests/opt-debug-file.mk14
-rw-r--r--contrib/bmake/unit-tests/opt-debug-lint.exp4
-rw-r--r--contrib/bmake/unit-tests/opt-debug-lint.mk6
-rw-r--r--contrib/bmake/unit-tests/opt-jobs-internal.exp18
-rw-r--r--contrib/bmake/unit-tests/parse.exp6
-rw-r--r--contrib/bmake/unit-tests/parse.mk8
-rw-r--r--contrib/bmake/unit-tests/var-op-assign.exp2
-rw-r--r--contrib/bmake/unit-tests/var-op-assign.mk4
-rw-r--r--contrib/bmake/unit-tests/var-op-expand.exp14
-rw-r--r--contrib/bmake/unit-tests/var-op-expand.mk8
-rw-r--r--contrib/bmake/unit-tests/varmisc.exp2
-rw-r--r--contrib/bmake/unit-tests/varmisc.mk4
-rw-r--r--contrib/bmake/unit-tests/varmod-edge.exp4
-rw-r--r--contrib/bmake/unit-tests/varmod-edge.mk6
-rw-r--r--contrib/bmake/unit-tests/varmod-ifelse.exp43
-rw-r--r--contrib/bmake/unit-tests/varmod-ifelse.mk11
-rwxr-xr-xcontrib/bmake/unit-tests/varmod-match-escape.exp14
-rwxr-xr-xcontrib/bmake/unit-tests/varmod-match-escape.mk10
-rw-r--r--contrib/bmake/unit-tests/varmod-match.exp20
-rw-r--r--contrib/bmake/unit-tests/varmod-match.mk28
-rw-r--r--contrib/bmake/unit-tests/varmod-mtime.exp6
-rw-r--r--contrib/bmake/unit-tests/varmod-mtime.mk8
-rw-r--r--contrib/bmake/unit-tests/varmod-order.exp6
-rw-r--r--contrib/bmake/unit-tests/varmod-order.mk8
-rw-r--r--contrib/bmake/unit-tests/varmod-range.exp2
-rw-r--r--contrib/bmake/unit-tests/varmod-range.mk4
-rw-r--r--contrib/bmake/unit-tests/varmod.exp49
-rw-r--r--contrib/bmake/unit-tests/varmod.mk49
-rw-r--r--contrib/bmake/unit-tests/varname-circumflex.exp9
-rw-r--r--contrib/bmake/unit-tests/varname-circumflex.mk47
-rw-r--r--contrib/bmake/unit-tests/varname-vpath.exp8
-rw-r--r--contrib/bmake/unit-tests/varname.exp4
-rw-r--r--contrib/bmake/unit-tests/varname.mk6
-rw-r--r--contrib/bmake/unit-tests/varparse-errors.exp28
-rw-r--r--contrib/bmake/unit-tests/varparse-errors.mk30
-rw-r--r--contrib/bmake/var.c38
-rw-r--r--contrib/bsnmp/lib/snmpclient.c12
-rw-r--r--contrib/bsnmp/lib/snmpclient.h1
-rw-r--r--contrib/bsnmp/lib/snmppriv.h1
-rw-r--r--contrib/bsnmp/snmpd/main.c17
-rw-r--r--contrib/bsnmp/snmpd/trans_lsock.c2
-rw-r--r--contrib/elftoolchain/libelf/elf_open.35
-rw-r--r--contrib/elftoolchain/libelf/gelf_xlatetof.311
-rw-r--r--contrib/less/NEWS10
-rw-r--r--contrib/less/decode.c2
-rw-r--r--contrib/less/help.c2
-rw-r--r--contrib/less/less.h9
-rw-r--r--contrib/less/less.nro2
-rw-r--r--contrib/less/lessecho.nro2
-rw-r--r--contrib/less/lesskey.nro2
-rw-r--r--contrib/less/os.c6
-rw-r--r--contrib/less/version.c4
-rw-r--r--contrib/libbegemot/rpoll.c22
-rw-r--r--contrib/tzcode/localtime.c34
-rw-r--r--lib/libc/gen/fdopendir.c10
-rw-r--r--lib/libc/stdio/fdopen.c18
-rw-r--r--lib/libc/stdio/freopen.c10
-rw-r--r--lib/libc/stdtime/Makefile.inc1
-rw-r--r--lib/libc/stdtime/Symbol.map6
-rw-r--r--lib/libc/tests/stdtime/Makefile5
-rw-r--r--lib/libc/tests/stdtime/detect_tz_changes_test.c281
-rw-r--r--lib/libfetch/common.c7
-rw-r--r--lib/libsecureboot/h/libsecureboot.h1
-rw-r--r--lib/libsys/fhopen.24
-rw-r--r--lib/libsys/statfs.26
-rw-r--r--libexec/rc/rc.conf2
-rwxr-xr-xlibexec/rc/rc.d/pf2
-rw-r--r--release/Makefile3
-rwxr-xr-xrelease/amd64/make-memstick.sh7
-rw-r--r--release/amd64/mkisoimages.sh13
-rwxr-xr-xrelease/arm64/make-memstick.sh5
-rw-r--r--release/arm64/mkisoimages.sh13
-rwxr-xr-xrelease/i386/make-memstick.sh9
-rw-r--r--release/i386/mkisoimages.sh5
-rw-r--r--release/packages/Makefile.package193
-rw-r--r--release/packages/certctl.ucl9
-rw-r--r--release/packages/clang-all.ucl1
-rwxr-xr-xrelease/packages/generate-ucl.lua155
-rwxr-xr-xrelease/packages/generate-ucl.sh102
-rw-r--r--release/packages/lld-all.ucl1
-rw-r--r--release/packages/lldb-all.ucl1
-rw-r--r--release/packages/ssh-all.ucl1
-rw-r--r--release/packages/template.ucl6
-rw-r--r--release/packages/ucl/acct-all.ucl4
-rw-r--r--release/packages/ucl/acpi-all.ucl4
-rw-r--r--release/packages/ucl/amd-all.ucl4
-rw-r--r--release/packages/ucl/apm-all.ucl4
-rw-r--r--release/packages/ucl/at-all.ucl4
-rw-r--r--release/packages/ucl/audit-all.ucl4
-rw-r--r--release/packages/ucl/autofs-all.ucl4
-rw-r--r--release/packages/ucl/bhyve-all.ucl4
-rw-r--r--release/packages/ucl/blocklist-all.ucl4
-rw-r--r--release/packages/ucl/bluetooth-all.ucl4
-rw-r--r--release/packages/ucl/bootloader-all.ucl4
-rw-r--r--release/packages/ucl/bsdinstall-all.ucl4
-rw-r--r--release/packages/ucl/bsnmp-all.ucl4
-rw-r--r--release/packages/ucl/caroot-all.ucl4
-rw-r--r--release/packages/ucl/caroot.ucl10
-rw-r--r--release/packages/ucl/ccdconfig-all.ucl5
-rw-r--r--release/packages/ucl/certctl-all.ucl4
-rw-r--r--release/packages/ucl/certctl.ucl6
-rw-r--r--release/packages/ucl/clang-all.ucl5
-rw-r--r--release/packages/ucl/clang.ucl11
-rw-r--r--release/packages/ucl/clibs-all.ucl4
-rw-r--r--release/packages/ucl/clibs.ucl (renamed from release/packages/clibs.ucl)0
-rw-r--r--release/packages/ucl/console-tools-all.ucl4
-rw-r--r--release/packages/ucl/cron-all.ucl4
-rw-r--r--release/packages/ucl/csh-all.ucl4
-rw-r--r--release/packages/ucl/ctf-tools-all.ucl4
-rw-r--r--release/packages/ucl/ctl-all.ucl4
-rw-r--r--release/packages/ucl/cxgbe-tools-all.ucl4
-rw-r--r--release/packages/ucl/devd-all.ucl4
-rw-r--r--release/packages/ucl/devmatch-all.ucl4
-rw-r--r--release/packages/ucl/dhclient-all.ucl4
-rw-r--r--release/packages/ucl/dma-all.ucl4
-rw-r--r--release/packages/ucl/docs-all.ucl4
-rw-r--r--release/packages/ucl/dtb-all.ucl4
-rw-r--r--release/packages/ucl/dtrace-all.ucl4
-rw-r--r--release/packages/ucl/dwatch-all.ucl4
-rw-r--r--release/packages/ucl/ee-all.ucl4
-rw-r--r--release/packages/ucl/efi-tools-all.ucl4
-rw-r--r--release/packages/ucl/examples-all.ucl4
-rw-r--r--release/packages/ucl/fd-all.ucl4
-rw-r--r--release/packages/ucl/fetch-all.ucl4
-rw-r--r--release/packages/ucl/firmware-iwm-all.ucl4
-rw-r--r--release/packages/ucl/ftp-all.ucl4
-rw-r--r--release/packages/ucl/ftpd-all.ucl4
-rw-r--r--release/packages/ucl/fwget-all.ucl4
-rw-r--r--release/packages/ucl/games-all.ucl4
-rw-r--r--release/packages/ucl/geom-all.ucl4
-rw-r--r--release/packages/ucl/ggate-all.ucl4
-rw-r--r--release/packages/ucl/hast-all.ucl4
-rw-r--r--release/packages/ucl/hostapd-all.ucl4
-rw-r--r--release/packages/ucl/hyperv-tools-all.ucl4
-rw-r--r--release/packages/ucl/inetd-all.ucl4
-rw-r--r--release/packages/ucl/ipf-all.ucl4
-rw-r--r--release/packages/ucl/ipfw-all.ucl4
-rw-r--r--release/packages/ucl/iscsi-all.ucl6
-rw-r--r--release/packages/ucl/jail-all.ucl4
-rw-r--r--release/packages/ucl/kerberos-all.ucl4
-rw-r--r--release/packages/ucl/kerberos-lib-all.ucl4
-rw-r--r--release/packages/ucl/kernel-all.ucl4
-rw-r--r--release/packages/ucl/lib9p-all.ucl5
-rw-r--r--release/packages/ucl/libarchive-all.ucl4
-rw-r--r--release/packages/ucl/libbegemot-all.ucl5
-rw-r--r--release/packages/ucl/libblocksruntime-all.ucl4
-rw-r--r--release/packages/ucl/libbsdstat-all.ucl5
-rw-r--r--release/packages/ucl/libbsm-all.ucl6
-rw-r--r--release/packages/ucl/libbz2-all.ucl5
-rw-r--r--release/packages/ucl/libcasper-all.ucl5
-rw-r--r--release/packages/ucl/libcompat-all.ucl4
-rw-r--r--release/packages/ucl/libcompiler_rt-all.ucl4
-rw-r--r--release/packages/ucl/libcuse-all.ucl5
-rw-r--r--release/packages/ucl/libdwarf-all.ucl6
-rw-r--r--release/packages/ucl/libevent1-all.ucl4
-rw-r--r--release/packages/ucl/libexecinfo-all.ucl5
-rw-r--r--release/packages/ucl/libipt-all.ucl6
-rw-r--r--release/packages/ucl/libldns-all.ucl6
-rw-r--r--release/packages/ucl/liblzma-all.ucl5
-rw-r--r--release/packages/ucl/libmagic-all.ucl5
-rw-r--r--release/packages/ucl/libopencsd-all.ucl5
-rw-r--r--release/packages/ucl/libpathconv-all.ucl5
-rw-r--r--release/packages/ucl/librpcsec_gss-all.ucl5
-rw-r--r--release/packages/ucl/librss-all.ucl5
-rw-r--r--release/packages/ucl/libsdp-all.ucl5
-rw-r--r--release/packages/ucl/libsqlite3-all.ucl4
-rw-r--r--release/packages/ucl/libstdbuf-all.ucl6
-rw-r--r--release/packages/ucl/libstdthreads-all.ucl4
-rw-r--r--release/packages/ucl/libthread_db-all.ucl5
-rw-r--r--release/packages/ucl/libucl-all.ucl5
-rw-r--r--release/packages/ucl/libufs-all.ucl8
-rw-r--r--release/packages/ucl/libvgl-all.ucl13
-rw-r--r--release/packages/ucl/libvmmapi-all.ucl4
-rw-r--r--release/packages/ucl/liby-all.ucl5
-rw-r--r--release/packages/ucl/libyaml-all.ucl5
-rw-r--r--release/packages/ucl/libzfs-all.ucl5
-rw-r--r--release/packages/ucl/lld-all.ucl6
-rw-r--r--release/packages/ucl/lldb-all.ucl6
-rw-r--r--release/packages/ucl/locales-all.ucl4
-rw-r--r--release/packages/ucl/lp-all.ucl4
-rw-r--r--release/packages/ucl/manuals-all.ucl4
-rw-r--r--release/packages/ucl/mlx-tools-all.ucl4
-rw-r--r--release/packages/ucl/mtree-all.ucl4
-rw-r--r--release/packages/ucl/natd-all.ucl4
-rw-r--r--release/packages/ucl/netmap-all.ucl4
-rw-r--r--release/packages/ucl/newsyslog-all.ucl4
-rw-r--r--release/packages/ucl/nfs-all.ucl4
-rw-r--r--release/packages/ucl/ntp-all.ucl4
-rw-r--r--release/packages/ucl/nuageinit-all.ucl4
-rw-r--r--release/packages/ucl/nvme-tools-all.ucl4
-rw-r--r--release/packages/ucl/openssl-all.ucl4
-rw-r--r--release/packages/ucl/openssl-lib-all.ucl4
-rw-r--r--release/packages/ucl/periodic-all.ucl4
-rw-r--r--release/packages/ucl/periodic.ucl6
-rw-r--r--release/packages/ucl/pf-all.ucl4
-rw-r--r--release/packages/ucl/pkg-bootstrap-all.ucl4
-rw-r--r--release/packages/ucl/ppp-all.ucl5
-rw-r--r--release/packages/ucl/quotacheck-all.ucl8
-rw-r--r--release/packages/ucl/rc-all.ucl4
-rw-r--r--release/packages/ucl/rcmds-all.ucl7
-rw-r--r--release/packages/ucl/rcmds.ucl8
-rw-r--r--release/packages/ucl/rdma-all.ucl1
-rw-r--r--release/packages/ucl/rescue-all.ucl4
-rw-r--r--release/packages/ucl/resolvconf-all.ucl4
-rw-r--r--release/packages/ucl/runtime-all.ucl4
-rw-r--r--release/packages/ucl/runtime.ucl (renamed from release/packages/runtime.ucl)0
-rw-r--r--release/packages/ucl/sendmail-all.ucl4
-rw-r--r--release/packages/ucl/smbutils-all.ucl4
-rw-r--r--release/packages/ucl/src-all.ucl5
-rw-r--r--release/packages/ucl/src-sys-all.ucl5
-rw-r--r--release/packages/ucl/ssh-all.ucl5
-rw-r--r--release/packages/ucl/syscons-data-all.ucl4
-rw-r--r--release/packages/ucl/syslogd-all.ucl4
-rw-r--r--release/packages/ucl/tcpd-all.ucl4
-rw-r--r--release/packages/ucl/telnet-all.ucl4
-rw-r--r--release/packages/ucl/tests-all.ucl4
-rw-r--r--release/packages/ucl/toolchain-all.ucl4
-rw-r--r--release/packages/ucl/ufs-all.ucl4
-rw-r--r--release/packages/ucl/unbound-all.ucl5
-rw-r--r--release/packages/ucl/utilities-all.ucl4
-rw-r--r--release/packages/ucl/utilities.ucl (renamed from release/packages/utilities.ucl)0
-rw-r--r--release/packages/ucl/vi-all.ucl4
-rw-r--r--release/packages/ucl/vt-data-all.ucl4
-rw-r--r--release/packages/ucl/wpa-all.ucl4
-rw-r--r--release/packages/ucl/yp-all.ucl7
-rw-r--r--release/packages/ucl/zfs-all.ucl4
-rw-r--r--release/packages/ucl/zoneinfo-all.ucl5
-rw-r--r--release/packages/unbound-all.ucl1
-rw-r--r--release/powerpc/mkisoimages.sh5
-rwxr-xr-xrelease/riscv/make-memstick.sh5
-rw-r--r--release/riscv/mkisoimages.sh13
-rw-r--r--release/scripts/tools.subr13
-rw-r--r--release/tools/vmimage.subr7
-rw-r--r--sbin/kldstat/kldstat.c4
-rw-r--r--sbin/mount/mount.86
-rw-r--r--sbin/pfctl/parse.y46
-rw-r--r--sbin/pfctl/pfctl.c15
-rw-r--r--sbin/pfctl/pfctl_parser.c5
-rw-r--r--sbin/pfctl/tests/files/pf0088.in2
-rw-r--r--sbin/pfctl/tests/files/pf0088.ok2
-rw-r--r--sbin/pfctl/tests/files/pf1072.fail1
-rw-r--r--sbin/pfctl/tests/files/pf1072.in1
-rw-r--r--sbin/pfctl/tests/pfctl_test_list.inc1
-rw-r--r--sbin/route/route_netlink.c1
-rw-r--r--sbin/savecore/savecore.86
-rw-r--r--share/man/man4/Makefile7
-rw-r--r--share/man/man4/dtrace_fbt.4332
-rw-r--r--share/man/man4/dtrace_kinst.412
-rw-r--r--share/man/man4/md.44
-rw-r--r--share/man/man4/mtw.478
-rw-r--r--share/man/man4/sa.43
-rw-r--r--share/man/man4/snd_uaudio.436
-rw-r--r--share/man/man4/ufshci.4181
-rw-r--r--share/man/man5/pf.conf.517
-rw-r--r--share/man/man5/rc.conf.56
-rw-r--r--share/man/man7/arch.72
-rw-r--r--share/man/man9/vnode.94
-rw-r--r--share/misc/committers-src.dot5
-rw-r--r--stand/common/dev_net.c57
-rw-r--r--stand/libsa/bootp.c78
-rw-r--r--stand/libsa/pkgfs.c33
-rw-r--r--stand/libsa/stand.h13
-rw-r--r--stand/libsa/zfs/zfsimpl.c52
-rw-r--r--sys/amd64/amd64/apic_vector.S6
-rw-r--r--sys/amd64/amd64/pmap.c77
-rw-r--r--sys/amd64/include/pmap.h7
-rw-r--r--sys/amd64/include/vmparam.h8
-rw-r--r--sys/amd64/pt/pt.c978
-rw-r--r--sys/amd64/pt/pt.h49
-rw-r--r--sys/amd64/vmm/intel/vmx_support.S6
-rw-r--r--sys/arm64/arm64/pmap.c12
-rw-r--r--sys/arm64/broadcom/genet/if_genet.c4
-rw-r--r--sys/cddl/boot/zfs/zfsimpl.h2
-rw-r--r--sys/conf/files13
-rw-r--r--sys/conf/files.amd644
-rw-r--r--sys/dev/gpio/gpiobus.c24
-rw-r--r--sys/dev/ice/ice_features.h2
-rw-r--r--sys/dev/ice/ice_iflib.h16
-rw-r--r--sys/dev/ice/ice_iov.c1856
-rw-r--r--sys/dev/ice/ice_iov.h125
-rw-r--r--sys/dev/ice/ice_lib.c28
-rw-r--r--sys/dev/ice/ice_lib.h4
-rw-r--r--sys/dev/ice/ice_vf_mbx.c471
-rw-r--r--sys/dev/ice/ice_vf_mbx.h67
-rw-r--r--sys/dev/ice/if_ice_iflib.c132
-rw-r--r--sys/dev/md/md.c6
-rw-r--r--sys/dev/mgb/if_mgb.c2
-rw-r--r--sys/dev/mlx5/mlx5_accel/ipsec.h8
-rw-r--r--sys/dev/mlx5/mlx5_accel/mlx5_ipsec_rxtx.c16
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c3
-rw-r--r--sys/dev/mlx5/mlx5_en/mlx5_en_rx.c2
-rw-r--r--sys/dev/qlnx/qlnxe/qlnx_os.c6
-rw-r--r--sys/dev/random/fortuna.c7
-rw-r--r--sys/dev/random/random_harvestq.c232
-rw-r--r--sys/dev/random/random_harvestq.h2
-rw-r--r--sys/dev/random/randomdev.c2
-rw-r--r--sys/dev/ufshci/ufshci_private.h4
-rw-r--r--sys/dev/ufshci/ufshci_req_sdb.c45
-rw-r--r--sys/fs/fdescfs/fdesc_vnops.c9
-rw-r--r--sys/fs/msdosfs/msdosfs_conv.c11
-rw-r--r--sys/fs/nfs/nfs_commonsubs.c32
-rw-r--r--sys/fs/nfs/nfs_var.h8
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c3
-rw-r--r--sys/fs/nfsclient/nfs_clstate.c2
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c41
-rw-r--r--sys/fs/nfsserver/nfs_nfsdserv.c34
-rw-r--r--sys/fs/p9fs/p9fs_vnops.c8
-rw-r--r--sys/fs/udf/ecma167-udf.h4
-rw-r--r--sys/fs/udf/udf_vfsops.c7
-rw-r--r--sys/fs/udf/udf_vnops.c48
-rw-r--r--sys/i386/i386/pmap.c10
-rw-r--r--sys/kern/subr_asan.c3
-rw-r--r--sys/kern/sys_generic.c6
-rw-r--r--sys/kern/vfs_cache.c13
-rw-r--r--sys/kern/vfs_inotify.c5
-rw-r--r--sys/modules/Makefile2
-rw-r--r--sys/modules/ice/Makefile1
-rw-r--r--sys/modules/pt/Makefile8
-rw-r--r--sys/modules/qlnx/qlnxe/Makefile1
-rw-r--r--sys/net/ethernet.h6
-rw-r--r--sys/net/if_ethersubr.c5
-rw-r--r--sys/net/pfvar.h1
-rw-r--r--sys/net80211/ieee80211_hostap.c7
-rw-r--r--sys/net80211/ieee80211_ht.c13
-rw-r--r--sys/net80211/ieee80211_vht.c4
-rw-r--r--sys/net80211/ieee80211_vht.h3
-rw-r--r--sys/netinet/tcp_hpts.c73
-rw-r--r--sys/netinet/tcp_hpts.h17
-rw-r--r--sys/netinet/tcp_input.c17
-rw-r--r--sys/netinet/tcp_log_buf.c2
-rw-r--r--sys/netinet/tcp_log_buf.h8
-rw-r--r--sys/netinet6/mld6.c29
-rw-r--r--sys/netinet6/raw_ip6.c3
-rw-r--r--sys/netipsec/ipsec.c6
-rw-r--r--sys/netipsec/ipsec_offload.c25
-rw-r--r--sys/netipsec/ipsec_offload.h16
-rw-r--r--sys/netipsec/key.c2
-rw-r--r--sys/netlink/netlink_message_parser.h3
-rw-r--r--sys/netpfil/pf/if_pflog.c4
-rw-r--r--sys/netpfil/pf/if_pfsync.c11
-rw-r--r--sys/netpfil/pf/pf.c28
-rw-r--r--sys/netpfil/pf/pf.h2
-rw-r--r--sys/netpfil/pf/pf_ioctl.c250
-rw-r--r--sys/netpfil/pf/pf_lb.c9
-rw-r--r--sys/netpfil/pf/pf_table.c23
-rw-r--r--sys/rpc/clnt_rc.c7
-rw-r--r--sys/rpc/rpcsec_gss/rpcsec_gss.c14
-rw-r--r--sys/rpc/rpcsec_tls/rpctls_impl.c8
-rw-r--r--sys/sys/exterrvar.h1
-rw-r--r--sys/sys/inotify.h14
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/random.h3
-rw-r--r--sys/vm/swap_pager.c23
-rw-r--r--sys/vm/vm_pagequeue.h6
-rwxr-xr-xtests/ci/tools/freebsdci9
-rw-r--r--tests/sys/kern/Makefile1
-rw-r--r--tests/sys/kern/exterr_test.c108
-rwxr-xr-xtests/sys/netinet6/addr6.sh25
-rw-r--r--tests/sys/netpfil/pf/mbuf.sh6
-rw-r--r--tests/sys/netpfil/pf/nat64.py15
-rw-r--r--tools/build/mk/OptionalObsoleteFiles.inc4
-rw-r--r--tools/test/stress2/misc/all.exclude8
-rwxr-xr-xtools/test/stress2/misc/fullpath2.sh2
-rwxr-xr-xtools/test/stress2/misc/syzkaller80.sh320
-rwxr-xr-xtools/test/stress2/misc/syzkaller81.sh72
-rw-r--r--usr.bin/bmake/Makefile.config2
-rw-r--r--usr.bin/bmake/unit-tests/Makefile7
-rw-r--r--usr.bin/calendar/calendars/calendar.freebsd1
-rw-r--r--usr.bin/du/du.16
-rw-r--r--usr.bin/iscsictl/iscsictl.86
-rw-r--r--usr.bin/last/last.16
-rw-r--r--usr.bin/netstat/netstat.16
-rw-r--r--usr.bin/nfsstat/nfsstat.14
-rw-r--r--usr.bin/procstat/procstat.16
-rw-r--r--usr.bin/sed/sed.111
-rw-r--r--usr.bin/sockstat/sockstat.16
-rw-r--r--usr.bin/sockstat/sockstat.c74
-rw-r--r--usr.bin/top/top.13
-rw-r--r--usr.bin/vmstat/vmstat.86
-rw-r--r--usr.bin/w/w.16
-rw-r--r--usr.bin/wc/wc.16
-rw-r--r--usr.sbin/arp/arp.86
-rwxr-xr-xusr.sbin/bsdinstall/scripts/wlanconfig8
-rw-r--r--usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c6
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c9
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h1
-rw-r--r--usr.sbin/certctl/certctl.810
-rwxr-xr-xusr.sbin/certctl/certctl.sh22
-rw-r--r--usr.sbin/efitable/efitable.84
-rw-r--r--usr.sbin/fwget/Makefile2
-rw-r--r--usr.sbin/fwget/fwget.814
-rwxr-xr-xusr.sbin/fwget/fwget.sh6
-rw-r--r--usr.sbin/fwget/usb/Makefile10
-rwxr-xr-xusr.sbin/fwget/usb/usb43
-rwxr-xr-xusr.sbin/fwget/usb/usb_ralink12
-rw-r--r--usr.sbin/inetd/inetd.conf4
-rw-r--r--usr.sbin/lastlogin/lastlogin.84
-rw-r--r--usr.sbin/makefs/ffs.c2
-rw-r--r--usr.sbin/makefs/tests/makefs_msdos_tests.sh2
-rw-r--r--usr.sbin/sesutil/sesutil.86
-rw-r--r--usr.sbin/trim/trim.818
-rw-r--r--usr.sbin/trim/trim.c11
519 files changed, 8910 insertions, 2020 deletions
diff --git a/.github/workflows/checklist.yml b/.github/workflows/checklist.yml
index f5c3ea599abf..7f7b0d51f46e 100644
--- a/.github/workflows/checklist.yml
+++ b/.github/workflows/checklist.yml
@@ -89,6 +89,7 @@ jobs:
/* Loop for each key in "checklist". */
for (const c in checklist)
msg += "- " + c + "<sup>" + checklist[c].join(", ") + "</sup>\n";
+ msg += "\nPlease review CONTRIBUTING.md, then update and push your branch again.\n"
comment_func({
owner: context.repo.owner,
diff --git a/Makefile.inc1 b/Makefile.inc1
index d366be09f497..010f5ac2bb55 100644
--- a/Makefile.inc1
+++ b/Makefile.inc1
@@ -2130,11 +2130,10 @@ create-source-src-package: _pkgbootstrap .PHONY
PKGNAME "src" \
PKGGENNAME "src" \
VERSION "${PKG_VERSION}" \
- DESC "FreeBSD Kernel Sources" \
- COMMENT "FreeBSD Userland Sources" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
PKG_WWW "${PKG_WWW}" \
+ UCLFILES "${SRCDIR}/release/packages/ucl" \
${SRCDIR}/release/packages/template.ucl \
${SSTAGEDIR}/src.ucl
${PKG_CMD} -o ABI=${PKG_ABI} \
@@ -2155,13 +2154,12 @@ create-source-src-sys-package: _pkgbootstrap .PHONY
> ${SSTAGEDIR}/src-sys.plist
${SRCDIR}/release/packages/generate-ucl.lua \
PKGNAME "src-sys" \
- PKGGENNAME "src" \
+ PKGGENNAME "src-sys" \
VERSION "${PKG_VERSION}" \
- DESC "FreeBSD Kernel Sources" \
- COMMENT "FreeBSD Kernel Sources" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
PKG_WWW "${PKG_WWW}" \
+ UCLFILES "${SRCDIR}/release/packages/ucl" \
${SRCDIR}/release/packages/template.ucl \
${SSTAGEDIR}/src-sys.ucl
${PKG_CMD} -o ABI=${PKG_ABI} \
@@ -2226,12 +2224,12 @@ create-dtb-package:
@if [ -f ${KSTAGEDIR}/${DISTDIR}/dtb.plist ]; then \
${SRCDIR}/release/packages/generate-ucl.lua \
PKGNAME "dtb" \
+ PKGGENNAME "dtb" \
VERSION "${PKG_VERSION}" \
- COMMENT "FreeBSD Devicetree Blobs" \
- DESC "FreeBSD Devicetree Blobs" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
PKG_WWW "${PKG_WWW}" \
+ UCLFILES "${SRCDIR}/release/packages/ucl" \
${SRCDIR}/release/packages/template.ucl \
${KSTAGEDIR}/${DISTDIR}/dtb.ucl ; \
awk -F\" ' \
@@ -2257,13 +2255,15 @@ create-kernel-packages-flavor${flavor:C,^""$,${_default_flavor},}: _pkgbootstrap
-v kernel=yes -v _kernconf=${INSTALLKERNEL} ; \
${SRCDIR}/release/packages/generate-ucl.lua \
PKGNAME "kernel-${INSTALLKERNEL:tl}${flavor}" \
+ PKGGENNAME "kernel" \
VERSION "${PKG_VERSION}" \
KERNELDIR "kernel" \
- COMMENT "FreeBSD ${INSTALLKERNEL} kernel ${flavor}" \
- DESC "FreeBSD ${INSTALLKERNEL} kernel ${flavor}" \
+ KERNEL_NAME "${INSTALLKERNEL}" \
+ KERNEL_FLAVOR "${flavor}" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
PKG_WWW "${PKG_WWW}" \
+ UCLFILES "${SRCDIR}/release/packages/ucl" \
${SRCDIR}/release/packages/template.ucl \
${KSTAGEDIR}/${DISTDIR}/kernel.${INSTALLKERNEL}${flavor}.ucl ; \
awk -F\" ' \
@@ -2296,14 +2296,14 @@ create-kernel-packages-extra-flavor${flavor:C,^""$,${_default_flavor},}-${_kerne
PKGNAME "kernel-${_kernel:tl}${flavor}" \
PKGGENNAME "kernel" \
FORCEINCLUDE "kernel${flavor}" \
- UCLFILES "${SRCDIR}/release/packages/" \
VERSION "${PKG_VERSION}" \
+ KERNEL_NAME "${_kernel:tl}" \
+ KERNEL_FLAVOR "${flavor}" \
KERNELDIR "kernel.${_kernel}" \
- DESC "FreeBSD ${_kernel} kernel ${flavor}" \
- COMMENT "FreeBSD ${_kernel} kernel ${flavor}" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
PKG_WWW "${PKG_WWW}" \
+ UCLFILES "${SRCDIR}/release/packages/ucl" \
${SRCDIR}/release/packages/template.ucl \
${KSTAGEDIR}/kernel.${_kernel}/kernel.${_kernel}${flavor}.ucl ; \
awk -F\" ' \
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index a5e41d9ac6d6..e5a3da94e127 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -51,6 +51,9 @@
# xargs -n1 | sort | uniq -d;
# done
+# 20250716: Remove an old manual page, vn(4) was removed in FreeBSD 5.0
+OLD_FILES+=usr/share/man/man4/vn.4.gz
+
# 20250710: share: Delete bitrotted make_*_driver.sh scripts
OLD_FILES+=usr/share/examples/drivers/README
OLD_FILES+=usr/share/examples/drivers/make_device_driver.sh
diff --git a/UPDATING b/UPDATING
index 2b8320c1204d..196443581158 100644
--- a/UPDATING
+++ b/UPDATING
@@ -27,6 +27,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 15.x IS SLOW:
world, or to merely disable the most expensive debugging functionality
at runtime, run "ln -s 'abort:false,junk:false' /etc/malloc.conf".)
+20250719:
+ Commits 392a82b225 and c00baac0ab both changed the
+ internal API between the NFS modules. As such, all
+ these modules need to be rebuilt from sources.
+ __FreeBSD_version was bumped to 1500053 for this.
+
20250710:
The shar(1) utility has been removed from base. The
sysutils/freebsd-shar port was created to maintain this version of
diff --git a/bin/df/df.1 b/bin/df/df.1
index ceb1bb45babf..2de72e4e3bb2 100644
--- a/bin/df/df.1
+++ b/bin/df/df.1
@@ -26,7 +26,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 29, 2023
+.Dd July 16, 2025
.Dt DF 1
.Os
.Sh NAME
@@ -65,7 +65,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl a
Show all mount points, including those that were mounted with the
@@ -264,7 +264,7 @@ each file or directory name or disk label
.Xr getmntinfo 3 ,
.Xr libxo 3 ,
.Xr localeconv 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr fstab 5 ,
.Xr mount 8 ,
.Xr pstat 8 ,
diff --git a/bin/ps/ps.1 b/bin/ps/ps.1
index 1c964157f53f..542004453658 100644
--- a/bin/ps/ps.1
+++ b/bin/ps/ps.1
@@ -33,7 +33,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 06, 2025
+.Dd July 16, 2025
.Dt PS 1
.Os
.Sh NAME
@@ -194,7 +194,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
The default is the traditional text style output.
.It Fl A
@@ -925,7 +925,7 @@ Display information on all system processes:
.Xr kvm 3 ,
.Xr libxo 3 ,
.Xr strftime 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr mac 4 ,
.Xr procfs 4 ,
.Xr pstat 8 ,
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1 b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
index d44ee5023e78..da8cbd9ffe50 100644
--- a/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
+++ b/cddl/contrib/opensolaris/cmd/dtrace/dtrace.1
@@ -20,7 +20,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 14, 2025
+.Dd July 16, 2025
.Dt DTRACE 1
.Os
.Sh NAME
@@ -1270,6 +1270,7 @@ Invalid command line options or arguments were specified.
.Xr dwatch 1 ,
.Xr dtrace_audit 4 ,
.Xr dtrace_dtrace 4 ,
+.Xr dtrace_fbt 4 ,
.Xr dtrace_io 4 ,
.Xr dtrace_ip 4 ,
.Xr dtrace_kinst 4 ,
diff --git a/contrib/bmake/ChangeLog b/contrib/bmake/ChangeLog
index 0a5eced2d439..5a1c30a95750 100644
--- a/contrib/bmake/ChangeLog
+++ b/contrib/bmake/ChangeLog
@@ -1,3 +1,30 @@
+2025-07-07 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * VERSION (_MAKE_VERSION): 20250707
+ Merge with NetBSD make, pick up
+ o cond.c: improve debug log message for 'exists' function.
+ complain about unfinished escape sequences or string literals.
+
+2025-07-04 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * VERSION (_MAKE_VERSION): 20250704
+ Merge with NetBSD make, pick up
+ o make.1: add a DIAGNOSTICS section for make to reference.
+ o main.c: simplify the warning for invalid -J by refering to
+ manual page.
+
+2025-06-30 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * VERSION (_MAKE_VERSION): 20250630
+ Merge with NetBSD make, pick up
+ o consistently use double quotes in error messages
+ o cond.c: if a condition is erroneous, skip the whole .if/.endif
+ o make_malloc.c: in cleanup mode, initialize freshly allocated memory
+ o str.c: error out on an ":M" modifier whose pattern ends with
+ backslash
+ o var.c: fix parsing of modifier parts for :gmtime and :localtime
+ add POSIX $^ support
+
2025-06-18 Simon J Gerraty <sjg@beast.crufty.net>
* VERSION (_MAKE_VERSION): 20250618
diff --git a/contrib/bmake/FILES b/contrib/bmake/FILES
index 8bed07d546a3..1cec16b73ef4 100644
--- a/contrib/bmake/FILES
+++ b/contrib/bmake/FILES
@@ -76,6 +76,8 @@ unit-tests/archive-suffix.exp
unit-tests/archive-suffix.mk
unit-tests/archive.exp
unit-tests/archive.mk
+unit-tests/char-005c-reverse-solidus.exp
+unit-tests/char-005c-reverse-solidus.mk
unit-tests/check-expect.lua
unit-tests/cmd-errors-jobs.exp
unit-tests/cmd-errors-jobs.mk
@@ -602,8 +604,6 @@ unit-tests/shell-ksh.exp
unit-tests/shell-ksh.mk
unit-tests/shell-sh.exp
unit-tests/shell-sh.mk
-unit-tests/suff.exp
-unit-tests/suff.mk
unit-tests/suff-add-later.exp
unit-tests/suff-add-later.mk
unit-tests/suff-clear-regular.exp
@@ -634,6 +634,8 @@ unit-tests/suff-transform-select.exp
unit-tests/suff-transform-select.mk
unit-tests/suff-use.exp
unit-tests/suff-use.mk
+unit-tests/suff.exp
+unit-tests/suff.mk
unit-tests/sunshcmd.exp
unit-tests/sunshcmd.mk
unit-tests/ternary.exp
@@ -780,6 +782,8 @@ unit-tests/varmod-unique.exp
unit-tests/varmod-unique.mk
unit-tests/varmod.exp
unit-tests/varmod.mk
+unit-tests/varname-circumflex.exp
+unit-tests/varname-circumflex.mk
unit-tests/varname-dollar.exp
unit-tests/varname-dollar.mk
unit-tests/varname-dot-alltargets.exp
diff --git a/contrib/bmake/VERSION b/contrib/bmake/VERSION
index 1467403891f1..eef1ef4b8ba9 100644
--- a/contrib/bmake/VERSION
+++ b/contrib/bmake/VERSION
@@ -1,2 +1,2 @@
# keep this compatible with sh and make
-_MAKE_VERSION=20250618
+_MAKE_VERSION=20250707
diff --git a/contrib/bmake/arch.c b/contrib/bmake/arch.c
index 77ac7f3c5707..87e2b128ae00 100644
--- a/contrib/bmake/arch.c
+++ b/contrib/bmake/arch.c
@@ -1,4 +1,4 @@
-/* $NetBSD: arch.c,v 1.222 2024/08/06 17:46:01 rillig Exp $ */
+/* $NetBSD: arch.c,v 1.223 2025/06/28 22:39:27 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -147,7 +147,7 @@ struct ar_hdr {
#include "dir.h"
/* "@(#)arch.c 8.2 (Berkeley) 1/2/94" */
-MAKE_RCSID("$NetBSD: arch.c,v 1.222 2024/08/06 17:46:01 rillig Exp $");
+MAKE_RCSID("$NetBSD: arch.c,v 1.223 2025/06/28 22:39:27 rillig Exp $");
typedef struct List ArchList;
typedef struct ListNode ArchListNode;
@@ -314,7 +314,7 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
if (*cp == '\0') {
Parse_Error(PARSE_FATAL,
- "Missing ')' in archive specification");
+ "Missing \")\" in archive specification");
return false;
}
diff --git a/contrib/bmake/bmake.1 b/contrib/bmake/bmake.1
index 92ed9e201ea5..01f173bc1a69 100644
--- a/contrib/bmake/bmake.1
+++ b/contrib/bmake/bmake.1
@@ -1,4 +1,4 @@
-.\" $NetBSD: make.1,v 1.385 2025/06/13 03:51:18 rillig Exp $
+.\" $NetBSD: make.1,v 1.387 2025/07/02 17:11:56 rillig Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
-.Dd June 12, 2025
+.Dd July 2, 2025
.Dt BMAKE 1
.Os
.Sh NAME
@@ -785,11 +785,13 @@ Is redundant with respect to global variables,
which have already been expanded.
.El
.Pp
-The seven built-in local variables are:
+The built-in local variables are:
.Bl -tag -width ".Va .ARCHIVE" -offset indent
.It Va .ALLSRC
The list of all sources for this target; also known as
-.Sq Va \&> .
+.Sq Va \&>
+or
+.Sq Va \&^ .
.It Va .ARCHIVE
The name of the archive file; also known as
.Sq Va \&! .
@@ -823,6 +825,7 @@ in archive member rules.
The shorter forms
.Po
.Sq Va \&> ,
+.Sq Va \&^ ,
.Sq Va \&! ,
.Sq Va \&< ,
.Sq Va \&% ,
@@ -2714,6 +2717,8 @@ If the
environment variable is set to
.Dq yes ,
any stack traces include the call chain of the parent processes.
+.\" .Sh EXIT STATUS
+.\" .Sh ENVIRONMENT
.Sh FILES
.Bl -tag -width /usr/share/mk -compact
.It .depend
@@ -2727,6 +2732,68 @@ system makefile
.It /usr/share/mk
system makefile directory
.El
+.\" .Sh EXAMPLES
+.Sh DIAGNOSTICS
+.Bl -tag
+.It Dv Invalid internal option \(dq-J\(dq in \(dq Ns Ar directory Ns Dv \(dq
+The internal
+.Fl J
+option coordinates the main
+.Nm
+process with the sub-make processes to limit
+the number of jobs that run in parallel.
+The option is passed to all child processes via the
+.Ev MAKEFLAGS
+environment variable.
+To become valid,
+this option requires that the target running the sub-make is marked with the
+.Dv .MAKE
+special source,
+or that one of the target's commands directly contains the word
+.Dq make
+or one of the expressions
+.Dq ${MAKE} ,
+.Dq ${.MAKE} ,
+.Dq $(MAKE) ,
+.Dq $(.MAKE) .
+If that's not the case,
+make issues the above warning and falls back to compat mode.
+.Pp
+To see the chain of sub-makes that leads to the invalid option, set the
+.Ev MAKE_STACK_TRACE
+environment variable to
+.Dq yes .
+.Pp
+To run the sub-make in parallel mode, even in dry-run mode (see the
+.Fl n
+option), add the
+.Dv .MAKE
+pseudo source to the target.
+This is appropriate when the sub-make runs the same target in a subdirectory.
+.Pp
+To run the sub-make in parallel mode but not in dry-mode,
+add a
+.Dq ${:D make}
+marker to one of the target's commands.
+This marker expands to an empty string
+and thus does not affect the executed commands.
+.\" The marker can even be added before any of the "@+-" modifiers,
+.\" so no need to mention this explicitly.
+.Pp
+To run the sub-make in compat mode, add the
+.Fl B
+option to its invocation.
+This is appropriate when the sub-make is only used to print a variable's
+value using the
+.Fl v
+or
+.Fl V
+options.
+.Pp
+To make the sub-make independent from the parent make, unset the
+.Ev MAKEFLAGS
+environment variable in the target's commands.
+.El
.Sh COMPATIBILITY
The basic make syntax is compatible between different make variants;
however the special variables, variable modifiers and conditionals are not.
@@ -2813,6 +2880,7 @@ not trying to chain transformations together, etc.) is also reasonably
portable.
.Sh SEE ALSO
.Xr mkdep 1
+.\" .Sh STANDARDS
.Sh HISTORY
.Nm
is derived from NetBSD
@@ -2837,6 +2905,8 @@ has been used to FoRCe rebuilding (since the target/dependency
does not exist ... unless someone creates an
.Pa FRC
file).
+.\" .Sh AUTHORS
+.\" .Sh CAVEATS
.Sh BUGS
The
.Nm
@@ -2858,3 +2928,4 @@ using that token pool to abort the build and exit with error code 6.
Sometimes the attempt to suppress a cascade of unnecessary errors,
can result in a seemingly unexplained
.Ql *** Error code 6
+.\" .Sh SECURITY CONSIDERATIONS
diff --git a/contrib/bmake/bmake.cat1 b/contrib/bmake/bmake.cat1
index 667c80898def..950437a8db9c 100644
--- a/contrib/bmake/bmake.cat1
+++ b/contrib/bmake/bmake.cat1
@@ -507,10 +507,10 @@ VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS
::== Is redundant with respect to global variables, which have
already been expanded.
- The seven built-in local variables are:
+ The built-in local variables are:
_._A_L_L_S_R_C The list of all sources for this target; also known as
- `_>'.
+ `_>' or `_^'.
_._A_R_C_H_I_V_E The name of the archive file; also known as `_!'.
@@ -531,9 +531,9 @@ VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS
compatibility with other makes this is an alias for
_._A_R_C_H_I_V_E in archive member rules.
- The shorter forms (`_>', `_!', `_<', `_%', `_?', `_*', and `_@') are permitted
- for backward compatibility with historical makefiles and legacy POSIX
- make and are not recommended.
+ The shorter forms (`_>', `_^', `_!', `_<', `_%', `_?', `_*', and `_@') are
+ permitted for backward compatibility with historical makefiles and legacy
+ POSIX make and are not recommended.
Variants of these variables with the punctuation followed immediately by
`D' or `F', e.g. `$(@D)', are legacy forms equivalent to using the `:H'
@@ -1748,6 +1748,39 @@ FFIILLEESS
sys.mk system makefile
/usr/share/mk system makefile directory
+DDIIAAGGNNOOSSTTIICCSS
+ Invalid internal option "-J" in "_d_i_r_e_c_t_o_r_y"
+ The internal --JJ option coordinates the main bbmmaakkee process with
+ the sub-make processes to limit the number of jobs that run in
+ parallel. The option is passed to all child processes via the
+ MAKEFLAGS environment variable. To become valid, this option
+ requires that the target running the sub-make is marked with the
+ .MAKE special source, or that one of the target's commands
+ directly contains the word "make" or one of the expressions
+ "${MAKE}", "${.MAKE}", "$(MAKE)", "$(.MAKE)". If that's not the
+ case, make issues the above warning and falls back to compat
+ mode.
+
+ To see the chain of sub-makes that leads to the invalid option,
+ set the MAKE_STACK_TRACE environment variable to "yes".
+
+ To run the sub-make in parallel mode, even in dry-run mode (see
+ the --nn option), add the .MAKE pseudo source to the target. This
+ is appropriate when the sub-make runs the same target in a
+ subdirectory.
+
+ To run the sub-make in parallel mode but not in dry-mode, add a
+ "${:D make}" marker to one of the target's commands. This marker
+ expands to an empty string and thus does not affect the executed
+ commands.
+
+ To run the sub-make in compat mode, add the --BB option to its
+ invocation. This is appropriate when the sub-make is only used
+ to print a variable's value using the --vv or --VV options.
+
+ To make the sub-make independent from the parent make, unset the
+ MAKEFLAGS environment variable in the target's commands.
+
CCOOMMPPAATTIIBBIILLIITTYY
The basic make syntax is compatible between different make variants;
however the special variables, variable modifiers and conditionals are
@@ -1831,4 +1864,4 @@ BBUUGGSS
attempt to suppress a cascade of unnecessary errors, can result in a
seemingly unexplained `*** Error code 6'
-FreeBSD 14.2-RELEASE-p1 June 12, 2025 FreeBSD 14.2-RELEASE-p1
+FreeBSD 14.2-RELEASE-p1 July 2, 2025 FreeBSD 14.2-RELEASE-p1
diff --git a/contrib/bmake/compat.c b/contrib/bmake/compat.c
index 7a51a99be4ba..f32213bf67e5 100644
--- a/contrib/bmake/compat.c
+++ b/contrib/bmake/compat.c
@@ -1,4 +1,4 @@
-/* $NetBSD: compat.c,v 1.267 2025/06/13 03:51:18 rillig Exp $ */
+/* $NetBSD: compat.c,v 1.268 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -97,7 +97,7 @@
#include "pathnames.h"
/* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: compat.c,v 1.267 2025/06/13 03:51:18 rillig Exp $");
+MAKE_RCSID("$NetBSD: compat.c,v 1.268 2025/07/06 07:11:31 rillig Exp $");
static GNode *curTarg;
static pid_t compatChild;
@@ -334,11 +334,8 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
if (useShell) {
static const char *shargv[5];
- if (Cmd_Argv(cmd, cmd_len, shargv, 5,
- cmd_file, sizeof(cmd_file),
- errCheck && shellErrFlag != NULL,
- DEBUG(SHELL)) < 0)
- Fatal("cannot run \"%s\"", cmd);
+ Cmd_Argv(cmd, cmd_len, shargv, cmd_file, sizeof(cmd_file),
+ errCheck && shellErrFlag != NULL, DEBUG(SHELL));
av = shargv;
bp = NULL;
mav = NULL;
diff --git a/contrib/bmake/cond.c b/contrib/bmake/cond.c
index f83163cbb50e..b3613bbadf5d 100644
--- a/contrib/bmake/cond.c
+++ b/contrib/bmake/cond.c
@@ -1,4 +1,4 @@
-/* $NetBSD: cond.c,v 1.373 2025/04/22 19:28:50 rillig Exp $ */
+/* $NetBSD: cond.c,v 1.378 2025/07/06 07:56:16 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -77,9 +77,8 @@
* '.if <cond>', '.elifnmake <cond>', '.else', '.endif'.
*
* Cond_EvalCondition
- * Evaluate the conditional, which is either the argument
- * of one of the .if directives or the condition in a
- * ':?then:else' variable modifier.
+ * Evaluate a condition, either from one of the .if
+ * directives, or from a ':?then:else' modifier.
*
* Cond_EndFile At the end of reading a makefile, ensure that the
* conditional directives are well-balanced.
@@ -91,14 +90,14 @@
#include "dir.h"
/* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */
-MAKE_RCSID("$NetBSD: cond.c,v 1.373 2025/04/22 19:28:50 rillig Exp $");
+MAKE_RCSID("$NetBSD: cond.c,v 1.378 2025/07/06 07:56:16 rillig Exp $");
/*
* Conditional expressions conform to this grammar:
* Or -> And ('||' And)*
* And -> Term ('&&' Term)*
* Term -> Function '(' Argument ')'
- * Term -> Leaf Operator Leaf
+ * Term -> Leaf ComparisonOp Leaf
* Term -> Leaf
* Term -> '(' Or ')'
* Term -> '!' Term
@@ -106,7 +105,7 @@ MAKE_RCSID("$NetBSD: cond.c,v 1.373 2025/04/22 19:28:50 rillig Exp $");
* Leaf -> Number
* Leaf -> VariableExpression
* Leaf -> BareWord
- * Operator -> '==' | '!=' | '>' | '<' | '>=' | '<='
+ * ComparisonOp -> '==' | '!=' | '>' | '<' | '>=' | '<='
*
* BareWord is an unquoted string literal, its evaluation depends on the kind
* of '.if' directive.
@@ -156,12 +155,12 @@ typedef struct CondParser {
* been an expression or a plain word.
*
* In conditional directives like '.if', the left-hand side must
- * either be an expression, a quoted string or a number.
+ * either be a defined expression, a quoted string or a number.
*/
bool leftUnquotedOK;
const char *p; /* The remaining condition to parse */
- Token curr; /* Single push-back token used in parsing */
+ Token curr; /* The push-back token, or TOK_NONE */
} CondParser;
static CondResult CondParser_Or(CondParser *, bool);
@@ -255,7 +254,7 @@ ParseFuncArg(const char **pp, bool doEval, const char *func)
len++;
Parse_Error(PARSE_FATAL,
- "Missing ')' after argument '%.*s' for '%.*s'",
+ "Missing \")\" after argument \"%.*s\" for \"%.*s\"",
(int)(argEnd - argStart), argStart, len, func);
free(res);
return NULL;
@@ -284,7 +283,8 @@ FuncMake(const char *targetPattern)
if (res.error != NULL && !warned) {
warned = true;
Parse_Error(PARSE_WARNING,
- "%s in pattern argument '%s' to function 'make'",
+ "%s in pattern argument \"%s\" "
+ "to function \"make\"",
res.error, targetPattern);
}
if (res.matched)
@@ -301,14 +301,16 @@ FuncExists(const char *file)
char *path;
path = Dir_FindFile(file, &dirSearchPath);
- DEBUG2(COND, "exists(%s) result is \"%s\"\n",
- file, path != NULL ? path : "");
result = path != NULL;
+ if (result)
+ DEBUG2(COND, "\"%s\" exists in \"%s\"\n", file, path);
+ else
+ DEBUG1(COND, "\"%s\" does not exist\n", file);
free(path);
return result;
}
-/* See if the given node exists and is an actual target. */
+/* See if the given node is an actual target. */
static bool
FuncTarget(const char *node)
{
@@ -316,10 +318,7 @@ FuncTarget(const char *node)
return gn != NULL && GNode_IsTarget(gn);
}
-/*
- * See if the given node exists and is an actual target with commands
- * associated with it.
- */
+/* See if the given node is an actual target with commands. */
static bool
FuncCommands(const char *node)
{
@@ -374,38 +373,37 @@ is_separator(char ch)
*
* Return whether to continue parsing the leaf.
*
- * Example: .if x${CENTER}y == "${PREFIX}${SUFFIX}" || 0x${HEX}
+ * Examples: .if x${CENTER}y == "${PREFIX}${SUFFIX}" || 0x${HEX}
*/
static bool
CondParser_StringExpr(CondParser *par, const char *start,
bool doEval, bool quoted,
- Buffer *buf, FStr *inout_str)
+ Buffer *buf, FStr *out_str)
{
VarEvalMode emode;
const char *p;
- bool atStart; /* true means an expression outside quotes */
+ bool outsideQuotes;
emode = doEval && quoted ? VARE_EVAL
: doEval ? VARE_EVAL_DEFINED_LOUD
: VARE_PARSE;
p = par->p;
- atStart = p == start;
- *inout_str = Var_Parse(&p, SCOPE_CMDLINE, emode);
- /* TODO: handle errors */
- if (inout_str->str == var_Error) {
- FStr_Done(inout_str);
- *inout_str = FStr_InitRefer(NULL);
+ outsideQuotes = p == start;
+ *out_str = Var_Parse(&p, SCOPE_CMDLINE, emode);
+ if (out_str->str == var_Error) {
+ FStr_Done(out_str);
+ *out_str = FStr_InitRefer(NULL);
return false;
}
par->p = p;
- if (atStart && is_separator(par->p[0]))
+ if (outsideQuotes && is_separator(par->p[0]))
return false;
- Buf_AddStr(buf, inout_str->str);
- FStr_Done(inout_str);
- *inout_str = FStr_InitRefer(NULL); /* not finished yet */
+ Buf_AddStr(buf, out_str->str);
+ FStr_Done(out_str);
+ *out_str = FStr_InitRefer(NULL); /* not finished yet */
return true;
}
@@ -414,7 +412,7 @@ CondParser_StringExpr(CondParser *par, const char *start,
* on the left-hand and right-hand sides of comparisons.
*
* Return the string without any enclosing quotes, or NULL on error.
- * Sets out_quoted if the leaf was a quoted string literal.
+ * Set out_quoted if the leaf was a quoted string literal.
*/
static FStr
CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK,
@@ -439,12 +437,14 @@ CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK,
if (par->p[0] != '\0') {
Buf_AddByte(&buf, par->p[0]);
par->p++;
- }
+ } else
+ Parse_Error(PARSE_FATAL,
+ "Unfinished backslash escape sequence");
continue;
case '"':
par->p++;
if (quoted)
- goto return_buf; /* skip the closing quote */
+ goto return_buf;
Buf_AddByte(&buf, '"');
continue;
case ')': /* see is_separator */
@@ -475,6 +475,9 @@ CondParser_Leaf(CondParser *par, bool doEval, bool unquotedOK,
continue;
}
}
+ if (quoted)
+ Parse_Error(PARSE_FATAL,
+ "Unfinished string literal \"%s\"", start);
return_buf:
str = FStr_InitOwn(buf.data);
buf.data = NULL;
@@ -528,8 +531,8 @@ EvalCompareStr(const char *lhs, ComparisonOp op, const char *rhs)
{
if (op != EQ && op != NE) {
Parse_Error(PARSE_FATAL,
- "Comparison with '%s' requires both operands "
- "'%s' and '%s' to be numeric",
+ "Comparison with \"%s\" requires both operands "
+ "\"%s\" and \"%s\" to be numeric",
opname[op], lhs, rhs);
return TOK_ERROR;
}
@@ -603,7 +606,7 @@ CondParser_Comparison(CondParser *par, bool doEval)
if (par->p[0] == '\0') {
Parse_Error(PARSE_FATAL,
- "Missing right-hand side of operator '%s'", opname[op]);
+ "Missing right-hand side of operator \"%s\"", opname[op]);
goto done_lhs;
}
@@ -768,7 +771,7 @@ CondParser_Token(CondParser *par, bool doEval)
if (par->p[0] == '|')
par->p++;
else {
- Parse_Error(PARSE_FATAL, "Unknown operator '|'");
+ Parse_Error(PARSE_FATAL, "Unknown operator \"|\"");
return TOK_ERROR;
}
return TOK_OR;
@@ -778,7 +781,7 @@ CondParser_Token(CondParser *par, bool doEval)
if (par->p[0] == '&')
par->p++;
else {
- Parse_Error(PARSE_FATAL, "Unknown operator '&'");
+ Parse_Error(PARSE_FATAL, "Unknown operator \"&\"");
return TOK_ERROR;
}
return TOK_AND;
@@ -825,7 +828,7 @@ CondParser_Skip(CondParser *par, Token t)
/*
* Term -> '(' Or ')'
* Term -> '!' Term
- * Term -> Leaf Operator Leaf
+ * Term -> Leaf ComparisonOp Leaf
* Term -> Leaf
*/
static CondResult
@@ -923,8 +926,10 @@ CondEvalExpression(const char *cond, bool plain,
if (par.curr != TOK_EOF)
rval = CR_ERROR;
- if (rval == CR_ERROR && eprint && parseErrors == parseErrorsBefore)
- Parse_Error(PARSE_FATAL, "Malformed conditional '%s'", cond);
+ if (parseErrors != parseErrorsBefore)
+ rval = CR_ERROR;
+ else if (rval == CR_ERROR && eprint)
+ Parse_Error(PARSE_FATAL, "Malformed conditional \"%s\"", cond);
return rval;
}
diff --git a/contrib/bmake/for.c b/contrib/bmake/for.c
index 438fb4e84de0..904853107db8 100644
--- a/contrib/bmake/for.c
+++ b/contrib/bmake/for.c
@@ -1,4 +1,4 @@
-/* $NetBSD: for.c,v 1.185 2025/04/22 19:28:50 rillig Exp $ */
+/* $NetBSD: for.c,v 1.186 2025/06/28 22:39:27 rillig Exp $ */
/*
* Copyright (c) 1992, The Regents of the University of California.
@@ -58,7 +58,7 @@
#include "make.h"
/* "@(#)for.c 8.1 (Berkeley) 6/6/93" */
-MAKE_RCSID("$NetBSD: for.c,v 1.185 2025/04/22 19:28:50 rillig Exp $");
+MAKE_RCSID("$NetBSD: for.c,v 1.186 2025/06/28 22:39:27 rillig Exp $");
typedef struct ForLoop {
@@ -153,7 +153,8 @@ ForLoop_ParseVarnames(ForLoop *f, const char **pp)
for (;;) {
cpp_skip_whitespace(&p);
if (*p == '\0') {
- Parse_Error(PARSE_FATAL, "missing `in' in for");
+ Parse_Error(PARSE_FATAL,
+ "Missing \"in\" in .for loop");
goto cleanup;
}
@@ -168,7 +169,8 @@ ForLoop_ParseVarnames(ForLoop *f, const char **pp)
}
if (f->vars.len == 0) {
- Parse_Error(PARSE_FATAL, "no iteration variables in for");
+ Parse_Error(PARSE_FATAL,
+ "Missing iteration variables in .for loop");
return;
}
@@ -177,7 +179,7 @@ ForLoop_ParseVarnames(ForLoop *f, const char **pp)
invalid_variable_name:
Parse_Error(PARSE_FATAL,
- "invalid character '%c' in .for loop variable name", *p);
+ "Invalid character \"%c\" in .for loop variable name", *p);
cleanup:
while (f->vars.len > 0)
free(*(char **)Vector_Pop(&f->vars));
diff --git a/contrib/bmake/job.c b/contrib/bmake/job.c
index 582870088f2d..0c54e710afeb 100644
--- a/contrib/bmake/job.c
+++ b/contrib/bmake/job.c
@@ -1,4 +1,4 @@
-/* $NetBSD: job.c,v 1.516 2025/06/13 06:13:19 rillig Exp $ */
+/* $NetBSD: job.c,v 1.517 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -89,7 +89,7 @@
* define the shell that is used for the creation
* commands in jobs mode.
*
- * Job_Finish Make the .END target. Must only be called when the
+ * Job_MakeDotEnd Make the .END target. Must only be called when the
* job table is empty.
*
* Job_AbortAll Kill all currently running jobs, in an emergency.
@@ -137,7 +137,7 @@
#include "trace.h"
/* "@(#)job.c 8.2 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: job.c,v 1.516 2025/06/13 06:13:19 rillig Exp $");
+MAKE_RCSID("$NetBSD: job.c,v 1.517 2025/07/06 07:11:31 rillig Exp $");
#ifdef USE_SELECT
@@ -599,7 +599,7 @@ Job_Pid(Job *job)
}
static void
-DumpJobs(const char *where)
+JobTable_Dump(const char *where)
{
const Job *job;
char flags[4];
@@ -663,6 +663,13 @@ SetNonblocking(int fd)
}
static void
+SetCloseOnExec(int fd)
+{
+ if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ Punt("SetCloseOnExec: %s", strerror(errno));
+}
+
+static void
JobCreatePipe(Job *job, int minfd)
{
int i;
@@ -683,10 +690,8 @@ JobCreatePipe(Job *job, int minfd)
job->inPipe = pipe_fds[0];
job->outPipe = pipe_fds[1];
- if (fcntl(job->inPipe, F_SETFD, FD_CLOEXEC) == -1)
- Punt("SetCloseOnExec: %s", strerror(errno));
- if (fcntl(job->outPipe, F_SETFD, FD_CLOEXEC) == -1)
- Punt("SetCloseOnExec: %s", strerror(errno));
+ SetCloseOnExec(job->inPipe);
+ SetCloseOnExec(job->outPipe);
/*
* We mark the input side of the pipe non-blocking; we poll(2) the
@@ -822,7 +827,7 @@ JobFindPid(int pid, enum JobStatus status, bool isJobs)
return job;
}
if (DEBUG(JOB) && isJobs)
- DumpJobs("no pid");
+ JobTable_Dump("no pid");
return NULL;
}
@@ -1624,7 +1629,7 @@ JobExec(Job *job, char **argv)
debug_printf(
"JobExec: target %s, pid %d added to jobs table\n",
job->node->name, job->pid);
- DumpJobs("job started");
+ JobTable_Dump("job started");
}
JobsTable_Unlock(&mask);
}
@@ -2433,7 +2438,6 @@ static void
JobInterrupt(bool runINTERRUPT, int signo)
{
Job *job;
- GNode *interrupt;
sigset_t mask;
aborting = ABORT_INTERRUPT;
@@ -2460,10 +2464,10 @@ JobInterrupt(bool runINTERRUPT, int signo)
JobsTable_Unlock(&mask);
if (runINTERRUPT && !opts.touch) {
- interrupt = Targ_FindNode(".INTERRUPT");
- if (interrupt != NULL) {
+ GNode *dotInterrupt = Targ_FindNode(".INTERRUPT");
+ if (dotInterrupt != NULL) {
opts.ignoreErrors = false;
- JobRun(interrupt);
+ JobRun(dotInterrupt);
}
}
Trace_Log(MAKEINTR, NULL);
@@ -2472,15 +2476,15 @@ JobInterrupt(bool runINTERRUPT, int signo)
/* Make the .END target, returning the number of job-related errors. */
int
-Job_Finish(void)
+Job_MakeDotEnd(void)
{
- GNode *endNode = Targ_GetEndNode();
- if (!Lst_IsEmpty(&endNode->commands) ||
- !Lst_IsEmpty(&endNode->children)) {
+ GNode *dotEnd = Targ_GetEndNode();
+ if (!Lst_IsEmpty(&dotEnd->commands) ||
+ !Lst_IsEmpty(&dotEnd->children)) {
if (job_errors != 0)
Error("Errors reported so .END ignored");
else
- JobRun(endNode);
+ JobRun(dotEnd);
}
return job_errors;
}
diff --git a/contrib/bmake/job.h b/contrib/bmake/job.h
index 901be0eef1dd..2b4b5e59c37e 100644
--- a/contrib/bmake/job.h
+++ b/contrib/bmake/job.h
@@ -1,4 +1,4 @@
-/* $NetBSD: job.h,v 1.84 2025/04/22 19:28:50 rillig Exp $ */
+/* $NetBSD: job.h,v 1.85 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -101,7 +101,7 @@ void Job_CatchOutput(void);
void Job_Make(GNode *);
void Job_Init(void);
bool Job_ParseShell(char *) MAKE_ATTR_USE;
-int Job_Finish(void);
+int Job_MakeDotEnd(void);
#ifdef CLEANUP
void Job_End(void);
#endif
diff --git a/contrib/bmake/main.c b/contrib/bmake/main.c
index d020ba85f16b..a773b44f42c4 100644
--- a/contrib/bmake/main.c
+++ b/contrib/bmake/main.c
@@ -1,4 +1,4 @@
-/* $NetBSD: main.c,v 1.659 2025/06/13 05:41:36 rillig Exp $ */
+/* $NetBSD: main.c,v 1.661 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -111,7 +111,7 @@
#include "trace.h"
/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: main.c,v 1.659 2025/06/13 05:41:36 rillig Exp $");
+MAKE_RCSID("$NetBSD: main.c,v 1.661 2025/07/06 07:11:31 rillig Exp $");
#if defined(MAKE_NATIVE)
__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
"The Regents of the University of California. "
@@ -1221,23 +1221,8 @@ InitMaxJobs(void)
if (bogusJflag && !opts.compatMake) {
opts.compatMake = true;
Parse_Error(PARSE_WARNING,
- "internal option \"-J\" in \"%s\" "
- "refers to unopened file descriptors; "
- "falling back to compat mode.\n"
- "\t"
- "To run the target even in -n mode, "
- "add the .MAKE pseudo-source to the target.\n"
- "\t"
- "To run the target in default mode only, "
- "add a ${:D make} marker to a target's command. "
- "(This marker expression expands to an empty string.)\n"
- "\t"
- "To make the sub-make run in compat mode, add -B to "
- "its invocation.\n"
- "\t"
- "To make the sub-make independent from the parent make, "
- "unset the MAKEFLAGS environment variable in the "
- "target's commands.",
+ "Invalid internal option \"-J\" in \"%s\"; "
+ "see the manual page",
curdir);
PrintStackTrace(true);
return;
@@ -1734,11 +1719,10 @@ found:
}
/* populate av for Cmd_Exec and Compat_RunCommand */
-int
-Cmd_Argv(const char *cmd, size_t cmd_len, const char **av, size_t avsz,
+void
+Cmd_Argv(const char *cmd, size_t cmd_len, const char *av[5],
char *cmd_file, size_t cmd_filesz, bool eflag, bool xflag)
{
- int ac = 0;
int cmd_fd = -1;
if (shellPath == NULL)
@@ -1764,23 +1748,19 @@ Cmd_Argv(const char *cmd, size_t cmd_len, const char **av, size_t avsz,
cmd_file[0] = '\0';
}
- if (avsz < 4 || (eflag && avsz < 5))
- return -1;
-
/* The following works for any of the builtin shell specs. */
- av[ac++] = shellPath;
+ *av++ = shellPath;
if (eflag)
- av[ac++] = shellErrFlag;
+ *av++ = shellErrFlag;
if (cmd_fd >= 0) {
if (xflag)
- av[ac++] = "-x";
- av[ac++] = cmd_file;
+ *av++ = "-x";
+ *av++ = cmd_file;
} else {
- av[ac++] = xflag ? "-xc" : "-c";
- av[ac++] = cmd;
+ *av++ = xflag ? "-xc" : "-c";
+ *av++ = cmd;
}
- av[ac] = NULL;
- return ac;
+ *av = NULL;
}
/*
@@ -1790,7 +1770,7 @@ Cmd_Argv(const char *cmd, size_t cmd_len, const char **av, size_t avsz,
char *
Cmd_Exec(const char *cmd, char **error)
{
- const char *args[4]; /* Arguments for invoking the shell */
+ const char *args[5]; /* Arguments for invoking the shell */
int pipefds[2];
int cpid; /* Child PID */
int pid; /* PID from wait() */
@@ -1804,8 +1784,8 @@ Cmd_Exec(const char *cmd, char **error)
DEBUG1(VAR, "Capturing the output of command \"%s\"\n", cmd);
- if (Cmd_Argv(cmd, 0, args, 4, cmd_file, sizeof(cmd_file), false, false) < 0
- || pipe(pipefds) == -1) {
+ Cmd_Argv(cmd, 0, args, cmd_file, sizeof(cmd_file), false, false);
+ if (pipe(pipefds) == -1) {
*error = str_concat3(
"Couldn't create pipe for \"", cmd, "\"");
return bmake_strdup("");
@@ -2083,7 +2063,7 @@ shouldDieQuietly(GNode *gn, int bf)
else if (bf >= 0)
quietly = bf;
else
- quietly = (gn != NULL && (gn->type & OP_MAKE)) ? 1 : 0;
+ quietly = gn != NULL && gn->type & OP_MAKE ? 1 : 0;
}
return quietly != 0;
}
diff --git a/contrib/bmake/make.1 b/contrib/bmake/make.1
index f05653af7e31..de67759290c4 100644
--- a/contrib/bmake/make.1
+++ b/contrib/bmake/make.1
@@ -1,4 +1,4 @@
-.\" $NetBSD: make.1,v 1.385 2025/06/13 03:51:18 rillig Exp $
+.\" $NetBSD: make.1,v 1.387 2025/07/02 17:11:56 rillig Exp $
.\"
.\" Copyright (c) 1990, 1993
.\" The Regents of the University of California. All rights reserved.
@@ -29,7 +29,7 @@
.\"
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
.\"
-.Dd June 12, 2025
+.Dd July 2, 2025
.Dt MAKE 1
.Os
.Sh NAME
@@ -785,11 +785,13 @@ Is redundant with respect to global variables,
which have already been expanded.
.El
.Pp
-The seven built-in local variables are:
+The built-in local variables are:
.Bl -tag -width ".Va .ARCHIVE" -offset indent
.It Va .ALLSRC
The list of all sources for this target; also known as
-.Sq Va \&> .
+.Sq Va \&>
+or
+.Sq Va \&^ .
.It Va .ARCHIVE
The name of the archive file; also known as
.Sq Va \&! .
@@ -823,6 +825,7 @@ in archive member rules.
The shorter forms
.Po
.Sq Va \&> ,
+.Sq Va \&^ ,
.Sq Va \&! ,
.Sq Va \&< ,
.Sq Va \&% ,
@@ -2725,6 +2728,8 @@ If the
environment variable is set to
.Dq yes ,
any stack traces include the call chain of the parent processes.
+.\" .Sh EXIT STATUS
+.\" .Sh ENVIRONMENT
.Sh FILES
.Bl -tag -width /usr/share/mk -compact
.It .depend
@@ -2738,6 +2743,68 @@ system makefile
.It /usr/share/mk
system makefile directory
.El
+.\" .Sh EXAMPLES
+.Sh DIAGNOSTICS
+.Bl -tag
+.It Dv Invalid internal option \(dq-J\(dq in \(dq Ns Ar directory Ns Dv \(dq
+The internal
+.Fl J
+option coordinates the main
+.Nm
+process with the sub-make processes to limit
+the number of jobs that run in parallel.
+The option is passed to all child processes via the
+.Ev MAKEFLAGS
+environment variable.
+To become valid,
+this option requires that the target running the sub-make is marked with the
+.Dv .MAKE
+special source,
+or that one of the target's commands directly contains the word
+.Dq make
+or one of the expressions
+.Dq ${MAKE} ,
+.Dq ${.MAKE} ,
+.Dq $(MAKE) ,
+.Dq $(.MAKE) .
+If that's not the case,
+make issues the above warning and falls back to compat mode.
+.Pp
+To see the chain of sub-makes that leads to the invalid option, set the
+.Ev MAKE_STACK_TRACE
+environment variable to
+.Dq yes .
+.Pp
+To run the sub-make in parallel mode, even in dry-run mode (see the
+.Fl n
+option), add the
+.Dv .MAKE
+pseudo source to the target.
+This is appropriate when the sub-make runs the same target in a subdirectory.
+.Pp
+To run the sub-make in parallel mode but not in dry-mode,
+add a
+.Dq ${:D make}
+marker to one of the target's commands.
+This marker expands to an empty string
+and thus does not affect the executed commands.
+.\" The marker can even be added before any of the "@+-" modifiers,
+.\" so no need to mention this explicitly.
+.Pp
+To run the sub-make in compat mode, add the
+.Fl B
+option to its invocation.
+This is appropriate when the sub-make is only used to print a variable's
+value using the
+.Fl v
+or
+.Fl V
+options.
+.Pp
+To make the sub-make independent from the parent make, unset the
+.Ev MAKEFLAGS
+environment variable in the target's commands.
+.El
.Sh COMPATIBILITY
The basic make syntax is compatible between different make variants;
however the special variables, variable modifiers and conditionals are not.
@@ -2825,6 +2892,7 @@ portable.
.Sh SEE ALSO
.Xr mkdep 1 ,
.Xr style.Makefile 5
+.\" .Sh STANDARDS
.Sh HISTORY
A
.Nm
@@ -2844,6 +2912,8 @@ has been used to FoRCe rebuilding (since the target/dependency
does not exist ... unless someone creates an
.Pa FRC
file).
+.\" .Sh AUTHORS
+.\" .Sh CAVEATS
.Sh BUGS
The
.Nm
@@ -2865,3 +2935,4 @@ using that token pool to abort the build and exit with error code 6.
Sometimes the attempt to suppress a cascade of unnecessary errors,
can result in a seemingly unexplained
.Ql *** Error code 6
+.\" .Sh SECURITY CONSIDERATIONS
diff --git a/contrib/bmake/make.c b/contrib/bmake/make.c
index 3826c4d4e6a1..811f6e0849c4 100644
--- a/contrib/bmake/make.c
+++ b/contrib/bmake/make.c
@@ -1,4 +1,4 @@
-/* $NetBSD: make.c,v 1.272 2025/05/18 07:02:00 rillig Exp $ */
+/* $NetBSD: make.c,v 1.273 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -107,7 +107,7 @@
#endif
/* "@(#)make.c 8.1 (Berkeley) 6/6/93" */
-MAKE_RCSID("$NetBSD: make.c,v 1.272 2025/05/18 07:02:00 rillig Exp $");
+MAKE_RCSID("$NetBSD: make.c,v 1.273 2025/07/06 07:11:31 rillig Exp $");
/* Sequence # to detect recursion. */
static unsigned checked_seqno = 1;
@@ -1404,7 +1404,7 @@ Make_MakeParallel(GNodeList *targets)
(void)MakeStartJobs();
}
- errors = Job_Finish();
+ errors = Job_MakeDotEnd();
DEBUG1(MAKE, "done: errors %d\n", errors);
if (errors == 0) {
diff --git a/contrib/bmake/make.h b/contrib/bmake/make.h
index 405f03144b69..6b2b215592dd 100644
--- a/contrib/bmake/make.h
+++ b/contrib/bmake/make.h
@@ -1,4 +1,4 @@
-/* $NetBSD: make.h,v 1.360 2025/06/13 18:31:08 rillig Exp $ */
+/* $NetBSD: make.h,v 1.361 2025/07/06 07:11:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -884,7 +884,8 @@ void JobReapChild(pid_t, int, bool);
#endif
/* main.c */
void Main_ParseArgLine(const char *);
-int Cmd_Argv(const char *, size_t, const char **, size_t, char *, size_t, bool, bool);
+void Cmd_Argv(const char *, size_t, const char *[5], char *, size_t,
+ bool, bool);
char *Cmd_Exec(const char *, char **) MAKE_ATTR_USE;
void Var_ExportStackTrace(const char *, const char *);
void Error(const char *, ...) MAKE_ATTR_PRINTFLIKE(1, 2);
diff --git a/contrib/bmake/make_malloc.c b/contrib/bmake/make_malloc.c
index d7a735b8b08e..86e339de5dd2 100644
--- a/contrib/bmake/make_malloc.c
+++ b/contrib/bmake/make_malloc.c
@@ -1,4 +1,4 @@
-/* $NetBSD: make_malloc.c,v 1.27 2025/06/12 18:51:05 rillig Exp $ */
+/* $NetBSD: make_malloc.c,v 1.28 2025/06/29 09:37:58 rillig Exp $ */
/*
* Copyright (c) 2009 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
#include "make.h"
-MAKE_RCSID("$NetBSD: make_malloc.c,v 1.27 2025/06/12 18:51:05 rillig Exp $");
+MAKE_RCSID("$NetBSD: make_malloc.c,v 1.28 2025/06/29 09:37:58 rillig Exp $");
#ifndef USE_EMALLOC
@@ -50,6 +50,9 @@ bmake_malloc(size_t len)
if ((p = malloc(len)) == NULL)
enomem();
+#ifdef CLEANUP
+ memset(p, 'Z', len);
+#endif
return p;
}
diff --git a/contrib/bmake/mk/ChangeLog b/contrib/bmake/mk/ChangeLog
index 1822f917a138..db524d2343b6 100644
--- a/contrib/bmake/mk/ChangeLog
+++ b/contrib/bmake/mk/ChangeLog
@@ -1,3 +1,7 @@
+2025-07-04 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * prog.mk: .MADE is a special source not a target!
+
2025-05-28 Simon J Gerraty <sjg@beast.crufty.net>
* install-mk (MK_VERSION): 20250528
diff --git a/contrib/bmake/mk/prog.mk b/contrib/bmake/mk/prog.mk
index 119645c49859..a7ced7b15d31 100644
--- a/contrib/bmake/mk/prog.mk
+++ b/contrib/bmake/mk/prog.mk
@@ -1,4 +1,4 @@
-# $Id: prog.mk,v 1.45 2024/12/12 19:56:36 sjg Exp $
+# $Id: prog.mk,v 1.46 2025/07/05 16:43:03 sjg Exp $
# should be set properly in sys.mk
_this ?= ${.PARSEFILE:S,bsd.,,}
@@ -27,11 +27,11 @@ CFLAGS+= -mcmodel=medlow
.if ${OBJECT_FMT} == "ELF"
.ifndef LIBCRTBEGIN
LIBCRTBEGIN= ${DESTDIR}/usr/lib/crtbegin.o
-.MADE: ${LIBCRTBEGIN}
+${LIBCRTBEGIN}: .MADE
.endif
.ifndef LIBCRTEND
LIBCRTEND= ${DESTDIR}/usr/lib/crtend.o
-.MADE: ${LIBCRTEND}
+${LIBCRTEND}: .MADE
.endif
_SHLINKER= ${SHLINKDIR}/ld.elf_so
.else
@@ -42,7 +42,7 @@ _SHLINKER= ${SHLINKDIR}/ld.so
.ifndef LIBCRT0
LIBCRT0= ${DESTDIR}/usr/lib/crt0.o
-.MADE: ${LIBCRT0}
+${LIBCRT0}: .MADE
.endif
.endif # NetBSD
diff --git a/contrib/bmake/parse.c b/contrib/bmake/parse.c
index 844d4db207ca..ecc77366d2d7 100644
--- a/contrib/bmake/parse.c
+++ b/contrib/bmake/parse.c
@@ -1,4 +1,4 @@
-/* $NetBSD: parse.c,v 1.752 2025/06/16 18:20:00 rillig Exp $ */
+/* $NetBSD: parse.c,v 1.753 2025/06/28 22:39:27 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -110,7 +110,7 @@
#include "pathnames.h"
/* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: parse.c,v 1.752 2025/06/16 18:20:00 rillig Exp $");
+MAKE_RCSID("$NetBSD: parse.c,v 1.753 2025/06/28 22:39:27 rillig Exp $");
/* Detects a multiple-inclusion guard in a makefile. */
typedef enum {
@@ -954,10 +954,10 @@ InvalidLineType(const char *line, const char *unexpanded_line)
Parse_Error(PARSE_FATAL, "Unknown directive \"%.*s\"",
(int)(dirend - dirstart), dirstart);
} else if (strcmp(line, unexpanded_line) == 0)
- Parse_Error(PARSE_FATAL, "Invalid line '%s'", line);
+ Parse_Error(PARSE_FATAL, "Invalid line \"%s\"", line);
else
Parse_Error(PARSE_FATAL,
- "Invalid line '%s', expanded to '%s'",
+ "Invalid line \"%s\", expanded to \"%s\"",
unexpanded_line, line);
}
@@ -1063,7 +1063,7 @@ HandleDependencyTargetPath(const char *suffixName,
path = Suff_GetPath(suffixName);
if (path == NULL) {
Parse_Error(PARSE_FATAL,
- "Suffix '%s' not defined (yet)", suffixName);
+ "Suffix \"%s\" not defined (yet)", suffixName);
return false;
}
@@ -1159,7 +1159,7 @@ SkipExtraTargets(char **pp, const char *lstart)
if (warning) {
const char *start = *pp;
cpp_skip_whitespace(&start);
- Parse_Error(PARSE_WARNING, "Extra target '%.*s' ignored",
+ Parse_Error(PARSE_WARNING, "Extra target \"%.*s\" ignored",
(int)(p - start), start);
}
@@ -1446,7 +1446,8 @@ ApplyDependencyTarget(char *name, char *nameEnd, ParseSpecial *inout_special,
if (*inout_special == SP_NOT && *name != '\0')
HandleDependencyTargetMundane(name);
else if (*inout_special == SP_PATH && *name != '.' && *name != '\0')
- Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", name);
+ Parse_Error(PARSE_WARNING, "Extra target \"%s\" ignored",
+ name);
*nameEnd = savedNameEnd;
return true;
@@ -2066,7 +2067,7 @@ ParseInclude(char *directive)
if (*p != '"' && *p != '<') {
Parse_Error(PARSE_FATAL,
- ".include filename must be delimited by '\"' or '<'");
+ ".include filename must be delimited by \"\" or <>");
return;
}
@@ -2078,7 +2079,7 @@ ParseInclude(char *directive)
if (*p != endc) {
Parse_Error(PARSE_FATAL,
- "Unclosed .include filename. '%c' expected", endc);
+ "Unclosed .include filename, \"%c\" expected", endc);
return;
}
diff --git a/contrib/bmake/str.c b/contrib/bmake/str.c
index f705b0deb874..e66cdbc8682e 100644
--- a/contrib/bmake/str.c
+++ b/contrib/bmake/str.c
@@ -1,4 +1,4 @@
-/* $NetBSD: str.c,v 1.105 2024/07/07 07:50:57 rillig Exp $ */
+/* $NetBSD: str.c,v 1.106 2025/06/28 21:09:43 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -71,7 +71,7 @@
#include "make.h"
/* "@(#)str.c 5.8 (Berkeley) 6/1/90" */
-MAKE_RCSID("$NetBSD: str.c,v 1.105 2024/07/07 07:50:57 rillig Exp $");
+MAKE_RCSID("$NetBSD: str.c,v 1.106 2025/06/28 21:09:43 rillig Exp $");
static HashTable interned_strings;
@@ -363,8 +363,11 @@ match_fixed_length:
continue;
}
- if (*pat == '\\') /* match the next character exactly */
+ if (*pat == '\\') { /* match the next character exactly */
pat++;
+ if (*pat == '\0')
+ res.error = "Unfinished backslash at the end";
+ }
if (*pat != *str) {
if (asterisk && str == fixed_str) {
while (*str != '\0' && *str != *pat)
diff --git a/contrib/bmake/unit-tests/Makefile b/contrib/bmake/unit-tests/Makefile
index 618a5959e304..4e639056815a 100644
--- a/contrib/bmake/unit-tests/Makefile
+++ b/contrib/bmake/unit-tests/Makefile
@@ -1,6 +1,6 @@
-# $Id: Makefile,v 1.239 2025/06/15 21:32:16 sjg Exp $
+# $Id: Makefile,v 1.240 2025/06/30 18:40:54 sjg Exp $
#
-# $NetBSD: Makefile,v 1.367 2025/06/13 20:23:16 rillig Exp $
+# $NetBSD: Makefile,v 1.369 2025/06/29 09:40:13 rillig Exp $
#
# Unit tests for make(1)
#
@@ -58,6 +58,7 @@ rm-tmpdir: .NOMETA
# src/tests/usr.bin/make/t_make.sh as well.
#TESTS+= archive
#TESTS+= archive-suffix
+TESTS+= char-005c-reverse-solidus
TESTS+= cmd-errors
TESTS+= cmd-errors-jobs
TESTS+= cmd-errors-lint
@@ -413,6 +414,7 @@ TESTS+= varmod-to-upper
TESTS+= varmod-undefined
TESTS+= varmod-unique
TESTS+= varname
+TESTS+= varname-circumflex
TESTS+= varname-dollar
TESTS+= varname-dot-alltargets
TESTS+= varname-dot-curdir
@@ -541,7 +543,6 @@ TESTS:= ${TESTS:${BROKEN_TESTS:S,^,N,:ts:}}
# Ideas for more tests:
# char-0020-space.mk
-# char-005C-backslash.mk
# escape-cond-str.mk
# escape-cond-func-arg.mk
# escape-varmod.mk
diff --git a/contrib/bmake/unit-tests/char-005c-reverse-solidus.exp b/contrib/bmake/unit-tests/char-005c-reverse-solidus.exp
new file mode 100644
index 000000000000..351ef95040e5
--- /dev/null
+++ b/contrib/bmake/unit-tests/char-005c-reverse-solidus.exp
@@ -0,0 +1,13 @@
+make: char-005c-reverse-solidus.mk:57: Unclosed expression, expecting "}" for modifier "Mx\}"
+ while evaluating variable "BACKSLASH" with value ""
+make: char-005c-reverse-solidus.mk:64: Unclosed expression, expecting "}" for modifier "Mx\\}"
+ while evaluating variable "BACKSLASH" with value ""
+make: char-005c-reverse-solidus.mk:71: Unclosed expression, expecting "}" for modifier "Mx\\\\\\\\}"
+ while evaluating variable "BACKSLASH" with value ""
+make: char-005c-reverse-solidus.mk:100: Unfinished backslash at the end in pattern "\" of modifier ":M"
+ while evaluating variable "BACKSLASH" with value "\"
+make: char-005c-reverse-solidus.mk:111: Unclosed expression, expecting "}" for modifier "M${:U\\\\}} != "\\""
+ while evaluating variable "BACKSLASH" with value ""
+make: Fatal errors encountered -- cannot continue
+make: stopped in unit-tests
+exit status 1
diff --git a/contrib/bmake/unit-tests/char-005c-reverse-solidus.mk b/contrib/bmake/unit-tests/char-005c-reverse-solidus.mk
new file mode 100644
index 000000000000..7a151ac46322
--- /dev/null
+++ b/contrib/bmake/unit-tests/char-005c-reverse-solidus.mk
@@ -0,0 +1,131 @@
+# $NetBSD: char-005c-reverse-solidus.mk,v 1.2 2025/06/29 11:27:21 rillig Exp $
+#
+# Tests for the character U+005C "REVERSE SOLIDUS".
+#
+# See also:
+# TODO
+# TODO
+# TODO
+
+# TODO: Where is this character used normally?
+# TODO: What are the edge cases?
+
+# TODO: escape '#' in lines
+# TODO: escape '#' in comments
+# TODO: escape ':' in modifiers
+# TODO: escape any character in condition strings
+
+# begin https://gnats.netbsd.org/46139
+
+# Too see the details of parsing, uncomment the following line.
+#.MAKEFLAGS: -dcpv
+
+# This backslash is treated as a line continuation.
+# It does not end up in the variable value.
+LINE_CONTINUATION=foo\
+# This line is still part of the variable assignment
+.if ${LINE_CONTINUATION:C,[^a-z],<>,gW} != "foo"
+. error
+.endif
+
+# The variable value contains two backslashes.
+TWO_BACKSLASHES_AT_EOL=foo\\
+.if ${TWO_BACKSLASHES_AT_EOL:C,[^a-z],<>,gW} != "foo<><>"
+. error
+.endif
+
+TRAILING_WHITESPACE=foo\ # trailing space
+.if ${TRAILING_WHITESPACE:C,[^a-z],<>,gW} != "foo<><>"
+. error
+.endif
+
+# The simplest was to produce a single backslash is the :U modifier.
+BACKSLASH= ${:U\\}
+.if ${BACKSLASH} != "\\"
+. error
+.endif
+BACKSLASH_C= ${:U1:C,.,\\,}
+.if ${BACKSLASH_C} != "\\"
+. error
+.endif
+
+# expect+5: Unclosed expression, expecting "}" for modifier "Mx\}"
+# At the point where the unclosed expression is detected, the ":M" modifier
+# has been applied to the expression. Its pattern is "x}", which doesn't
+# match the single backslash.
+# expect: while evaluating variable "BACKSLASH" with value ""
+.if ${BACKSLASH:Mx\}
+. error
+.else
+. error
+.endif
+
+# expect+1: Unclosed expression, expecting "}" for modifier "Mx\\}"
+.if ${BACKSLASH:Mx\\}
+. error
+.else
+. error
+.endif
+
+# expect+1: Unclosed expression, expecting "}" for modifier "Mx\\\\\\\\}"
+.if ${BACKSLASH:Mx\\\\\\\\}
+. error
+.else
+. error
+.endif
+
+# Adding more text after the backslash adds to the pattern, as the backslash
+# serves to escape the ":" that is otherwise used to separate the modifiers.
+# The result is a single ":M" modifier with the pattern "x:Nzzz".
+.if ${BACKSLASH:Mx\:Nzzz} != ""
+. error
+.endif
+
+# The pattern ends up as "x\:Nzzz". Only the sequence "\:" is unescaped, all
+# others, including "\\", are left as-is.
+.if ${BACKSLASH:Mx\\:Nzzz} != ""
+. error
+.endif
+
+# The pattern for the ":M" modifier ends up as "x\\\\\\\:Nzzz". Only the
+# sequence "\:" is unescaped, all others, including "\\", are left as-is.
+.if ${BACKSLASH:Mx\\\\\\\\:Nzzz} != ""
+. error
+.endif
+
+# The ":M" modifier is parsed differently than the other modifiers. To
+# circumvent the peculiarities of that parser, the pattern can be passed via
+# an expression. There, the usual escaping rules for modifiers apply.
+# expect+1: Unfinished backslash at the end in pattern "\" of modifier ":M"
+.if ${BACKSLASH:M${BACKSLASH}} != "\\"
+. error
+.else
+. error
+.endif
+
+# Trying to bypass the parser by using a direct expression doesn't work, as
+# the parser for the ":M" modifier does not parse the subexpression like in
+# all other places, but instead counts the braces and tries to decode the
+# escaping, which fails in this case.
+# expect+1: Unclosed expression, expecting "}" for modifier "M${:U\\\\}} != "\\""
+.if ${BACKSLASH:M${:U\\\\}} != "\\"
+. error
+.else
+. error
+.endif
+
+# Matching a backslash with the pattern matching characters works.
+.if ${BACKSLASH:M?} != "\\"
+. error
+.endif
+.if ${BACKSLASH:M*} != "\\"
+. error
+.endif
+.if ${BACKSLASH:M[Z-a]} != "\\"
+. error
+.endif
+.if ${BACKSLASH:M[\\]} != "\\"
+. error
+.endif
+
+# end https://gnats.netbsd.org/46139
diff --git a/contrib/bmake/unit-tests/check-expect.lua b/contrib/bmake/unit-tests/check-expect.lua
index 218056fbc021..2f3adf49baa6 100644
--- a/contrib/bmake/unit-tests/check-expect.lua
+++ b/contrib/bmake/unit-tests/check-expect.lua
@@ -1,5 +1,5 @@
#! /usr/bin/lua
--- $NetBSD: check-expect.lua,v 1.13 2025/04/13 09:29:32 rillig Exp $
+-- $NetBSD: check-expect.lua,v 1.17 2025/07/01 05:03:18 rillig Exp $
--[[
@@ -9,29 +9,32 @@ Check that the various 'expect' comments in the .mk files produce the
expected text in the corresponding .exp file.
# expect: <line>
- All of these lines must occur in the .exp file, in the same order as
- in the .mk file.
-
-# expect-reset
- Search the following 'expect:' comments from the top of the .exp
- file again.
+ Each <line> must occur in the .exp file.
+ The order in the .mk file must be the same as in the .exp file.
# expect[+-]offset: <message>
- Each message must occur in the .exp file and refer back to the
+ Each <message> must occur in the .exp file and refer back to the
source line in the .mk file.
+ Each such line in the .exp file must have a corresponding expect line
+ in the .mk file.
+ The order in the .mk file must be the same as in the .exp file.
+
+# expect-reset
+ Search the following "expect:" and "expect[+-]offset:" comments
+ from the top of the .exp file again.
# expect-not: <substring>
- The substring must not occur as part of any line of the .exp file.
+ The <substring> must not occur as part of any line in the .exp file.
# expect-not-matches: <pattern>
- The pattern (see https://lua.org/manual/5.4/manual.html#6.4.1)
- must not occur as part of any line of the .exp file.
+ The <pattern> (see https://lua.org/manual/5.4/manual.html#6.4.1)
+ must not occur as part of any line in the .exp file.
]]
local had_errors = false
---@param fmt string
-function print_error(fmt, ...)
+local function print_error(fmt, ...)
print(fmt:format(...))
had_errors = true
end
@@ -42,7 +45,9 @@ local function load_lines(fname)
local lines = {}
local f = io.open(fname, "r")
- if f == nil then return nil end
+ if f == nil then
+ return nil
+ end
for line in f:lines() do
table.insert(lines, line)
@@ -53,135 +58,129 @@ local function load_lines(fname)
end
----@param exp_lines string[]
-local function collect_lineno_diagnostics(exp_lines)
- ---@type table<string, string[]>
- local by_location = {}
+--- @shape ExpLine
+--- @field filename string | nil
+--- @field lineno number | nil
+--- @field text string
- for _, line in ipairs(exp_lines) do
- ---@type string | nil, string, string
- local l_fname, l_lineno, l_msg =
- line:match('^make: ([^:]+):(%d+): (.*)')
- if l_fname ~= nil then
- local location = ("%s:%d"):format(l_fname, l_lineno)
- if by_location[location] == nil then
- by_location[location] = {}
- end
- table.insert(by_location[location], l_msg)
+
+--- @param lines string[]
+--- @return ExpLine[]
+local function parse_exp(lines)
+ local exp_lines = {}
+ for _, line in ipairs(lines) do
+ local l_filename, l_lineno, l_text =
+ line:match('^make: ([^:]+%.mk):(%d+):%s+(.*)')
+ if not l_filename then
+ l_text = line
end
+ l_text = l_text:gsub("^%s+", ""):gsub("%s+$", "")
+ table.insert(exp_lines, {
+ filename = l_filename,
+ lineno = tonumber(l_lineno),
+ text = l_text,
+ })
end
-
- return by_location
+ return exp_lines
end
-
-local function missing(by_location)
- ---@type {filename: string, lineno: number, location: string, message: string}[]
- local missing_expectations = {}
-
- for location, messages in pairs(by_location) do
- for _, message in ipairs(messages) do
- if message ~= "" and location:find(".mk:") then
- local filename, lineno = location:match("^(%S+):(%d+)$")
- table.insert(missing_expectations, {
- filename = filename,
- lineno = tonumber(lineno),
- location = location,
- message = message
- })
- end
+---@param exp_lines ExpLine[]
+local function detect_missing_expect_lines(exp_fname, exp_lines, s, e)
+ for i = s, e do
+ local exp_line = exp_lines[i]
+ if exp_line.filename then
+ print_error("error: %s:%d requires in %s:%d: # expect+1: %s",
+ exp_fname, i, exp_line.filename, exp_line.lineno, exp_line.text)
end
end
- table.sort(missing_expectations, function(a, b)
- if a.filename ~= b.filename then
- return a.filename < b.filename
- end
- return a.lineno < b.lineno
- end)
- return missing_expectations
end
-
local function check_mk(mk_fname)
local exp_fname = mk_fname:gsub("%.mk$", ".exp")
local mk_lines = load_lines(mk_fname)
- local exp_lines = load_lines(exp_fname)
- if exp_lines == nil then return end
- local by_location = collect_lineno_diagnostics(exp_lines)
- local prev_expect_line = 0
+ local exp_raw_lines = load_lines(exp_fname)
+ if exp_raw_lines == nil then
+ return
+ end
+ local exp_lines = parse_exp(exp_raw_lines)
+
+ local exp_it = 1
for mk_lineno, mk_line in ipairs(mk_lines) do
- for text in mk_line:gmatch("#%s*expect%-not:%s*(.*)") do
- local i = 1
- while i <= #exp_lines and not exp_lines[i]:find(text, 1, true) do
- i = i + 1
- end
- if i <= #exp_lines then
- print_error("error: %s:%d: %s must not contain '%s'",
- mk_fname, mk_lineno, exp_fname, text)
+ local function match(pattern, action)
+ local _, n = mk_line:gsub(pattern, action)
+ if n > 0 then
+ match = function() end
end
end
- for text in mk_line:gmatch("#%s*expect%-not%-matches:%s*(.*)") do
- local i = 1
- while i <= #exp_lines and not exp_lines[i]:find(text) do
- i = i + 1
+ match("^#%s+expect%-not:%s*(.*)", function(text)
+ for exp_lineno, exp_line in ipairs(exp_lines) do
+ if exp_line.text:find(text, 1, true) then
+ print_error("error: %s:%d: %s:%d must not contain '%s'",
+ mk_fname, mk_lineno, exp_fname, exp_lineno, text)
+ end
end
- if i <= #exp_lines then
- print_error("error: %s:%d: %s must not match '%s'",
- mk_fname, mk_lineno, exp_fname, text)
+ end)
+
+ match("^#%s+expect%-not%-matches:%s*(.*)", function(pattern)
+ for exp_lineno, exp_line in ipairs(exp_lines) do
+ if exp_line.text:find(pattern) then
+ print_error("error: %s:%d: %s:%d must not match '%s'",
+ mk_fname, mk_lineno, exp_fname, exp_lineno, pattern)
+ end
end
- end
+ end)
- for text in mk_line:gmatch("#%s*expect:%s*(.*)") do
- local i = prev_expect_line
- -- As of 2022-04-15, some lines in the .exp files contain trailing
- -- whitespace. If possible, this should be avoided by rewriting the
- -- debug logging. When done, the trailing gsub can be removed.
- -- See deptgt-phony.exp lines 14 and 15.
- while i < #exp_lines and text ~= exp_lines[i + 1]:gsub("^%s*", ""):gsub("%s*$", "") do
+ match("^#%s+expect:%s*(.*)", function(text)
+ local i = exp_it
+ while i <= #exp_lines and text ~= exp_lines[i].text do
i = i + 1
end
- if i < #exp_lines then
- prev_expect_line = i + 1
+ if i <= #exp_lines then
+ detect_missing_expect_lines(exp_fname, exp_lines, exp_it, i - 1)
+ exp_lines[i].text = ""
+ exp_it = i + 1
else
print_error("error: %s:%d: '%s:%d+' must contain '%s'",
- mk_fname, mk_lineno, exp_fname, prev_expect_line + 1, text)
+ mk_fname, mk_lineno, exp_fname, exp_it, text)
end
- end
- if mk_line:match("^#%s*expect%-reset$") then
- prev_expect_line = 0
- end
+ end)
- ---@param text string
- for offset, text in mk_line:gmatch("#%s*expect([+%-]%d+):%s*(.*)") do
- local location = ("%s:%d"):format(mk_fname, mk_lineno + tonumber(offset))
-
- local found = false
- if by_location[location] ~= nil then
- for i, message in ipairs(by_location[location]) do
- if message == text then
- by_location[location][i] = ""
- found = true
- break
- elseif message ~= "" then
- print_error("error: %s:%d: out-of-order '%s'",
- mk_fname, mk_lineno, message)
- end
- end
+ match("^#%s+expect%-reset$", function()
+ exp_it = 1
+ end)
+
+ match("^#%s+expect([+%-]%d+):%s*(.*)", function(offset, text)
+ local msg_lineno = mk_lineno + tonumber(offset)
+
+ local i = exp_it
+ while i <= #exp_lines and text ~= exp_lines[i].text do
+ i = i + 1
end
- if not found then
- print_error("error: %s:%d: %s must contain '%s'",
- mk_fname, mk_lineno, exp_fname, text)
+ if i <= #exp_lines and exp_lines[i].lineno == msg_lineno then
+ detect_missing_expect_lines(exp_fname, exp_lines, exp_it, i - 1)
+ exp_lines[i].text = ""
+ exp_it = i + 1
+ elseif i <= #exp_lines then
+ print_error("error: %s:%d: expect%+d must be expect%+d",
+ mk_fname, mk_lineno, tonumber(offset),
+ exp_lines[i].lineno - mk_lineno)
+ else
+ print_error("error: %s:%d: %s:%d+ must contain '%s'",
+ mk_fname, mk_lineno, exp_fname, exp_it, text)
end
- end
- end
+ end)
+
+ match("^#%s+expect[+%-:]", function()
+ print_error("error: %s:%d: invalid \"expect\" line: %s",
+ mk_fname, mk_lineno, mk_line)
+ end)
- for _, m in ipairs(missing(by_location)) do
- print_error("missing: %s: # expect+1: %s", m.location, m.message)
end
+ detect_missing_expect_lines(exp_fname, exp_lines, exp_it, #exp_lines)
end
for _, fname in ipairs(arg) do
diff --git a/contrib/bmake/unit-tests/cmd-errors-jobs.exp b/contrib/bmake/unit-tests/cmd-errors-jobs.exp
index bd3ae1e51332..3be1bb9b0773 100644
--- a/contrib/bmake/unit-tests/cmd-errors-jobs.exp
+++ b/contrib/bmake/unit-tests/cmd-errors-jobs.exp
@@ -11,7 +11,7 @@ make: Unclosed variable "UNCLOSED"
in command ": unexpected $@-${UNCLOSED"
in target "parse-error-unclosed-expression"
in make[1] in directory "<curdir>"
-make: Unclosed expression, expecting '}'
+make: Unclosed expression, expecting "}"
while evaluating variable "UNCLOSED" with value ""
in command ": unexpected $@-${UNCLOSED:"
in target "parse-error-unclosed-modifier"
@@ -28,7 +28,7 @@ make: Unclosed variable "UNCLOSED"
in command ": unexpected $@-${UNCLOSED"
in target "parse-error-unclosed-expression"
in make[1] in directory "<curdir>"
-make: Unclosed expression, expecting '}'
+make: Unclosed expression, expecting "}"
while evaluating variable "UNCLOSED" with value ""
in command ": unexpected $@-${UNCLOSED:"
in target "parse-error-unclosed-modifier"
diff --git a/contrib/bmake/unit-tests/cmd-errors-jobs.mk b/contrib/bmake/unit-tests/cmd-errors-jobs.mk
index a29883fc6676..f6261d6ad1a8 100644
--- a/contrib/bmake/unit-tests/cmd-errors-jobs.mk
+++ b/contrib/bmake/unit-tests/cmd-errors-jobs.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cmd-errors-jobs.mk,v 1.15 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: cmd-errors-jobs.mk,v 1.16 2025/06/28 22:39:28 rillig Exp $
#
# Demonstrate how errors in expressions affect whether the commands
# are actually executed in jobs mode.
@@ -50,11 +50,11 @@ parse-error-unknown-modifier:
# expect-not-matches: ^: unexpected
# expect: make: Unclosed variable "UNCLOSED"
# expect: in command ": unexpected $@-${UNCLOSED"
-# expect: make: Unclosed expression, expecting '}'
+# expect: make: Unclosed expression, expecting "}"
# expect: make: Unknown modifier ":Z"
# expect: end parse-error-direct with status 2
# expect: make: Unclosed variable "UNCLOSED"
-# expect: make: Unclosed expression, expecting '}'
+# expect: make: Unclosed expression, expecting "}"
# expect: make: Unknown modifier ":Z"
# expect: end parse-error-indirect with status 2
diff --git a/contrib/bmake/unit-tests/cmd-errors-lint.exp b/contrib/bmake/unit-tests/cmd-errors-lint.exp
index ec7336f618b8..b08a65ff96dc 100644
--- a/contrib/bmake/unit-tests/cmd-errors-lint.exp
+++ b/contrib/bmake/unit-tests/cmd-errors-lint.exp
@@ -2,7 +2,7 @@
make: Unclosed variable "UNCLOSED"
in command ": $@ ${UNCLOSED"
in target "unclosed-expression"
-make: Unclosed expression, expecting '}'
+make: Unclosed expression, expecting "}"
while evaluating variable "UNCLOSED" with value ""
in command ": $@ ${UNCLOSED:"
in target "unclosed-modifier"
diff --git a/contrib/bmake/unit-tests/cmd-errors-lint.mk b/contrib/bmake/unit-tests/cmd-errors-lint.mk
index eb2ec1171545..455ef2c0cfe7 100644
--- a/contrib/bmake/unit-tests/cmd-errors-lint.mk
+++ b/contrib/bmake/unit-tests/cmd-errors-lint.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cmd-errors-lint.mk,v 1.7 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: cmd-errors-lint.mk,v 1.8 2025/06/28 22:39:28 rillig Exp $
#
# Demonstrate how errors in expressions affect whether the commands
# are actually executed.
@@ -19,7 +19,7 @@ unclosed-expression:
: $@ ${UNCLOSED
unclosed-modifier:
-# expect: make: Unclosed expression, expecting '}'
+# expect: make: Unclosed expression, expecting "}"
# expect-not: : unclosed-modifier
: $@ ${UNCLOSED:
diff --git a/contrib/bmake/unit-tests/cmd-errors.exp b/contrib/bmake/unit-tests/cmd-errors.exp
index 62da47ff42c5..2916d423029e 100644
--- a/contrib/bmake/unit-tests/cmd-errors.exp
+++ b/contrib/bmake/unit-tests/cmd-errors.exp
@@ -2,7 +2,7 @@
make: Unclosed variable "UNCLOSED"
in command ": $@-${UNCLOSED"
in target "unclosed-expression"
-make: Unclosed expression, expecting '}'
+make: Unclosed expression, expecting "}"
while evaluating variable "UNCLOSED" with value ""
in command ": $@-${UNCLOSED:"
in target "unclosed-modifier"
diff --git a/contrib/bmake/unit-tests/cmd-errors.mk b/contrib/bmake/unit-tests/cmd-errors.mk
index 8766b6a856c7..52e314c5bd38 100644
--- a/contrib/bmake/unit-tests/cmd-errors.mk
+++ b/contrib/bmake/unit-tests/cmd-errors.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cmd-errors.mk,v 1.12 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: cmd-errors.mk,v 1.13 2025/06/28 22:39:28 rillig Exp $
#
# Demonstrate how errors in expressions affect whether the commands
# are actually executed in compat mode.
@@ -17,7 +17,7 @@ unclosed-expression:
: $@-${UNCLOSED
unclosed-modifier:
-# expect: make: Unclosed expression, expecting '}'
+# expect: make: Unclosed expression, expecting "}"
# expect-not: : unclosed-modifier-
: $@-${UNCLOSED:
diff --git a/contrib/bmake/unit-tests/cmdline-undefined.exp b/contrib/bmake/unit-tests/cmdline-undefined.exp
index 12fc45e50822..ae0b35dac420 100644
--- a/contrib/bmake/unit-tests/cmdline-undefined.exp
+++ b/contrib/bmake/unit-tests/cmdline-undefined.exp
@@ -1,17 +1,17 @@
The = assignment operator
-make: cmdline-undefined.mk:31: From the command line: Undefined is .
-make: cmdline-undefined.mk:34: From .MAKEFLAGS '=': Undefined is .
-make: cmdline-undefined.mk:37: From .MAKEFLAGS ':=': Undefined is .
-make: cmdline-undefined.mk:43: From the command line: Undefined is now defined.
-make: cmdline-undefined.mk:46: From .MAKEFLAGS '=': Undefined is now defined.
+make: cmdline-undefined.mk:41: From the command line: Undefined is .
+make: cmdline-undefined.mk:42: From .MAKEFLAGS '=': Undefined is .
+make: cmdline-undefined.mk:43: From .MAKEFLAGS ':=': Undefined is .
+make: cmdline-undefined.mk:47: From the command line: Undefined is now defined.
+make: cmdline-undefined.mk:48: From .MAKEFLAGS '=': Undefined is now defined.
make: cmdline-undefined.mk:49: From .MAKEFLAGS ':=': Undefined is now defined.
The := assignment operator
-make: cmdline-undefined.mk:31: From the command line: Undefined is .
-make: cmdline-undefined.mk:34: From .MAKEFLAGS '=': Undefined is .
-make: cmdline-undefined.mk:37: From .MAKEFLAGS ':=': Undefined is .
-make: cmdline-undefined.mk:43: From the command line: Undefined is now defined.
-make: cmdline-undefined.mk:46: From .MAKEFLAGS '=': Undefined is now defined.
+make: cmdline-undefined.mk:41: From the command line: Undefined is .
+make: cmdline-undefined.mk:42: From .MAKEFLAGS '=': Undefined is .
+make: cmdline-undefined.mk:43: From .MAKEFLAGS ':=': Undefined is .
+make: cmdline-undefined.mk:47: From the command line: Undefined is now defined.
+make: cmdline-undefined.mk:48: From .MAKEFLAGS '=': Undefined is now defined.
make: cmdline-undefined.mk:49: From .MAKEFLAGS ':=': Undefined is now defined.
exit status 0
diff --git a/contrib/bmake/unit-tests/cmdline-undefined.mk b/contrib/bmake/unit-tests/cmdline-undefined.mk
index e7c0400ad1e1..2deb944b1fab 100644
--- a/contrib/bmake/unit-tests/cmdline-undefined.mk
+++ b/contrib/bmake/unit-tests/cmdline-undefined.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cmdline-undefined.mk,v 1.5 2024/04/23 22:51:28 rillig Exp $
+# $NetBSD: cmdline-undefined.mk,v 1.6 2025/06/30 21:44:39 rillig Exp $
#
# Tests for undefined variables in expressions in the command line.
@@ -8,6 +8,12 @@ all:
# (which probably occurs rarely in practice, if at all), but their
# variable value is not expanded, as usual.
#
+# expect+30: From the command line: Undefined is .
+# expect+30: From .MAKEFLAGS '=': Undefined is .
+# expect+30: From .MAKEFLAGS ':=': Undefined is .
+# expect+33: From the command line: Undefined is now defined.
+# expect+33: From .MAKEFLAGS '=': Undefined is now defined.
+# expect+33: From .MAKEFLAGS ':=': Undefined is now defined.
@echo 'The = assignment operator'
@${.MAKE} -f ${MAKEFILE} print-undefined \
CMDLINE='Undefined is $${UNDEFINED}.'
@@ -16,6 +22,12 @@ all:
# The interesting case is using the ':=' assignment operator, which
# expands its right-hand side. But only those variables that are
# defined.
+# expect+16: From the command line: Undefined is .
+# expect+16: From .MAKEFLAGS '=': Undefined is .
+# expect+16: From .MAKEFLAGS ':=': Undefined is .
+# expect+19: From the command line: Undefined is now defined.
+# expect+19: From .MAKEFLAGS '=': Undefined is now defined.
+# expect+19: From .MAKEFLAGS ':=': Undefined is now defined.
@echo 'The := assignment operator'
@${.MAKE} -f ${MAKEFILE} print-undefined \
CMDLINE:='Undefined is $${UNDEFINED}.'
@@ -26,26 +38,14 @@ all:
.MAKEFLAGS: MAKEFLAGS_ASSIGN='Undefined is $${UNDEFINED}.'
.MAKEFLAGS: MAKEFLAGS_SUBST:='Undefined is $${UNDEFINED}.'
-# expect+2: From the command line: Undefined is .
-# expect+1: From the command line: Undefined is .
.info From the command line: ${CMDLINE}
-# expect+2: From .MAKEFLAGS '=': Undefined is .
-# expect+1: From .MAKEFLAGS '=': Undefined is .
.info From .MAKEFLAGS '=': ${MAKEFLAGS_ASSIGN}
-# expect+2: From .MAKEFLAGS ':=': Undefined is .
-# expect+1: From .MAKEFLAGS ':=': Undefined is .
.info From .MAKEFLAGS ':=': ${MAKEFLAGS_SUBST}
UNDEFINED?= now defined
-# expect+2: From the command line: Undefined is now defined.
-# expect+1: From the command line: Undefined is now defined.
.info From the command line: ${CMDLINE}
-# expect+2: From .MAKEFLAGS '=': Undefined is now defined.
-# expect+1: From .MAKEFLAGS '=': Undefined is now defined.
.info From .MAKEFLAGS '=': ${MAKEFLAGS_ASSIGN}
-# expect+2: From .MAKEFLAGS ':=': Undefined is now defined.
-# expect+1: From .MAKEFLAGS ':=': Undefined is now defined.
.info From .MAKEFLAGS ':=': ${MAKEFLAGS_SUBST}
print-undefined:
diff --git a/contrib/bmake/unit-tests/cond-cmp-numeric-eq.exp b/contrib/bmake/unit-tests/cond-cmp-numeric-eq.exp
index 1a386d53dbef..81c73d887c18 100644
--- a/contrib/bmake/unit-tests/cond-cmp-numeric-eq.exp
+++ b/contrib/bmake/unit-tests/cond-cmp-numeric-eq.exp
@@ -1,5 +1,5 @@
-make: cond-cmp-numeric-eq.mk:68: Malformed conditional '!(12345 = 12345)'
-make: cond-cmp-numeric-eq.mk:76: Malformed conditional '!(12345 === 12345)'
+make: cond-cmp-numeric-eq.mk:68: Malformed conditional "!(12345 = 12345)"
+make: cond-cmp-numeric-eq.mk:76: Malformed conditional "!(12345 === 12345)"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-cmp-numeric-eq.mk b/contrib/bmake/unit-tests/cond-cmp-numeric-eq.mk
index a8630cb37f1f..ea60f6f7b18d 100755
--- a/contrib/bmake/unit-tests/cond-cmp-numeric-eq.mk
+++ b/contrib/bmake/unit-tests/cond-cmp-numeric-eq.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-cmp-numeric-eq.mk,v 1.8 2024/08/06 18:00:16 rillig Exp $
+# $NetBSD: cond-cmp-numeric-eq.mk,v 1.9 2025/06/28 22:39:28 rillig Exp $
#
# Tests for numeric comparisons with the == operator in .if conditions.
@@ -64,7 +64,7 @@
.endif
# There is no = operator for numbers.
-# expect+1: Malformed conditional '!(12345 = 12345)'
+# expect+1: Malformed conditional "!(12345 = 12345)"
.if !(12345 = 12345)
. error
.else
@@ -72,7 +72,7 @@
.endif
# There is no === operator for numbers either.
-# expect+1: Malformed conditional '!(12345 === 12345)'
+# expect+1: Malformed conditional "!(12345 === 12345)"
.if !(12345 === 12345)
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-cmp-numeric.exp b/contrib/bmake/unit-tests/cond-cmp-numeric.exp
index 0945bef72300..2959ad99716c 100644
--- a/contrib/bmake/unit-tests/cond-cmp-numeric.exp
+++ b/contrib/bmake/unit-tests/cond-cmp-numeric.exp
@@ -1,15 +1,15 @@
CondParser_Eval: !(${:UINF} > 1e100)
-make: cond-cmp-numeric.mk:15: Comparison with '>' requires both operands 'INF' and '1e100' to be numeric
+make: cond-cmp-numeric.mk:15: Comparison with ">" requires both operands "INF" and "1e100" to be numeric
CondParser_Eval: ${:UNaN} > NaN
-make: cond-cmp-numeric.mk:21: Comparison with '>' requires both operands 'NaN' and 'NaN' to be numeric
+make: cond-cmp-numeric.mk:21: Comparison with ">" requires both operands "NaN" and "NaN" to be numeric
CondParser_Eval: !(${:UNaN} == NaN)
Comparing "NaN" == "NaN"
CondParser_Eval: 123 ! 123
-make: cond-cmp-numeric.mk:38: Malformed conditional '123 ! 123'
+make: cond-cmp-numeric.mk:38: Malformed conditional "123 ! 123"
CondParser_Eval: ${:U 123} < 124
Comparing 123.000000 < 124.000000
CondParser_Eval: ${:U123 } < 124
-make: cond-cmp-numeric.mk:54: Comparison with '<' requires both operands '123 ' and '124' to be numeric
+make: cond-cmp-numeric.mk:54: Comparison with "<" requires both operands "123 " and "124" to be numeric
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-cmp-numeric.mk b/contrib/bmake/unit-tests/cond-cmp-numeric.mk
index 63a3bff8d560..abe5cc4cce9c 100644
--- a/contrib/bmake/unit-tests/cond-cmp-numeric.mk
+++ b/contrib/bmake/unit-tests/cond-cmp-numeric.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-cmp-numeric.mk,v 1.8 2024/08/06 18:00:16 rillig Exp $
+# $NetBSD: cond-cmp-numeric.mk,v 1.9 2025/06/28 22:39:28 rillig Exp $
#
# Tests for numeric comparisons in .if conditions.
#
@@ -11,13 +11,13 @@
# Even if strtod(3) parses "INF" as +Infinity, make does not accept this
# since it is not really a number; see TryParseNumber.
-# expect+1: Comparison with '>' requires both operands 'INF' and '1e100' to be numeric
+# expect+1: Comparison with ">" requires both operands "INF" and "1e100" to be numeric
.if !(${:UINF} > 1e100)
. error
.endif
# Neither is NaN a number; see TryParseNumber.
-# expect+1: Comparison with '>' requires both operands 'NaN' and 'NaN' to be numeric
+# expect+1: Comparison with ">" requires both operands "NaN" and "NaN" to be numeric
.if ${:UNaN} > NaN
. error
.endif
@@ -34,7 +34,7 @@
# whether the operator is valid, leaving the rest of the work to the
# evaluation functions EvalCompareNum and EvalCompareStr. Ensure that this
# parse error is properly reported.
-# expect+1: Malformed conditional '123 ! 123'
+# expect+1: Malformed conditional "123 ! 123"
.if 123 ! 123
. error
.else
@@ -50,7 +50,7 @@
# Trailing spaces are NOT allowed for numbers.
# See EvalCompare and TryParseNumber.
-# expect+1: Comparison with '<' requires both operands '123 ' and '124' to be numeric
+# expect+1: Comparison with "<" requires both operands "123 " and "124" to be numeric
.if ${:U123 } < 124
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-cmp-string.exp b/contrib/bmake/unit-tests/cond-cmp-string.exp
index b55f30182442..8291d5300c3b 100644
--- a/contrib/bmake/unit-tests/cond-cmp-string.exp
+++ b/contrib/bmake/unit-tests/cond-cmp-string.exp
@@ -1,11 +1,11 @@
-make: cond-cmp-string.mk:19: Malformed conditional 'str != str'
-make: cond-cmp-string.mk:44: Malformed conditional '"string" != "str""ing"'
-make: cond-cmp-string.mk:52: Malformed conditional '!("value" = "value")'
-make: cond-cmp-string.mk:60: Malformed conditional '!("value" === "value")'
-make: cond-cmp-string.mk:118: Comparison with '<' requires both operands 'string' and 'string' to be numeric
-make: cond-cmp-string.mk:126: Comparison with '<=' requires both operands 'string' and 'string' to be numeric
-make: cond-cmp-string.mk:134: Comparison with '>' requires both operands 'string' and 'string' to be numeric
-make: cond-cmp-string.mk:142: Comparison with '>=' requires both operands 'string' and 'string' to be numeric
+make: cond-cmp-string.mk:19: Malformed conditional "str != str"
+make: cond-cmp-string.mk:44: Malformed conditional ""string" != "str""ing""
+make: cond-cmp-string.mk:52: Malformed conditional "!("value" = "value")"
+make: cond-cmp-string.mk:60: Malformed conditional "!("value" === "value")"
+make: cond-cmp-string.mk:118: Comparison with "<" requires both operands "string" and "string" to be numeric
+make: cond-cmp-string.mk:126: Comparison with "<=" requires both operands "string" and "string" to be numeric
+make: cond-cmp-string.mk:134: Comparison with ">" requires both operands "string" and "string" to be numeric
+make: cond-cmp-string.mk:142: Comparison with ">=" requires both operands "string" and "string" to be numeric
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-cmp-string.mk b/contrib/bmake/unit-tests/cond-cmp-string.mk
index a913750a017f..56427bda11d0 100644
--- a/contrib/bmake/unit-tests/cond-cmp-string.mk
+++ b/contrib/bmake/unit-tests/cond-cmp-string.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-cmp-string.mk,v 1.20 2024/08/06 18:00:16 rillig Exp $
+# $NetBSD: cond-cmp-string.mk,v 1.21 2025/06/28 22:39:28 rillig Exp $
#
# Tests for string comparisons in .if conditions.
@@ -15,7 +15,7 @@
# The left-hand side of the comparison must be enclosed in quotes.
# This one is not enclosed in quotes and thus generates an error message.
-# expect+1: Malformed conditional 'str != str'
+# expect+1: Malformed conditional "str != str"
.if str != str
. error
.endif
@@ -40,7 +40,7 @@
# It is not possible to concatenate two string literals to form a single
# string. In C, Python and the shell this is possible, but not in make.
-# expect+1: Malformed conditional '"string" != "str""ing"'
+# expect+1: Malformed conditional ""string" != "str""ing""
.if "string" != "str""ing"
. error
.else
@@ -48,7 +48,7 @@
.endif
# There is no = operator for strings.
-# expect+1: Malformed conditional '!("value" = "value")'
+# expect+1: Malformed conditional "!("value" = "value")"
.if !("value" = "value")
. error
.else
@@ -56,7 +56,7 @@
.endif
# There is no === operator for strings either.
-# expect+1: Malformed conditional '!("value" === "value")'
+# expect+1: Malformed conditional "!("value" === "value")"
.if !("value" === "value")
. error
.else
@@ -114,7 +114,7 @@
.endif
# Strings cannot be compared relationally, only for equality.
-# expect+1: Comparison with '<' requires both operands 'string' and 'string' to be numeric
+# expect+1: Comparison with "<" requires both operands "string" and "string" to be numeric
.if "string" < "string"
. error
.else
@@ -122,7 +122,7 @@
.endif
# Strings cannot be compared relationally, only for equality.
-# expect+1: Comparison with '<=' requires both operands 'string' and 'string' to be numeric
+# expect+1: Comparison with "<=" requires both operands "string" and "string" to be numeric
.if "string" <= "string"
. error
.else
@@ -130,7 +130,7 @@
.endif
# Strings cannot be compared relationally, only for equality.
-# expect+1: Comparison with '>' requires both operands 'string' and 'string' to be numeric
+# expect+1: Comparison with ">" requires both operands "string" and "string" to be numeric
.if "string" > "string"
. error
.else
@@ -138,7 +138,7 @@
.endif
# Strings cannot be compared relationally, only for equality.
-# expect+1: Comparison with '>=' requires both operands 'string' and 'string' to be numeric
+# expect+1: Comparison with ">=" requires both operands "string" and "string" to be numeric
.if "string" >= "string"
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-eof.exp b/contrib/bmake/unit-tests/cond-eof.exp
index 44e481745a24..fb23e248178e 100644
--- a/contrib/bmake/unit-tests/cond-eof.exp
+++ b/contrib/bmake/unit-tests/cond-eof.exp
@@ -1,6 +1,6 @@
-make: cond-eof.mk:17: Malformed conditional '0 ${SIDE_EFFECT} ${SIDE_EFFECT2}'
-make: cond-eof.mk:20: Malformed conditional '1 ${SIDE_EFFECT} ${SIDE_EFFECT2}'
-make: cond-eof.mk:23: Malformed conditional '(0) ${SIDE_EFFECT} ${SIDE_EFFECT2}'
+make: cond-eof.mk:17: Malformed conditional "0 ${SIDE_EFFECT} ${SIDE_EFFECT2}"
+make: cond-eof.mk:20: Malformed conditional "1 ${SIDE_EFFECT} ${SIDE_EFFECT2}"
+make: cond-eof.mk:23: Malformed conditional "(0) ${SIDE_EFFECT} ${SIDE_EFFECT2}"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-eof.mk b/contrib/bmake/unit-tests/cond-eof.mk
index 706a7deebd1a..04d79d0783ad 100644
--- a/contrib/bmake/unit-tests/cond-eof.mk
+++ b/contrib/bmake/unit-tests/cond-eof.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-eof.mk,v 1.7 2024/08/06 18:00:16 rillig Exp $
+# $NetBSD: cond-eof.mk,v 1.8 2025/06/28 22:39:28 rillig Exp $
#
# Tests for parsing the end of '.if' conditions, which are represented as the
# token TOK_EOF.
@@ -13,12 +13,12 @@ SIDE_EFFECT2= ${:!echo 'side effect 2' 1>&2!}
# These syntax errors are an edge case that does not occur during normal
# operation. Still, it is easy to avoid evaluating these expressions, just in
# case they have side effects.
-# expect+1: Malformed conditional '0 ${SIDE_EFFECT} ${SIDE_EFFECT2}'
+# expect+1: Malformed conditional "0 ${SIDE_EFFECT} ${SIDE_EFFECT2}"
.if 0 ${SIDE_EFFECT} ${SIDE_EFFECT2}
.endif
-# expect+1: Malformed conditional '1 ${SIDE_EFFECT} ${SIDE_EFFECT2}'
+# expect+1: Malformed conditional "1 ${SIDE_EFFECT} ${SIDE_EFFECT2}"
.if 1 ${SIDE_EFFECT} ${SIDE_EFFECT2}
.endif
-# expect+1: Malformed conditional '(0) ${SIDE_EFFECT} ${SIDE_EFFECT2}'
+# expect+1: Malformed conditional "(0) ${SIDE_EFFECT} ${SIDE_EFFECT2}"
.if (0) ${SIDE_EFFECT} ${SIDE_EFFECT2}
.endif
diff --git a/contrib/bmake/unit-tests/cond-func-defined.exp b/contrib/bmake/unit-tests/cond-func-defined.exp
index ea3ced9398e8..04b57061f803 100644
--- a/contrib/bmake/unit-tests/cond-func-defined.exp
+++ b/contrib/bmake/unit-tests/cond-func-defined.exp
@@ -1,5 +1,5 @@
-make: cond-func-defined.mk:24: Missing ')' after argument 'A' for 'defined'
-make: cond-func-defined.mk:34: Missing ')' after argument 'DEF' for 'defined'
+make: cond-func-defined.mk:24: Missing ")" after argument "A" for "defined"
+make: cond-func-defined.mk:34: Missing ")" after argument "DEF" for "defined"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-func-defined.mk b/contrib/bmake/unit-tests/cond-func-defined.mk
index 66f95f3380c1..52eeaec8ccfc 100644
--- a/contrib/bmake/unit-tests/cond-func-defined.mk
+++ b/contrib/bmake/unit-tests/cond-func-defined.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-func-defined.mk,v 1.14 2025/01/10 23:00:38 rillig Exp $
+# $NetBSD: cond-func-defined.mk,v 1.15 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the defined() function in .if conditions.
@@ -20,7 +20,7 @@ ${:UA B}= variable name with spaces
.endif
# The argument of a function must not directly contain whitespace.
-# expect+1: Missing ')' after argument 'A' for 'defined'
+# expect+1: Missing ")" after argument "A" for "defined"
.if !defined(A B)
. error
.endif
@@ -30,7 +30,7 @@ ${:UA B}= variable name with spaces
. error
.endif
-# expect+1: Missing ')' after argument 'DEF' for 'defined'
+# expect+1: Missing ")" after argument "DEF" for "defined"
.if defined(DEF
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-func-make.exp b/contrib/bmake/unit-tests/cond-func-make.exp
index 4d493b3c3ccb..ab25dfc5b553 100644
--- a/contrib/bmake/unit-tests/cond-func-make.exp
+++ b/contrib/bmake/unit-tests/cond-func-make.exp
@@ -1,4 +1,4 @@
-make: cond-func-make.mk:24: warning: Unfinished character list in pattern argument '[' to function 'make'
+make: cond-func-make.mk:24: warning: Unfinished character list in pattern argument "[" to function "make"
: via-cmdline
: via-dot-makeflags
exit status 0
diff --git a/contrib/bmake/unit-tests/cond-func-make.mk b/contrib/bmake/unit-tests/cond-func-make.mk
index 1a14fd320a3c..8903f9c0e723 100644
--- a/contrib/bmake/unit-tests/cond-func-make.mk
+++ b/contrib/bmake/unit-tests/cond-func-make.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-func-make.mk,v 1.6 2025/01/10 23:00:38 rillig Exp $
+# $NetBSD: cond-func-make.mk,v 1.7 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the make() function in .if conditions, which tests whether
# the argument has been passed as a target via the command line or later
@@ -20,7 +20,7 @@
. error
.endif
-# expect+1: warning: Unfinished character list in pattern argument '[' to function 'make'
+# expect+1: warning: Unfinished character list in pattern argument "[" to function "make"
.if make([)
. error
.endif
diff --git a/contrib/bmake/unit-tests/cond-func.exp b/contrib/bmake/unit-tests/cond-func.exp
index c80f95f39c0b..77f65e77d46c 100644
--- a/contrib/bmake/unit-tests/cond-func.exp
+++ b/contrib/bmake/unit-tests/cond-func.exp
@@ -1,13 +1,13 @@
-make: cond-func.mk:37: Missing ')' after argument 'A' for 'defined'
-make: cond-func.mk:53: Missing ')' after argument 'A' for 'defined'
-make: cond-func.mk:57: Missing ')' after argument 'A' for 'defined'
-make: cond-func.mk:91: Unknown operator '&'
+make: cond-func.mk:37: Missing ")" after argument "A" for "defined"
+make: cond-func.mk:53: Missing ")" after argument "A" for "defined"
+make: cond-func.mk:57: Missing ")" after argument "A" for "defined"
+make: cond-func.mk:91: Unknown operator "&"
make: cond-func.mk:107: A plain function name is parsed as defined(...).
make: cond-func.mk:115: A plain function name is parsed as defined(...).
make: cond-func.mk:126: Symbols may start with a function name.
make: cond-func.mk:132: Symbols may start with a function name.
-make: cond-func.mk:138: Missing ')' after argument '' for 'defined'
-make: cond-func.mk:145: Missing ')' after argument '${:UVARNAME}.param' for 'defined'
+make: cond-func.mk:138: Missing ")" after argument "" for "defined"
+make: cond-func.mk:145: Missing ")" after argument "${:UVARNAME}.param" for "defined"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-func.mk b/contrib/bmake/unit-tests/cond-func.mk
index 3e4f8a9f151f..50b3f83cd4cb 100644
--- a/contrib/bmake/unit-tests/cond-func.mk
+++ b/contrib/bmake/unit-tests/cond-func.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-func.mk,v 1.18 2024/08/07 05:48:45 rillig Exp $
+# $NetBSD: cond-func.mk,v 1.19 2025/06/28 22:39:28 rillig Exp $
#
# Tests for those parts of the functions in .if conditions that are common
# among several functions.
@@ -33,7 +33,7 @@ ${VARNAME_UNBALANCED_BRACES}= variable name with unbalanced braces
.endif
# The argument of a function must not directly contain whitespace.
-# expect+1: Missing ')' after argument 'A' for 'defined'
+# expect+1: Missing ")" after argument "A" for "defined"
.if !defined(A B)
. error
.endif
@@ -49,11 +49,11 @@ ${VARNAME_UNBALANCED_BRACES}= variable name with unbalanced braces
#
# It's not entirely clear why these characters are forbidden.
# The most plausible reason seems to be typo detection.
-# expect+1: Missing ')' after argument 'A' for 'defined'
+# expect+1: Missing ")" after argument "A" for "defined"
.if !defined(A&B)
. error
.endif
-# expect+1: Missing ')' after argument 'A' for 'defined'
+# expect+1: Missing ")" after argument "A" for "defined"
.if !defined(A|B)
. error
.endif
@@ -87,7 +87,7 @@ ${VARNAME_UNBALANCED_BRACES}= variable name with unbalanced braces
# interpreted as defined(A) && defined(B). Each kind of .if directive has a
# default function that is called when a bare word is parsed. For the plain
# .if directive, this function is 'defined'; see "struct If ifs" in cond.c.
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if A&B
. error
.endif
@@ -134,14 +134,14 @@ defined-var= # defined but empty
. error
.endif
-# expect+1: Missing ')' after argument '' for 'defined'
+# expect+1: Missing ")" after argument "" for "defined"
.if defined(
. error
.else
. error
.endif
-# expect+1: Missing ')' after argument '${:UVARNAME}.param' for 'defined'
+# expect+1: Missing ")" after argument "${:UVARNAME}.param" for "defined"
.if defined(${:UVARNAME}.param extra)
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-late.exp b/contrib/bmake/unit-tests/cond-late.exp
index 13846e8c822a..e4b3fdac85f4 100644
--- a/contrib/bmake/unit-tests/cond-late.exp
+++ b/contrib/bmake/unit-tests/cond-late.exp
@@ -1,4 +1,4 @@
-make: cond-late.mk:38: Bad condition
+make: cond-late.mk:29: Bad condition
while evaluating condition " != "no""
while evaluating variable "VAR" with value "${${UNDEF} != "no":?:}"
in make[1] in directory "<curdir>"
diff --git a/contrib/bmake/unit-tests/cond-late.mk b/contrib/bmake/unit-tests/cond-late.mk
index a8f381590a6e..154617f4f2b2 100644
--- a/contrib/bmake/unit-tests/cond-late.mk
+++ b/contrib/bmake/unit-tests/cond-late.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-late.mk,v 1.9 2024/08/29 20:20:35 rillig Exp $
+# $NetBSD: cond-late.mk,v 1.10 2025/06/30 21:44:39 rillig Exp $
#
# Using the :? modifier, expressions can contain conditional
# expressions that are evaluated late, at expansion time.
@@ -23,6 +23,13 @@ parse-time: .PHONY
COND.true= "yes" == "yes"
COND.false= "yes" != "yes"
+.if make(do-parse-time)
+VAR= ${${UNDEF} != "no":?:}
+# expect+1: Bad condition
+. if empty(VAR:Mpattern)
+. endif
+.endif
+
# If the order of evaluation were to change to first parse the condition
# and then expand the variables, the output would change from the
# current "yes no" to "yes yes", since both variables are non-empty.
@@ -31,10 +38,3 @@ COND.false= "yes" != "yes"
cond-literal:
@echo ${ ${COND.true} :?yes:no}
@echo ${ ${COND.false} :?yes:no}
-
-.if make(do-parse-time)
-VAR= ${${UNDEF} != "no":?:}
-# expect+1: Bad condition
-. if empty(VAR:Mpattern)
-. endif
-.endif
diff --git a/contrib/bmake/unit-tests/cond-op-and-lint.exp b/contrib/bmake/unit-tests/cond-op-and-lint.exp
index 8896fea5c9b6..74ac32e205e6 100644
--- a/contrib/bmake/unit-tests/cond-op-and-lint.exp
+++ b/contrib/bmake/unit-tests/cond-op-and-lint.exp
@@ -1,4 +1,4 @@
-make: cond-op-and-lint.mk:10: Unknown operator '&'
+make: cond-op-and-lint.mk:10: Unknown operator "&"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-and-lint.mk b/contrib/bmake/unit-tests/cond-op-and-lint.mk
index bac4566314b0..0daa3a728f86 100644
--- a/contrib/bmake/unit-tests/cond-op-and-lint.mk
+++ b/contrib/bmake/unit-tests/cond-op-and-lint.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-and-lint.mk,v 1.2 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: cond-op-and-lint.mk,v 1.3 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the && operator in .if conditions, in lint mode.
@@ -6,7 +6,7 @@
# The '&' operator is not allowed in lint mode.
# It is not used in practice anyway.
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if 0 & 0
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op-and.exp b/contrib/bmake/unit-tests/cond-op-and.exp
index 1ada96a00bdd..b3e45ea1767e 100644
--- a/contrib/bmake/unit-tests/cond-op-and.exp
+++ b/contrib/bmake/unit-tests/cond-op-and.exp
@@ -1,11 +1,11 @@
make: cond-op-and.mk:36: Variable "UNDEF" is undefined
make: cond-op-and.mk:41: Variable "UNDEF" is undefined
make: cond-op-and.mk:44: Variable "UNDEF" is undefined
-make: cond-op-and.mk:60: Unknown operator '&'
-make: cond-op-and.mk:66: Unknown operator '&'
-make: cond-op-and.mk:72: Unknown operator '&'
-make: cond-op-and.mk:78: Unknown operator '&'
-make: cond-op-and.mk:87: Unknown operator '&'
+make: cond-op-and.mk:60: Unknown operator "&"
+make: cond-op-and.mk:66: Unknown operator "&"
+make: cond-op-and.mk:72: Unknown operator "&"
+make: cond-op-and.mk:78: Unknown operator "&"
+make: cond-op-and.mk:87: Unknown operator "&"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-and.mk b/contrib/bmake/unit-tests/cond-op-and.mk
index 5d7f8a06800a..cb84e39e9217 100644
--- a/contrib/bmake/unit-tests/cond-op-and.mk
+++ b/contrib/bmake/unit-tests/cond-op-and.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-and.mk,v 1.12 2025/01/11 21:21:33 rillig Exp $
+# $NetBSD: cond-op-and.mk,v 1.13 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the && operator in .if conditions.
@@ -56,25 +56,25 @@ DEF= defined
# The && operator may be abbreviated as &. This is not widely known though
# and is also not documented in the manual page.
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if 0 & 0
. error
.else
. error
.endif
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if 1 & 0
. error
.else
. error
.endif
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if 0 & 1
. error
.else
. error
.endif
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if !(1 & 1)
. error
.else
@@ -83,7 +83,7 @@ DEF= defined
# There is no operator '&&&'. The first two '&&' form an operator, the third
# '&' forms the next (incomplete) token.
-# expect+1: Unknown operator '&'
+# expect+1: Unknown operator "&"
.if 0 &&& 0
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op-not.exp b/contrib/bmake/unit-tests/cond-op-not.exp
index 63aa928eabc3..f0dfb3b757b1 100644
--- a/contrib/bmake/unit-tests/cond-op-not.exp
+++ b/contrib/bmake/unit-tests/cond-op-not.exp
@@ -3,7 +3,7 @@ make: cond-op-not.mk:39: Not space evaluates to false.
make: cond-op-not.mk:44: Not 0 evaluates to true.
make: cond-op-not.mk:53: Not 1 evaluates to false.
make: cond-op-not.mk:60: Not word evaluates to false.
-make: cond-op-not.mk:65: Malformed conditional '!'
+make: cond-op-not.mk:65: Malformed conditional "!"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-not.mk b/contrib/bmake/unit-tests/cond-op-not.mk
index 4565b60b115d..393d68675fca 100644
--- a/contrib/bmake/unit-tests/cond-op-not.mk
+++ b/contrib/bmake/unit-tests/cond-op-not.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-not.mk,v 1.9 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: cond-op-not.mk,v 1.10 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the ! operator in .if conditions, which negates its argument.
@@ -61,7 +61,7 @@
.endif
# A single exclamation mark is a parse error.
-# expect+1: Malformed conditional '!'
+# expect+1: Malformed conditional "!"
.if !
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op-or-lint.exp b/contrib/bmake/unit-tests/cond-op-or-lint.exp
index 1c5837a9aca6..32d39dead9a1 100644
--- a/contrib/bmake/unit-tests/cond-op-or-lint.exp
+++ b/contrib/bmake/unit-tests/cond-op-or-lint.exp
@@ -1,4 +1,4 @@
-make: cond-op-or-lint.mk:10: Unknown operator '|'
+make: cond-op-or-lint.mk:10: Unknown operator "|"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-or-lint.mk b/contrib/bmake/unit-tests/cond-op-or-lint.mk
index 9ece9d5c9af6..1efc5d94cbf2 100644
--- a/contrib/bmake/unit-tests/cond-op-or-lint.mk
+++ b/contrib/bmake/unit-tests/cond-op-or-lint.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-or-lint.mk,v 1.2 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: cond-op-or-lint.mk,v 1.3 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the || operator in .if conditions, in lint mode.
@@ -6,7 +6,7 @@
# The '|' operator is not allowed in lint mode.
# It is not used in practice anyway.
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if 0 | 0
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op-or.exp b/contrib/bmake/unit-tests/cond-op-or.exp
index 6213759c24f7..fe42ffd6b310 100644
--- a/contrib/bmake/unit-tests/cond-op-or.exp
+++ b/contrib/bmake/unit-tests/cond-op-or.exp
@@ -1,11 +1,11 @@
make: cond-op-or.mk:36: Variable "UNDEF" is undefined
make: cond-op-or.mk:41: Variable "UNDEF" is undefined
make: cond-op-or.mk:44: Variable "UNDEF" is undefined
-make: cond-op-or.mk:60: Unknown operator '|'
-make: cond-op-or.mk:66: Unknown operator '|'
-make: cond-op-or.mk:72: Unknown operator '|'
-make: cond-op-or.mk:78: Unknown operator '|'
-make: cond-op-or.mk:87: Unknown operator '|'
+make: cond-op-or.mk:60: Unknown operator "|"
+make: cond-op-or.mk:66: Unknown operator "|"
+make: cond-op-or.mk:72: Unknown operator "|"
+make: cond-op-or.mk:78: Unknown operator "|"
+make: cond-op-or.mk:87: Unknown operator "|"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-or.mk b/contrib/bmake/unit-tests/cond-op-or.mk
index 381516499093..1c6e081dcac1 100644
--- a/contrib/bmake/unit-tests/cond-op-or.mk
+++ b/contrib/bmake/unit-tests/cond-op-or.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-or.mk,v 1.14 2025/01/11 21:21:33 rillig Exp $
+# $NetBSD: cond-op-or.mk,v 1.15 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the || operator in .if conditions.
@@ -56,25 +56,25 @@ DEF= defined
# The || operator may be abbreviated as |. This is not widely known though
# and is also not documented in the manual page.
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if 0 | 0
. error
.else
. error
.endif
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if !(1 | 0)
. error
.else
. error
.endif
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if !(0 | 1)
. error
.else
. error
.endif
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if !(1 | 1)
. error
.else
@@ -83,7 +83,7 @@ DEF= defined
# There is no operator '|||'. The first two '||' form an operator, the third
# '|' forms the next (incomplete) token.
-# expect+1: Unknown operator '|'
+# expect+1: Unknown operator "|"
.if 0 ||| 0
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op-parentheses.exp b/contrib/bmake/unit-tests/cond-op-parentheses.exp
index a4091226ec34..f8f9efc00772 100644
--- a/contrib/bmake/unit-tests/cond-op-parentheses.exp
+++ b/contrib/bmake/unit-tests/cond-op-parentheses.exp
@@ -1,7 +1,7 @@
-make: cond-op-parentheses.mk:22: Comparison with '>' requires both operands '3' and '(2' to be numeric
-make: cond-op-parentheses.mk:25: Malformed conditional '(3) > 2'
-make: cond-op-parentheses.mk:44: Malformed conditional '('
-make: cond-op-parentheses.mk:58: Malformed conditional ')'
+make: cond-op-parentheses.mk:22: Comparison with ">" requires both operands "3" and "(2" to be numeric
+make: cond-op-parentheses.mk:25: Malformed conditional "(3) > 2"
+make: cond-op-parentheses.mk:44: Malformed conditional "("
+make: cond-op-parentheses.mk:58: Malformed conditional ")"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op-parentheses.mk b/contrib/bmake/unit-tests/cond-op-parentheses.mk
index 17d5d767cd41..17d6504ede9e 100644
--- a/contrib/bmake/unit-tests/cond-op-parentheses.mk
+++ b/contrib/bmake/unit-tests/cond-op-parentheses.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op-parentheses.mk,v 1.8 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: cond-op-parentheses.mk,v 1.9 2025/06/28 22:39:28 rillig Exp $
#
# Tests for parentheses in .if conditions, which group expressions to override
# the precedence of the operators '!', '&&' and '||'. Parentheses cannot be
@@ -18,10 +18,10 @@
#
# XXX: It's inconsistent that the right operand has unbalanced parentheses.
#
-# expect+1: Comparison with '>' requires both operands '3' and '(2' to be numeric
+# expect+1: Comparison with ">" requires both operands "3" and "(2" to be numeric
.if 3 > (2)
.endif
-# expect+1: Malformed conditional '(3) > 2'
+# expect+1: Malformed conditional "(3) > 2"
.if (3) > 2
.endif
@@ -40,7 +40,7 @@
.endif
# An unbalanced opening parenthesis is a parse error.
-# expect+1: Malformed conditional '('
+# expect+1: Malformed conditional "("
.if (
. error
.else
@@ -54,7 +54,7 @@
# TOK_TRUE, TOK_FALSE or TOK_ERROR. In cond.c 1.241, the return type of that
# function was changed to a properly restricted enum type, to prevent this bug
# from occurring again.
-# expect+1: Malformed conditional ')'
+# expect+1: Malformed conditional ")"
.if )
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-op.exp b/contrib/bmake/unit-tests/cond-op.exp
index 1125a35fa3b3..692698b91a96 100644
--- a/contrib/bmake/unit-tests/cond-op.exp
+++ b/contrib/bmake/unit-tests/cond-op.exp
@@ -1,7 +1,7 @@
-make: cond-op.mk:51: Malformed conditional '"!word" == !word'
-make: cond-op.mk:72: Malformed conditional '0 ${ERR::=evaluated}'
+make: cond-op.mk:51: Malformed conditional ""!word" == !word"
+make: cond-op.mk:72: Malformed conditional "0 ${ERR::=evaluated}"
make: cond-op.mk:77: A misplaced expression after 0 is not evaluated.
-make: cond-op.mk:82: Malformed conditional '1 ${ERR::=evaluated}'
+make: cond-op.mk:82: Malformed conditional "1 ${ERR::=evaluated}"
make: cond-op.mk:87: A misplaced expression after 1 is not evaluated.
make: cond-op.mk:93: A B C => (A || B) && C A || B && C A || (B && C)
make: cond-op.mk:108: 0 0 0 => 0 0 0
@@ -12,10 +12,10 @@ make: cond-op.mk:108: 1 0 0 => 0 1 1
make: cond-op.mk:108: 1 0 1 => 1 1 1
make: cond-op.mk:108: 1 1 0 => 0 1 1
make: cond-op.mk:108: 1 1 1 => 1 1 1
-make: cond-op.mk:120: Malformed conditional '1 &&'
-make: cond-op.mk:129: Malformed conditional '0 &&'
-make: cond-op.mk:138: Malformed conditional '1 ||'
-make: cond-op.mk:148: Malformed conditional '0 ||'
+make: cond-op.mk:120: Malformed conditional "1 &&"
+make: cond-op.mk:129: Malformed conditional "0 &&"
+make: cond-op.mk:138: Malformed conditional "1 ||"
+make: cond-op.mk:148: Malformed conditional "0 ||"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-op.mk b/contrib/bmake/unit-tests/cond-op.mk
index 6493d887c806..974cb938065c 100644
--- a/contrib/bmake/unit-tests/cond-op.mk
+++ b/contrib/bmake/unit-tests/cond-op.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-op.mk,v 1.17 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: cond-op.mk,v 1.18 2025/06/28 22:39:28 rillig Exp $
#
# Tests for operators like &&, ||, ! in .if conditions.
#
@@ -47,7 +47,7 @@
# appear unquoted. If any, it must be enclosed in quotes.
# In any case, it is not interpreted as a negation of an unquoted string.
# See CondParser_String.
-# expect+1: Malformed conditional '"!word" == !word'
+# expect+1: Malformed conditional ""!word" == !word"
.if "!word" == !word
. error
.endif
@@ -68,7 +68,7 @@
# next token, even though in this position of the condition, only comparison
# operators, TOK_AND, TOK_OR or TOK_RPAREN are allowed.
.undef ERR
-# expect+1: Malformed conditional '0 ${ERR::=evaluated}'
+# expect+1: Malformed conditional "0 ${ERR::=evaluated}"
.if 0 ${ERR::=evaluated}
. error
.endif
@@ -78,7 +78,7 @@
.endif
.undef ERR
-# expect+1: Malformed conditional '1 ${ERR::=evaluated}'
+# expect+1: Malformed conditional "1 ${ERR::=evaluated}"
.if 1 ${ERR::=evaluated}
. error
.endif
@@ -116,7 +116,7 @@
# This condition is obviously malformed. It is properly detected and also
# was properly detected before 2021-01-19, but only because the left hand
# side of the '&&' evaluated to true.
-# expect+1: Malformed conditional '1 &&'
+# expect+1: Malformed conditional "1 &&"
.if 1 &&
. error
.else
@@ -125,7 +125,7 @@
# This obviously malformed condition was not detected as such before cond.c
# 1.238 from 2021-01-19.
-# expect+1: Malformed conditional '0 &&'
+# expect+1: Malformed conditional "0 &&"
.if 0 &&
. error
.else
@@ -134,7 +134,7 @@
# This obviously malformed condition was not detected as such before cond.c
# 1.238 from 2021-01-19.
-# expect+1: Malformed conditional '1 ||'
+# expect+1: Malformed conditional "1 ||"
.if 1 ||
. error
.else
@@ -144,7 +144,7 @@
# This condition is obviously malformed. It is properly detected and also
# was properly detected before 2021-01-19, but only because the left hand
# side of the '||' evaluated to false.
-# expect+1: Malformed conditional '0 ||'
+# expect+1: Malformed conditional "0 ||"
.if 0 ||
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-short.exp b/contrib/bmake/unit-tests/cond-short.exp
index 19c7ef3d0b89..4100e6e5ef2b 100644
--- a/contrib/bmake/unit-tests/cond-short.exp
+++ b/contrib/bmake/unit-tests/cond-short.exp
@@ -7,7 +7,7 @@ expected M pattern
expected or
expected or exists
expected or empty
-make: cond-short.mk:231: Comparison with '<' requires both operands '' and '42' to be numeric
+make: cond-short.mk:231: Comparison with "<" requires both operands "" and "42" to be numeric
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-short.mk b/contrib/bmake/unit-tests/cond-short.mk
index bcdf372ca6e6..8c4c4140596e 100644
--- a/contrib/bmake/unit-tests/cond-short.mk
+++ b/contrib/bmake/unit-tests/cond-short.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-short.mk,v 1.23 2023/11/19 22:32:44 rillig Exp $
+# $NetBSD: cond-short.mk,v 1.24 2025/06/28 22:39:28 rillig Exp $
#
# Demonstrates that in conditions, the right-hand side of an && or ||
# is only evaluated if it can actually influence the result.
@@ -227,7 +227,7 @@ VAR= ${VAR${:U1}}
# Due to the quotes around the left-hand side of the '<', the operand is
# marked as a string, thus preventing a numerical comparison.
#
-# expect+1: Comparison with '<' requires both operands '' and '42' to be numeric
+# expect+1: Comparison with "<" requires both operands "" and "42" to be numeric
.if "${INDIR_UNDEF}" < ${NUMBER}
. info yes
.else
diff --git a/contrib/bmake/unit-tests/cond-token-number.exp b/contrib/bmake/unit-tests/cond-token-number.exp
index 401f8a2364b7..a3b53c2dcd44 100644
--- a/contrib/bmake/unit-tests/cond-token-number.exp
+++ b/contrib/bmake/unit-tests/cond-token-number.exp
@@ -1,7 +1,7 @@
-make: cond-token-number.mk:16: Malformed conditional '-0'
-make: cond-token-number.mk:27: Malformed conditional '+0'
-make: cond-token-number.mk:38: Malformed conditional '!-1'
-make: cond-token-number.mk:49: Malformed conditional '!+1'
+make: cond-token-number.mk:16: Malformed conditional "-0"
+make: cond-token-number.mk:27: Malformed conditional "+0"
+make: cond-token-number.mk:38: Malformed conditional "!-1"
+make: cond-token-number.mk:49: Malformed conditional "!+1"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-token-number.mk b/contrib/bmake/unit-tests/cond-token-number.mk
index 329a51d73b2a..1d0f8d20287e 100644
--- a/contrib/bmake/unit-tests/cond-token-number.mk
+++ b/contrib/bmake/unit-tests/cond-token-number.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-token-number.mk,v 1.11 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: cond-token-number.mk,v 1.12 2025/06/28 22:39:28 rillig Exp $
#
# Tests for number tokens in .if conditions.
#
@@ -12,7 +12,7 @@
# accepted by the condition parser.
#
# See the ch_isdigit call in CondParser_String.
-# expect+1: Malformed conditional '-0'
+# expect+1: Malformed conditional "-0"
.if -0
. error
.else
@@ -23,7 +23,7 @@
# accepted by the condition parser.
#
# See the ch_isdigit call in CondParser_String.
-# expect+1: Malformed conditional '+0'
+# expect+1: Malformed conditional "+0"
.if +0
. error
.else
@@ -34,7 +34,7 @@
# accepted by the condition parser.
#
# See the ch_isdigit call in CondParser_String.
-# expect+1: Malformed conditional '!-1'
+# expect+1: Malformed conditional "!-1"
.if !-1
. error
.else
@@ -45,7 +45,7 @@
# accepted by the condition parser.
#
# See the ch_isdigit call in CondParser_String.
-# expect+1: Malformed conditional '!+1'
+# expect+1: Malformed conditional "!+1"
.if !+1
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-token-plain.exp b/contrib/bmake/unit-tests/cond-token-plain.exp
index 52d7e6fcddaa..0b430eba7d39 100644
--- a/contrib/bmake/unit-tests/cond-token-plain.exp
+++ b/contrib/bmake/unit-tests/cond-token-plain.exp
@@ -1,10 +1,12 @@
CondParser_Eval: ${:Uvalue} != value
Comparing "value" != "value"
CondParser_Eval: ${:U} != "
+make: cond-token-plain.mk:19: Unfinished string literal """
Comparing "" != ""
CondParser_Eval: ${:U#hash} != "#hash"
Comparing "#hash" != "#hash"
CondParser_Eval: ${:U\\} != "\\
+make: cond-token-plain.mk:43: Unfinished string literal ""\\"
Comparing "\" != "\"
CondParser_Eval: ${:U#hash} != #hash
Comparing "#hash" != "#hash"
@@ -39,9 +41,9 @@ make: cond-token-plain.mk:139: Numbers can be composed from literals and express
CondParser_Eval: 0${:Ux01}
make: cond-token-plain.mk:144: Numbers can be composed from literals and expressions.
CondParser_Eval: "" ==
-make: cond-token-plain.mk:151: Missing right-hand side of operator '=='
+make: cond-token-plain.mk:151: Missing right-hand side of operator "=="
CondParser_Eval: == ""
-make: cond-token-plain.mk:160: Malformed conditional '== ""'
+make: cond-token-plain.mk:160: Malformed conditional "== """
CondParser_Eval: \\
make: cond-token-plain.mk:176: The variable '\\' is not defined.
CondParser_Eval: \\
@@ -49,15 +51,23 @@ make: cond-token-plain.mk:182: Now the variable '\\' is defined.
CondParser_Eval: "unquoted\"quoted" != unquoted"quoted
Comparing "unquoted"quoted" != "unquoted"quoted"
CondParser_Eval: $$$$$$$$ != ""
-make: cond-token-plain.mk:197: Malformed conditional '$$$$$$$$ != ""'
+make: cond-token-plain.mk:197: Malformed conditional "$$$$$$$$ != """
CondParser_Eval: left == right
-make: cond-token-plain.mk:206: Malformed conditional 'left == right'
+make: cond-token-plain.mk:206: Malformed conditional "left == right"
CondParser_Eval: ${0:?:} || left == right
CondParser_Eval: 0
-make: cond-token-plain.mk:212: Malformed conditional '${0:?:} || left == right'
+make: cond-token-plain.mk:212: Malformed conditional "${0:?:} || left == right"
CondParser_Eval: left == right || ${0:?:}
-make: cond-token-plain.mk:217: Malformed conditional 'left == right || ${0:?:}'
-make: cond-token-plain.mk:236: Malformed conditional 'VAR.${IF_COUNT::+=1} != ""'
+make: cond-token-plain.mk:217: Malformed conditional "left == right || ${0:?:}"
+make: cond-token-plain.mk:236: Malformed conditional "VAR.${IF_COUNT::+=1} != """
+make: cond-token-plain.mk:272: Unfinished backslash escape sequence
+ while evaluating condition " str == str\"
+make: cond-token-plain.mk:282: Unfinished backslash escape sequence
+ while evaluating condition " str == "str\"
+make: cond-token-plain.mk:282: Unfinished string literal ""str\"
+ while evaluating condition " str == "str\"
+make: cond-token-plain.mk:289: Unfinished string literal ""str"
+ while evaluating condition " str == "str"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/cond-token-plain.mk b/contrib/bmake/unit-tests/cond-token-plain.mk
index 4509c1feca80..400af22f92d7 100644
--- a/contrib/bmake/unit-tests/cond-token-plain.mk
+++ b/contrib/bmake/unit-tests/cond-token-plain.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-token-plain.mk,v 1.20 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: cond-token-plain.mk,v 1.23 2025/07/06 07:56:16 rillig Exp $
#
# Tests for plain tokens (that is, string literals without quotes)
# in .if conditions. These are also called bare words.
@@ -14,8 +14,8 @@
# condition since comment parsing is done in an early phase and removes the
# '#' and everything after it long before the condition parser gets to see it.
#
-# XXX: The error message is missing for this malformed condition.
-# The right-hand side of the comparison is just a '"', before unescaping.
+#
+# expect+1: Unfinished string literal """
.if ${:U} != "#hash"
. error
.endif
@@ -38,8 +38,8 @@
# comments are stripped in an earlier phase. See "case '#'" in
# CondParser_Token.
#
-# XXX: Missing error message for the malformed condition. The right-hand
-# side before unescaping is double-quotes, backslash, backslash.
+#
+# expect+1: Unfinished string literal ""\\"
.if ${:U\\} != "\\#hash"
. error
.endif
@@ -147,7 +147,7 @@ VAR= defined
.endif
# If the right-hand side is missing, it's a parse error.
-# expect+1: Missing right-hand side of operator '=='
+# expect+1: Missing right-hand side of operator "=="
.if "" ==
. error
.else
@@ -156,7 +156,7 @@ VAR= defined
# If the left-hand side is missing, it's a parse error as well, but without
# a specific error message.
-# expect+1: Malformed conditional '== ""'
+# expect+1: Malformed conditional "== """
.if == ""
. error
.else
@@ -193,7 +193,7 @@ ${:U\\\\}= backslash
# FIXME: In CondParser_String, Var_Parse returns var_Error without a
# corresponding error message.
-# expect+1: Malformed conditional '$$$$$$$$ != ""'
+# expect+1: Malformed conditional "$$$$$$$$ != """
.if $$$$$$$$ != ""
. error
.else
@@ -202,18 +202,18 @@ ${:U\\\\}= backslash
# In a condition in an .if directive, the left-hand side must not be an
# unquoted string literal.
-# expect+1: Malformed conditional 'left == right'
+# expect+1: Malformed conditional "left == right"
.if left == right
.endif
# Before cond.c 1.276 from 2021-09-21, an expression containing the
# modifier ':?:' allowed unquoted string literals for the rest of the
# condition. This was an unintended implementation mistake.
-# expect+1: Malformed conditional '${0:?:} || left == right'
+# expect+1: Malformed conditional "${0:?:} || left == right"
.if ${0:?:} || left == right
.endif
# This affected only the comparisons after the expression, so the following
# was still a syntax error.
-# expect+1: Malformed conditional 'left == right || ${0:?:}'
+# expect+1: Malformed conditional "left == right || ${0:?:}"
.if left == right || ${0:?:}
.endif
@@ -232,7 +232,7 @@ ${:U\\\\}= backslash
# for the second time. The right-hand side of a comparison may be a bare
# word, but that side has no risk of being parsed more than once.
#
-# expect+1: Malformed conditional 'VAR.${IF_COUNT::+=1} != ""'
+# expect+1: Malformed conditional "VAR.${IF_COUNT::+=1} != """
.if VAR.${IF_COUNT::+=1} != ""
. error
.else
@@ -265,3 +265,29 @@ COND= VAR.$${MOD_COUNT::+=1}
. error
.endif
#.MAKEFLAGS: -d0
+
+
+# A trailing backslash in a bare word does not escape anything.
+# expect+1: Unfinished backslash escape sequence
+.if ${${:U str == str\\}:?yes:no}
+. error
+.else
+. error
+.endif
+
+# A trailing backslash in an unfinished string literal word does not escape
+# anything.
+# expect+2: Unfinished backslash escape sequence
+# expect+1: Unfinished string literal ""str\"
+.if ${${:U str == "str\\}:?yes:no}
+. error
+.else
+. error
+.endif
+
+# expect+1: Unfinished string literal ""str"
+.if ${${:U str == "str}:?yes:no}
+. error
+.else
+. error
+.endif
diff --git a/contrib/bmake/unit-tests/cond-token-string.exp b/contrib/bmake/unit-tests/cond-token-string.exp
index d0a5a25f2aa4..d31c0abda17d 100644
--- a/contrib/bmake/unit-tests/cond-token-string.exp
+++ b/contrib/bmake/unit-tests/cond-token-string.exp
@@ -1,7 +1,7 @@
make: cond-token-string.mk:14: Unknown modifier ":Z"
while evaluating "${:Uvalue:Z}"" with value "value"
make: cond-token-string.mk:24: xvalue is not defined.
-make: cond-token-string.mk:31: Malformed conditional 'x${:Uvalue} == ""'
+make: cond-token-string.mk:31: Malformed conditional "x${:Uvalue} == """
make: cond-token-string.mk:41: Expected.
CondParser_Eval: "UNDEF"
make: cond-token-string.mk:51: The string literal "UNDEF" is not empty.
diff --git a/contrib/bmake/unit-tests/cond-token-string.mk b/contrib/bmake/unit-tests/cond-token-string.mk
index fb069f830582..9afe64dca821 100644
--- a/contrib/bmake/unit-tests/cond-token-string.mk
+++ b/contrib/bmake/unit-tests/cond-token-string.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-token-string.mk,v 1.16 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: cond-token-string.mk,v 1.17 2025/06/28 22:39:28 rillig Exp $
#
# Tests for quoted string literals in .if conditions.
#
@@ -27,7 +27,7 @@
# The 'x' produces a "Malformed conditional" since the left-hand side of a
# comparison in an .if directive must be either an expression, a
# quoted string literal or a number that starts with a digit.
-# expect+1: Malformed conditional 'x${:Uvalue} == ""'
+# expect+1: Malformed conditional "x${:Uvalue} == """
.if x${:Uvalue} == ""
. error
.else
diff --git a/contrib/bmake/unit-tests/cond-token-var.exp b/contrib/bmake/unit-tests/cond-token-var.exp
index 1bf61e79ca61..b63d606c7e5a 100644
--- a/contrib/bmake/unit-tests/cond-token-var.exp
+++ b/contrib/bmake/unit-tests/cond-token-var.exp
@@ -6,11 +6,11 @@ make: cond-token-var.mk:64: Variable "U" is undefined
make: cond-token-var.mk:69: Variable "U" is undefined
make: cond-token-var.mk:78: Variable "U" is undefined
Var_Parse: ${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3} (eval)
-make: cond-token-var.mk:106: Malformed conditional 'x${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3}'
+make: cond-token-var.mk:106: Malformed conditional "x${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3}"
Var_Parse: ${DEF}y == "${UNDEF2}" || 0x${UNDEF3} (eval)
-make: cond-token-var.mk:111: Malformed conditional 'x${DEF}y == "${UNDEF2}" || 0x${UNDEF3}'
+make: cond-token-var.mk:111: Malformed conditional "x${DEF}y == "${UNDEF2}" || 0x${UNDEF3}"
Var_Parse: ${DEF}y == "${DEF}" || 0x${UNDEF3} (eval)
-make: cond-token-var.mk:116: Malformed conditional 'x${DEF}y == "${DEF}" || 0x${UNDEF3}'
+make: cond-token-var.mk:116: Malformed conditional "x${DEF}y == "${DEF}" || 0x${UNDEF3}"
Global: VAR.param = value of VAR.param
Var_Parse: ${VAR.param$U} (eval-defined-loud)
Var_Parse: $U} (eval)
diff --git a/contrib/bmake/unit-tests/cond-token-var.mk b/contrib/bmake/unit-tests/cond-token-var.mk
index 8da8a2436390..842ca4d2cb12 100644
--- a/contrib/bmake/unit-tests/cond-token-var.mk
+++ b/contrib/bmake/unit-tests/cond-token-var.mk
@@ -1,4 +1,4 @@
-# $NetBSD: cond-token-var.mk,v 1.13 2025/04/04 18:57:01 rillig Exp $
+# $NetBSD: cond-token-var.mk,v 1.14 2025/06/28 22:39:28 rillig Exp $
#
# Tests for expressions in .if conditions.
#
@@ -102,17 +102,17 @@ DEF= defined
.MAKEFLAGS: -dv
# The left-hand side of a comparison must not be an unquoted word.
-# expect+1: Malformed conditional 'x${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3}'
+# expect+1: Malformed conditional "x${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3}"
.if x${UNDEF1}y == "${UNDEF2}" || 0x${UNDEF3}
.endif
# The left-hand side of a comparison must not be an unquoted word.
-# expect+1: Malformed conditional 'x${DEF}y == "${UNDEF2}" || 0x${UNDEF3}'
+# expect+1: Malformed conditional "x${DEF}y == "${UNDEF2}" || 0x${UNDEF3}"
.if x${DEF}y == "${UNDEF2}" || 0x${UNDEF3}
.endif
# The left-hand side of a comparison must not be an unquoted word.
-# expect+1: Malformed conditional 'x${DEF}y == "${DEF}" || 0x${UNDEF3}'
+# expect+1: Malformed conditional "x${DEF}y == "${DEF}" || 0x${UNDEF3}"
.if x${DEF}y == "${DEF}" || 0x${UNDEF3}
.endif
diff --git a/contrib/bmake/unit-tests/dep-op-missing.exp b/contrib/bmake/unit-tests/dep-op-missing.exp
index 8521dbf79792..7c03092e09be 100644
--- a/contrib/bmake/unit-tests/dep-op-missing.exp
+++ b/contrib/bmake/unit-tests/dep-op-missing.exp
@@ -1,4 +1,4 @@
-make: dep-op-missing.tmp:1: Invalid line 'target'
+make: dep-op-missing.tmp:1: Invalid line "target"
in make[1] in directory "<curdir>"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
diff --git a/contrib/bmake/unit-tests/deptgt-begin.exp b/contrib/bmake/unit-tests/deptgt-begin.exp
index bf6f61a51e72..5aa673e33d30 100644
--- a/contrib/bmake/unit-tests/deptgt-begin.exp
+++ b/contrib/bmake/unit-tests/deptgt-begin.exp
@@ -1,5 +1,5 @@
make: deptgt-begin.mk:19: warning: duplicate script for target ".BEGIN" ignored
-make: deptgt-begin.mk:9: warning: using previous script for ".BEGIN" defined here
+make: deptgt-begin.mk:8: warning: using previous script for ".BEGIN" defined here
: parse time
: Making before-begin before .BEGIN.
: .BEGIN
diff --git a/contrib/bmake/unit-tests/deptgt-begin.mk b/contrib/bmake/unit-tests/deptgt-begin.mk
index 8b9842641a2d..a29155cb5fc2 100644
--- a/contrib/bmake/unit-tests/deptgt-begin.mk
+++ b/contrib/bmake/unit-tests/deptgt-begin.mk
@@ -1,10 +1,9 @@
-# $NetBSD: deptgt-begin.mk,v 1.7 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: deptgt-begin.mk,v 1.8 2025/06/30 21:44:39 rillig Exp $
#
# Tests for the special target .BEGIN in dependency declarations,
# which is a container for commands that are run before any other
# commands from the shell lines.
-# expect+2: warning: using previous script for ".BEGIN" defined here
.BEGIN:
: $@
@@ -14,7 +13,8 @@
# add its commands after this.
#
# There are several ways to resolve this situation, which are detailed below.
-# expect+2: warning: duplicate script for target ".BEGIN" ignored
+# expect+3: warning: duplicate script for target ".BEGIN" ignored
+# expect-9: warning: using previous script for ".BEGIN" defined here
.BEGIN:
: Making another $@.
diff --git a/contrib/bmake/unit-tests/deptgt-path-suffix.exp b/contrib/bmake/unit-tests/deptgt-path-suffix.exp
index 6294d8a39dc0..e1c67daa8787 100644
--- a/contrib/bmake/unit-tests/deptgt-path-suffix.exp
+++ b/contrib/bmake/unit-tests/deptgt-path-suffix.exp
@@ -1,4 +1,4 @@
-make: deptgt-path-suffix.mk:8: Suffix '.c' not defined (yet)
+make: deptgt-path-suffix.mk:8: Suffix ".c" not defined (yet)
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/deptgt-path-suffix.mk b/contrib/bmake/unit-tests/deptgt-path-suffix.mk
index 494a076a5520..68bb27036b68 100644
--- a/contrib/bmake/unit-tests/deptgt-path-suffix.mk
+++ b/contrib/bmake/unit-tests/deptgt-path-suffix.mk
@@ -1,10 +1,10 @@
-# $NetBSD: deptgt-path-suffix.mk,v 1.3 2021/12/13 23:38:54 rillig Exp $
+# $NetBSD: deptgt-path-suffix.mk,v 1.4 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the special target .PATH.suffix in dependency declarations.
# TODO: Implementation
-# expect+1: Suffix '.c' not defined (yet)
+# expect+1: Suffix ".c" not defined (yet)
.PATH.c: ..
.SUFFIXES: .c
diff --git a/contrib/bmake/unit-tests/deptgt.exp b/contrib/bmake/unit-tests/deptgt.exp
index 4c7cb4e50ddc..230fa497fcbd 100644
--- a/contrib/bmake/unit-tests/deptgt.exp
+++ b/contrib/bmake/unit-tests/deptgt.exp
@@ -1,4 +1,4 @@
-make: deptgt.mk:11: warning: Extra target '.PHONY' ignored
+make: deptgt.mk:11: warning: Extra target ".PHONY" ignored
make: deptgt.mk:30: Unassociated shell command ": command3 # parse error, since targets == NULL"
Parsing deptgt.mk:36: ${:U}: empty-source
ParseDependency(: empty-source)
@@ -18,8 +18,8 @@ make: deptgt.mk:51: Unknown modifier ":Z"
while evaluating "${:U:Z}:" with value ""
make: deptgt.mk:55: Unknown modifier ":Z"
while parsing "${:U:Z}:"
-make: deptgt.mk:58: warning: Extra target 'ordinary' ignored
-make: deptgt.mk:61: warning: Extra target (ordinary) ignored
+make: deptgt.mk:58: warning: Extra target "ordinary" ignored
+make: deptgt.mk:61: warning: Extra target "ordinary" ignored
make: deptgt.mk:64: warning: Special and mundane targets don't mix. Mundane ones ignored
make: Fatal errors encountered -- cannot continue
make: stopped making "target1" in unit-tests
diff --git a/contrib/bmake/unit-tests/deptgt.mk b/contrib/bmake/unit-tests/deptgt.mk
index 779a1faf7115..fd7a716e3ebc 100644
--- a/contrib/bmake/unit-tests/deptgt.mk
+++ b/contrib/bmake/unit-tests/deptgt.mk
@@ -1,4 +1,4 @@
-# $NetBSD: deptgt.mk,v 1.23 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: deptgt.mk,v 1.24 2025/06/28 22:39:28 rillig Exp $
#
# Tests for special targets like .BEGIN or .SUFFIXES in dependency
# declarations.
@@ -7,7 +7,7 @@
# Just in case anyone tries to compile several special targets in a single
# dependency line: That doesn't work, and make immediately rejects it.
-# expect+1: warning: Extra target '.PHONY' ignored
+# expect+1: warning: Extra target ".PHONY" ignored
.SUFFIXES .PHONY: .c.o
# The following lines demonstrate how 'targets' is set and reset during
@@ -54,10 +54,10 @@ ${:U:Z}:
# expect+1: Unknown modifier ":Z"
$${:U:Z}:
-# expect+1: warning: Extra target 'ordinary' ignored
+# expect+1: warning: Extra target "ordinary" ignored
.END ordinary:
-# expect+1: warning: Extra target (ordinary) ignored
+# expect+1: warning: Extra target "ordinary" ignored
.PATH ordinary:
# expect+1: warning: Special and mundane targets don't mix. Mundane ones ignored
diff --git a/contrib/bmake/unit-tests/directive-dinclude.exp b/contrib/bmake/unit-tests/directive-dinclude.exp
index 5f5fec4d403e..55f1f77fbfde 100755
--- a/contrib/bmake/unit-tests/directive-dinclude.exp
+++ b/contrib/bmake/unit-tests/directive-dinclude.exp
@@ -1,4 +1,4 @@
-make: directive-dinclude-error.inc:1: Invalid line 'syntax error'
+make: directive-dinclude-error.inc:1: Invalid line "syntax error"
in directive-dinclude.mk:21
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
diff --git a/contrib/bmake/unit-tests/directive-dinclude.mk b/contrib/bmake/unit-tests/directive-dinclude.mk
index c363209579ad..da063083235f 100755
--- a/contrib/bmake/unit-tests/directive-dinclude.mk
+++ b/contrib/bmake/unit-tests/directive-dinclude.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-dinclude.mk,v 1.4 2025/03/30 09:51:50 rillig Exp $
+# $NetBSD: directive-dinclude.mk,v 1.5 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the .dinclude directive, which includes another file,
# silently skipping it if it cannot be opened. This is primarily used for
@@ -16,7 +16,7 @@
.dinclude "${MAKEFILE}/subdir"
# Errors that are not related to opening the file are still reported.
-# expect: make: directive-dinclude-error.inc:1: Invalid line 'syntax error'
+# expect: make: directive-dinclude-error.inc:1: Invalid line "syntax error"
_!= echo 'syntax error' > directive-dinclude-error.inc
.dinclude "${.CURDIR}/directive-dinclude-error.inc"
_!= rm directive-dinclude-error.inc
diff --git a/contrib/bmake/unit-tests/directive-export-gmake.exp b/contrib/bmake/unit-tests/directive-export-gmake.exp
index f7bb07ab9da2..2c2875d669d2 100644
--- a/contrib/bmake/unit-tests/directive-export-gmake.exp
+++ b/contrib/bmake/unit-tests/directive-export-gmake.exp
@@ -1,4 +1,4 @@
-make: directive-export-gmake.mk:71: Invalid line 'export VAR=${:U1}', expanded to 'export VAR=1'
+make: directive-export-gmake.mk:71: Invalid line "export VAR=${:U1}", expanded to "export VAR=1"
in .for loop from directive-export-gmake.mk:67 with value = 1
make: directive-export-gmake.mk:85: 16:00:00
make: directive-export-gmake.mk:92: Variable/Value missing from "export"
diff --git a/contrib/bmake/unit-tests/directive-export-gmake.mk b/contrib/bmake/unit-tests/directive-export-gmake.mk
index de79470bf305..6e1d57c6a62d 100644
--- a/contrib/bmake/unit-tests/directive-export-gmake.mk
+++ b/contrib/bmake/unit-tests/directive-export-gmake.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-export-gmake.mk,v 1.9 2023/12/17 09:44:00 rillig Exp $
+# $NetBSD: directive-export-gmake.mk,v 1.10 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the export directive (without leading dot), as in GNU make.
@@ -67,7 +67,7 @@ export VAR=an ${UNDEF} variable
.for value in 1
# XXX: The ':' in this line is inside an expression and should thus not be
# interpreted as a dependency operator.
-# expect+1: Invalid line 'export VAR=${:U1}', expanded to 'export VAR=1'
+# expect+1: Invalid line "export VAR=${:U1}", expanded to "export VAR=1"
export VAR=${value}
.endfor
diff --git a/contrib/bmake/unit-tests/directive-for-errors.exp b/contrib/bmake/unit-tests/directive-for-errors.exp
index 39929864314d..1bae631b967a 100644
--- a/contrib/bmake/unit-tests/directive-for-errors.exp
+++ b/contrib/bmake/unit-tests/directive-for-errors.exp
@@ -4,10 +4,10 @@ make: directive-for-errors.mk:13: for-less endfor
make: directive-for-errors.mk:25: Unknown directive "for"
make: directive-for-errors.mk:27: warning: <>
make: directive-for-errors.mk:29: for-less endfor
-make: directive-for-errors.mk:44: invalid character '$' in .for loop variable name
-make: directive-for-errors.mk:52: no iteration variables in for
+make: directive-for-errors.mk:44: Invalid character "$" in .for loop variable name
+make: directive-for-errors.mk:52: Missing iteration variables in .for loop
make: directive-for-errors.mk:64: Wrong number of words (5) in .for substitution list with 3 variables
-make: directive-for-errors.mk:78: missing `in' in for
+make: directive-for-errors.mk:78: Missing "in" in .for loop
make: directive-for-errors.mk:85: Unknown modifier ":Z"
while evaluating "${:U3:Z} 4" with value "3"
make: Fatal errors encountered -- cannot continue
diff --git a/contrib/bmake/unit-tests/directive-for-errors.mk b/contrib/bmake/unit-tests/directive-for-errors.mk
index a58b8294289b..2571b600bf38 100644
--- a/contrib/bmake/unit-tests/directive-for-errors.mk
+++ b/contrib/bmake/unit-tests/directive-for-errors.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-for-errors.mk,v 1.17 2025/05/03 08:18:33 rillig Exp $
+# $NetBSD: directive-for-errors.mk,v 1.18 2025/06/28 22:39:28 rillig Exp $
#
# Tests for error handling in .for loops.
@@ -40,7 +40,7 @@
# error everywhere outside a .for loop.
${:U\$}= dollar # see whether the "variable" '$' is local
${:U\\}= backslash # see whether the "variable" '\' is local
-# expect+1: invalid character '$' in .for loop variable name
+# expect+1: Invalid character "$" in .for loop variable name
.for a b $ \ in 1 2 3 4
. info Dollar $$ ${$} $($) and backslash $\ ${\} $(\).
.endfor
@@ -48,7 +48,7 @@ ${:U\\}= backslash # see whether the "variable" '\' is local
# If there are no variables, there is no point in expanding the .for loop
# since this would end up in an endless loop, consuming 0 of the 3 values in
# each iteration.
-# expect+1: no iteration variables in for
+# expect+1: Missing iteration variables in .for loop
.for in 1 2 3
# XXX: This should not be reached. It should be skipped, as already done
# when the number of values is not a multiple of the number of variables,
@@ -74,7 +74,7 @@ ${:U\\}= backslash # see whether the "variable" '\' is local
# A missing 'in' parses the .for loop but skips the body.
-# expect+1: missing `in' in for
+# expect+1: Missing "in" in .for loop
.for i over k
. error
.endfor
diff --git a/contrib/bmake/unit-tests/directive-for-escape.exp b/contrib/bmake/unit-tests/directive-for-escape.exp
index 6ab8a333a10f..78cc57a738a2 100644
--- a/contrib/bmake/unit-tests/directive-for-escape.exp
+++ b/contrib/bmake/unit-tests/directive-for-escape.exp
@@ -1,14 +1,14 @@
For: end for 1
For: loop body with chars = !"#$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~:
. info ${:U!"#$%&'()*+,-./0-9\:;<=>?@A-Z[\\]_^a-z{|\}~}
-make: directive-for-escape.mk:21: Unclosed expression, expecting '}' for modifier "U!""
+make: directive-for-escape.mk:21: Unclosed expression, expecting "}" for modifier "U!""
while evaluating "${:U!"" with value "!""
in .for loop from directive-for-escape.mk:20 with chars = !"#$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
make: directive-for-escape.mk:21: !"
For: end for 1
For: loop body with chars = !"\\#$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~:
. info ${:U!"\\\\#$%&'()*+,-./0-9\:;<=>?@A-Z[\\]_^a-z{|\}~}
-make: directive-for-escape.mk:33: Unclosed expression, expecting '}' for modifier "U!"\\\\"
+make: directive-for-escape.mk:33: Unclosed expression, expecting "}" for modifier "U!"\\\\"
while evaluating "${:U!"\\\\" with value "!"\\"
in .for loop from directive-for-escape.mk:32 with chars = !"\\#$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
make: directive-for-escape.mk:33: !"\\
@@ -69,9 +69,9 @@ For: end for 1
For: loop body with i = $:
. info ${:U\$}
make: directive-for-escape.mk:147: $
-make: directive-for-escape.mk:155: invalid character ':' in .for loop variable name
+make: directive-for-escape.mk:155: Invalid character ":" in .for loop variable name
For: end for 1
-make: directive-for-escape.mk:165: invalid character '}' in .for loop variable name
+make: directive-for-escape.mk:165: Invalid character "}" in .for loop variable name
For: end for 1
For: end for 1
For: loop body with i = inner:
@@ -89,7 +89,7 @@ For: end for 1
For: loop body with i = inner:
. info ${i2} ${i,} ${:Uinner}${:Uinner}${:Uinner:M*}${:Uinner}
make: directive-for-escape.mk:187: two comma innerinnerinnerinner
-make: directive-for-escape.mk:196: invalid character '$' in .for loop variable name
+make: directive-for-escape.mk:196: Invalid character "$" in .for loop variable name
For: end for 1
make: directive-for-escape.mk:208: eight and no cents.
For: end for 1
diff --git a/contrib/bmake/unit-tests/directive-for-escape.mk b/contrib/bmake/unit-tests/directive-for-escape.mk
index e688ce98f258..913d61831c46 100644
--- a/contrib/bmake/unit-tests/directive-for-escape.mk
+++ b/contrib/bmake/unit-tests/directive-for-escape.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-for-escape.mk,v 1.29 2024/08/29 20:20:36 rillig Exp $
+# $NetBSD: directive-for-escape.mk,v 1.30 2025/06/28 22:39:28 rillig Exp $
#
# Test escaping of special characters in the iteration values of a .for loop.
# These values get expanded later using the :U variable modifier, and this
@@ -15,7 +15,7 @@ ASCII= !"\#$$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
# XXX: As of 2020-12-31, the '#' is not preserved in the expanded body of
# the loop. Not only would it need the escaping for the variable modifier
# ':U' but also the escaping for the line-end comment.
-# expect+3: Unclosed expression, expecting '}' for modifier "U!""
+# expect+3: Unclosed expression, expecting "}" for modifier "U!""
# expect+2: !"
.for chars in ${ASCII}
. info ${chars}
@@ -27,7 +27,7 @@ ASCII= !"\#$$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
# This means that a '#' sign cannot be passed in the value of a .for loop
# at all.
ASCII.2020-12-31= !"\\\#$$%&'()*+,-./0-9:;<=>?@A-Z[\]_^a-z{|}~
-# expect+3: Unclosed expression, expecting '}' for modifier "U!"\\\\"
+# expect+3: Unclosed expression, expecting "}" for modifier "U!"\\\\"
# expect+2: !"\\
.for chars in ${ASCII.2020-12-31}
. info ${chars}
@@ -151,7 +151,7 @@ VALUES= begin<$${UNDEF:Ufallback:N{{{}}}}>end
# could contain colons, which affected expressions having this exact
# modifier. This possibility was neither intended nor documented.
NUMBERS= one two three
-# expect+1: invalid character ':' in .for loop variable name
+# expect+1: Invalid character ":" in .for loop variable name
.for NUMBERS:M*e in replaced
. info ${NUMBERS} ${NUMBERS:M*e}
.endfor
@@ -161,7 +161,7 @@ NUMBERS= one two three
# expressions. This possibility was neither intended nor documented.
BASENAME= one
EXT= .c
-# expect+1: invalid character '}' in .for loop variable name
+# expect+1: Invalid character "}" in .for loop variable name
.for BASENAME}${EXT in replaced
. info ${BASENAME}${EXT}
.endfor
@@ -192,7 +192,7 @@ i,= comma
# skipped "stupid" variable names though, but ForLoop_SubstVarLong naively
# parsed the body of the loop, substituting each '${$}' with an actual
# '${:Udollar}'.
-# expect+1: invalid character '$' in .for loop variable name
+# expect+1: Invalid character "$" in .for loop variable name
.for $ in dollar
. info eight $$$$$$$$ and no cents.
. info eight ${$}${$}${$}${$} and no cents.
diff --git a/contrib/bmake/unit-tests/directive-for-lines.exp b/contrib/bmake/unit-tests/directive-for-lines.exp
index bf5b2b8b1209..23227122ffd3 100644
--- a/contrib/bmake/unit-tests/directive-for-lines.exp
+++ b/contrib/bmake/unit-tests/directive-for-lines.exp
@@ -1,9 +1,9 @@
-make: directive-for-lines.mk:27: expect 23
-make: directive-for-lines.mk:27: expect 23
-make: directive-for-lines.mk:36: expect 30
-make: directive-for-lines.mk:27: expect 23
-make: directive-for-lines.mk:27: expect 23
-make: directive-for-lines.mk:36: expect 30
+make: directive-for-lines.mk:31: This is line 31.
+make: directive-for-lines.mk:31: This is line 31.
+make: directive-for-lines.mk:38: This is line 38.
+make: directive-for-lines.mk:31: This is line 31.
+make: directive-for-lines.mk:31: This is line 31.
+make: directive-for-lines.mk:38: This is line 38.
make: no target to make.
make: stopped in unit-tests
diff --git a/contrib/bmake/unit-tests/directive-for-lines.mk b/contrib/bmake/unit-tests/directive-for-lines.mk
index cae4e0a38897..898a1960e76a 100644
--- a/contrib/bmake/unit-tests/directive-for-lines.mk
+++ b/contrib/bmake/unit-tests/directive-for-lines.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-for-lines.mk,v 1.5 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: directive-for-lines.mk,v 1.6 2025/06/30 21:44:39 rillig Exp $
#
# Tests for the line numbers that are reported in .for loops.
#
@@ -7,6 +7,14 @@
# messages inside .for loops had been wrong since ParseGetLine skipped empty
# lines, even when collecting the lines for the .for loop body.
+# expect+21: This is line 31.
+# expect+20: This is line 31.
+# expect+26: This is line 38.
+
+# expect+17: This is line 31.
+# expect+16: This is line 31.
+# expect+22: This is line 38.
+
.for outer in a b
# comment \
@@ -20,19 +28,13 @@
VAR= \
multi-line
-# expect+4: expect 23
-# expect+3: expect 23
-# expect+2: expect 23
-# expect+1: expect 23
-.info expect 23
+.info This is line 31.
.endfor
# comment \
# continued comment
-# expect+2: expect 30
-# expect+1: expect 30
-.info expect 30
+.info This is line 38.
.endfor
diff --git a/contrib/bmake/unit-tests/directive-for.exp b/contrib/bmake/unit-tests/directive-for.exp
index cf87e6ea8569..d1c1064f0ef5 100755
--- a/contrib/bmake/unit-tests/directive-for.exp
+++ b/contrib/bmake/unit-tests/directive-for.exp
@@ -14,16 +14,16 @@ make: directive-for.mk:158: {{}} {{}} {{}}
make: directive-for.mk:158: )( )( )(
make: directive-for.mk:158: ][ ][ ][
make: directive-for.mk:158: }{ }{ }{
-make: directive-for.mk:166: invalid character ':' in .for loop variable name
-make: directive-for.mk:173: invalid character '$' in .for loop variable name
-make: directive-for.mk:185: invalid character '$' in .for loop variable name
-make: directive-for.mk:207: no iteration variables in for
-make: directive-for.mk:233: 1 open conditional
- in .for loop from directive-for.mk:231 with var = value
-make: directive-for.mk:249: for-less endfor
-make: directive-for.mk:250: if-less endif
-make: directive-for.mk:258: if-less endif
- in .for loop from directive-for.mk:257 with var = value
+make: directive-for.mk:166: Invalid character ":" in .for loop variable name
+make: directive-for.mk:173: Invalid character "$" in .for loop variable name
+make: directive-for.mk:185: Invalid character "$" in .for loop variable name
+make: directive-for.mk:208: Missing iteration variables in .for loop
+make: directive-for.mk:234: 1 open conditional
+ in .for loop from directive-for.mk:232 with var = value
+make: directive-for.mk:252: for-less endfor
+make: directive-for.mk:254: if-less endif
+make: directive-for.mk:263: if-less endif
+ in .for loop from directive-for.mk:261 with var = value
For: new loop 2
For: end for 2
For: end for 1
@@ -34,7 +34,7 @@ For: loop body with outer = o:
endfor
For: end for 1
For: loop body with inner = i:
-make: directive-for.mk:307: newline-item=(a)
+make: directive-for.mk:312: newline-item=(a)
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/directive-for.mk b/contrib/bmake/unit-tests/directive-for.mk
index 2f989f54f228..72ffaa142ad6 100755
--- a/contrib/bmake/unit-tests/directive-for.mk
+++ b/contrib/bmake/unit-tests/directive-for.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-for.mk,v 1.30 2025/03/30 16:43:10 rillig Exp $
+# $NetBSD: directive-for.mk,v 1.32 2025/07/01 04:24:20 rillig Exp $
#
# Tests for the .for directive.
#
@@ -162,14 +162,14 @@ EXPANSION${plus}= value
# except for whitespace, allowing for creative side effects, as usual for
# arbitrary code injection.
var= outer
-# expect+1: invalid character ':' in .for loop variable name
+# expect+1: Invalid character ":" in .for loop variable name
.for var:Q in value "quoted"
. info <${var}> <${var:Q}> <${var:Q:Q}>
.endfor
# Before 2023-05-09, when variable names could contain '$', the short
# expression '$$' was preserved, the long expressions were substituted.
-# expect+1: invalid character '$' in .for loop variable name
+# expect+1: Invalid character "$" in .for loop variable name
.for $ in value
. info <$$> <${$}> <$($)>
.endfor
@@ -181,7 +181,7 @@ var= outer
# possibility, therefore the variable names are restricted to using harmless
# characters only.
INDIRECT= direct
-# expect+1: invalid character '$' in .for loop variable name
+# expect+1: Invalid character "$" in .for loop variable name
.for $(INDIRECT) in value
# If the variable name could be chosen dynamically, the iteration variable
# might have been 'direct', thereby expanding the expression '${direct}'.
@@ -204,7 +204,8 @@ INDIRECT= ${DIRECT}
# An empty list of variables to the left of the 'in' is a parse error.
-.for in value # expect+0: no iteration variables in for
+# expect+1: Missing iteration variables in .for loop
+.for in value
. error
.endfor
@@ -230,7 +231,8 @@ INDIRECT= ${DIRECT}
# is processed.
.for var in value
. if 0
-.endfor # expect+0: 1 open conditional
+.endfor
+# expect-1: 1 open conditional
# If there are no iteration values, the loop body is not processed, and the
# check for mismatched conditionals is not performed.
@@ -246,8 +248,10 @@ INDIRECT= ${DIRECT}
.if 0
. for var in value # does not need a corresponding .endfor
.endif
-.endfor # expect+0: for-less endfor
-.endif # expect+0: if-less endif
+# expect+1: for-less endfor
+.endfor
+# expect+1: if-less endif
+.endif
# When a .for without the corresponding .endfor occurs in an active branch of
@@ -255,7 +259,8 @@ INDIRECT= ${DIRECT}
# without looking at any other directives.
.if 1
. for var in value
-. endif # expect+0: if-less endif
+# expect+1: if-less endif
+. endif
. endfor # no 'for-less endfor'
.endif # no 'if-less endif'
diff --git a/contrib/bmake/unit-tests/directive-hyphen-include.exp b/contrib/bmake/unit-tests/directive-hyphen-include.exp
index 3f17f0c41f0b..d1d37e783ca9 100755
--- a/contrib/bmake/unit-tests/directive-hyphen-include.exp
+++ b/contrib/bmake/unit-tests/directive-hyphen-include.exp
@@ -1,4 +1,4 @@
-make: directive-hyphen-include-error.inc:1: Invalid line 'syntax error'
+make: directive-hyphen-include-error.inc:1: Invalid line "syntax error"
in directive-hyphen-include.mk:20
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
diff --git a/contrib/bmake/unit-tests/directive-hyphen-include.mk b/contrib/bmake/unit-tests/directive-hyphen-include.mk
index ad596f4c47db..de438dfaffac 100755
--- a/contrib/bmake/unit-tests/directive-hyphen-include.mk
+++ b/contrib/bmake/unit-tests/directive-hyphen-include.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-hyphen-include.mk,v 1.4 2025/03/30 09:51:50 rillig Exp $
+# $NetBSD: directive-hyphen-include.mk,v 1.5 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the .-include directive, which includes another file,
# silently skipping it if it cannot be opened.
@@ -15,7 +15,7 @@
.-include "${MAKEFILE}/subdir"
# Errors that are not related to opening the file are still reported.
-# expect: make: directive-hyphen-include-error.inc:1: Invalid line 'syntax error'
+# expect: make: directive-hyphen-include-error.inc:1: Invalid line "syntax error"
_!= echo 'syntax error' > directive-hyphen-include-error.inc
.-include "${.CURDIR}/directive-hyphen-include-error.inc"
_!= rm directive-hyphen-include-error.inc
diff --git a/contrib/bmake/unit-tests/directive-if.exp b/contrib/bmake/unit-tests/directive-if.exp
index 0d4a7ea16d34..634c9ee6b1df 100644
--- a/contrib/bmake/unit-tests/directive-if.exp
+++ b/contrib/bmake/unit-tests/directive-if.exp
@@ -5,7 +5,7 @@ make: directive-if.mk:45: This is not conditional.
make: directive-if.mk:47: if-less else
make: directive-if.mk:49: This is not conditional.
make: directive-if.mk:51: if-less endif
-make: directive-if.mk:55: Malformed conditional ''
+make: directive-if.mk:55: Malformed conditional ""
make: directive-if.mk:66: Quotes in plain words are probably a mistake.
make: directive-if.mk:76: Don't do this, always put a space after a directive.
make: directive-if.mk:81: Don't do this, always put a space after a directive.
diff --git a/contrib/bmake/unit-tests/directive-if.mk b/contrib/bmake/unit-tests/directive-if.mk
index 7ff04da0755b..5d1232d245a9 100644
--- a/contrib/bmake/unit-tests/directive-if.mk
+++ b/contrib/bmake/unit-tests/directive-if.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-if.mk,v 1.13 2024/08/06 18:00:17 rillig Exp $
+# $NetBSD: directive-if.mk,v 1.14 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the .if directive.
#
@@ -51,7 +51,7 @@
.endif
# Missing condition.
-# expect+1: Malformed conditional ''
+# expect+1: Malformed conditional ""
.if
. error
.else
diff --git a/contrib/bmake/unit-tests/directive-include.exp b/contrib/bmake/unit-tests/directive-include.exp
index 71f39c57e807..361389cf1cad 100755
--- a/contrib/bmake/unit-tests/directive-include.exp
+++ b/contrib/bmake/unit-tests/directive-include.exp
@@ -8,7 +8,7 @@ make: directive-include.mk:56: Unknown modifier ":Z"
while evaluating "${:U123:Z}.mk" with value "123"
make: directive-include.mk:56: Could not find nonexistent.mk
make: directive-include.mk:61: Cannot open /nonexistent
-make: directive-include.mk:66: Invalid line 'include'
+make: directive-include.mk:66: Invalid line "include"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/directive-include.mk b/contrib/bmake/unit-tests/directive-include.mk
index 42cdd97c43c7..ad6936ab2f3c 100755
--- a/contrib/bmake/unit-tests/directive-include.mk
+++ b/contrib/bmake/unit-tests/directive-include.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-include.mk,v 1.19 2025/03/30 09:51:50 rillig Exp $
+# $NetBSD: directive-include.mk,v 1.20 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the .include directive, which includes another file.
@@ -62,7 +62,7 @@ include /nonexistent # comment
sinclude /nonexistent # comment
include ${:U/dev/null} # comment
include /dev/null /dev/null
-# expect+1: Invalid line 'include'
+# expect+1: Invalid line "include"
include
# XXX: trailing whitespace in diagnostic, missing quotes around filename
diff --git a/contrib/bmake/unit-tests/directive-misspellings.exp b/contrib/bmake/unit-tests/directive-misspellings.exp
index b918d05a2683..c551d73d5f98 100644
--- a/contrib/bmake/unit-tests/directive-misspellings.exp
+++ b/contrib/bmake/unit-tests/directive-misspellings.exp
@@ -1,6 +1,6 @@
make: directive-misspellings.mk:13: Unknown directive "dinclud"
make: directive-misspellings.mk:16: Unknown directive "dincludx"
-make: directive-misspellings.mk:18: .include filename must be delimited by '"' or '<'
+make: directive-misspellings.mk:18: .include filename must be delimited by "" or <>
make: directive-misspellings.mk:21: Unknown directive "erro"
make: directive-misspellings.mk:23: Unknown directive "errox"
make: directive-misspellings.mk:28: Unknown directive "expor"
@@ -13,18 +13,18 @@ make: directive-misspellings.mk:46: Unknown directive "export-literax"
make: directive-misspellings.mk:48: Unknown directive "export-literally"
make: directive-misspellings.mk:51: Unknown directive "-includ"
make: directive-misspellings.mk:54: Unknown directive "-includx"
-make: directive-misspellings.mk:56: .include filename must be delimited by '"' or '<'
+make: directive-misspellings.mk:56: .include filename must be delimited by "" or <>
make: directive-misspellings.mk:59: Unknown directive "includ"
make: directive-misspellings.mk:61: Could not find file
make: directive-misspellings.mk:63: Unknown directive "includx"
-make: directive-misspellings.mk:65: .include filename must be delimited by '"' or '<'
+make: directive-misspellings.mk:65: .include filename must be delimited by "" or <>
make: directive-misspellings.mk:68: Unknown directive "inf"
make: directive-misspellings.mk:70: msg
make: directive-misspellings.mk:72: Unknown directive "infx"
make: directive-misspellings.mk:74: Unknown directive "infos"
make: directive-misspellings.mk:77: Unknown directive "sinclud"
make: directive-misspellings.mk:80: Unknown directive "sincludx"
-make: directive-misspellings.mk:82: .include filename must be delimited by '"' or '<'
+make: directive-misspellings.mk:82: .include filename must be delimited by "" or <>
make: directive-misspellings.mk:85: Unknown directive "unde"
make: directive-misspellings.mk:88: Unknown directive "undex"
make: directive-misspellings.mk:90: Unknown directive "undefs"
diff --git a/contrib/bmake/unit-tests/directive-misspellings.mk b/contrib/bmake/unit-tests/directive-misspellings.mk
index 0014076d041f..cd6222b378f5 100644
--- a/contrib/bmake/unit-tests/directive-misspellings.mk
+++ b/contrib/bmake/unit-tests/directive-misspellings.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-misspellings.mk,v 1.4 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: directive-misspellings.mk,v 1.5 2025/06/28 22:39:28 rillig Exp $
#
# Tests for misspelled directives.
#
@@ -14,7 +14,7 @@
.dinclude "file"
# expect+1: Unknown directive "dincludx"
.dincludx "file"
-# expect+1: .include filename must be delimited by '"' or '<'
+# expect+1: .include filename must be delimited by "" or <>
.dincludes "file" # XXX: the 's' is not meant to be a filename
# expect+1: Unknown directive "erro"
@@ -52,7 +52,7 @@
.-include "file"
# expect+1: Unknown directive "-includx"
.-includx "file"
-# expect+1: .include filename must be delimited by '"' or '<'
+# expect+1: .include filename must be delimited by "" or <>
.-includes "file" # XXX: the 's' is not meant to be a filename
# expect+1: Unknown directive "includ"
@@ -61,7 +61,7 @@
.include "file"
# expect+1: Unknown directive "includx"
.includx "file"
-# expect+1: .include filename must be delimited by '"' or '<'
+# expect+1: .include filename must be delimited by "" or <>
.includex "file" # XXX: the 's' is not meant to be a filename
# expect+1: Unknown directive "inf"
@@ -78,7 +78,7 @@
.sinclude "file"
# expect+1: Unknown directive "sincludx"
.sincludx "file"
-# expect+1: .include filename must be delimited by '"' or '<'
+# expect+1: .include filename must be delimited by "" or <>
.sincludes "file" # XXX: the 's' is not meant to be a filename
# expect+1: Unknown directive "unde"
diff --git a/contrib/bmake/unit-tests/directive-sinclude.exp b/contrib/bmake/unit-tests/directive-sinclude.exp
index b7503e18c9b5..74db51227f07 100755
--- a/contrib/bmake/unit-tests/directive-sinclude.exp
+++ b/contrib/bmake/unit-tests/directive-sinclude.exp
@@ -1,4 +1,4 @@
-make: directive-include-error.inc:1: Invalid line 'syntax error'
+make: directive-include-error.inc:1: Invalid line "syntax error"
in directive-sinclude.mk:20
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
diff --git a/contrib/bmake/unit-tests/directive-sinclude.mk b/contrib/bmake/unit-tests/directive-sinclude.mk
index d40915fa86d5..4c856d22be4f 100755
--- a/contrib/bmake/unit-tests/directive-sinclude.mk
+++ b/contrib/bmake/unit-tests/directive-sinclude.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-sinclude.mk,v 1.6 2025/03/30 09:51:50 rillig Exp $
+# $NetBSD: directive-sinclude.mk,v 1.7 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the .sinclude directive, which includes another file,
# silently skipping it if it cannot be opened.
@@ -15,7 +15,7 @@
.sinclude "${MAKEFILE}/subdir"
# Errors that are not related to opening the file are still reported.
-# expect: make: directive-include-error.inc:1: Invalid line 'syntax error'
+# expect: make: directive-include-error.inc:1: Invalid line "syntax error"
_!= echo 'syntax error' > directive-include-error.inc
.sinclude "${.CURDIR}/directive-include-error.inc"
_!= rm directive-include-error.inc
diff --git a/contrib/bmake/unit-tests/directive-unexport.exp b/contrib/bmake/unit-tests/directive-unexport.exp
index 1be4b03e3874..25bab7d7fd35 100644
--- a/contrib/bmake/unit-tests/directive-unexport.exp
+++ b/contrib/bmake/unit-tests/directive-unexport.exp
@@ -1,5 +1,5 @@
make: directive-unexport.mk:19: UT_A=a UT_B=b UT_C=c
make: directive-unexport.mk:21: UT_A UT_B UT_C
make: directive-unexport.mk:30: UT_A=a UT_B=b UT_C=c
-make: directive-unexport.mk:31:
+make: directive-unexport.mk:32:
exit status 0
diff --git a/contrib/bmake/unit-tests/directive-unexport.mk b/contrib/bmake/unit-tests/directive-unexport.mk
index e759fe3e35f2..3c10ffa07d6a 100644
--- a/contrib/bmake/unit-tests/directive-unexport.mk
+++ b/contrib/bmake/unit-tests/directive-unexport.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-unexport.mk,v 1.8 2023/06/01 20:56:35 rillig Exp $
+# $NetBSD: directive-unexport.mk,v 1.9 2025/06/30 21:44:39 rillig Exp $
#
# Tests for the .unexport directive.
#
@@ -28,6 +28,7 @@ UT_C= c
# expect+1: UT_A=a UT_B=b UT_C=c
.info ${:!env|sort|grep '^UT_'!}
+# expect+1:
.info ${.MAKE.EXPORTED}
.unexport # oops: missing argument
diff --git a/contrib/bmake/unit-tests/directive-warning.exp b/contrib/bmake/unit-tests/directive-warning.exp
index 2dd4e8ceb7f9..250e32583847 100644
--- a/contrib/bmake/unit-tests/directive-warning.exp
+++ b/contrib/bmake/unit-tests/directive-warning.exp
@@ -3,9 +3,9 @@ make: directive-warning.mk:12: Unknown directive "warn"
make: directive-warning.mk:14: Unknown directive "warnin"
make: directive-warning.mk:16: Unknown directive "warnin"
make: directive-warning.mk:18: Missing argument for ".warning"
-make: directive-warning.mk:19: warning: message
-make: directive-warning.mk:21: Unknown directive "warnings"
-make: directive-warning.mk:23: Unknown directive "warnings"
+make: directive-warning.mk:20: warning: message
+make: directive-warning.mk:22: Unknown directive "warnings"
+make: directive-warning.mk:24: Unknown directive "warnings"
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/directive-warning.mk b/contrib/bmake/unit-tests/directive-warning.mk
index bf0683f8911f..50666487c13f 100644
--- a/contrib/bmake/unit-tests/directive-warning.mk
+++ b/contrib/bmake/unit-tests/directive-warning.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive-warning.mk,v 1.9 2023/12/17 09:44:00 rillig Exp $
+# $NetBSD: directive-warning.mk,v 1.10 2025/07/01 04:24:20 rillig Exp $
#
# Tests for the .warning directive.
#
@@ -16,7 +16,8 @@
.warnin message # misspelled
# expect+1: Missing argument for ".warning"
.warning # "Missing argument"
-.warning message # expect+0: warning: message
+# expect+1: warning: message
+.warning message
# expect+1: Unknown directive "warnings"
.warnings # misspelled
# expect+1: Unknown directive "warnings"
diff --git a/contrib/bmake/unit-tests/directive.exp b/contrib/bmake/unit-tests/directive.exp
index 2f1da18cdbb5..dce759abfe52 100644
--- a/contrib/bmake/unit-tests/directive.exp
+++ b/contrib/bmake/unit-tests/directive.exp
@@ -7,8 +7,8 @@ Global: .info = value
make: directive.mk:31: := value
Global: .MAKEFLAGS = -r -k -d v -d
Global: .MAKEFLAGS = -r -k -d v -d 0
-make: directive.mk:40: Invalid line 'target-without-colon'
-make: directive.mk:43: Invalid line 'target-without-colon another-target'
+make: directive.mk:40: Invalid line "target-without-colon"
+make: directive.mk:43: Invalid line "target-without-colon another-target"
make: Fatal errors encountered -- cannot continue
make: stopped making ".target" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/directive.mk b/contrib/bmake/unit-tests/directive.mk
index 61938360dfc7..5f5be5aa0fab 100644
--- a/contrib/bmake/unit-tests/directive.mk
+++ b/contrib/bmake/unit-tests/directive.mk
@@ -1,4 +1,4 @@
-# $NetBSD: directive.mk,v 1.9 2023/11/19 22:32:44 rillig Exp $
+# $NetBSD: directive.mk,v 1.10 2025/06/28 22:39:28 rillig Exp $
#
# Tests for the preprocessing directives, such as .if or .info.
@@ -36,8 +36,8 @@
# Not even the space after the '.info' can change anything about this.
.${:Uinfo} : source
-# expect+1: Invalid line 'target-without-colon'
+# expect+1: Invalid line "target-without-colon"
target-without-colon
-# expect+1: Invalid line 'target-without-colon another-target'
+# expect+1: Invalid line "target-without-colon another-target"
target-without-colon another-target
diff --git a/contrib/bmake/unit-tests/moderrs.exp b/contrib/bmake/unit-tests/moderrs.exp
index 08aa2582f6be..4758294f0993 100644
--- a/contrib/bmake/unit-tests/moderrs.exp
+++ b/contrib/bmake/unit-tests/moderrs.exp
@@ -7,11 +7,11 @@ make: Unknown modifier ":Z"
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 'VAR:${MOD_UNKN}=before-${VAR:${MOD_UNKN}:inner}-after'"
in target "mod-unknown-indirect"
-make: Unclosed expression, expecting '}' for modifier "S,V,v,"
+make: Unclosed expression, expecting "}" for modifier "S,V,v,"
while evaluating variable "VAR" with value "Thevariable"
in command "@echo VAR:S,V,v,=${VAR:S,V,v,"
in target "unclosed-direct"
-make: Unclosed expression after indirect modifier, expecting '}'
+make: Unclosed expression after indirect modifier, expecting "}"
while evaluating variable "VAR" with value "Thevariable"
in command "@echo VAR:${MOD_TERM},=${VAR:${MOD_S}"
in target "unclosed-indirect"
@@ -29,7 +29,7 @@ make: Unfinished modifier after "...}", expecting "@"
in command "@echo ${UNDEF:U1 2 3:@var@...}"
in target "unfinished-loop-2"
1 2 3
-make: Unclosed expression, expecting '}' for modifier "@var@${var}}...@"
+make: Unclosed expression, expecting "}" for modifier "@var@${var}}...@"
while evaluating variable "UNDEF" with value "1}... 2}... 3}..."
in command "@echo ${UNDEF:U1 2 3:@var@${var}}...@"
in target "loop-close-1"
@@ -55,7 +55,7 @@ make: Unfinished modifier after "=exclam}", expecting "!"
while evaluating variable "!" with value "!"
in command "@echo ${!:L:!=exclam}"
in target "exclam-2"
-make: Missing delimiter for modifier ':S'
+make: Missing delimiter for modifier ":S"
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 1: ${VAR:S"
in target "mod-subst-delimiter-1"
@@ -75,12 +75,12 @@ make: Unfinished modifier after "to", expecting ","
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 5: ${VAR:S,from,to"
in target "mod-subst-delimiter-5"
-make: Unclosed expression, expecting '}' for modifier "S,from,to,"
+make: Unclosed expression, expecting "}" for modifier "S,from,to,"
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 6: ${VAR:S,from,to,"
in target "mod-subst-delimiter-6"
7: TheVariable
-make: Missing delimiter for modifier ':C'
+make: Missing delimiter for modifier ":C"
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 1: ${VAR:C"
in target "mod-regex-delimiter-1"
@@ -100,7 +100,7 @@ make: Unfinished modifier after "to", expecting ","
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 5: ${VAR:C,from,to"
in target "mod-regex-delimiter-5"
-make: Unclosed expression, expecting '}' for modifier "C,from,to,"
+make: Unclosed expression, expecting "}" for modifier "C,from,to,"
while evaluating variable "VAR" with value "TheVariable"
in command "@echo 6: ${VAR:C,from,to,"
in target "mod-regex-delimiter-6"
diff --git a/contrib/bmake/unit-tests/moderrs.mk b/contrib/bmake/unit-tests/moderrs.mk
index ca5cc082e6b8..c2ee320e2df2 100644
--- a/contrib/bmake/unit-tests/moderrs.mk
+++ b/contrib/bmake/unit-tests/moderrs.mk
@@ -1,4 +1,4 @@
-# $NetBSD: moderrs.mk,v 1.46 2025/03/30 00:35:52 rillig Exp $
+# $NetBSD: moderrs.mk,v 1.47 2025/06/28 22:39:29 rillig Exp $
#
# various modifier error tests
@@ -33,11 +33,11 @@ mod-unknown-indirect:
@echo 'VAR:${MOD_UNKN}=before-${VAR:${MOD_UNKN}:inner}-after'
unclosed-direct:
-# expect: make: Unclosed expression, expecting '}' for modifier "S,V,v,"
+# expect: make: Unclosed expression, expecting "}" for modifier "S,V,v,"
@echo VAR:S,V,v,=${VAR:S,V,v,
unclosed-indirect:
-# expect: make: Unclosed expression after indirect modifier, expecting '}'
+# expect: make: Unclosed expression after indirect modifier, expecting "}"
@echo VAR:${MOD_TERM},=${VAR:${MOD_S}
unfinished-indirect:
@@ -60,7 +60,7 @@ unfinished-loop-3:
# This is also contrary to the SysV modifier, where only the actually
# used delimiter (either braces or parentheses) must be balanced.
loop-close-1:
-# expect: make: Unclosed expression, expecting '}' for modifier "@var@${var}}...@"
+# expect: make: Unclosed expression, expecting "}" for modifier "@var@${var}}...@"
@echo ${UNDEF:U1 2 3:@var@${var}}...@
loop-close-2:
@echo ${UNDEF:U1 2 3:@var@${var}}...@}
@@ -107,7 +107,7 @@ exclam-2:
@echo ${!:L:!=exclam}
mod-subst-delimiter-1:
-# expect: make: Missing delimiter for modifier ':S'
+# expect: make: Missing delimiter for modifier ":S"
@echo 1: ${VAR:S
mod-subst-delimiter-2:
# expect: make: Unfinished modifier after "", expecting ","
@@ -122,13 +122,13 @@ mod-subst-delimiter-5:
# expect: make: Unfinished modifier after "to", expecting ","
@echo 5: ${VAR:S,from,to
mod-subst-delimiter-6:
-# expect: make: Unclosed expression, expecting '}' for modifier "S,from,to,"
+# expect: make: Unclosed expression, expecting "}" for modifier "S,from,to,"
@echo 6: ${VAR:S,from,to,
mod-subst-delimiter-7:
@echo 7: ${VAR:S,from,to,}
mod-regex-delimiter-1:
-# expect: make: Missing delimiter for modifier ':C'
+# expect: make: Missing delimiter for modifier ":C"
@echo 1: ${VAR:C
mod-regex-delimiter-2:
# expect: make: Unfinished modifier after "", expecting ","
@@ -143,7 +143,7 @@ mod-regex-delimiter-5:
# expect: make: Unfinished modifier after "to", expecting ","
@echo 5: ${VAR:C,from,to
mod-regex-delimiter-6:
-# expect: make: Unclosed expression, expecting '}' for modifier "C,from,to,"
+# expect: make: Unclosed expression, expecting "}" for modifier "C,from,to,"
@echo 6: ${VAR:C,from,to,
mod-regex-delimiter-7:
@echo 7: ${VAR:C,from,to,}
diff --git a/contrib/bmake/unit-tests/opt-debug-file.exp b/contrib/bmake/unit-tests/opt-debug-file.exp
index 1059351188e4..4a497f3011d9 100644
--- a/contrib/bmake/unit-tests/opt-debug-file.exp
+++ b/contrib/bmake/unit-tests/opt-debug-file.exp
@@ -1,6 +1,6 @@
-make: opt-debug-file.mk:44: This goes to stderr only, once.
-make: opt-debug-file.mk:47: This goes to stderr only, once.
-make: opt-debug-file.mk:50: This goes to stderr, and in addition to the debug log.
+make: opt-debug-file.mk:54: This goes to stderr only, once.
+make: opt-debug-file.mk:57: This goes to stderr only, once.
+make: opt-debug-file.mk:60: This goes to stderr, and in addition to the debug log.
CondParser_Eval: ${:!cat opt-debug-file.debuglog!:Maddition:[#]} != 1
Comparing 1.000000 != 1.000000
make: Unterminated quoted string [make 'This goes to stdout only, once.]
diff --git a/contrib/bmake/unit-tests/opt-debug-file.mk b/contrib/bmake/unit-tests/opt-debug-file.mk
index 33a35e0a458a..d107f177dae3 100644
--- a/contrib/bmake/unit-tests/opt-debug-file.mk
+++ b/contrib/bmake/unit-tests/opt-debug-file.mk
@@ -1,4 +1,4 @@
-# $NetBSD: opt-debug-file.mk,v 1.11 2024/06/30 15:21:24 rillig Exp $
+# $NetBSD: opt-debug-file.mk,v 1.12 2025/07/06 08:48:34 rillig Exp $
#
# Tests for the -dF command line option, which redirects the debug log
# to a file instead of writing it to stderr.
@@ -27,7 +27,9 @@ DEBUG_OUTPUT:= ${:!cat opt-debug-file.debuglog!}
.endif
# To get the unexpanded text that was actually written to the debug log
-# file, the content of that log file must not be stored in a variable.
+# file, the content of that log file must not be stored in a variable
+# directly. Instead, it can be processed in a single expression by a chain
+# of modifiers.
#
# XXX: In the :M modifier, a dollar is escaped using '$$', not '\$'. This
# escaping scheme unnecessarily differs from all other modifiers.
@@ -35,6 +37,14 @@ DEBUG_OUTPUT:= ${:!cat opt-debug-file.debuglog!}
. error
.endif
+# To get the unexpanded text that was actually written to the debug log
+# file, the content of that log file must not be stored in a variable
+# directly. Instead, each dollar sign must be escaped first.
+DEBUG_OUTPUT:= ${:!cat opt-debug-file.debuglog!:S,\$,\$\$,g}
+.if ${DEBUG_OUTPUT:M*Uexpanded*} != "\${:Uexpanded}"
+. error
+.endif
+
.MAKEFLAGS: -d0
diff --git a/contrib/bmake/unit-tests/opt-debug-lint.exp b/contrib/bmake/unit-tests/opt-debug-lint.exp
index 8e7339fcd2e9..7173ec476ec5 100644
--- a/contrib/bmake/unit-tests/opt-debug-lint.exp
+++ b/contrib/bmake/unit-tests/opt-debug-lint.exp
@@ -1,8 +1,8 @@
make: opt-debug-lint.mk:20: Variable "X" is undefined
make: opt-debug-lint.mk:43: Variable "UNDEF" is undefined
-make: opt-debug-lint.mk:65: Missing delimiter ':' after modifier "L"
+make: opt-debug-lint.mk:65: Missing delimiter ":" after modifier "L"
while evaluating variable "value" with value "value"
-make: opt-debug-lint.mk:65: Missing delimiter ':' after modifier "P"
+make: opt-debug-lint.mk:65: Missing delimiter ":" after modifier "P"
while evaluating variable "value" with value "value"
make: opt-debug-lint.mk:74: Unknown modifier ":${"
while evaluating variable "value" with value ""
diff --git a/contrib/bmake/unit-tests/opt-debug-lint.mk b/contrib/bmake/unit-tests/opt-debug-lint.mk
index 59cd36fb05e9..2f73c9bf645c 100644
--- a/contrib/bmake/unit-tests/opt-debug-lint.mk
+++ b/contrib/bmake/unit-tests/opt-debug-lint.mk
@@ -1,4 +1,4 @@
-# $NetBSD: opt-debug-lint.mk,v 1.24 2025/04/04 18:57:01 rillig Exp $
+# $NetBSD: opt-debug-lint.mk,v 1.25 2025/06/28 22:39:29 rillig Exp $
#
# Tests for the -dL command line option, which runs additional checks
# to catch common mistakes, such as unclosed expressions.
@@ -60,8 +60,8 @@ ${UNDEF}: ${UNDEF}
# Since 2020-10-03, in lint mode the variable modifier must be separated
# by colons. See varparse-mod.mk.
-# expect+2: Missing delimiter ':' after modifier "L"
-# expect+1: Missing delimiter ':' after modifier "P"
+# expect+2: Missing delimiter ":" after modifier "L"
+# expect+1: Missing delimiter ":" after modifier "P"
.if ${value:LPL} != "value"
. error
.endif
diff --git a/contrib/bmake/unit-tests/opt-jobs-internal.exp b/contrib/bmake/unit-tests/opt-jobs-internal.exp
index e3e8ee498224..61c96256a2e4 100644
--- a/contrib/bmake/unit-tests/opt-jobs-internal.exp
+++ b/contrib/bmake/unit-tests/opt-jobs-internal.exp
@@ -1,25 +1,13 @@
direct: mode=parallel
make: error: invalid internal option "-J garbage" in "<curdir>"
-make: warning: internal option "-J" in "<curdir>" refers to unopened file descriptors; falling back to compat mode.
- To run the target even in -n mode, add the .MAKE pseudo-source to the target.
- To run the target in default mode only, add a ${:D make} marker to a target's command. (This marker expression expands to an empty string.)
- To make the sub-make run in compat mode, add -B to its invocation.
- To make the sub-make independent from the parent make, unset the MAKEFLAGS environment variable in the target's commands.
+make: warning: Invalid internal option "-J" in "<curdir>"; see the manual page
in make[2] in directory "<curdir>"
direct-open: mode=compat
-make: warning: internal option "-J" in "<curdir>" refers to unopened file descriptors; falling back to compat mode.
- To run the target even in -n mode, add the .MAKE pseudo-source to the target.
- To run the target in default mode only, add a ${:D make} marker to a target's command. (This marker expression expands to an empty string.)
- To make the sub-make run in compat mode, add -B to its invocation.
- To make the sub-make independent from the parent make, unset the MAKEFLAGS environment variable in the target's commands.
+make: warning: Invalid internal option "-J" in "<curdir>"; see the manual page
in make[2] in directory "<curdir>"
indirect-open: mode=compat
indirect-expr: mode=parallel
-make: warning: internal option "-J" in "<curdir>" refers to unopened file descriptors; falling back to compat mode.
- To run the target even in -n mode, add the .MAKE pseudo-source to the target.
- To run the target in default mode only, add a ${:D make} marker to a target's command. (This marker expression expands to an empty string.)
- To make the sub-make run in compat mode, add -B to its invocation.
- To make the sub-make independent from the parent make, unset the MAKEFLAGS environment variable in the target's commands.
+make: warning: Invalid internal option "-J" in "<curdir>"; see the manual page
in make[2] in directory "<curdir>"
indirect-comment: mode=compat
indirect-silent-comment: mode=parallel
diff --git a/contrib/bmake/unit-tests/parse.exp b/contrib/bmake/unit-tests/parse.exp
index 86d12effb5c7..4f97a9350550 100644
--- a/contrib/bmake/unit-tests/parse.exp
+++ b/contrib/bmake/unit-tests/parse.exp
@@ -1,6 +1,6 @@
-make: parse.mk:7: Invalid line '<<<<<< old'
-make: parse.mk:14: Invalid line '>>>>>> new'
-make: parse.mk:25: Invalid line 'one-target ${:U }', expanded to 'one-target '
+make: parse.mk:7: Invalid line "<<<<<< old"
+make: parse.mk:14: Invalid line ">>>>>> new"
+make: parse.mk:25: Invalid line "one-target ${:U }", expanded to "one-target "
make: Fatal errors encountered -- cannot continue
make: stopped making "Try_to_crash_FreeBSD.xxxxxxxxxxxxxxxxxx" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/parse.mk b/contrib/bmake/unit-tests/parse.mk
index 80a51f2de11e..fb959a4a5e1b 100644
--- a/contrib/bmake/unit-tests/parse.mk
+++ b/contrib/bmake/unit-tests/parse.mk
@@ -1,16 +1,16 @@
-# $NetBSD: parse.mk,v 1.7 2023/08/19 11:09:02 rillig Exp $
+# $NetBSD: parse.mk,v 1.8 2025/06/28 22:39:29 rillig Exp $
#
# Test those parts of the parsing that do not belong in any of the other
# categories.
-# expect+1: Invalid line '<<<<<< old'
+# expect+1: Invalid line "<<<<<< old"
<<<<<< old
# No diagnostic since the following line is parsed as a variable assignment,
# even though the variable name is empty. See also varname-empty.mk.
====== middle
-# expect+1: Invalid line '>>>>>> new'
+# expect+1: Invalid line ">>>>>> new"
>>>>>> new
@@ -21,7 +21,7 @@
# the expanded line's terminating '\0'.
#
# https://bugs.freebsd.org/265119
-# expect+1: Invalid line 'one-target ${:U }', expanded to 'one-target '
+# expect+1: Invalid line "one-target ${:U }", expanded to "one-target "
one-target ${:U }
diff --git a/contrib/bmake/unit-tests/var-op-assign.exp b/contrib/bmake/unit-tests/var-op-assign.exp
index 4e287e518eb7..83459de4184d 100644
--- a/contrib/bmake/unit-tests/var-op-assign.exp
+++ b/contrib/bmake/unit-tests/var-op-assign.exp
@@ -1,5 +1,5 @@
this will be evaluated later
-make: var-op-assign.mk:60: Invalid line 'VARIABLE NAME= variable value'
+make: var-op-assign.mk:60: Invalid line "VARIABLE NAME= variable value"
make: var-op-assign.mk:95: Parsing still continues until here.
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
diff --git a/contrib/bmake/unit-tests/var-op-assign.mk b/contrib/bmake/unit-tests/var-op-assign.mk
index a900c28a918d..a218dbfdac0a 100644
--- a/contrib/bmake/unit-tests/var-op-assign.mk
+++ b/contrib/bmake/unit-tests/var-op-assign.mk
@@ -1,4 +1,4 @@
-# $NetBSD: var-op-assign.mk,v 1.11 2023/11/19 21:47:52 rillig Exp $
+# $NetBSD: var-op-assign.mk,v 1.12 2025/06/28 22:39:29 rillig Exp $
#
# Tests for the = variable assignment operator, which overwrites an existing
# variable or creates it.
@@ -56,7 +56,7 @@ VAR= ${:! echo 'this will be evaluated later' 1>&2 !}
# In a variable assignment, the variable name must consist of a single word.
# The following line therefore generates a parse error.
-# expect+1: Invalid line 'VARIABLE NAME= variable value'
+# expect+1: Invalid line "VARIABLE NAME= variable value"
VARIABLE NAME= variable value
# But if the whitespace appears inside parentheses or braces, everything is
diff --git a/contrib/bmake/unit-tests/var-op-expand.exp b/contrib/bmake/unit-tests/var-op-expand.exp
index 105d2f50acc8..5e2c3d1936d7 100644
--- a/contrib/bmake/unit-tests/var-op-expand.exp
+++ b/contrib/bmake/unit-tests/var-op-expand.exp
@@ -1,22 +1,20 @@
make: var-op-expand.mk:274: Unknown modifier ":s,value,replaced,"
while evaluating variable "later" with value ""
while evaluating variable "indirect" with value "${later:s,value,replaced,} ok ${later:value=sysv}"
-make: var-op-expand.mk:278: warning: XXX Neither branch should be taken.
-make: var-op-expand.mk:283: Unknown modifier ":s,value,replaced,"
+make: var-op-expand.mk:282: Unknown modifier ":s,value,replaced,"
while evaluating variable "later" with value "lowercase-value"
while evaluating variable "indirect" with value "${later:s,value,replaced,} ok ${later:value=sysv}"
-make: var-op-expand.mk:285: warning: XXX Neither branch should be taken.
-make: var-op-expand.mk:297: Bad condition
+make: var-op-expand.mk:295: Bad condition
while evaluating condition " < 0 "
-make: var-op-expand.mk:297: Unknown modifier ":Z1"
+make: var-op-expand.mk:295: Unknown modifier ":Z1"
while parsing "${:Z1}:${:Z2}}"
while evaluating then-branch of condition " < 0 "
-make: var-op-expand.mk:297: Unknown modifier ":Z2"
+make: var-op-expand.mk:295: Unknown modifier ":Z2"
while parsing "${:Z2}}"
while evaluating else-branch of condition " < 0 "
-make: var-op-expand.mk:297: Unknown modifier ":Z1"
+make: var-op-expand.mk:295: Unknown modifier ":Z1"
while evaluating "${:Z1}:${:Z2}}" with value ""
-make: var-op-expand.mk:297: Unknown modifier ":Z2"
+make: var-op-expand.mk:295: Unknown modifier ":Z2"
while evaluating "${:Z2}}" with value ""
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
diff --git a/contrib/bmake/unit-tests/var-op-expand.mk b/contrib/bmake/unit-tests/var-op-expand.mk
index 6a49648f0618..fb9e1713438b 100644
--- a/contrib/bmake/unit-tests/var-op-expand.mk
+++ b/contrib/bmake/unit-tests/var-op-expand.mk
@@ -1,4 +1,4 @@
-# $NetBSD: var-op-expand.mk,v 1.24 2025/04/30 06:01:07 rillig Exp $
+# $NetBSD: var-op-expand.mk,v 1.25 2025/06/29 11:27:21 rillig Exp $
#
# Tests for the := variable assignment operator, which expands its
# right-hand side.
@@ -274,15 +274,13 @@ indirect:= ${INDIRECT:tl}
.if ${indirect} != " ok "
. error
.else
-# expect+1: warning: XXX Neither branch should be taken.
-. warning XXX Neither branch should be taken.
+. error
.endif
LATER= uppercase-value
later= lowercase-value
# expect+1: Unknown modifier ":s,value,replaced,"
.if ${indirect} != "uppercase-replaced ok uppercase-sysv"
-# expect+1: warning: XXX Neither branch should be taken.
-. warning XXX Neither branch should be taken.
+. error
.else
. error
.endif
diff --git a/contrib/bmake/unit-tests/varmisc.exp b/contrib/bmake/unit-tests/varmisc.exp
index 509dbcc5e689..44b3c8e759cb 100644
--- a/contrib/bmake/unit-tests/varmisc.exp
+++ b/contrib/bmake/unit-tests/varmisc.exp
@@ -57,7 +57,7 @@ make: Unclosed variable "PATTERN"
while evaluating variable "UNCLOSED" with value ""
in command "@echo ${UNCLOSED:M${PATTERN"
in target "varerror-unclosed-5"
-make: Unclosed expression, expecting '}' for modifier "M${PATTERN"
+make: Unclosed expression, expecting "}" for modifier "M${PATTERN"
while evaluating variable "UNCLOSED" with value ""
in command "@echo ${UNCLOSED:M${PATTERN"
in target "varerror-unclosed-5"
diff --git a/contrib/bmake/unit-tests/varmisc.mk b/contrib/bmake/unit-tests/varmisc.mk
index b067742e9ac4..e36396633dc2 100644
--- a/contrib/bmake/unit-tests/varmisc.mk
+++ b/contrib/bmake/unit-tests/varmisc.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmisc.mk,v 1.37 2024/08/29 20:20:36 rillig Exp $
+# $NetBSD: varmisc.mk,v 1.38 2025/06/28 22:39:29 rillig Exp $
#
# Miscellaneous variable tests.
@@ -200,7 +200,7 @@ varerror-unclosed-4:
# expect: make: Unclosed variable "UNCLOSED"
@echo ${UNCLOSED
varerror-unclosed-5:
-# expect: make: Unclosed expression, expecting '}' for modifier "M${PATTERN"
+# expect: make: Unclosed expression, expecting "}" for modifier "M${PATTERN"
@echo ${UNCLOSED:M${PATTERN
varerror-unclosed-6:
# expect: make: Unclosed variable "param"
diff --git a/contrib/bmake/unit-tests/varmod-edge.exp b/contrib/bmake/unit-tests/varmod-edge.exp
index 2b41623bb66c..b80380fb702c 100644
--- a/contrib/bmake/unit-tests/varmod-edge.exp
+++ b/contrib/bmake/unit-tests/varmod-edge.exp
@@ -1,8 +1,8 @@
-make: varmod-edge.mk:60: Unclosed expression, expecting '}' for modifier "U*)"
+make: varmod-edge.mk:60: Unclosed expression, expecting "}" for modifier "U*)"
while evaluating "${:U*)" with value "*)"
while evaluating variable "INP" with value "(parentheses)"
while evaluating variable "MOD" with value "${INP:M${:U*)}}"
-make: varmod-edge.mk:88: Unfinished character list in pattern '[[' of modifier ':M'
+make: varmod-edge.mk:88: Unfinished character list in pattern "[[" of modifier ":M"
while evaluating variable "INP" with value "[ [[ [[["
while evaluating variable "MOD" with value "${INP:M${:U[[}}"
make: varmod-edge.mk:178: Unfinished modifier after "a\=b}", expecting "="
diff --git a/contrib/bmake/unit-tests/varmod-edge.mk b/contrib/bmake/unit-tests/varmod-edge.mk
index 473c7ad171e5..b5f879372afd 100644
--- a/contrib/bmake/unit-tests/varmod-edge.mk
+++ b/contrib/bmake/unit-tests/varmod-edge.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-edge.mk,v 1.36 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: varmod-edge.mk,v 1.37 2025/06/28 22:39:29 rillig Exp $
#
# Tests for edge cases in variable modifiers.
#
@@ -56,7 +56,7 @@ EXP= \(\{}\):
INP= (parentheses)
MOD= ${INP:M${:U*)}}
EXP= (parentheses)}
-# expect+1: Unclosed expression, expecting '}' for modifier "U*)"
+# expect+1: Unclosed expression, expecting "}" for modifier "U*)"
.if ${MOD} != ${EXP}
. warning expected "${EXP}", got "${MOD}"
.endif
@@ -84,7 +84,7 @@ EXP= [
INP= [ [[ [[[
MOD= ${INP:M${:U[[}}
EXP= [
-# expect+1: Unfinished character list in pattern '[[' of modifier ':M'
+# expect+1: Unfinished character list in pattern "[[" of modifier ":M"
.if ${MOD} != ${EXP}
. warning expected "${EXP}", got "${MOD}"
.endif
diff --git a/contrib/bmake/unit-tests/varmod-ifelse.exp b/contrib/bmake/unit-tests/varmod-ifelse.exp
index 039f0fd0b9a7..bf642c86fc8c 100644
--- a/contrib/bmake/unit-tests/varmod-ifelse.exp
+++ b/contrib/bmake/unit-tests/varmod-ifelse.exp
@@ -12,26 +12,25 @@ Comparing 1.000000 == 0.000000
make: varmod-ifelse.mk:94: Bad condition
while evaluating condition "1 == == 2"
Comparing "" != ""
-make: varmod-ifelse.mk:98: warning: Oops, the parse error should have been propagated.
CondParser_Eval: ${ ${:U\$}{VAR} == value:?ok:bad} != "ok"
CondParser_Eval: ${VAR} == value
Comparing "value" == "value"
Comparing "ok" != "ok"
-make: varmod-ifelse.mk:160: no.
-make: varmod-ifelse.mk:163: Comparison with '>=' requires both operands 'no' and '10' to be numeric
+make: varmod-ifelse.mk:159: no.
+make: varmod-ifelse.mk:162: Comparison with ">=" requires both operands "no" and "10" to be numeric
while evaluating condition "string == "literal" || no >= 10"
-make: varmod-ifelse.mk:163: .
-make: varmod-ifelse.mk:170: Bad condition
+make: varmod-ifelse.mk:162: .
+make: varmod-ifelse.mk:169: Bad condition
while evaluating condition "string == "literal" && >= 10"
-make: varmod-ifelse.mk:170: .
-make: varmod-ifelse.mk:173: Bad condition
+make: varmod-ifelse.mk:169: .
+make: varmod-ifelse.mk:172: Bad condition
while evaluating condition "string == "literal" || >= 10"
-make: varmod-ifelse.mk:173: .
-make: varmod-ifelse.mk:181: <true>
-make: varmod-ifelse.mk:184: <false>
-make: varmod-ifelse.mk:188: Bad condition
+make: varmod-ifelse.mk:172: .
+make: varmod-ifelse.mk:180: <true>
+make: varmod-ifelse.mk:183: <false>
+make: varmod-ifelse.mk:187: Bad condition
while evaluating condition " "
-make: varmod-ifelse.mk:188: <>
+make: varmod-ifelse.mk:187: <>
CondParser_Eval: 0 && ${1:?${:Uthen0:S,}},,}:${:Uelse0:S,}},,}} != "not evaluated"
CondParser_Eval: 1 && ${0:?${:Uthen1:S,}},,}:${:Uelse1:S,}},,}} != "else1"
CondParser_Eval: 0
@@ -41,31 +40,31 @@ CondParser_Eval: 1
Comparing "then2" != "then2"
CondParser_Eval: ${DELAYED} == "one"
Comparing "two" == "one"
-make: varmod-ifelse.mk:284: no
+make: varmod-ifelse.mk:283: no
CondParser_Eval: ${DELAYED} == "two"
Comparing "two" == "two"
-make: varmod-ifelse.mk:286: yes
+make: varmod-ifelse.mk:285: yes
CondParser_Eval: ${DELAYED} == "one"
Comparing "two" == "one"
-make: varmod-ifelse.mk:289: no
+make: varmod-ifelse.mk:288: no
CondParser_Eval: ${DELAYED} == "two"
Comparing "two" == "two"
-make: varmod-ifelse.mk:292: yes
-make: varmod-ifelse.mk:314: Unknown modifier ":X-then"
+make: varmod-ifelse.mk:291: yes
+make: varmod-ifelse.mk:313: Unknown modifier ":X-then"
while evaluating "${:X-then}:${:X-else}}" with value ""
while evaluating then-branch of condition "1"
-make: varmod-ifelse.mk:314: Unknown modifier ":X-else"
+make: varmod-ifelse.mk:313: Unknown modifier ":X-else"
while parsing "${:X-else}}"
while evaluating else-branch of condition "1"
-make: varmod-ifelse.mk:322: Bad condition
+make: varmod-ifelse.mk:321: Bad condition
while evaluating condition " < 0 "
-make: varmod-ifelse.mk:322: Unknown modifier ":Z1"
+make: varmod-ifelse.mk:321: Unknown modifier ":Z1"
while parsing "${:Z1}:${:Z2}}>"
while evaluating then-branch of condition " < 0 "
-make: varmod-ifelse.mk:322: Unknown modifier ":Z2"
+make: varmod-ifelse.mk:321: Unknown modifier ":Z2"
while parsing "${:Z2}}>"
while evaluating else-branch of condition " < 0 "
-make: varmod-ifelse.mk:322: <>
+make: varmod-ifelse.mk:321: <>
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/varmod-ifelse.mk b/contrib/bmake/unit-tests/varmod-ifelse.mk
index 986524330a97..fcd483d0c497 100644
--- a/contrib/bmake/unit-tests/varmod-ifelse.mk
+++ b/contrib/bmake/unit-tests/varmod-ifelse.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-ifelse.mk,v 1.39 2025/04/30 06:01:07 rillig Exp $
+# $NetBSD: varmod-ifelse.mk,v 1.41 2025/06/29 11:27:21 rillig Exp $
#
# Tests for the ${cond:?then:else} variable modifier, which evaluates either
# the then-expression or the else-expression, depending on the condition.
@@ -73,9 +73,9 @@ COND:= ${${UNDEF} == "":?bad-assign:bad-assign}
. error
.endif
-# If the "Bad conditional expression" appears in a quoted string literal, the
+# If the "Bad condition" appears in a quoted string literal, the
# error message "Malformed conditional" is not printed, leaving only the "Bad
-# conditional expression".
+# condition".
#
# XXX: The left-hand side is enclosed in quotes. This results in Var_Parse
# being called without VARE_EVAL_DEFINED. When ApplyModifier_IfElse
@@ -94,8 +94,7 @@ COND:= ${${UNDEF} == "":?bad-assign:bad-assign}
.if "${1 == == 2:?yes:no}" != ""
. error
.else
-# expect+1: warning: Oops, the parse error should have been propagated.
-. warning Oops, the parse error should have been propagated.
+. error
.endif
.MAKEFLAGS: -d0
@@ -158,7 +157,7 @@ STRING= string
NUMBER= no # not really a number
# expect+1: no.
.info ${${STRING} == "literal" && ${NUMBER} >= 10:?yes:no}.
-# expect+2: Comparison with '>=' requires both operands 'no' and '10' to be numeric
+# expect+2: Comparison with ">=" requires both operands "no" and "10" to be numeric
# expect+1: .
.info ${${STRING} == "literal" || ${NUMBER} >= 10:?yes:no}.
diff --git a/contrib/bmake/unit-tests/varmod-match-escape.exp b/contrib/bmake/unit-tests/varmod-match-escape.exp
index 25d78226345c..42e470310d4c 100755
--- a/contrib/bmake/unit-tests/varmod-match-escape.exp
+++ b/contrib/bmake/unit-tests/varmod-match-escape.exp
@@ -33,14 +33,18 @@ Comparing ":" != "::"
make: varmod-match-escape.mk:43: warning: XXX: Oops
Global: .MAKEFLAGS = -r -k -d cv -d
Global: .MAKEFLAGS = -r -k -d cv -d 0
-make: varmod-match-escape.mk:69: Dollar followed by nothing
+make: varmod-match-escape.mk:63: Unfinished backslash at the end in pattern "\" of modifier ":M"
while evaluating "${:U\$:M\$} != """ with value "$"
-make: varmod-match-escape.mk:110: Unfinished character list in pattern '[A-]' of modifier ':M'
+make: varmod-match-escape.mk:71: Dollar followed by nothing
+ while evaluating "${:U\$:M\$} != """ with value "$"
+make: varmod-match-escape.mk:71: Unfinished backslash at the end in pattern "\" of modifier ":M"
+ while evaluating "${:U\$:M\$} != """ with value "$"
+make: varmod-match-escape.mk:112: Unfinished character list in pattern "[A-]" of modifier ":M"
while evaluating variable "WORDS" with value "A A] A]] B B] B]] ] ]] ]]] a a] a]]"
- in .for loop from varmod-match-escape.mk:107 with pattern = [A-]
-make: varmod-match-escape.mk:110: Unfinished character list in pattern '[^A-]' of modifier ':M'
+ in .for loop from varmod-match-escape.mk:109 with pattern = [A-]
+make: varmod-match-escape.mk:112: Unfinished character list in pattern "[^A-]" of modifier ":M"
while evaluating variable "WORDS" with value "A A] A]] B B] B]] ] ]] ]]] a a] a]]"
- in .for loop from varmod-match-escape.mk:107 with pattern = [^A-]
+ in .for loop from varmod-match-escape.mk:109 with pattern = [^A-]
make: Fatal errors encountered -- cannot continue
make: stopped making "all" in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/varmod-match-escape.mk b/contrib/bmake/unit-tests/varmod-match-escape.mk
index d9e2009f9b60..5c492d9d1f72 100755
--- a/contrib/bmake/unit-tests/varmod-match-escape.mk
+++ b/contrib/bmake/unit-tests/varmod-match-escape.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-match-escape.mk,v 1.18 2024/08/29 20:20:36 rillig Exp $
+# $NetBSD: varmod-match-escape.mk,v 1.20 2025/06/28 22:39:29 rillig Exp $
#
# As of 2020-08-01, the :M and :N modifiers interpret backslashes differently,
# depending on whether there was an expression somewhere before the
@@ -59,13 +59,15 @@ VALUES= : :: :\:
# '\{' nor '\}'. But the text is expanded, and a lonely '$' at the end
# is silently discarded. The resulting expanded pattern is thus '\', that
# is a single backslash.
+# expect+1: Unfinished backslash at the end in pattern "\" of modifier ":M"
.if ${:U\$:M\$} != ""
. error
.endif
# In lint mode, the case of a lonely '$' is covered with an error message.
.MAKEFLAGS: -dL
-# expect+1: Dollar followed by nothing
+# expect+2: Dollar followed by nothing
+# expect+1: Unfinished backslash at the end in pattern "\" of modifier ":M"
.if ${:U\$:M\$} != ""
. error
.endif
@@ -105,8 +107,8 @@ EXP.[^A-]]= a
EXP.[^A-]]]= a]
.for pattern in [A-] [A-]] [A-]]] [^A-] [^A-]] [^A-]]]
-# expect+2: Unfinished character list in pattern '[A-]' of modifier ':M'
-# expect+1: Unfinished character list in pattern '[^A-]' of modifier ':M'
+# expect+2: Unfinished character list in pattern "[A-]" of modifier ":M"
+# expect+1: Unfinished character list in pattern "[^A-]" of modifier ":M"
. if ${WORDS:M${pattern}} != ${EXP.${pattern}}
. warning ${pattern}: ${WORDS:M${pattern}} != ${EXP.${pattern}}
. endif
diff --git a/contrib/bmake/unit-tests/varmod-match.exp b/contrib/bmake/unit-tests/varmod-match.exp
index 14eb7862d815..7bccc4283e32 100644
--- a/contrib/bmake/unit-tests/varmod-match.exp
+++ b/contrib/bmake/unit-tests/varmod-match.exp
@@ -1,22 +1,22 @@
-make: varmod-match.mk:289: Unfinished character list in pattern 'a[' of modifier ':M'
+make: varmod-match.mk:293: Unfinished character list in pattern "a[" of modifier ":M"
while evaluating variable "WORDS" with value "a a["
-make: varmod-match.mk:297: Unfinished character list in pattern 'a[^' of modifier ':M'
+make: varmod-match.mk:301: Unfinished character list in pattern "a[^" of modifier ":M"
while evaluating variable "WORDS" with value "a a[ aX"
-make: varmod-match.mk:305: Unfinished character list in pattern '[-x1-3' of modifier ':M'
+make: varmod-match.mk:309: Unfinished character list in pattern "[-x1-3" of modifier ":M"
while evaluating variable "WORDS" with value "- + x xx 0 1 2 3 4 [x1-3"
-make: varmod-match.mk:313: Unfinished character list in pattern '*[-x1-3' of modifier ':M'
+make: varmod-match.mk:317: Unfinished character list in pattern "*[-x1-3" of modifier ":M"
while evaluating variable "WORDS" with value "- + x xx 0 1 2 3 4 00 01 10 11 000 001 010 011 100 101 110 111 [x1-3"
-make: varmod-match.mk:322: Unfinished character list in pattern '[^-x1-3' of modifier ':M'
+make: varmod-match.mk:326: Unfinished character list in pattern "[^-x1-3" of modifier ":M"
while evaluating variable "WORDS" with value "- + x xx 0 1 2 3 4 [x1-3"
-make: varmod-match.mk:336: Unfinished character list in pattern '?[\' of modifier ':M'
+make: varmod-match.mk:340: Unfinished character list in pattern "?[\" of modifier ":M"
while evaluating variable "WORDS" with value "\\ \a x\"
-make: varmod-match.mk:344: Unfinished character range in pattern '[x-' of modifier ':M'
+make: varmod-match.mk:348: Unfinished character range in pattern "[x-" of modifier ":M"
while evaluating variable "WORDS" with value "[x- x x- y"
-make: varmod-match.mk:356: Unfinished character range in pattern '[^x-' of modifier ':M'
+make: varmod-match.mk:360: Unfinished character range in pattern "[^x-" of modifier ":M"
while evaluating variable "WORDS" with value "[x- x x- y yyyyy"
-make: varmod-match.mk:363: Unfinished character list in pattern '[' of modifier ':M'
+make: varmod-match.mk:367: Unfinished character list in pattern "[" of modifier ":M"
while evaluating variable " : :: " with value " : :: "
-make: varmod-match.mk:363: Unknown modifier ":]"
+make: varmod-match.mk:367: Unknown modifier ":]"
while evaluating variable " : :: " with value ""
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
diff --git a/contrib/bmake/unit-tests/varmod-match.mk b/contrib/bmake/unit-tests/varmod-match.mk
index 99184989fb83..5894196c9cd5 100644
--- a/contrib/bmake/unit-tests/varmod-match.mk
+++ b/contrib/bmake/unit-tests/varmod-match.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-match.mk,v 1.30 2025/03/29 19:08:52 rillig Exp $
+# $NetBSD: varmod-match.mk,v 1.32 2025/06/29 09:40:13 rillig Exp $
#
# Tests for the ':M' modifier, which keeps only those words that match the
# given pattern.
@@ -13,8 +13,12 @@
# 6. Error handling
# 7. Historical bugs
#
-# See ApplyModifier_Match, ParseModifier_Match, ModifyWord_Match and
-# Str_Match.
+# See also:
+# char-005c-reverse-solidus.mk
+# ApplyModifier_Match
+# ParseModifier_Match
+# ModifyWord_Match
+# Str_Match
# 1. Pattern characters '*', '?' and '\'
@@ -285,7 +289,7 @@ ${:U*}= asterisk
# [ Incomplete empty character list, never matches.
WORDS= a a[
-# expect+1: Unfinished character list in pattern 'a[' of modifier ':M'
+# expect+1: Unfinished character list in pattern "a[" of modifier ":M"
.if ${WORDS:Ma[} != ""
. error
.endif
@@ -293,7 +297,7 @@ WORDS= a a[
# [^ Incomplete negated empty character list, matches any single
# character.
WORDS= a a[ aX
-# expect+1: Unfinished character list in pattern 'a[^' of modifier ':M'
+# expect+1: Unfinished character list in pattern "a[^" of modifier ":M"
.if ${WORDS:Ma[^} != "a[ aX"
. error
.endif
@@ -301,7 +305,7 @@ WORDS= a a[ aX
# [-x1-3 Incomplete character list, matches those elements that can be
# parsed without lookahead.
WORDS= - + x xx 0 1 2 3 4 [x1-3
-# expect+1: Unfinished character list in pattern '[-x1-3' of modifier ':M'
+# expect+1: Unfinished character list in pattern "[-x1-3" of modifier ":M"
.if ${WORDS:M[-x1-3} != "- x 1 2 3"
. error
.endif
@@ -309,7 +313,7 @@ WORDS= - + x xx 0 1 2 3 4 [x1-3
# *[-x1-3 Incomplete character list after a wildcard, matches those
# words that end with one of the characters from the list.
WORDS= - + x xx 0 1 2 3 4 00 01 10 11 000 001 010 011 100 101 110 111 [x1-3
-# expect+1: Unfinished character list in pattern '*[-x1-3' of modifier ':M'
+# expect+1: Unfinished character list in pattern "*[-x1-3" of modifier ":M"
.if ${WORDS:M*[-x1-3} != "- x xx 1 2 3 01 11 001 011 101 111 [x1-3"
. warning ${WORDS:M*[-x1-3}
.endif
@@ -318,7 +322,7 @@ WORDS= - + x xx 0 1 2 3 4 00 01 10 11 000 001 010 011 100 101 110 111 [x1-3
# Incomplete negated character list, matches any character
# except those elements that can be parsed without lookahead.
WORDS= - + x xx 0 1 2 3 4 [x1-3
-# expect+1: Unfinished character list in pattern '[^-x1-3' of modifier ':M'
+# expect+1: Unfinished character list in pattern "[^-x1-3" of modifier ":M"
.if ${WORDS:M[^-x1-3} != "+ 0 4"
. error
.endif
@@ -332,7 +336,7 @@ WORDS= - + x xx 0 1 2 3 4 [x1-3
# '\', as there is no following space that could be escaped.
WORDS= \\ \a ${:Ux\\}
PATTERN= ${:U?[\\}
-# expect+1: Unfinished character list in pattern '?[\' of modifier ':M'
+# expect+1: Unfinished character list in pattern "?[\" of modifier ":M"
.if ${WORDS:M${PATTERN}} != "\\\\ x\\"
. error
.endif
@@ -340,7 +344,7 @@ PATTERN= ${:U?[\\}
# [x- Incomplete character list containing an incomplete character
# range, matches only the 'x'.
WORDS= [x- x x- y
-# expect+1: Unfinished character range in pattern '[x-' of modifier ':M'
+# expect+1: Unfinished character range in pattern "[x-" of modifier ":M"
.if ${WORDS:M[x-} != "x"
. error
.endif
@@ -352,13 +356,13 @@ WORDS= [x- x x- y
# XXX: Even matches strings that are longer than a single
# character.
WORDS= [x- x x- y yyyyy
-# expect+1: Unfinished character range in pattern '[^x-' of modifier ':M'
+# expect+1: Unfinished character range in pattern "[^x-" of modifier ":M"
.if ${WORDS:M[^x-} != "[x- y yyyyy"
. error
.endif
# [:] matches never since the ':' starts the next modifier
-# expect+2: Unfinished character list in pattern '[' of modifier ':M'
+# expect+2: Unfinished character list in pattern "[" of modifier ":M"
# expect+1: Unknown modifier ":]"
.if ${ ${:U\:} ${:U\:\:} :L:M[:]} != ":"
. error
diff --git a/contrib/bmake/unit-tests/varmod-mtime.exp b/contrib/bmake/unit-tests/varmod-mtime.exp
index 9960dd877768..53b86b99b867 100644
--- a/contrib/bmake/unit-tests/varmod-mtime.exp
+++ b/contrib/bmake/unit-tests/varmod-mtime.exp
@@ -1,12 +1,12 @@
-make: varmod-mtime.mk:46: Invalid argument '123x' for modifier ':mtime'
+make: varmod-mtime.mk:46: Invalid argument "123x" for modifier ":mtime"
while evaluating variable "no/such/file" with value "no/such/file"
make: varmod-mtime.mk:68: Cannot determine mtime for "no/such/file1": <ENOENT>
while evaluating variable "no/such/file1 no/such/file2" with value "no/such/file1 no/such/file2"
make: varmod-mtime.mk:68: Cannot determine mtime for "no/such/file2": <ENOENT>
while evaluating variable "no/such/file1 no/such/file2" with value "no/such/file1 no/such/file2"
-make: varmod-mtime.mk:78: Invalid argument 'errorhandler-no' for modifier ':mtime'
+make: varmod-mtime.mk:78: Invalid argument "errorhandler-no" for modifier ":mtime"
while evaluating variable "MAKEFILE" with value "varmod-mtime.mk"
-make: varmod-mtime.mk:86: Invalid argument 'warn' for modifier ':mtime'
+make: varmod-mtime.mk:86: Invalid argument "warn" for modifier ":mtime"
while evaluating variable "MAKEFILE" with value "varmod-mtime.mk"
make: varmod-mtime.mk:110: Unknown modifier ":mtim"
while evaluating variable "anything" with value "anything"
diff --git a/contrib/bmake/unit-tests/varmod-mtime.mk b/contrib/bmake/unit-tests/varmod-mtime.mk
index ec33cd698b41..aed7024efd6b 100644
--- a/contrib/bmake/unit-tests/varmod-mtime.mk
+++ b/contrib/bmake/unit-tests/varmod-mtime.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-mtime.mk,v 1.16 2025/06/12 18:51:05 rillig Exp $
+# $NetBSD: varmod-mtime.mk,v 1.17 2025/06/28 22:39:29 rillig Exp $
#
# Tests for the ':mtime' variable modifier, which maps each word of the
# expression to that file's modification time.
@@ -42,7 +42,7 @@ not_found_mtime:= ${no/such/file:L:mtime}
# The fallback timestamp must only be an integer, without trailing characters.
-# expect+1: Invalid argument '123x' for modifier ':mtime'
+# expect+1: Invalid argument "123x" for modifier ":mtime"
.if ${no/such/file:L:mtime=123x}
. error
.else
@@ -74,7 +74,7 @@ _!= rm -f ${COOKIE}
# Only the word 'error' is a special argument to the ':mtime' modifier, all
# other words result in a parse error.
-# expect+1: Invalid argument 'errorhandler-no' for modifier ':mtime'
+# expect+1: Invalid argument "errorhandler-no" for modifier ":mtime"
.if ${MAKEFILE:mtime=errorhandler-no} > 0
.else
. error
@@ -82,7 +82,7 @@ _!= rm -f ${COOKIE}
# Only the word 'error' can be used as a fallback argument to the modifier.
-# expect+1: Invalid argument 'warn' for modifier ':mtime'
+# expect+1: Invalid argument "warn" for modifier ":mtime"
.if ${MAKEFILE:mtime=warn} > 0
. error
.else
diff --git a/contrib/bmake/unit-tests/varmod-order.exp b/contrib/bmake/unit-tests/varmod-order.exp
index f48256c6ae0e..fd18f0e11ee1 100644
--- a/contrib/bmake/unit-tests/varmod-order.exp
+++ b/contrib/bmake/unit-tests/varmod-order.exp
@@ -2,11 +2,11 @@ make: varmod-order.mk:14: Unknown modifier ":OX"
while evaluating variable "WORDS" with value "one two three four five six seven eight nine ten"
make: varmod-order.mk:17: Unknown modifier ":OxXX"
while evaluating variable "WORDS" with value "one two three four five six seven eight nine ten"
-make: varmod-order.mk:20: Unclosed expression, expecting '}' for modifier "O"
+make: varmod-order.mk:20: Unclosed expression, expecting "}" for modifier "O"
while evaluating variable "WORDS" with value "eight five four nine one seven six ten three two"
-make: varmod-order.mk:22: Unclosed expression, expecting '}' for modifier "On"
+make: varmod-order.mk:22: Unclosed expression, expecting "}" for modifier "On"
while evaluating variable "NUMBERS" with value "1 2 3 4 5 6 7 8 9 10"
-make: varmod-order.mk:24: Unclosed expression, expecting '}' for modifier "Onr"
+make: varmod-order.mk:24: Unclosed expression, expecting "}" for modifier "Onr"
while evaluating variable "NUMBERS" with value "10 9 8 7 6 5 4 3 2 1"
make: varmod-order.mk:30: Unknown modifier ":Oxn"
while evaluating variable "NUMBERS" with value "8 5 4 9 1 7 6 10 3 2"
diff --git a/contrib/bmake/unit-tests/varmod-order.mk b/contrib/bmake/unit-tests/varmod-order.mk
index c8386ef951dc..f4fa5d10cdf8 100644
--- a/contrib/bmake/unit-tests/varmod-order.mk
+++ b/contrib/bmake/unit-tests/varmod-order.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-order.mk,v 1.19 2025/03/29 23:50:07 rillig Exp $
+# $NetBSD: varmod-order.mk,v 1.20 2025/06/28 22:39:29 rillig Exp $
#
# Tests for the :O variable modifier and its variants, which either sort the
# words of the value or shuffle them.
@@ -16,11 +16,11 @@ _:= ${WORDS:OX}
# expect+1: Unknown modifier ":OxXX"
_:= ${WORDS:OxXX}
-# expect+1: Unclosed expression, expecting '}' for modifier "O"
+# expect+1: Unclosed expression, expecting "}" for modifier "O"
_:= ${WORDS:O
-# expect+1: Unclosed expression, expecting '}' for modifier "On"
+# expect+1: Unclosed expression, expecting "}" for modifier "On"
_:= ${NUMBERS:On
-# expect+1: Unclosed expression, expecting '}' for modifier "Onr"
+# expect+1: Unclosed expression, expecting "}" for modifier "Onr"
_:= ${NUMBERS:Onr
# Shuffling numerically doesn't make sense, so don't allow 'x' and 'n' to be
diff --git a/contrib/bmake/unit-tests/varmod-range.exp b/contrib/bmake/unit-tests/varmod-range.exp
index 768ba9ac2f2d..b98865a4084a 100644
--- a/contrib/bmake/unit-tests/varmod-range.exp
+++ b/contrib/bmake/unit-tests/varmod-range.exp
@@ -1,6 +1,6 @@
make: varmod-range.mk:43: Variable "" is undefined
while evaluating "${:range=5} != """ with value "1 2 3 4 5"
-make: varmod-range.mk:66: Invalid number "x}Rest" != "Rest"" for ':range' modifier
+make: varmod-range.mk:66: Invalid number "x}Rest" != "Rest"" for modifier ":range"
while evaluating "${:U:range=x}Rest" != "Rest"" with value ""
make: varmod-range.mk:76: Unknown modifier ":x0"
while evaluating "${:U:range=0x0}Rest" != "Rest"" with value "1"
diff --git a/contrib/bmake/unit-tests/varmod-range.mk b/contrib/bmake/unit-tests/varmod-range.mk
index 7a60bcc23d86..69dcf6ad1a7d 100644
--- a/contrib/bmake/unit-tests/varmod-range.mk
+++ b/contrib/bmake/unit-tests/varmod-range.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod-range.mk,v 1.18 2025/04/04 18:57:01 rillig Exp $
+# $NetBSD: varmod-range.mk,v 1.19 2025/06/28 22:39:29 rillig Exp $
#
# Tests for the :range variable modifier, which generates sequences
# of integers from the given range.
@@ -62,7 +62,7 @@
#
# Since 2020-11-01, the parser issues a more precise "Invalid number" error
# instead.
-# expect+1: Invalid number "x}Rest" != "Rest"" for ':range' modifier
+# expect+1: Invalid number "x}Rest" != "Rest"" for modifier ":range"
.if "${:U:range=x}Rest" != "Rest"
. error
.else
diff --git a/contrib/bmake/unit-tests/varmod.exp b/contrib/bmake/unit-tests/varmod.exp
index 09c922aa16bd..022181d05cf1 100644
--- a/contrib/bmake/unit-tests/varmod.exp
+++ b/contrib/bmake/unit-tests/varmod.exp
@@ -1,47 +1,54 @@
make: varmod.mk:111: To escape a dollar, use \$, not $$, at "$$:L} != """
-make: varmod.mk:111: Invalid variable name ':', at "$:L} != """
+make: varmod.mk:111: Invalid variable name ":", at "$:L} != """
make: varmod.mk:117: Dollar followed by nothing
while evaluating "${:Uword:@word@${word}$@} != "word"" with value "word"
-make: varmod.mk:127: Missing delimiter ':' after modifier "P"
+make: varmod.mk:125: Missing delimiter ":" after modifier "P"
while evaluating variable "VAR" with value "VAR"
-make: varmod.mk:129: Missing argument for ".error"
-make: varmod.mk:135: Invalid modifier ":[99333000222000111000]"
+make: varmod.mk:134: Invalid modifier ":[99333000222000111000]"
while evaluating variable "word" with value "word"
-make: varmod.mk:138: Invalid modifier ":[2147483648]"
+make: varmod.mk:137: Invalid modifier ":[2147483648]"
while evaluating variable "word" with value "word"
-make: varmod.mk:144: Invalid number "99333000222000111000}" for ':range' modifier
+make: varmod.mk:143: Invalid number "99333000222000111000}" for modifier ":range"
while evaluating variable "word" with value "word"
-make: varmod.mk:151: Invalid time value "\"
+make: varmod.mk:150: Invalid time value "\"
while evaluating indirect modifiers "gmtime=\"
while evaluating "${:${:Ugmtime=\\}}" with value ""
-make: varmod.mk:166: Dollar followed by nothing
+make: varmod.mk:165: Dollar followed by nothing
while evaluating variable "VAR" with value "value$"
-make: varmod.mk:172: Dollar followed by nothing
+make: varmod.mk:171: Dollar followed by nothing
while evaluating variable "VAR" with value "value$"
-make: varmod.mk:172: Dollar followed by nothing
+make: varmod.mk:171: Dollar followed by nothing
while evaluating variable "VAR" with value "value$ appended$"
-make: varmod.mk:182: Dollar followed by nothing
+make: varmod.mk:181: Dollar followed by nothing
while evaluating variable "word" with value "word"
-make: varmod.mk:186: Invalid modifier ":[$]"
+make: varmod.mk:185: Invalid modifier ":[$]"
while evaluating variable "word" with value ""
-make: varmod.mk:203: Dollar followed by nothing
+make: varmod.mk:202: Dollar followed by nothing
while evaluating variable "VAR" with value "value$ appended$"
-make: varmod.mk:203: Invalid variable name '}', at "$} != "set""
+make: varmod.mk:202: Invalid variable name "}", at "$} != "set""
while evaluating variable "VAR" with value "value<space>appended"
-make: varmod.mk:207: Invalid variable name '}', at "$} != "fallback""
+make: varmod.mk:206: Invalid variable name "}", at "$} != "fallback""
while evaluating "${:Ufallback$} != "fallback"" with value ""
-make: varmod.mk:211: Invalid time value "1000$"
+make: varmod.mk:210: Invalid time value "1000$"
while evaluating variable "%y" with value "%y"
-make: varmod.mk:217: Invalid time value "1000$"
+make: varmod.mk:216: Invalid time value "1000$"
while evaluating variable "%y" with value "%y"
-make: varmod.mk:223: Dollar followed by nothing
+make: varmod.mk:222: Dollar followed by nothing
while evaluating variable "word" with value "word"
-make: varmod.mk:227: Dollar followed by nothing
+make: varmod.mk:226: Dollar followed by nothing
while evaluating variable "word" with value "word"
-make: varmod.mk:231: Invalid argument 'fallback$' for modifier ':mtime'
+make: varmod.mk:230: Invalid argument "fallback$" for modifier ":mtime"
while evaluating variable "." with value "."
-make: varmod.mk:245: Missing delimiter ':' after modifier "L"
+make: varmod.mk:244: Missing delimiter ":" after modifier "L"
while evaluating variable "VAR" with value "VAR"
+make: varmod.mk:256: Invalid time value " : } \ $ ) \) ( "
+ while evaluating variable "%Y" with value "%Y"
+make: varmod.mk:263: Invalid time value " : \) \ $ "
+ while evaluating variable "%Y" with value "%Y"
+make: varmod.mk:268: Invalid time value " : } \ $ ) \) ( "
+ while evaluating variable "%Y" with value "%Y"
+make: varmod.mk:273: Invalid time value " : \) \ $ "
+ while evaluating variable "%Y" with value "%Y"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1
diff --git a/contrib/bmake/unit-tests/varmod.mk b/contrib/bmake/unit-tests/varmod.mk
index cc7b08c447e9..af976f9d0086 100644
--- a/contrib/bmake/unit-tests/varmod.mk
+++ b/contrib/bmake/unit-tests/varmod.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varmod.mk,v 1.26 2025/03/30 01:27:13 rillig Exp $
+# $NetBSD: varmod.mk,v 1.30 2025/06/29 11:27:21 rillig Exp $
#
# Tests for variable modifiers, such as :Q, :S,from,to or :Ufallback.
#
@@ -107,7 +107,7 @@ DOLLAR2= ${:U\$}
# Should it?
.MAKEFLAGS: -dL
# expect+2: To escape a dollar, use \$, not $$, at "$$:L} != """
-# expect+1: Invalid variable name ':', at "$:L} != """
+# expect+1: Invalid variable name ":", at "$:L} != """
.if ${$$:L} != ""
. error
.endif
@@ -118,14 +118,13 @@ DOLLAR2= ${:U\$}
. error
.endif
-# The variable modifier :P does not fall back to the SysV modifier.
+# The modifier :P does not fall back to the SysV modifier.
# Therefore the modifier :P=RE generates a parse error.
-# XXX: The .error should not be reached since the expression is
-# malformed, and this error should be propagated up to Cond_EvalLine.
VAR= STOP
-# expect+1: Missing delimiter ':' after modifier "P"
+# expect+1: Missing delimiter ":" after modifier "P"
.if ${VAR:P=RE} != "STORE"
-# expect+1: Missing argument for ".error"
+. error
+.else
. error
.endif
@@ -140,7 +139,7 @@ VAR= STOP
# Test the range generation modifier ':range=n' with a very large number that
# is larger than SIZE_MAX for any supported platform.
-# expect+1: Invalid number "99333000222000111000}" for ':range' modifier
+# expect+1: Invalid number "99333000222000111000}" for modifier ":range"
.if ${word:L:range=99333000222000111000}
.endif
@@ -199,11 +198,11 @@ VAR_DOLLAR= VAR$$
. error
.endif
# expect+2: Dollar followed by nothing
-# expect+1: Invalid variable name '}', at "$} != "set""
+# expect+1: Invalid variable name "}", at "$} != "set""
.if ${VAR:Dset$} != "set"
. error
.endif
-# expect+1: Invalid variable name '}', at "$} != "fallback""
+# expect+1: Invalid variable name "}", at "$} != "fallback""
.if ${:Ufallback$} != "fallback"
. error
.endif
@@ -227,7 +226,7 @@ VAR_DOLLAR= VAR$$
.if ${word:L:NX*$} != "word"
. error
.endif
-# expect+1: Invalid argument 'fallback$' for modifier ':mtime'
+# expect+1: Invalid argument "fallback$" for modifier ":mtime"
.if ${.:L:mtime=fallback$}
. error
.else
@@ -241,10 +240,36 @@ VAR_DOLLAR= VAR$$
.endif
.undef VAR
-# expect+1: Missing delimiter ':' after modifier "L"
+# expect+1: Missing delimiter ":" after modifier "L"
.if ${VAR:LAR=ALUE} != "VALUE"
. error
.endif
.if ${VAR:L:AR=ALUE} != "VALUE"
. error
.endif
+
+
+# When an expression has the usual form ${...} with braces,
+# in the part of a modifier, ":}\$" can be escaped using a backslash.
+# All other characters are passed through unmodified.
+# expect+1: Invalid time value " : } \ $ ) \) ( "
+.if ${%Y:L:localtime= \: \} \\ \$ ) \) ( :M*} != ": } \\ \$ ) \\) ("
+. error
+.endif
+# When an expression has the unusual form $(...) with parentheses,
+# in the part of a modifier, ":)\$" can be escaped using a backslash.
+# All other characters are passed through unmodified.
+# expect+1: Invalid time value " : \) \ $ "
+.if ${%Y:L:localtime= \: \) \\ \$ } \} { :M*} != ": ) \\ \$ } \\} {"
+. error
+.endif
+# Same when the modifier is the last modifier in an expression.
+# expect+1: Invalid time value " : } \ $ ) \) ( "
+.if ${%Y:L:localtime= \: \} \\ \$ ) \) ( } != " : } \\ \$ ) \\) ( "
+. error
+.endif
+# Same when the modifier is the last modifier in an expression.
+# expect+1: Invalid time value " : \) \ $ "
+.if ${%Y:L:localtime= \: \) \\ \$ } \} { } != " : ) \\ \$ } \\} { "
+. error
+.endif
diff --git a/contrib/bmake/unit-tests/varname-circumflex.exp b/contrib/bmake/unit-tests/varname-circumflex.exp
new file mode 100644
index 000000000000..184b021fd5e5
--- /dev/null
+++ b/contrib/bmake/unit-tests/varname-circumflex.exp
@@ -0,0 +1,9 @@
+no_prerequisites:
+prerequisite: file1.o
+unique: file1.o file2.o file3.o
+duplicate: file1.o file2.o file3.o
+dir_part: /usr/include /usr/include .
+file_part: stdio.h unistd.h foo.h
+implicit.tout: implicit.tin
+wait: file1.o .WAIT_1 file2.o
+exit status 0
diff --git a/contrib/bmake/unit-tests/varname-circumflex.mk b/contrib/bmake/unit-tests/varname-circumflex.mk
new file mode 100644
index 000000000000..270f7123781b
--- /dev/null
+++ b/contrib/bmake/unit-tests/varname-circumflex.mk
@@ -0,0 +1,47 @@
+# $NetBSD: varname-circumflex.mk,v 1.1 2025/06/27 20:20:56 rillig Exp $
+#
+# Tests for the target-local variable "^", which is required by POSIX 2024
+# and provided by GNU make.
+
+# TODO: Support $^.
+
+all: .PHONY
+all: no_prerequisites prerequisite
+all: unique duplicate
+all: dir_part file_part
+all: implicit.tout
+all: wait
+
+.if defined(^)
+. error
+.endif
+
+no_prerequisites:
+ @echo $@: $^
+
+prerequisite: file1.o
+ @echo $@: $^
+
+unique: file1.o file2.o file3.o
+ @echo $@: $^
+
+duplicate: file1.o file2.o file3.o file3.o
+ @echo $@: $^
+
+dir_part: /usr/include/stdio.h /usr/include/unistd.h foo.h
+ @echo $@: $(^D)
+
+file_part: /usr/include/stdio.h /usr/include/unistd.h foo.h
+ @echo $@: ${^F}
+
+wait: file1.o .WAIT file2.o
+ @echo $@: $^
+
+.SUFFIXES:
+.SUFFIXES: .tin .tout
+
+.tin.tout:
+ @echo $@: $^
+
+file1.o file2.o file3.o:
+/usr/include/stdio.h /usr/include/unistd.h foo.h implicit.tin:
diff --git a/contrib/bmake/unit-tests/varname-vpath.exp b/contrib/bmake/unit-tests/varname-vpath.exp
index bf7a3036e99d..a750957b92ac 100644
--- a/contrib/bmake/unit-tests/varname-vpath.exp
+++ b/contrib/bmake/unit-tests/varname-vpath.exp
@@ -1,12 +1,12 @@
CondParser_Eval: !defined(TEST_MAIN)
CondParser_Eval: exists(file-in-subdirectory)
-exists(file-in-subdirectory) result is ""
+"file-in-subdirectory" does not exist
CondParser_Eval: exists(file2-in-subdirectory)
-exists(file2-in-subdirectory) result is ""
+"file2-in-subdirectory" does not exist
CondParser_Eval: exists(file-in-subdirectory)
-exists(file-in-subdirectory) result is "varname-vpath.dir/file-in-subdirectory"
+"file-in-subdirectory" exists in "varname-vpath.dir/file-in-subdirectory"
: yes 1
CondParser_Eval: exists(file2-in-subdirectory)
-exists(file2-in-subdirectory) result is "varname-vpath.dir2/file2-in-subdirectory"
+"file2-in-subdirectory" exists in "varname-vpath.dir2/file2-in-subdirectory"
: yes 2
exit status 0
diff --git a/contrib/bmake/unit-tests/varname.exp b/contrib/bmake/unit-tests/varname.exp
index d173d2025e9f..454e40cdf9cf 100644
--- a/contrib/bmake/unit-tests/varname.exp
+++ b/contrib/bmake/unit-tests/varname.exp
@@ -5,13 +5,13 @@ Var_Parse: ${VARNAME} (eval)
Global: VAR((( = 3 open parentheses
Var_Parse: ${VAR(((}}}}" != "3 open parentheses}}}" (eval)
Global: .ALLTARGETS = VAR(((=)
-make: varname.mk:31: Missing ')' in archive specification
+make: varname.mk:31: Missing ")" in archive specification
make: varname.mk:31: Error in archive specification: "VAR"
Var_Parse: ${:UVAR\(\(\(}= try2 (eval)
Evaluating modifier ${:U...} on value "" (eval, undefined)
Result of ${:UVAR\(\(\(} is "VAR\(\(\(" (eval, defined)
Global: .ALLTARGETS = VAR(((=) VAR\(\(\(=
-make: varname.mk:37: Invalid line '${:UVAR\(\(\(}= try2', expanded to 'VAR\(\(\(= try2'
+make: varname.mk:37: Invalid line "${:UVAR\(\(\(}= try2", expanded to "VAR\(\(\(= try2"
Var_Parse: ${VARNAME} (eval)
Global: VAR((( = try3
Global: .MAKEFLAGS = -r -k -d v -d
diff --git a/contrib/bmake/unit-tests/varname.mk b/contrib/bmake/unit-tests/varname.mk
index ae18819aa19e..17f29da7ef4c 100644
--- a/contrib/bmake/unit-tests/varname.mk
+++ b/contrib/bmake/unit-tests/varname.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varname.mk,v 1.17 2025/06/12 04:33:00 rillig Exp $
+# $NetBSD: varname.mk,v 1.18 2025/06/28 22:39:29 rillig Exp $
#
# Tests for variable names.
@@ -26,14 +26,14 @@ ${VARNAME}= 3 open parentheses
# This is not a variable assignment since the parentheses and braces are not
# balanced. At the end of the line, there are still 3 levels open, which
# means the variable name is not finished.
-# expect+2: Missing ')' in archive specification
+# expect+2: Missing ")" in archive specification
# expect+1: Error in archive specification: "VAR"
${:UVAR(((}= try1
# On the left-hand side of a variable assignments, the backslash is not parsed
# as an escape character, therefore the parentheses still count to the nesting
# level, which at the end of the line is still 3. Therefore this is not a
# variable assignment as well.
-# expect+1: Invalid line '${:UVAR\(\(\(}= try2', expanded to 'VAR\(\(\(= try2'
+# expect+1: Invalid line "${:UVAR\(\(\(}= try2", expanded to "VAR\(\(\(= try2"
${:UVAR\(\(\(}= try2
# To assign to a variable with an arbitrary name, the variable name has to
# come from an external source, not the text that is parsed in the assignment
diff --git a/contrib/bmake/unit-tests/varparse-errors.exp b/contrib/bmake/unit-tests/varparse-errors.exp
index d4d01c96627e..2a9be069075f 100644
--- a/contrib/bmake/unit-tests/varparse-errors.exp
+++ b/contrib/bmake/unit-tests/varparse-errors.exp
@@ -12,33 +12,33 @@ make: varparse-errors.mk:73: Unknown modifier ":OX"
make: varparse-errors.mk:73: Unknown modifier ":OX"
while evaluating "${:OX}" with value ""
while evaluating variable "IND" with value "${:OX}"
-make: varparse-errors.mk:81: Unclosed expression, expecting '}' for modifier "Q"
+make: varparse-errors.mk:81: Unclosed expression, expecting "}" for modifier "Q"
while evaluating "${:U:Q" with value ""
-make: varparse-errors.mk:83: Unclosed expression, expecting '}' for modifier "sh"
+make: varparse-errors.mk:83: Unclosed expression, expecting "}" for modifier "sh"
while evaluating "${:U:sh" with value ""
-make: varparse-errors.mk:85: Unclosed expression, expecting '}' for modifier "tA"
+make: varparse-errors.mk:85: Unclosed expression, expecting "}" for modifier "tA"
while evaluating "${:U:tA" with value ""
-make: varparse-errors.mk:87: Unclosed expression, expecting '}' for modifier "tsX"
+make: varparse-errors.mk:87: Unclosed expression, expecting "}" for modifier "tsX"
while evaluating "${:U:tsX" with value ""
-make: varparse-errors.mk:89: Unclosed expression, expecting '}' for modifier "ts"
+make: varparse-errors.mk:89: Unclosed expression, expecting "}" for modifier "ts"
while evaluating "${:U:ts" with value ""
-make: varparse-errors.mk:91: Unclosed expression, expecting '}' for modifier "ts\040"
+make: varparse-errors.mk:91: Unclosed expression, expecting "}" for modifier "ts\040"
while evaluating "${:U:ts\040" with value ""
-make: varparse-errors.mk:93: Unclosed expression, expecting '}' for modifier "u"
+make: varparse-errors.mk:93: Unclosed expression, expecting "}" for modifier "u"
while evaluating "${:U:u" with value ""
-make: varparse-errors.mk:95: Unclosed expression, expecting '}' for modifier "H"
+make: varparse-errors.mk:95: Unclosed expression, expecting "}" for modifier "H"
while evaluating "${:U:H" with value "."
-make: varparse-errors.mk:97: Unclosed expression, expecting '}' for modifier "[1]"
+make: varparse-errors.mk:97: Unclosed expression, expecting "}" for modifier "[1]"
while evaluating "${:U:[1]" with value ""
-make: varparse-errors.mk:99: Unclosed expression, expecting '}' for modifier "hash"
+make: varparse-errors.mk:99: Unclosed expression, expecting "}" for modifier "hash"
while evaluating "${:U:hash" with value "b2af338b"
-make: varparse-errors.mk:101: Unclosed expression, expecting '}' for modifier "range"
+make: varparse-errors.mk:101: Unclosed expression, expecting "}" for modifier "range"
while evaluating "${:U:range" with value "1"
-make: varparse-errors.mk:103: Unclosed expression, expecting '}' for modifier "_"
+make: varparse-errors.mk:103: Unclosed expression, expecting "}" for modifier "_"
while evaluating "${:U:_" with value ""
-make: varparse-errors.mk:105: Unclosed expression, expecting '}' for modifier "gmtime"
+make: varparse-errors.mk:105: Unclosed expression, expecting "}" for modifier "gmtime"
while evaluating "${:U:gmtime" with value "<timestamp>"
-make: varparse-errors.mk:107: Unclosed expression, expecting '}' for modifier "localtime"
+make: varparse-errors.mk:107: Unclosed expression, expecting "}" for modifier "localtime"
while evaluating "${:U:localtime" with value "<timestamp>"
make: varparse-errors.tmp:1: Unknown modifier ":Z"
while evaluating "${:Z}" with value ""
diff --git a/contrib/bmake/unit-tests/varparse-errors.mk b/contrib/bmake/unit-tests/varparse-errors.mk
index 2d1142fbb65c..bd74c442e789 100644
--- a/contrib/bmake/unit-tests/varparse-errors.mk
+++ b/contrib/bmake/unit-tests/varparse-errors.mk
@@ -1,4 +1,4 @@
-# $NetBSD: varparse-errors.mk,v 1.25 2025/05/03 08:18:33 rillig Exp $
+# $NetBSD: varparse-errors.mk,v 1.26 2025/06/28 22:39:29 rillig Exp $
# Tests for parsing and evaluating all kinds of expressions.
#
@@ -77,33 +77,33 @@ _:= ${:U:OX:U${IND}} ${:U:OX:U${IND}}
# Before var.c 1.032 from 2022-08-24, make complained about 'Unknown modifier'
# or 'Bad modifier' when in fact the modifier was entirely correct, it was
# just not delimited by either ':' or '}' but instead by '\0'.
-# expect+1: Unclosed expression, expecting '}' for modifier "Q"
+# expect+1: Unclosed expression, expecting "}" for modifier "Q"
UNCLOSED:= ${:U:Q
-# expect+1: Unclosed expression, expecting '}' for modifier "sh"
+# expect+1: Unclosed expression, expecting "}" for modifier "sh"
UNCLOSED:= ${:U:sh
-# expect+1: Unclosed expression, expecting '}' for modifier "tA"
+# expect+1: Unclosed expression, expecting "}" for modifier "tA"
UNCLOSED:= ${:U:tA
-# expect+1: Unclosed expression, expecting '}' for modifier "tsX"
+# expect+1: Unclosed expression, expecting "}" for modifier "tsX"
UNCLOSED:= ${:U:tsX
-# expect+1: Unclosed expression, expecting '}' for modifier "ts"
+# expect+1: Unclosed expression, expecting "}" for modifier "ts"
UNCLOSED:= ${:U:ts
-# expect+1: Unclosed expression, expecting '}' for modifier "ts\040"
+# expect+1: Unclosed expression, expecting "}" for modifier "ts\040"
UNCLOSED:= ${:U:ts\040
-# expect+1: Unclosed expression, expecting '}' for modifier "u"
+# expect+1: Unclosed expression, expecting "}" for modifier "u"
UNCLOSED:= ${:U:u
-# expect+1: Unclosed expression, expecting '}' for modifier "H"
+# expect+1: Unclosed expression, expecting "}" for modifier "H"
UNCLOSED:= ${:U:H
-# expect+1: Unclosed expression, expecting '}' for modifier "[1]"
+# expect+1: Unclosed expression, expecting "}" for modifier "[1]"
UNCLOSED:= ${:U:[1]
-# expect+1: Unclosed expression, expecting '}' for modifier "hash"
+# expect+1: Unclosed expression, expecting "}" for modifier "hash"
UNCLOSED:= ${:U:hash
-# expect+1: Unclosed expression, expecting '}' for modifier "range"
+# expect+1: Unclosed expression, expecting "}" for modifier "range"
UNCLOSED:= ${:U:range
-# expect+1: Unclosed expression, expecting '}' for modifier "_"
+# expect+1: Unclosed expression, expecting "}" for modifier "_"
UNCLOSED:= ${:U:_
-# expect+1: Unclosed expression, expecting '}' for modifier "gmtime"
+# expect+1: Unclosed expression, expecting "}" for modifier "gmtime"
UNCLOSED:= ${:U:gmtime
-# expect+1: Unclosed expression, expecting '}' for modifier "localtime"
+# expect+1: Unclosed expression, expecting "}" for modifier "localtime"
UNCLOSED:= ${:U:localtime
diff --git a/contrib/bmake/var.c b/contrib/bmake/var.c
index 55d20bd324ac..66b18f769371 100644
--- a/contrib/bmake/var.c
+++ b/contrib/bmake/var.c
@@ -1,4 +1,4 @@
-/* $NetBSD: var.c,v 1.1168 2025/06/13 18:31:08 rillig Exp $ */
+/* $NetBSD: var.c,v 1.1171 2025/06/29 11:02:17 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@@ -143,7 +143,7 @@
#endif
/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: var.c,v 1.1168 2025/06/13 18:31:08 rillig Exp $");
+MAKE_RCSID("$NetBSD: var.c,v 1.1171 2025/06/29 11:02:17 rillig Exp $");
/*
* Variables are defined using one of the VAR=value assignments. Their
@@ -452,6 +452,8 @@ VarNew(FStr name, const char *value,
static Substring
CanonicalVarname(Substring name)
{
+ if (Substring_Equals(name, "^"))
+ return Substring_InitStr(ALLSRC);
if (!(Substring_Length(name) > 0 && name.start[0] == '.'))
return name;
@@ -471,8 +473,6 @@ CanonicalVarname(Substring name)
if (Substring_Equals(name, ".TARGET"))
return Substring_InitStr(TARGET);
- /* GNU make has an additional alias $^ == ${.ALLSRC}. */
-
if (Substring_Equals(name, ".SHELL") && shellPath == NULL)
Shell_Init();
@@ -2134,16 +2134,16 @@ typedef enum ApplyModifierResult {
} ApplyModifierResult;
/*
- * Allow backslashes to escape the delimiter, $, and \, but don't touch other
+ * Allow backslashes to escape the delimiters, $, and \, but don't touch other
* backslashes.
*/
static bool
-IsEscapedModifierPart(const char *p, char delim,
+IsEscapedModifierPart(const char *p, char end1, char end2,
struct ModifyWord_SubstArgs *subst)
{
if (p[0] != '\\' || p[1] == '\0')
return false;
- if (p[1] == delim || p[1] == '\\' || p[1] == '$')
+ if (p[1] == end1 || p[1] == end2 || p[1] == '\\' || p[1] == '$')
return true;
return p[1] == '&' && subst != NULL;
}
@@ -2236,7 +2236,7 @@ ParseModifierPart(
LazyBuf_Init(part, p);
while (*p != '\0' && *p != end1 && *p != end2) {
- if (IsEscapedModifierPart(p, end2, subst)) {
+ if (IsEscapedModifierPart(p, end1, end2, subst)) {
LazyBuf_Add(part, p[1]);
p += 2;
} else if (*p != '$') { /* Unescaped, simple text */
@@ -2703,7 +2703,7 @@ ApplyModifier_Range(const char **pp, ModChain *ch)
const char *p = mod + 6;
if (!TryParseSize(&p, &n)) {
Parse_Error(PARSE_FATAL,
- "Invalid number \"%s\" for ':range' modifier",
+ "Invalid number \"%s\" for modifier \":range\"",
mod + 6);
return AMR_CLEANUP;
}
@@ -2834,7 +2834,7 @@ ModifyWord_Match(Substring word, SepBuf *buf, void *data)
if (res.error != NULL && !args->error_reported) {
args->error_reported = true;
Parse_Error(PARSE_FATAL,
- "%s in pattern '%s' of modifier '%s'",
+ "%s in pattern \"%s\" of modifier \"%s\"",
res.error, args->pattern, args->neg ? ":N" : ":M");
}
if (res.matched != args->neg)
@@ -2927,7 +2927,7 @@ ApplyModifier_Mtime(const char **pp, ModChain *ch)
invalid_argument:
Parse_Error(PARSE_FATAL,
- "Invalid argument '%.*s' for modifier ':mtime'",
+ "Invalid argument \"%.*s\" for modifier \":mtime\"",
(int)strcspn(*pp + 1, ":{}()"), *pp + 1);
return AMR_CLEANUP;
}
@@ -2965,7 +2965,7 @@ ApplyModifier_Subst(const char **pp, ModChain *ch)
char delim = (*pp)[1];
if (delim == '\0') {
Parse_Error(PARSE_FATAL,
- "Missing delimiter for modifier ':S'");
+ "Missing delimiter for modifier \":S\"");
(*pp)++;
return AMR_CLEANUP;
}
@@ -3017,7 +3017,7 @@ ApplyModifier_Regex(const char **pp, ModChain *ch)
char delim = (*pp)[1];
if (delim == '\0') {
Parse_Error(PARSE_FATAL,
- "Missing delimiter for modifier ':C'");
+ "Missing delimiter for modifier \":C\"");
(*pp)++;
return AMR_CLEANUP;
}
@@ -3995,7 +3995,7 @@ ApplyModifiersIndirect(ModChain *ch, const char **pp)
else if (*p == '\0' && ch->endc != '\0') {
Parse_Error(PARSE_FATAL,
"Unclosed expression after indirect modifier, "
- "expecting '%c'",
+ "expecting \"%c\"",
ch->endc);
*pp = p;
return AMIR_OUT;
@@ -4051,14 +4051,14 @@ ApplySingleModifier(const char **pp, ModChain *ch)
if (*p == '\0' && ch->endc != '\0') {
Parse_Error(PARSE_FATAL,
- "Unclosed expression, expecting '%c' for "
+ "Unclosed expression, expecting \"%c\" for "
"modifier \"%.*s\"",
ch->endc, (int)(p - mod), mod);
} else if (*p == ':') {
p++;
} else if (opts.strict && *p != '\0' && *p != ch->endc) {
Parse_Error(PARSE_FATAL,
- "Missing delimiter ':' after modifier \"%.*s\"",
+ "Missing delimiter \":\" after modifier \"%.*s\"",
(int)(p - mod), mod);
/*
* TODO: propagate parse error to the enclosing
@@ -4106,7 +4106,7 @@ ApplyModifiers(
if (*p == '\0' && endc != '\0') {
Parse_Error(PARSE_FATAL,
- "Unclosed expression, expecting '%c'", ch.endc);
+ "Unclosed expression, expecting \"%c\"", ch.endc);
goto cleanup;
}
@@ -4263,7 +4263,7 @@ IsShortVarnameValid(char varname, const char *start)
Parse_Error(PARSE_FATAL, "Dollar followed by nothing");
else if (save_dollars)
Parse_Error(PARSE_FATAL,
- "Invalid variable name '%c', at \"%s\"", varname, start);
+ "Invalid variable name \"%c\", at \"%s\"", varname, start);
return false;
}
@@ -4330,7 +4330,7 @@ FindLocalLegacyVar(Substring varname, GNode *scope,
return NULL;
if (varname.start[1] != 'F' && varname.start[1] != 'D')
return NULL;
- if (strchr("@%?*!<>", varname.start[0]) == NULL)
+ if (strchr("@%?*!<>^", varname.start[0]) == NULL)
return NULL;
v = VarFindSubstring(Substring_Init(varname.start, varname.start + 1),
diff --git a/contrib/bsnmp/lib/snmpclient.c b/contrib/bsnmp/lib/snmpclient.c
index b312a37ed3ed..d5d4af998a0c 100644
--- a/contrib/bsnmp/lib/snmpclient.c
+++ b/contrib/bsnmp/lib/snmpclient.c
@@ -981,14 +981,8 @@ open_client_local(const char *path)
char *ptr;
int stype;
- if (snmp_client.chost == NULL) {
- if ((snmp_client.chost = malloc(1 + sizeof(DEFAULT_LOCAL)))
- == NULL) {
- seterr(&snmp_client, "%s", strerror(errno));
- return (-1);
- }
- strcpy(snmp_client.chost, DEFAULT_LOCAL);
- }
+ if (snmp_client.chost == NULL && path == NULL)
+ path = SNMP_DEFAULT_LOCAL;
if (path != NULL) {
if ((ptr = malloc(1 + strlen(path))) == NULL) {
seterr(&snmp_client, "%s", strerror(errno));
@@ -1012,7 +1006,7 @@ open_client_local(const char *path)
snprintf(snmp_client.local_path, sizeof(snmp_client.local_path),
"%s", SNMP_LOCAL_PATH);
- if (mkstemp(snmp_client.local_path) == -1) {
+ if (mktemp(snmp_client.local_path) == NULL) {
seterr(&snmp_client, "%s", strerror(errno));
(void)close(snmp_client.fd);
snmp_client.fd = -1;
diff --git a/contrib/bsnmp/lib/snmpclient.h b/contrib/bsnmp/lib/snmpclient.h
index a19bdb2ea653..662dc7c4a204 100644
--- a/contrib/bsnmp/lib/snmpclient.h
+++ b/contrib/bsnmp/lib/snmpclient.h
@@ -40,6 +40,7 @@
#define SNMP_STRERROR_LEN 200
+#define SNMP_DEFAULT_LOCAL "/var/run/snmpd.sock"
#define SNMP_LOCAL_PATH "/tmp/snmpXXXXXXXXXXXXXX"
diff --git a/contrib/bsnmp/lib/snmppriv.h b/contrib/bsnmp/lib/snmppriv.h
index 5b66992ca985..6ed51cf39369 100644
--- a/contrib/bsnmp/lib/snmppriv.h
+++ b/contrib/bsnmp/lib/snmppriv.h
@@ -44,4 +44,3 @@ enum snmp_code snmp_pdu_decrypt(const struct snmp_pdu *);
#define DEFAULT_HOST "localhost"
#define DEFAULT_PORT "snmp"
-#define DEFAULT_LOCAL "/var/run/snmp.sock"
diff --git a/contrib/bsnmp/snmpd/main.c b/contrib/bsnmp/snmpd/main.c
index 928b84121f82..c77572934d24 100644
--- a/contrib/bsnmp/snmpd/main.c
+++ b/contrib/bsnmp/snmpd/main.c
@@ -42,6 +42,7 @@
#include <sys/un.h>
#include <sys/ucred.h>
#include <sys/uio.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
@@ -1509,7 +1510,7 @@ main(int argc, char *argv[])
{
int opt;
FILE *fp;
- int background = 1;
+ bool background = true;
struct tport *p;
const char *prefix = "snmpd";
struct lmodule *m;
@@ -1526,11 +1527,6 @@ main(int argc, char *argv[])
NULL
};
- snmp_printf = snmp_printf_func;
- snmp_error = snmp_error_func;
- snmp_debug = snmp_debug_func;
- asn_error = asn_error_func;
-
while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF)
switch (opt) {
@@ -1539,7 +1535,7 @@ main(int argc, char *argv[])
break;
case 'd':
- background = 0;
+ background = false;
break;
case 'D':
@@ -1601,6 +1597,13 @@ main(int argc, char *argv[])
break;
}
+ if (background) {
+ snmp_printf = snmp_printf_func;
+ snmp_error = snmp_error_func;
+ snmp_debug = snmp_debug_func;
+ asn_error = asn_error_func;
+ }
+
openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER);
setlogmask(LOG_UPTO(debug.logpri - 1));
diff --git a/contrib/bsnmp/snmpd/trans_lsock.c b/contrib/bsnmp/snmpd/trans_lsock.c
index fa3bd34d14f0..ca2311be7cc3 100644
--- a/contrib/bsnmp/snmpd/trans_lsock.c
+++ b/contrib/bsnmp/snmpd/trans_lsock.c
@@ -417,7 +417,7 @@ lsock_send(struct tport *tp, const u_char *buf, size_t len,
}
}
- return (sendto(peer->input.fd, buf, len, 0, addr, addrlen));
+ return (sendto(peer->input.fd, buf, len, MSG_NOSIGNAL, addr, addrlen));
}
static void
diff --git a/contrib/elftoolchain/libelf/elf_open.3 b/contrib/elftoolchain/libelf/elf_open.3
index 054036a24935..896bf8455ae5 100644
--- a/contrib/elftoolchain/libelf/elf_open.3
+++ b/contrib/elftoolchain/libelf/elf_open.3
@@ -23,11 +23,12 @@
.\"
.\" $Id: elf_open.3 3743 2019-06-12 19:36:30Z jkoshy $
.\"
-.Dd June 12, 2019
+.Dd July 15, 2025
.Dt ELF_OPEN 3
.Os
.Sh NAME
-.Nm elf_open
+.Nm elf_open ,
+.Nm elf_openmemory
.Nd open ELF objects and ar(1) archives
.Sh LIBRARY
.Lb libelf
diff --git a/contrib/elftoolchain/libelf/gelf_xlatetof.3 b/contrib/elftoolchain/libelf/gelf_xlatetof.3
index 2e5ee0fe15e0..4a7b25c99b5a 100644
--- a/contrib/elftoolchain/libelf/gelf_xlatetof.3
+++ b/contrib/elftoolchain/libelf/gelf_xlatetof.3
@@ -23,13 +23,16 @@
.\"
.\" $Id: gelf_xlatetof.3 3639 2018-10-14 14:07:02Z jkoshy $
.\"
-.Dd October 11, 2018
+.Dd July 15, 2025
.Dt GELF_XLATETOF 3
.Os
.Sh NAME
-.Nm elf32_xlate ,
-.Nm elf64_xlate ,
-.Nm gelf_xlate
+.Nm elf32_xlatetof ,
+.Nm elf32_xlatetom ,
+.Nm elf64_xlatetof ,
+.Nm elf64_xlatetom ,
+.Nm gelf_xlatetof ,
+.Nm gelf_xlatetom
.Nd translate data between files and memory
.Sh LIBRARY
.Lb libelf
diff --git a/contrib/less/NEWS b/contrib/less/NEWS
index 5767ded21a00..cdc8196a5f16 100644
--- a/contrib/less/NEWS
+++ b/contrib/less/NEWS
@@ -11,6 +11,16 @@
======================================================================
+ Major changes between "less" versions 678 and 679
+
+* Fix bad parsing of lesskey file an env var is a prefix of another
+ env var (github #626).
+
+* Fix unexpected exit using -K if a key press is received while reading
+ the input file (github #628).
+
+======================================================================
+
Major changes between "less" versions 668 and 678
* Treat -r in LESS environment variable as -R.
diff --git a/contrib/less/decode.c b/contrib/less/decode.c
index 2942a30863cb..8e451d1810c9 100644
--- a/contrib/less/decode.c
+++ b/contrib/less/decode.c
@@ -750,7 +750,7 @@ static int cmd_search(constant char *cmd, constant unsigned char *table, constan
{
action = taction;
*extra = textra;
- } else if (match > 0) /* cmd is a prefix of this table entry */
+ } else if (match > 0 && action == A_INVALID) /* cmd is a prefix of this table entry */
{
action = A_PREFIX;
}
diff --git a/contrib/less/help.c b/contrib/less/help.c
index 81e0943fe4e2..5d8ba9a1b0fe 100644
--- a/contrib/less/help.c
+++ b/contrib/less/help.c
@@ -1,4 +1,4 @@
-/* This file was generated by mkhelp.pl from less.hlp at 20:41 on 2025/5/1 */
+/* This file was generated by mkhelp.pl from less.hlp at 19:46 on 2025/5/28 */
#include "less.h"
constant char helpdata[] = {
'\n',
diff --git a/contrib/less/less.h b/contrib/less/less.h
index 94a3e2235906..7b2d2c25bfc6 100644
--- a/contrib/less/less.h
+++ b/contrib/less/less.h
@@ -575,10 +575,11 @@ typedef enum {
#endif
#endif
-#define S_INTERRUPT 01
-#define S_STOP 02
-#define S_WINCH 04
-#define ABORT_SIGS() (sigs & (S_INTERRUPT|S_STOP))
+#define S_INTERRUPT (1<<0)
+#define S_SWINTERRUPT (1<<1)
+#define S_STOP (1<<2)
+#define S_WINCH (1<<3)
+#define ABORT_SIGS() (sigs & (S_INTERRUPT|S_SWINTERRUPT|S_STOP))
#ifdef EXIT_SUCCESS
#define QUIT_OK EXIT_SUCCESS
diff --git a/contrib/less/less.nro b/contrib/less/less.nro
index 6b74ec5f161b..25a9869a9c59 100644
--- a/contrib/less/less.nro
+++ b/contrib/less/less.nro
@@ -1,5 +1,5 @@
'\" t
-.TH LESS 1 "Version 678: 01 May 2025"
+.TH LESS 1 "Version 679: 28 May 2025"
.SH NAME
less \- display the contents of a file in a terminal
.SH SYNOPSIS
diff --git a/contrib/less/lessecho.nro b/contrib/less/lessecho.nro
index 696fcb13b214..f0cccc4de6da 100644
--- a/contrib/less/lessecho.nro
+++ b/contrib/less/lessecho.nro
@@ -1,4 +1,4 @@
-.TH LESSECHO 1 "Version 678: 01 May 2025"
+.TH LESSECHO 1 "Version 679: 28 May 2025"
.SH NAME
lessecho \- expand metacharacters
.SH SYNOPSIS
diff --git a/contrib/less/lesskey.nro b/contrib/less/lesskey.nro
index 61ba056b04c6..0a17c9deff71 100644
--- a/contrib/less/lesskey.nro
+++ b/contrib/less/lesskey.nro
@@ -1,5 +1,5 @@
'\" t
-.TH LESSKEY 1 "Version 678: 01 May 2025"
+.TH LESSKEY 1 "Version 679: 28 May 2025"
.SH NAME
lesskey \- customize key bindings for less
.SH "SYNOPSIS (deprecated)"
diff --git a/contrib/less/os.c b/contrib/less/os.c
index 98a7ecf70c3c..357cbb356a16 100644
--- a/contrib/less/os.c
+++ b/contrib/less/os.c
@@ -275,7 +275,7 @@ start:
if (ret != 0)
{
if (ret == READ_INTR)
- sigs |= S_INTERRUPT;
+ sigs |= S_SWINTERRUPT;
reading = FALSE;
return (ret);
}
@@ -287,7 +287,7 @@ start:
int c;
c = WIN32getch();
- sigs |= S_INTERRUPT;
+ sigs |= S_SWINTERRUPT;
reading = FALSE;
if (c != CONTROL('C') && c != intr_char)
WIN32ungetch((char) c);
@@ -348,7 +348,7 @@ public int iopen(constant char *filename, int flags)
while (!opening && SET_JUMP(open_label))
{
opening = FALSE;
- if (sigs & S_INTERRUPT)
+ if (sigs & (S_INTERRUPT|S_SWINTERRUPT))
{
sigs = 0;
#if HAVE_SETTABLE_ERRNO
diff --git a/contrib/less/version.c b/contrib/less/version.c
index 9a97f1658940..68a42a6272fa 100644
--- a/contrib/less/version.c
+++ b/contrib/less/version.c
@@ -1047,6 +1047,8 @@ v675 4/3/25 Add ESC-b.
v676 4/16/25 Fix two OSC 8 display bugs.
v677 4/27/25 Fix & filtering bug.
v678 5/1/25 Don't change stty tab setting.
+v679 5/28/25 Fix lesskey parsing bug when env var is prefix of another;
+ fix unexpected exit when using -K.
*/
-char version[] = "678";
+char version[] = "679";
diff --git a/contrib/libbegemot/rpoll.c b/contrib/libbegemot/rpoll.c
index c61b84057eba..f5ce43140205 100644
--- a/contrib/libbegemot/rpoll.c
+++ b/contrib/libbegemot/rpoll.c
@@ -285,8 +285,8 @@ poll_register(int fd, poll_f func, void *arg, int mask)
poll_unblocksig();
if(rpoll_trace)
- fprintf(stderr, "poll_register(%d, %p, %p, %#x)->%tu",
- fd, (void *)func, (void *)arg, mask, p - regs);
+ fprintf(stderr, "%s(%d, %p, %p, %#x)->%tu\n", __func__, fd,
+ (void *)func, (void *)arg, mask, p - regs);
return p - regs;
}
@@ -297,7 +297,7 @@ void
poll_unregister(int handle)
{
if(rpoll_trace)
- fprintf(stderr, "poll_unregister(%d)", handle);
+ fprintf(stderr, "%s(%d)\n", __func__, handle);
poll_blocksig();
@@ -399,8 +399,8 @@ poll_start_utimer(unsigned long long usecs, int repeat, timer_f func, void *arg)
resort = 1;
if(rpoll_trace)
- fprintf(stderr, "poll_start_utimer(%llu, %d, %p, %p)->%tu",
- usecs, repeat, (void *)func, (void *)arg, p - tims);
+ fprintf(stderr, "%s(%llu, %d, %p, %p)->%tu\n", __func__, usecs,
+ repeat, (void *)func, (void *)arg, p - tims);
return p - tims;
}
@@ -418,7 +418,7 @@ poll_stop_timer(int handle)
u_int i;
if(rpoll_trace)
- fprintf(stderr, "poll_stop_timer(%d)", handle);
+ fprintf(stderr, "%s(%d)\n", __func__, handle);
tims[handle].func = NULL;
tims_used--;
@@ -597,9 +597,10 @@ poll_dispatch(int wait)
if(mask) {
if(rpoll_trace)
- fprintf(stderr, "poll_dispatch() -- "
- "file %d/%d %x",
- regs[idx].fd, idx, mask);
+ fprintf(stderr,
+ "%s() -- file %d/%d %x\n",
+ __func__, regs[idx].fd,
+ idx, mask);
(*regs[idx].func)(regs[idx].fd, mask, regs[idx].arg);
}
}
@@ -617,7 +618,8 @@ poll_dispatch(int wait)
if(tims[tfd[i]].when > now)
break;
if(rpoll_trace)
- fprintf(stderr, "rpoll_dispatch() -- timeout %d",tfd[i]);
+ fprintf(stderr, "%s() -- timeout %d\n",
+ __func__, tfd[i]);
(*tims[tfd[i]].func)(tfd[i], tims[tfd[i]].arg);
if(tfd[i] < 0)
continue;
diff --git a/contrib/tzcode/localtime.c b/contrib/tzcode/localtime.c
index f5814a43da54..a6ec3d8e4e21 100644
--- a/contrib/tzcode/localtime.c
+++ b/contrib/tzcode/localtime.c
@@ -18,6 +18,7 @@
#ifndef DETECT_TZ_CHANGES_INTERVAL
#define DETECT_TZ_CHANGES_INTERVAL 61
#endif
+int __tz_change_interval = DETECT_TZ_CHANGES_INTERVAL;
#include <sys/stat.h>
#endif
#include <fcntl.h>
@@ -408,10 +409,8 @@ change_in_tz(const char *name)
static char old_name[PATH_MAX];
static struct stat old_sb;
struct stat sb;
- int error;
- error = stat(name, &sb);
- if (error != 0)
+ if (stat(name, &sb) != 0)
return -1;
if (strcmp(name, old_name) != 0) {
@@ -510,13 +509,13 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
* 'doextend' to ignore TZDEFRULES; the change_in_tz()
* function can only keep state for a single file.
*/
- int ret = change_in_tz(name);
- if (ret <= 0) {
- /*
- * Returns an errno value if there was an error,
- * and 0 if the timezone had not changed.
- */
+ switch (change_in_tz(name)) {
+ case -1:
return errno;
+ case 0:
+ return 0;
+ case 1:
+ break;
}
}
fid = _open(name, O_RDONLY | O_BINARY);
@@ -1376,22 +1375,13 @@ recheck_tzdata()
{
static time_t last_checked;
struct timespec now;
- time_t current_time;
- int error;
- /*
- * We want to recheck the timezone file every 61 sec.
- */
- error = clock_gettime(CLOCK_MONOTONIC, &now);
- if (error < 0) {
- /* XXX: Can we somehow report this? */
+ if (clock_gettime(CLOCK_MONOTONIC, &now) < 0)
return 0;
- }
- current_time = now.tv_sec;
- if ((current_time - last_checked > DETECT_TZ_CHANGES_INTERVAL) ||
- (last_checked > current_time)) {
- last_checked = current_time;
+ if ((now.tv_sec - last_checked >= __tz_change_interval) ||
+ (last_checked > now.tv_sec)) {
+ last_checked = now.tv_sec;
return 1;
}
diff --git a/lib/libc/gen/fdopendir.c b/lib/libc/gen/fdopendir.c
index df6709fbcb85..9393cbe28f85 100644
--- a/lib/libc/gen/fdopendir.c
+++ b/lib/libc/gen/fdopendir.c
@@ -48,8 +48,16 @@
DIR *
fdopendir(int fd)
{
+ int flags, rc;
- if (_fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
+ flags = _fcntl(fd, F_GETFD, 0);
+ if (flags == -1)
return (NULL);
+
+ if ((flags & FD_CLOEXEC) == 0) {
+ rc = _fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+ if (rc == -1)
+ return (NULL);
+ }
return (__opendir_common(fd, DTF_HIDEW | DTF_NODUP, true));
}
diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c
index a0d7b71df782..49ec97eda39d 100644
--- a/lib/libc/stdio/fdopen.c
+++ b/lib/libc/stdio/fdopen.c
@@ -46,7 +46,7 @@ FILE *
fdopen(int fd, const char *mode)
{
FILE *fp;
- int flags, oflags, fdflags, tmp;
+ int flags, oflags, fdflags, rc, tmp;
/*
* File descriptors are a full int, but _file is only a short.
@@ -76,9 +76,19 @@ fdopen(int fd, const char *mode)
if ((fp = __sfp()) == NULL)
return (NULL);
- if ((oflags & O_CLOEXEC) && _fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
- fp->_flags = 0;
- return (NULL);
+ if ((oflags & O_CLOEXEC) != 0) {
+ tmp = _fcntl(fd, F_GETFD, 0);
+ if (tmp == -1) {
+ fp->_flags = 0;
+ return (NULL);
+ }
+ if ((tmp & FD_CLOEXEC) == 0) {
+ rc = _fcntl(fd, F_SETFD, tmp | FD_CLOEXEC);
+ if (rc == -1) {
+ fp->_flags = 0;
+ return (NULL);
+ }
+ }
}
fp->_flags = flags;
diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c
index f0732b6d6741..048fd30b3193 100644
--- a/lib/libc/stdio/freopen.c
+++ b/lib/libc/stdio/freopen.c
@@ -55,7 +55,7 @@ freopen(const char * __restrict file, const char * __restrict mode,
FILE * __restrict fp)
{
int f;
- int dflags, flags, isopen, oflags, sverrno, wantfd;
+ int dflags, fdflags, flags, isopen, oflags, sverrno, wantfd;
if ((flags = __sflags(mode, &oflags)) == 0) {
sverrno = errno;
@@ -113,8 +113,12 @@ freopen(const char * __restrict file, const char * __restrict mode,
(void) ftruncate(fp->_file, (off_t)0);
if (!(oflags & O_APPEND))
(void) _sseek(fp, (fpos_t)0, SEEK_SET);
- if (oflags & O_CLOEXEC)
- (void) _fcntl(fp->_file, F_SETFD, FD_CLOEXEC);
+ if ((oflags & O_CLOEXEC) != 0) {
+ fdflags = _fcntl(fp->_file, F_GETFD, 0);
+ if (fdflags != -1 && (fdflags & FD_CLOEXEC) == 0)
+ (void) _fcntl(fp->_file, F_SETFD,
+ fdflags | FD_CLOEXEC);
+ }
f = fp->_file;
isopen = 0;
wantfd = -1;
diff --git a/lib/libc/stdtime/Makefile.inc b/lib/libc/stdtime/Makefile.inc
index 5d0ce7765b63..647cbe6f40ba 100644
--- a/lib/libc/stdtime/Makefile.inc
+++ b/lib/libc/stdtime/Makefile.inc
@@ -18,6 +18,7 @@ CFLAGS.${src}+= -I${LIBC_SRCTOP}/stdtime
CFLAGS.localtime.c+= -DALL_STATE -DTHREAD_SAFE
.if ${MK_DETECT_TZ_CHANGES} != "no"
CFLAGS.localtime.c+= -DDETECT_TZ_CHANGES
+CFLAGS.Version.map+= -DDETECT_TZ_CHANGES
.endif
MAN+= ctime.3 strftime.3 strptime.3 time2posix.3 tzset.3
diff --git a/lib/libc/stdtime/Symbol.map b/lib/libc/stdtime/Symbol.map
index 669d4d47907b..6a34cd3ea590 100644
--- a/lib/libc/stdtime/Symbol.map
+++ b/lib/libc/stdtime/Symbol.map
@@ -35,3 +35,9 @@ FBSD_1.8 {
daylight;
timezone;
};
+
+FBSDprivate_1.0 {
+#ifdef DETECT_TZ_CHANGES
+ __tz_change_interval;
+#endif
+};
diff --git a/lib/libc/tests/stdtime/Makefile b/lib/libc/tests/stdtime/Makefile
index c7a7f5b9436f..adb883cc5b9a 100644
--- a/lib/libc/tests/stdtime/Makefile
+++ b/lib/libc/tests/stdtime/Makefile
@@ -1,6 +1,9 @@
-.include <bsd.own.mk>
+.include <src.opts.mk>
ATF_TESTS_C+= strptime_test
+.if ${MK_DETECT_TZ_CHANGES} != "no"
+ATF_TESTS_C+= detect_tz_changes_test
+.endif
TESTSDIR:= ${TESTSBASE}/${RELDIR:C/libc\/tests/libc/}
diff --git a/lib/libc/tests/stdtime/detect_tz_changes_test.c b/lib/libc/tests/stdtime/detect_tz_changes_test.c
new file mode 100644
index 000000000000..9722546747fd
--- /dev/null
+++ b/lib/libc/tests/stdtime/detect_tz_changes_test.c
@@ -0,0 +1,281 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <atf-c.h>
+
+static const time_t then = 1751328000; /* 2025-07-01 00:00:00 UTC */
+static const char *tz_change_interval_sym = "__tz_change_interval";
+static int *tz_change_interval_p;
+static const int tz_change_interval = 3;
+static int tz_change_timeout = 90;
+
+static bool debugging;
+
+static void
+debug(const char *fmt, ...)
+{
+ va_list ap;
+
+ if (debugging) {
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+ }
+}
+
+static void
+change_tz(const char *tzn)
+{
+ static const char *zfn = "/usr/share/zoneinfo";
+ static const char *tfn = "root/etc/.localtime";
+ static const char *dfn = "root/etc/localtime";
+ ssize_t clen;
+ int zfd, sfd, dfd;
+
+ ATF_REQUIRE((zfd = open(zfn, O_DIRECTORY | O_SEARCH)) >= 0);
+ ATF_REQUIRE((sfd = openat(zfd, tzn, O_RDONLY)) >= 0);
+ ATF_REQUIRE((dfd = open(tfn, O_CREAT | O_TRUNC | O_WRONLY)) >= 0);
+ do {
+ clen = copy_file_range(sfd, NULL, dfd, NULL, SSIZE_MAX, 0);
+ ATF_REQUIRE_MSG(clen != -1, "failed to copy %s/%s: %m",
+ zfn, tzn);
+ } while (clen > 0);
+ ATF_CHECK_EQ(0, close(dfd));
+ ATF_CHECK_EQ(0, close(sfd));
+ ATF_CHECK_EQ(0, close(zfd));
+ ATF_REQUIRE_EQ(0, rename(tfn, dfn));
+ debug("time zone %s installed", tzn);
+}
+
+/*
+ * Test time zone change detection.
+ *
+ * The parent creates a chroot containing only /etc/localtime, initially
+ * set to UTC. It then forks a child which enters the chroot, repeatedly
+ * checks the current time zone, and prints it to stdout if it changes
+ * (including once on startup). Meanwhile, the parent waits for output
+ * from the child. Every time it receives a line of text from the child,
+ * it checks that it is as expected, then changes /etc/localtime within
+ * the chroot to the next case in the list. Once it reaches the end of
+ * the list, it closes a pipe to notify the child, which terminates.
+ *
+ * Note that ATF and / or Kyua may have set the timezone before the test
+ * case starts (even unintentionally). Therefore, we start the test only
+ * after we've received and discarded the first report from the child,
+ * which should come almost immediately on startup.
+ */
+ATF_TC(detect_tz_changes);
+ATF_TC_HEAD(detect_tz_changes, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Test timezone change detection");
+ atf_tc_set_md_var(tc, "require.user", "root");
+ atf_tc_set_md_var(tc, "timeout", "600");
+}
+ATF_TC_BODY(detect_tz_changes, tc)
+{
+ static const struct tzcase {
+ const char *tzfn;
+ const char *expect;
+ } tzcases[] = {
+ /*
+ * A handful of time zones and the expected result of
+ * strftime("%z (%Z)", tm) when that time zone is active
+ * and tm represents a date in the summer of 2025.
+ */
+ { "America/Vancouver", "-0700 (PDT)" },
+ { "America/New_York", "-0400 (EDT)" },
+ { "Europe/London", "+0100 (BST)" },
+ { "Europe/Paris", "+0200 (CEST)" },
+ { "Asia/Kolkata", "+0530 (IST)" },
+ { "Asia/Tokyo", "+0900 (JST)" },
+ { "Australia/Canberra", "+1000 (AEST)" },
+ { "UTC", "+0000 (UTC)" },
+ { 0 },
+ };
+ char obuf[1024] = "";
+ char ebuf[1024] = "";
+ struct pollfd fds[3];
+ int opd[2], epd[2], spd[2];
+ time_t changed, now;
+ const struct tzcase *tzcase = NULL;
+ struct tm *tm;
+ size_t olen = 0, elen = 0;
+ ssize_t rlen;
+ long curoff = LONG_MIN;
+ pid_t pid;
+ int nfds, status;
+
+ /* speed up the test if possible */
+ tz_change_interval_p = dlsym(RTLD_SELF, tz_change_interval_sym);
+ if (tz_change_interval_p != NULL &&
+ *tz_change_interval_p > tz_change_interval) {
+ debug("reducing detection interval from %d to %d",
+ *tz_change_interval_p, tz_change_interval);
+ *tz_change_interval_p = tz_change_interval;
+ tz_change_timeout = tz_change_interval * 3;
+ }
+ /* prepare chroot */
+ ATF_REQUIRE_EQ(0, mkdir("root", 0755));
+ ATF_REQUIRE_EQ(0, mkdir("root/etc", 0755));
+ change_tz("UTC");
+ time(&changed);
+ /* output, error, sync pipes */
+ if (pipe(opd) != 0 || pipe(epd) != 0 || pipe(spd) != 0)
+ atf_tc_fail("failed to pipe");
+ /* fork child */
+ if ((pid = fork()) < 0)
+ atf_tc_fail("failed to fork");
+ if (pid == 0) {
+ /* child */
+ dup2(opd[1], STDOUT_FILENO);
+ close(opd[0]);
+ close(opd[1]);
+ dup2(epd[1], STDERR_FILENO);
+ close(epd[0]);
+ close(epd[1]);
+ close(spd[0]);
+ unsetenv("TZ");
+ ATF_REQUIRE_EQ(0, chroot("root"));
+ ATF_REQUIRE_EQ(0, chdir("/"));
+ fds[0].fd = spd[1];
+ fds[0].events = POLLIN;
+ for (;;) {
+ ATF_REQUIRE(poll(fds, 1, 100) >= 0);
+ if (fds[0].revents & POLLHUP) {
+ /* parent closed sync pipe */
+ _exit(0);
+ }
+ ATF_REQUIRE((tm = localtime(&then)) != NULL);
+ if (tm->tm_gmtoff == curoff)
+ continue;
+ olen = strftime(obuf, sizeof(obuf), "%z (%Z)", tm);
+ ATF_REQUIRE(olen > 0);
+ fprintf(stdout, "%s\n", obuf);
+ fflush(stdout);
+ curoff = tm->tm_gmtoff;
+ }
+ _exit(2);
+ }
+ /* parent */
+ close(opd[1]);
+ close(epd[1]);
+ close(spd[1]);
+ /* receive output until child terminates */
+ fds[0].fd = opd[0];
+ fds[0].events = POLLIN;
+ fds[1].fd = epd[0];
+ fds[1].events = POLLIN;
+ fds[2].fd = spd[0];
+ fds[2].events = POLLIN;
+ nfds = 3;
+ for (;;) {
+ ATF_REQUIRE(poll(fds, 3, 1000) >= 0);
+ time(&now);
+ if (fds[0].revents & POLLIN && olen < sizeof(obuf)) {
+ rlen = read(opd[0], obuf + olen, sizeof(obuf) - olen);
+ ATF_REQUIRE(rlen >= 0);
+ olen += rlen;
+ }
+ if (olen > 0) {
+ ATF_REQUIRE_EQ('\n', obuf[olen - 1]);
+ obuf[--olen] = '\0';
+ /* tzcase will be NULL at first */
+ if (tzcase != NULL) {
+ debug("%s", obuf);
+ ATF_REQUIRE_STREQ(tzcase->expect, obuf);
+ debug("change to %s detected after %d s",
+ tzcase->tzfn, (int)(now - changed));
+ if (tz_change_interval_p != NULL) {
+ ATF_CHECK((int)(now - changed) >=
+ *tz_change_interval_p - 1);
+ ATF_CHECK((int)(now - changed) <=
+ *tz_change_interval_p + 1);
+ }
+ }
+ olen = 0;
+ /* first / next test case */
+ if (tzcase == NULL)
+ tzcase = tzcases;
+ else
+ tzcase++;
+ if (tzcase->tzfn == NULL) {
+ /* test is over */
+ break;
+ }
+ change_tz(tzcase->tzfn);
+ changed = now;
+ }
+ if (fds[1].revents & POLLIN && elen < sizeof(ebuf)) {
+ rlen = read(epd[0], ebuf + elen, sizeof(ebuf) - elen);
+ ATF_REQUIRE(rlen >= 0);
+ elen += rlen;
+ }
+ if (elen > 0) {
+ ATF_REQUIRE_EQ(elen, fwrite(ebuf, 1, elen, stderr));
+ elen = 0;
+ }
+ if (nfds > 2 && fds[2].revents & POLLHUP) {
+ /* child closed sync pipe */
+ break;
+ }
+ /*
+ * The timeout for this test case is set to 10 minutes,
+ * because it can take that long to run with the default
+ * 61-second interval. However, each individual tzcase
+ * entry should not take much longer than the detection
+ * interval to test, so we can detect a problem long
+ * before Kyua terminates us.
+ */
+ if ((now - changed) > tz_change_timeout) {
+ close(spd[0]);
+ if (tz_change_interval_p == NULL &&
+ tzcase == tzcases) {
+ /*
+ * The most likely explanation in this
+ * case is that libc was built without
+ * time zone change detection.
+ */
+ atf_tc_skip("time zone change detection "
+ "does not appear to be enabled");
+ }
+ atf_tc_fail("timed out waiting for change to %s "
+ "to be detected", tzcase->tzfn);
+ }
+ }
+ close(opd[0]);
+ close(epd[0]);
+ close(spd[0]); /* this will wake up and terminate the child */
+ if (olen > 0)
+ ATF_REQUIRE_EQ(olen, fwrite(obuf, 1, olen, stdout));
+ if (elen > 0)
+ ATF_REQUIRE_EQ(elen, fwrite(ebuf, 1, elen, stderr));
+ ATF_REQUIRE_EQ(pid, waitpid(pid, &status, 0));
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE_EQ(0, WEXITSTATUS(status));
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ debugging = !getenv("__RUNNING_INSIDE_ATF_RUN") &&
+ isatty(STDERR_FILENO);
+ ATF_TP_ADD_TC(tp, detect_tz_changes);
+ return (atf_no_error());
+}
diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c
index 0d85ed468284..786d5647d993 100644
--- a/lib/libfetch/common.c
+++ b/lib/libfetch/common.c
@@ -277,13 +277,16 @@ conn_t *
fetch_reopen(int sd)
{
conn_t *conn;
+ int flags;
int opt = 1;
/* allocate and fill connection structure */
if ((conn = calloc(1, sizeof(*conn))) == NULL)
return (NULL);
- fcntl(sd, F_SETFD, FD_CLOEXEC);
- setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof opt);
+ flags = fcntl(sd, F_GETFD);
+ if (flags != -1 && (flags & FD_CLOEXEC) == 0)
+ (void)fcntl(sd, F_SETFD, flags | FD_CLOEXEC);
+ (void)setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof(opt));
conn->sd = sd;
++conn->ref;
return (conn);
diff --git a/lib/libsecureboot/h/libsecureboot.h b/lib/libsecureboot/h/libsecureboot.h
index 017558536825..d32df9594332 100644
--- a/lib/libsecureboot/h/libsecureboot.h
+++ b/lib/libsecureboot/h/libsecureboot.h
@@ -29,6 +29,7 @@
#include <sys/param.h>
#ifdef _STANDALONE
+#define _DEBUG_LEVEL_VAR DebugVe
#include <stand.h>
#else
#include <sys/types.h>
diff --git a/lib/libsys/fhopen.2 b/lib/libsys/fhopen.2
index aba53f1dd907..b281ac3d8949 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 April 6, 2025
+.Dd July 20, 2025
.Dt FHOPEN 2
.Os
.Sh NAME
@@ -140,7 +140,7 @@ is no longer valid.
.Xr fstatfs 2 ,
.Xr getfh 2 ,
.Xr open 2 ,
-.Xr named_attribute 9
+.Xr named_attribute 7
.Sh HISTORY
The
.Fn fhopen ,
diff --git a/lib/libsys/statfs.2 b/lib/libsys/statfs.2
index 49e8b5120558..ab65def11ebb 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 April 7, 2025
+.Dd July 20, 2025
.Dt STATFS 2
.Os
.Sh NAME
@@ -127,7 +127,7 @@ Mandatory Access Control (MAC) support for individual objects
.Xr mac 4 ) .
.It Dv MNT_NAMEDATTR
The file system supports named attributes as described in
-.Xr named_attribute 9 .
+.Xr named_attribute 7 .
.It Dv MNT_NFS4ACLS
ACLs in NFSv4 variant are supported.
.It Dv MNT_NOATIME
@@ -264,7 +264,7 @@ each file or directory name or disk label
.Sh SEE ALSO
.Xr fhstatfs 2 ,
.Xr getfsstat 2 ,
-.Xr named_attribute 9
+.Xr named_attribute 7
.Sh HISTORY
The
.Fn statfs
diff --git a/libexec/rc/rc.conf b/libexec/rc/rc.conf
index 00f4b718bfad..d502361eca37 100644
--- a/libexec/rc/rc.conf
+++ b/libexec/rc/rc.conf
@@ -694,7 +694,7 @@ entropy_file="/entropy" # Set to NO to disable late (used when going multi-user)
entropy_dir="/var/db/entropy" # Set to NO to disable caching entropy via cron.
entropy_save_sz="4096" # Size of the entropy cache files.
entropy_save_num="8" # Number of entropy cache files to save.
-harvest_mask="511" # Entropy device harvests all but the very invasive sources.
+harvest_mask="4607" # Entropy device harvests all but the very invasive sources.
# (See 'sysctl kern.random.harvest' and random(4))
osrelease_enable="YES" # Update /var/run/os-release on boot (or NO).
osrelease_file="/var/run/os-release" # File to update for os-release.
diff --git a/libexec/rc/rc.d/pf b/libexec/rc/rc.d/pf
index 0b4c086db22b..46fb085e5175 100755
--- a/libexec/rc/rc.d/pf
+++ b/libexec/rc/rc.d/pf
@@ -38,7 +38,7 @@ pf_fallback()
$pf_program -f "$pf_fallback_rules_file" $pf_flags
else
warn "Loading fallback rules: $pf_fallback_rules"
- echo $pf_fallback_rules | $pf_program -f - $pf_flags
+ echo "$pf_fallback_rules" | $pf_program -f - $pf_flags
fi
}
diff --git a/release/Makefile b/release/Makefile
index 84f29983b6c7..5d7d1402d6f8 100644
--- a/release/Makefile
+++ b/release/Makefile
@@ -276,6 +276,7 @@ bootonly:
.if ${.MAKE.OS} == "FreeBSD" && (!defined(NOPKG) || empty(NOPKG))
# Install packages onto release media.
${PKG_INSTALL} pkg || true
+ ${PKG_INSTALL} wifi-firmware-iwlwifi-kmod wifi-firmware-rtw88-kmod || true
${PKG_CLEAN} || true
.endif
# Set up installation environment
@@ -340,8 +341,8 @@ dvd: ${PKGBASE_REPO}
echo hostid_enable=\"NO\" >> ${.TARGET}/etc/rc.conf
echo debug.witness.trace=0 >> ${.TARGET}/etc/sysctl.conf
echo vfs.mountroot.timeout=\"10\" >> ${.TARGET}/boot/loader.conf
- echo loader_brand=\"install\" >> ${.TARGET}/boot/loader.conf
echo kernels_autodetect=\"NO\" >> ${.TARGET}/boot/loader.conf
+ echo loader_brand=\"install\" >> ${.TARGET}/boot/loader.conf
echo loader_menu_multi_user_prompt=\"Installer\" >> ${.TARGET}/boot/loader.conf
cp ${.CURDIR}/rc.local ${.TARGET}/etc
echo "./etc/resolv.conf type=link uname=root gname=wheel mode=0644 link=/tmp/bsdinstall_etc/resolv.conf" >> ${.TARGET}/METALOG
diff --git a/release/amd64/make-memstick.sh b/release/amd64/make-memstick.sh
index cbb80e971343..cec4b27b5b96 100755
--- a/release/amd64/make-memstick.sh
+++ b/release/amd64/make-memstick.sh
@@ -12,6 +12,7 @@
set -e
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
if [ "$(uname -s)" = "FreeBSD" ]; then
@@ -51,7 +52,7 @@ if [ -n "${METALOG}" ]; then
echo "./etc/rc.conf.local type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
MAKEFSARG=${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
rm ${BASEBITSDIR}/etc/fstab
rm ${BASEBITSDIR}/etc/rc.conf.local
if [ -n "${METALOG}" ]; then
@@ -67,10 +68,10 @@ else
make_esp_file ${espfilename} ${fat32min} ${BASEBITSDIR}/boot/loader.efi
fi
-mkimg -s mbr \
+${MKIMG} -s mbr \
-b ${BASEBITSDIR}/boot/mbr \
-p efi:=${espfilename} \
- -p freebsd:-"mkimg -s bsd -b ${BASEBITSDIR}/boot/boot -p freebsd-ufs:=${2}.part" \
+ -p freebsd:-"${MKIMG} -s bsd -b ${BASEBITSDIR}/boot/boot -p freebsd-ufs:=${2}.part" \
-a 2 \
-o ${2}
rm ${espfilename}
diff --git a/release/amd64/mkisoimages.sh b/release/amd64/mkisoimages.sh
index 245beb660c3f..8f7163e05261 100644
--- a/release/amd64/mkisoimages.sh
+++ b/release/amd64/mkisoimages.sh
@@ -25,20 +25,9 @@
set -e
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
-if [ -z $ETDUMP ]; then
- ETDUMP=etdump
-fi
-
-if [ -z $MAKEFS ]; then
- MAKEFS=makefs
-fi
-
-if [ -z $MKIMG ]; then
- MKIMG=mkimg
-fi
-
if [ "$1" = "-b" ]; then
MAKEFSARG="$4"
else
diff --git a/release/arm64/make-memstick.sh b/release/arm64/make-memstick.sh
index 90ff98b394c7..0da59c29635b 100755
--- a/release/arm64/make-memstick.sh
+++ b/release/arm64/make-memstick.sh
@@ -17,6 +17,7 @@ if [ "$(uname -s)" = "FreeBSD" ]; then
fi
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
if [ $# -ne 2 ]; then
@@ -51,7 +52,7 @@ if [ -n "${METALOG}" ]; then
echo "./etc/rc.conf.local type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
MAKEFSARG=${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
rm ${BASEBITSDIR}/etc/fstab
rm ${BASEBITSDIR}/etc/rc.conf.local
if [ -n "${METALOG}" ]; then
@@ -62,7 +63,7 @@ fi
espfilename=$(mktemp /tmp/efiboot.XXXXXX)
make_esp_file ${espfilename} ${fat32min} ${BASEBITSDIR}/boot/loader.efi
-mkimg -s gpt \
+${MKIMG} -s gpt \
-p efi:=${espfilename} \
-p freebsd-ufs:=${2}.part \
-o ${2}
diff --git a/release/arm64/mkisoimages.sh b/release/arm64/mkisoimages.sh
index cb58178ed4b9..46b16f0ce08d 100644
--- a/release/arm64/mkisoimages.sh
+++ b/release/arm64/mkisoimages.sh
@@ -21,20 +21,9 @@
set -e
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
-if [ -z $ETDUMP ]; then
- ETDUMP=etdump
-fi
-
-if [ -z $MAKEFS ]; then
- MAKEFS=makefs
-fi
-
-if [ -z $MKIMG ]; then
- MKIMG=mkimg
-fi
-
if [ "$1" = "-b" ]; then
MAKEFSARG="$4"
else
diff --git a/release/i386/make-memstick.sh b/release/i386/make-memstick.sh
index 7a20be20c026..ad2126b0a8f8 100755
--- a/release/i386/make-memstick.sh
+++ b/release/i386/make-memstick.sh
@@ -11,6 +11,9 @@
set -e
+scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
+
if [ "$(uname -s)" = "FreeBSD" ]; then
PATH=/bin:/usr/bin:/sbin:/usr/sbin
export PATH
@@ -48,16 +51,16 @@ if [ -n "${METALOG}" ]; then
echo "./etc/rc.conf.local type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
MAKEFSARG=${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
rm ${BASEBITSDIR}/etc/fstab
rm ${BASEBITSDIR}/etc/rc.conf.local
if [ -n "${METALOG}" ]; then
rm ${metalogfilename}
fi
-mkimg -s mbr \
+${MKIMG} -s mbr \
-b ${BASEBITSDIR}/boot/mbr \
- -p freebsd:-"mkimg -s bsd -b ${BASEBITSDIR}/boot/boot -p freebsd-ufs:=${2}.part" \
+ -p freebsd:-"${MKIMG} -s bsd -b ${BASEBITSDIR}/boot/boot -p freebsd-ufs:=${2}.part" \
-o ${2}
rm ${2}.part
diff --git a/release/i386/mkisoimages.sh b/release/i386/mkisoimages.sh
index 8f000aae3b17..1918b36eeb44 100644
--- a/release/i386/mkisoimages.sh
+++ b/release/i386/mkisoimages.sh
@@ -24,6 +24,9 @@
set -e
+scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
+
if [ "$1" = "-b" ]; then
MAKEFSARG="$4"
else
@@ -67,7 +70,7 @@ if [ -n "${METALOG}" ]; then
echo "./etc/fstab type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
MAKEFSARG=${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$MAKEFSARG" "$@"
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$MAKEFSARG" "$@"
rm -f "$BASEBITSDIR/etc/fstab"
if [ -n "${METALOG}" ]; then
rm ${metalogfilename}
diff --git a/release/packages/Makefile.package b/release/packages/Makefile.package
deleted file mode 100644
index c2427aa16945..000000000000
--- a/release/packages/Makefile.package
+++ /dev/null
@@ -1,193 +0,0 @@
-#
-#
-
-acct_COMMENT= System Accounting Utilities
-acct_DESC= System Accounting Utilities
-acpi_COMMENT= ACPI Utilities
-acpi_DESC= ACPI Utilities
-amd_COMMENT= AMD Utilities
-amd_DESC= AMD Utilities
-apm_COMMENT= APM Utilities
-apm_DESC= APM Utilities
-at_COMMENT= AT Utilities
-at_DESC= AT Utilities
-audit_COMMENT= OpenBSM auditing utilities
-audit_DESC= OpenBSM auditing utilities
-autofs_COMMENT= Autofs Utilities
-autofs_DESC= Autofs Utilities
-bhyve_COMMENT= Bhyve Utilities
-bhyve_DESC= Bhyve Utilities
-blocklist_COMMENT= Blocklist Utilities
-blocklist_DESC= Blocklist Utilities
-bluetooth_COMMENT= Bluetooth Utilities
-bluetooth_DESC= Bluetooth Utilities
-bootloader_COMMENT= Bootloader
-bootloader_DESC= Bootloader and configuration files
-bsdinstall_COMMENT= BSDInstall Utilities
-bsdinstall_DESC= BSDInstall Utilities
-bsnmp_COMMENT= BSNMP Utilities
-bsnmp_DESC= BSNMP Utilities
-caroot_COMMENT= SSL Certificates
-caroot_DESC= SSL Certificates
-clang_COMMENT= Clang Utilities
-clang_DESC= Clang Utilities
-clibs_COMMENT= Core C Libraries
-clibs_DESC= Core C Libraries
-certctl_COMMENT= SSL Certificate Utility
-certctl_DESC= SSL Certificate Utility
-console-tools_COMMENT= Console Utilities
-console-tools_DESC= Console Utilities
-cron_COMMENT= cron(8) and crontab(1)
-cron_DESC= cron(8) and crontab(1)
-csh_COMMENT= C Shell
-csh_DESC= C Shell
-ctf-tools_COMMENT= CTF Utilities
-ctf-tools_DESC= CTF Utilities
-cxgbe-tools_COMMENT= Chelsio cxbge Utilities
-cxgbe-tools_DESC= Chelsio cxbge Utilities
-devd_COMMENT= Devd Utility and scripts
-devd_DESC= Devd Utility and scripts
-devmatch_COMMENT= Devmatch Utility
-devmatch_DESC= Devmatch Utility
-dhclient_COMMENT= DHCP Client
-dhclient_DESC= DHCP Client
-dma_COMMENT= DMA Mail Agent Utilities
-dma_DESC= DMA Mail Agent Utilities
-docs_COMMENT= Documentation
-docs_DESC= Documentation
-dtrace_COMMENT= Dtrace Utilities
-dtrace_DESC= Dtrace Utilities
-dwatch_COMMENT= Dwatch Utilities
-dwatch_DESC= Dwatch Utilities
-ee_COMMENT= Easy Editor Utilities
-ee_DESC= Easy Editor Utilities
-efi-tools_COMMENT= UEFI Utilities
-efi-tools_DESC= UEFI Utilities
-examples_COMMENT= Examples in /usr/share/examples
-examples_DESC= Examples in /usr/share/examples
-fd_COMMENT= Floppy disk support
-fd_DESC= Floppy disk support
-fetch_COMMENT= Fetch Utility
-fetch_DESC= Fetch Utility
-firmware-iwm_DESC= iwm(4) firmwares
-firmware-iwm_COMMENT= iwm(4) firmwares
-ftp_COMMENT= FTP Utilities
-ftp_DESC= FTP Utilities
-ftpd_COMMENT= FTP Daemon
-ftpd_DESC= FTP Daemon
-fwget_COMMENT= FWGET Utility
-fwget_DESC= FWGET Utility
-games_COMMENT= Games
-games_DESC= Games
-geom_COMMENT= GEOM Utilitites
-geom_DESC= GEOM Utilitites
-ggate_COMMENT= GEOM Gate Utilities
-ggate_DESC= GEOM Gate Utilities
-hast_COMMENT= Highly Available Storage daemon
-hast_DESC= Highly Available Storage daemon
-hostapd_COMMENT= 802.11 Access Point Daemon an Utilities
-hostapd_DESC= 802.11 Access Point Daemon an Utilities
-hyperv-tools_COMMENT= Microsoft HyperV Utilities
-hyperv-tools_DESC= Microsoft HyperV Utilities
-inetd_COMMENT= Internet super-server
-inetd_DESC= Internet super-server
-jail_COMMENT= Jail Utilities
-jail_DESC= Jail Utilities
-jail-debug_DESCR= Debugging Symbols
-jail-development_DESCR=Development Files
-jail-profile_DESCR= Profiling Libraries
-jail-lib32_DESCR= 32-bit Libraries
-jail-lib32-debug_DESCR=32-bit Debugging Symbols
-jail-lib32-development_DESCR=32-bit Development Files
-jail-lib32-profile_DESCR=32-bit Profiling Libraries
-kerberos_COMMENT= Kerberos Utilities
-kerberos_DESC= Kerberos Utilities
-kerberos-lib_COMMENT= Kerberos Libraries
-kerberos-lib_DESC= Kerberos Libraries
-kernel_COMMENT= FreeBSD Kernel
-kernel_DESC= FreeBSD Kernel
-lp_COMMENT= Printer subsystem
-lp_DESC= Printer subsystem
-manuals_COMMENT= Manual Pages
-manuals_DESC= Manual Pages
-mlx-tools_COMMENT= Mellanox Utilities
-mlx-tools_DESC= Mellanox Utilities
-mtree_COMMENT= MTREE Files
-mtree_DESC= MTREE Files
-netmap_COMMENT= Netmap Library and Utilities
-netmap_DESC= Netmap Library and Utilities
-newsyslog_COMMENT= Newsyslog Utility
-newsyslog_DESC= Newsyslog Utility
-nfs_COMMENT= NFS Utilities
-nfs_DESC= NFS Utilities
-ntp_COMMENT= Network Time Protocol server and client
-ntp_DESC= Network Time Protocol server and client
-nuageinit_COMMENT= CloudInit support scripts
-nuageinit_DESC= CloudInit support scripts
-nvme-tools_COMMENT= NVME Utilities
-nvme-tools_DESC= NVME Utilities
-openssl_COMMENT= OpenSSL Utility
-openssl_DESC= OpenSSL Utility
-openssl-lib_COMMENT= OpenSSL Libraries
-openssl-lib_DESC= OpenSSL Libraries
-pkg-bootstrap_COMMENT= pkg bootstrap Utility
-pkg-bootstrap_DESC= pkg bootstrap Utility
-periodic_COMMENT= Periodic Utility
-periodic_DESC= Periodic Utility
-rc_COMMENT= RC Scripts
-rc_DESC= RC Scripts
-rcmds_COMMENT= BSD/SunOS remote status commands
-rcmds_DESC=\
-The BSD/SunOS remote status commands, which can be used to query or interact\
-with remote hosts over the network. This includes the command-line utilities\
-rwho, ruptime, rup, rusers and rwall and the daemons rwhod, rpc.rstatd,\
-rpc.rusersd, and rpc.rwalld.
-rdma_COMMENT= RDMA Utilities
-rdma_DESC= RDMA Utilities
-rescue_COMMENT= Rescue Utilities
-rescue_DESC= Rescue Utilities
-resolvconf_COMMENT= Resolvconf Utility and scripts
-resolvconf_DESC= Resolvconf Utility and scripts
-runtime_COMMENT= FreeBSD Base System
-runtime_DESC= FreeBSD Base System
-runtime-debug_DESCR= Debugging Symbols
-runtime-development_DESCR=Development Files
-runtime-profile_DESCR= Profiling Libraries
-runtime-lib32_DESCR= 32-bit Libraries
-runtime-lib32-debug_DESCR=32-bit Debugging Symbols
-runtime-lib32-development_DESCR=32-bit Development Files
-runtime-lib32-profile_DESCR=32-bit Profiling Libraries
-sendmail_COMMENT= Sendmail Utilities
-sendmail_DESC= Sendmail Utilities
-smbutils_COMMENT= SMB Utilities
-smbutils_DESC= SMB Utilities
-ssh_COMMENT= Secure Shell Utilities
-ssh_DESC= Secure Shell Utilities
-syscons_COMMENT= Syscons Console
-syscons_DESC= Syscons Console
-syslogd_COMMENT= Syslog Daemon
-syslogd_DESC= Syslog Daemon
-tcpd_COMMENT= TCP Wrapper utilities
-tcpd_DESC= TCP Wrapper utilities
-telnet_COMMENT= Telnet client
-telnet_DESC= Telnet client
-tests_COMMENT= Test Suite
-tests_DESC= Test Suite
-toolchain_COMMENT= Utilities for program development
-toolchain_DESC= Utilities for program development
-ufs_COMMENT= UFS Libraries and Utilities
-ufs_DESC= UFS Libraries and Utilities
-unbound_COMMENT= Unbound DNS Resolver
-unbound_DESC= Unbound DNS Resolver
-utilities_COMMENT= Non-vital programs and libraries
-utilities_DESC= Non-vital programs and libraries
-vi_COMMENT= Vi Editor
-vi_DESC= Vi Editor
-vt_COMMENT= VT fonts and keyboard files
-vt_DESC= VT fonts and keyboard files
-wpa_COMMENT= 802.11 Supplicant
-wpa_DESC= 802.11 Supplicant
-yp_COMMENT= Yellow Pages programs
-yp_DESC= Yellow Pages programs
-zfs_COMMENT= ZFS Libraries and Utilities
-zfs_DESC= ZFS Libraries and Utilities
diff --git a/release/packages/certctl.ucl b/release/packages/certctl.ucl
deleted file mode 100644
index 664a6d139585..000000000000
--- a/release/packages/certctl.ucl
+++ /dev/null
@@ -1,9 +0,0 @@
-scripts: {
- # XXX If pkg picks up a mechanism to detect in the post-install script
- # files being added or removed, we should use it instead to gate the
- # rehash.
- post-install = <<EOD
- [ -x /usr/sbin/certctl ] && env DESTDIR=${PKG_ROOTDIR} \
- /usr/sbin/certctl rehash
-EOD
-}
diff --git a/release/packages/clang-all.ucl b/release/packages/clang-all.ucl
deleted file mode 100644
index 41a697ebe53d..000000000000
--- a/release/packages/clang-all.ucl
+++ /dev/null
@@ -1 +0,0 @@
-licenses = [ NCSA ]
diff --git a/release/packages/generate-ucl.lua b/release/packages/generate-ucl.lua
index ae6ee58dd84a..3d91d11bc42f 100755
--- a/release/packages/generate-ucl.lua
+++ b/release/packages/generate-ucl.lua
@@ -3,33 +3,174 @@
--[[ usage:
generare-ucl.lua [<variablename> <variablevalue>]... <sourceucl> <destucl>
-In the <destucl> files the variable <variablename> (in the form ${variablename}
-in the <sourceucl>) will be expanded to <variablevalue>.
-
-The undefined variables will reamin unmofifier "${variablename}"
+Build a package's UCL configuration by loading the template UCL file
+<sourceucl>, replacing any $VARIABLES in the UCL based on the provided
+variables, then writing the result to <destucl>.
]]--
local ucl = require("ucl")
+-- Give subpackages a special comment and description suffix to indicate what
+-- they contain, so e.g. "foo-man" has " (manual pages)" appended to its
+-- comment. This avoids having to create a separate ucl files for every
+-- subpackage just to set this.
+--
+-- Note that this is not a key table because the order of the pattern matches
+-- is important.
+pkg_suffixes = {
+ {
+ "%-dev%-lib32$", "(32-bit development files)",
+ "This package contains development files for compiling "..
+ "32-bit applications on a 64-bit host."
+ },
+ {
+ "%-dbg%-lib32$", "(32-bit debugging symbols)",
+ "This package contains 32-bit external debugging symbols "..
+ "for use with a source-level debugger.",
+ },
+ {
+ "%-man%-lib32$", "(32-bit manual pages)",
+ "This package contains the online manual pages for 32-bit "..
+ "components on a 64-bit host.",
+ },
+ {
+ "%-lib32$", "(32-bit libraries)",
+ "This package contains 32-bit libraries for running 32-bit "..
+ "applications on a 64-bit host.",
+ },
+ {
+ "%-dev$", "(development files)",
+ "This package contains development files for "..
+ "compiling applications."
+ },
+ {
+ "%-man$", "(manual pages)",
+ "This package contains the online manual pages."
+ },
+ {
+ "%-dbg$", "(debugging symbols)",
+ "This package contains external debugging symbols for use "..
+ "with a source-level debugger.",
+ },
+}
+
+function add_suffixes(obj)
+ local pkgname = obj["name"]
+ for _,pattern in pairs(pkg_suffixes) do
+ if pkgname:match(pattern[1]) ~= nil then
+ obj["comment"] = obj["comment"] .. " " .. pattern[2]
+ obj["desc"] = obj["desc"] .. "\n\n" .. pattern[3]
+ return
+ end
+ end
+end
+
+-- Hardcode a list of packages which don't get the automatic pkggenname
+-- dependency because the base package doesn't exist. We should have a better
+-- way to handle this.
+local no_gen_deps = {
+ ["libcompat-dev"] = true,
+ ["libcompat-dev-lib32"] = true,
+ ["libcompat-man"] = true,
+ ["libcompiler_rt-dev"] = true,
+ ["libcompiler_rt-dev-lib32"] = true,
+ ["liby-dev"] = true,
+ ["liby-dev-lib32"] = true,
+}
+
+-- Return true if the package 'pkgname' should have a dependency on the package
+-- pkggenname.
+function add_gen_dep(pkgname, pkggenname)
+ if pkgname == pkggenname then
+ return false
+ end
+ if pkgname == nil or pkggenname == nil then
+ return false
+ end
+ if no_gen_deps[pkgname] ~= nil then
+ return false
+ end
+ if pkggenname == "kernel" then
+ return false
+ end
+
+ return true
+end
+
+local pkgname = nil
+local pkggenname = nil
+local pkgprefix = nil
+local pkgversion = nil
+
+-- This parser is the output UCL we want to build.
+local parser = ucl.parser()
+
+-- Set any $VARIABLES from the command line in the parser. This causes ucl to
+-- automatically replace them when we load the source ucl.
if #arg < 2 or #arg % 2 ~= 0 then
io.stderr:write(arg[0] .. ": expected an even number of arguments, got " .. #arg)
os.exit(1)
end
-local parser = ucl.parser()
for i = 2, #arg - 2, 2 do
- parser:register_variable(arg[i - 1], arg[i])
+ local varname = arg[i - 1]
+ local varvalue = arg[i]
+
+ if varname == "PKGNAME" and #varvalue > 0 then
+ pkgname = varvalue
+ elseif varname == "PKGGENNAME" and #varvalue > 0 then
+ pkggenname = varvalue
+ elseif varname == "VERSION" and #varvalue > 0 then
+ pkgversion = varvalue
+ elseif varname == "PKG_NAME_PREFIX" and #varvalue > 0 then
+ pkgprefix = varvalue
+ end
+
+ parser:register_variable(varname, varvalue)
end
+
+-- Load the source ucl file.
local res,err = parser:parse_file(arg[#arg - 1])
if not res then
io.stderr:write(arg[0] .. ": fail to parse("..arg[#arg - 1].."): "..err)
os.exit(1)
end
+
+local obj = parser:get_object()
+
+-- If pkgname is different from pkggenname, add a dependency on pkggenname.
+-- This means that e.g. -dev packages depend on their respective base package.
+if add_gen_dep(pkgname, pkggenname) then
+ if obj["deps"] == nil then
+ obj["deps"] = {}
+ end
+ obj["deps"][pkggenname] = {
+ ["version"] = pkgversion,
+ ["origin"] = "base"
+ }
+end
+
+-- If PKG_NAME_PREFIX is provided, rewrite the names of dependency packages.
+-- We can't do this in UCL since variable substitution doesn't work in array
+-- keys.
+if pkgprefix ~= nil and obj["deps"] ~= nil then
+ newdeps = {}
+ for dep, opts in pairs(obj["deps"]) do
+ local newdep = pkgprefix .. "-" .. dep
+ newdeps[newdep] = opts
+ end
+ obj["deps"] = newdeps
+end
+
+-- Add comment and desc suffix.
+add_suffixes(obj)
+
+-- Write the output file.
local f,err = io.open(arg[#arg], "w")
if not f then
io.stderr:write(arg[0] .. ": fail to open("..arg[#arg].."): ".. err)
os.exit(1)
end
-local obj = parser:get_object()
+
f:write(ucl.to_format(obj, 'ucl', true))
f:close()
diff --git a/release/packages/generate-ucl.sh b/release/packages/generate-ucl.sh
index b7d7bad35023..3078185a3c4e 100755
--- a/release/packages/generate-ucl.sh
+++ b/release/packages/generate-ucl.sh
@@ -3,8 +3,8 @@
#
main() {
- desc=
- comment=
+ outname=""
+ origname=""
debug=
uclsource=
while getopts "do:s:u:" arg; do
@@ -31,73 +31,26 @@ main() {
shift $(( ${OPTIND} - 1 ))
case "${outname}" in
- bootloader)
- pkgdeps=""
- ;;
- certctl)
- pkgdeps="caroot openssl"
- ;;
- clang)
- pkgdeps="lld libcompiler_rt-dev"
- ;;
- periodic)
- pkgdeps="cron"
- ;;
- rcmds)
- # the RPC daemons require rpcbind
- pkgdeps="utilities"
- ;;
-
- # -dev packages that have no corresponding non-dev package
- # as a dependency.
- libcompat-dev|libcompiler_rt-dev|liby-dev)
- outname=${outname%%-dev}
- _descr="Development Files"
- ;;
- libcompat-lib32_dev|libcompiler_rt-lib32_dev|liby-lib32_dev)
- outname=${outname%%-lib32_dev}
- _descr="32-bit Libraries, Development Files"
- ;;
- libcompat-man|libelftc-man)
- outname=${outname%%-man}
- _descr="Manual Pages"
+ *-dev)
+ outname="${outname%%-dev}"
;;
- utilities)
- uclfile="${uclfile}"
+ *-dbg)
+ outname="${outname%%-dbg}"
;;
- runtime)
- outname="runtime"
- _descr="$(make -C ${srctree}/release/packages -f Makefile.package -V ${outname}_DESCR)"
+ *-dev-lib32)
+ outname="${outname%%-dev-lib32}"
;;
- *-lib32_dev)
- outname="${outname%%-lib32_dev}"
- _descr="32-bit Libraries, Development Files"
- pkgdeps="${outname}"
+ *-dbg-lib32)
+ outname="${outname%%-dbg-lib32}"
;;
- *-lib32_dbg)
- outname="${outname%%-lib32_dbg}"
- _descr="32-bit Libraries, Debugging Symbols"
- pkgdeps="${outname}"
+ *-man-lib32)
+ outname="${outname%%-man-lib32}"
;;
*-lib32)
outname="${outname%%-lib32}"
- _descr="32-bit Libraries"
- pkgdeps="${outname}"
- ;;
- *-dev)
- outname="${outname%%-dev}"
- _descr="Development Files"
- pkgdeps="${outname}"
- ;;
- *-dbg)
- outname="${outname%%-dbg}"
- _descr="Debugging Symbols"
- pkgdeps="${outname}"
;;
*-man)
outname="${outname%%-man}"
- _descr="Manual Pages"
- pkgdeps="${outname}"
;;
${origname})
;;
@@ -107,22 +60,16 @@ main() {
;;
esac
- desc="$(make -C ${srctree}/release/packages -f Makefile.package -V ${outname}_DESC)"
- comment="$(make -C ${srctree}/release/packages -f Makefile.package -V ${outname}_COMMENT)"
-
uclsource="${srctree}/release/packages/template.ucl"
if [ -n "${debug}" ]; then
echo ""
echo "==============================================================="
echo "DEBUG:"
- echo "_descr=${_descr}"
echo "outname=${outname}"
echo "origname=${origname}"
echo "srctree=${srctree}"
echo "uclfile=${uclfile}"
- echo "desc=${desc}"
- echo "comment=${comment}"
echo "vital=${vital}"
echo "cp ${uclsource} -> ${uclfile}"
echo "==============================================================="
@@ -131,38 +78,17 @@ main() {
echo ""
fi
- [ -z "${comment}" ] && comment="${outname} package"
- [ -n "${_descr}" ] && comment="${comment} (${_descr})"
- [ -z "${desc}" ] && desc="${outname} package"
-
- cp "${uclsource}" "${uclfile}"
- if [ -n "${pkgdeps}" ]; then
- echo 'deps: {' >> ${uclfile}
- for dep in ${pkgdeps}; do
- cat <<EOF >> ${uclfile}
- ${PKG_NAME_PREFIX}-${dep}: {
- origin: "base",
- version: "${PKG_VERSION}"
- }
-EOF
- done
- echo '}' >> ${uclfile}
- fi
cap_arg="$( make -f ${srctree}/share/mk/bsd.endian.mk -VCAP_MKDB_ENDIAN )"
${srctree}/release/packages/generate-ucl.lua \
VERSION "${PKG_VERSION}" \
PKGNAME "${origname}" \
PKGGENNAME "${outname}" \
PKG_NAME_PREFIX "${PKG_NAME_PREFIX}" \
- COMMENT "${comment}" \
- DESC "${desc}" \
CAP_MKDB_ENDIAN "${cap_arg}" \
PKG_WWW "${PKG_WWW}" \
PKG_MAINTAINER "${PKG_MAINTAINER}" \
- UCLFILES "${srctree}/release/packages/" \
- ${uclfile} ${uclfile}
-
- return 0
+ UCLFILES "${srctree}/release/packages/ucl" \
+ ${uclsource} ${uclfile}
}
main "${@}"
diff --git a/release/packages/lld-all.ucl b/release/packages/lld-all.ucl
deleted file mode 100644
index 41a697ebe53d..000000000000
--- a/release/packages/lld-all.ucl
+++ /dev/null
@@ -1 +0,0 @@
-licenses = [ NCSA ]
diff --git a/release/packages/lldb-all.ucl b/release/packages/lldb-all.ucl
deleted file mode 100644
index 41a697ebe53d..000000000000
--- a/release/packages/lldb-all.ucl
+++ /dev/null
@@ -1 +0,0 @@
-licenses = [ NCSA ]
diff --git a/release/packages/ssh-all.ucl b/release/packages/ssh-all.ucl
deleted file mode 100644
index 4f78d80fa68e..000000000000
--- a/release/packages/ssh-all.ucl
+++ /dev/null
@@ -1 +0,0 @@
-licenses = [ ISCL ]
diff --git a/release/packages/template.ucl b/release/packages/template.ucl
index a65f58868118..faa48effe1ad 100644
--- a/release/packages/template.ucl
+++ b/release/packages/template.ucl
@@ -4,7 +4,7 @@
name = "${PKG_NAME_PREFIX}-${PKGNAME}"
origin = "base"
version = "${VERSION}"
-comment = "${COMMENT}"
+comment = "${PKGNAME} package"
categories = [ base ]
maintainer = "${PKG_MAINTAINER}"
www = "${PKG_WWW}"
@@ -12,8 +12,8 @@ prefix = "/"
licenselogic = "single"
licenses = [ BSD2CLAUSE ]
desc = <<EOD
-${DESC}
+${PKGNAME} package
EOD
-.include(try=true,duplicate=rewrite) "${UCLFILES}/${PKGGENNAME}-all.ucl"
+.include(try=false,duplicate=rewrite) "${UCLFILES}/${PKGGENNAME}-all.ucl"
.include(try=true,duplicate=rewrite) "${UCLFILES}/${PKGNAME}.ucl"
.include(try=true,duplicate=rewrite) "${UCLFILES}/${FORCEINCLUDE}.ucl"
diff --git a/release/packages/ucl/acct-all.ucl b/release/packages/ucl/acct-all.ucl
new file mode 100644
index 000000000000..ac4bd8868511
--- /dev/null
+++ b/release/packages/ucl/acct-all.ucl
@@ -0,0 +1,4 @@
+comment = "System Accounting Utilities"
+desc = <<EOD
+System Accounting Utilities
+EOD
diff --git a/release/packages/ucl/acpi-all.ucl b/release/packages/ucl/acpi-all.ucl
new file mode 100644
index 000000000000..70ea39fc3862
--- /dev/null
+++ b/release/packages/ucl/acpi-all.ucl
@@ -0,0 +1,4 @@
+comment = "ACPI Utilities"
+desc = <<EOD
+ACPI Utilities
+EOD
diff --git a/release/packages/ucl/amd-all.ucl b/release/packages/ucl/amd-all.ucl
new file mode 100644
index 000000000000..e2bc7cfc1b2a
--- /dev/null
+++ b/release/packages/ucl/amd-all.ucl
@@ -0,0 +1,4 @@
+comment = "AMD Utilities"
+desc = <<EOD
+AMD Utilities
+EOD
diff --git a/release/packages/ucl/apm-all.ucl b/release/packages/ucl/apm-all.ucl
new file mode 100644
index 000000000000..bf1b40000805
--- /dev/null
+++ b/release/packages/ucl/apm-all.ucl
@@ -0,0 +1,4 @@
+comment = "APM Utilities"
+desc = <<EOD
+APM Utilities
+EOD
diff --git a/release/packages/ucl/at-all.ucl b/release/packages/ucl/at-all.ucl
new file mode 100644
index 000000000000..c15642737b36
--- /dev/null
+++ b/release/packages/ucl/at-all.ucl
@@ -0,0 +1,4 @@
+comment = "AT Utilities"
+desc = <<EOD
+AT Utilities
+EOD
diff --git a/release/packages/ucl/audit-all.ucl b/release/packages/ucl/audit-all.ucl
new file mode 100644
index 000000000000..e0f3d4bf1675
--- /dev/null
+++ b/release/packages/ucl/audit-all.ucl
@@ -0,0 +1,4 @@
+comment = "OpenBSM auditing utilities"
+desc = <<EOD
+OpenBSM auditing utilities
+EOD
diff --git a/release/packages/ucl/autofs-all.ucl b/release/packages/ucl/autofs-all.ucl
new file mode 100644
index 000000000000..0e3e8d2336ca
--- /dev/null
+++ b/release/packages/ucl/autofs-all.ucl
@@ -0,0 +1,4 @@
+comment = "Autofs Utilities"
+desc = <<EOD
+Autofs Utilities
+EOD
diff --git a/release/packages/ucl/bhyve-all.ucl b/release/packages/ucl/bhyve-all.ucl
new file mode 100644
index 000000000000..2b20ca9a716f
--- /dev/null
+++ b/release/packages/ucl/bhyve-all.ucl
@@ -0,0 +1,4 @@
+comment = "Bhyve Utilities"
+desc = <<EOD
+Bhyve Utilities
+EOD
diff --git a/release/packages/ucl/blocklist-all.ucl b/release/packages/ucl/blocklist-all.ucl
new file mode 100644
index 000000000000..03330a417af9
--- /dev/null
+++ b/release/packages/ucl/blocklist-all.ucl
@@ -0,0 +1,4 @@
+comment = "Blocklist Utilities"
+desc = <<EOD
+Blocklist Utilities
+EOD
diff --git a/release/packages/ucl/bluetooth-all.ucl b/release/packages/ucl/bluetooth-all.ucl
new file mode 100644
index 000000000000..c139d9056a14
--- /dev/null
+++ b/release/packages/ucl/bluetooth-all.ucl
@@ -0,0 +1,4 @@
+comment = "Bluetooth Utilities"
+desc = <<EOD
+Bluetooth Utilities
+EOD
diff --git a/release/packages/ucl/bootloader-all.ucl b/release/packages/ucl/bootloader-all.ucl
new file mode 100644
index 000000000000..c5690e85c7ba
--- /dev/null
+++ b/release/packages/ucl/bootloader-all.ucl
@@ -0,0 +1,4 @@
+comment = "Bootloader"
+desc = <<EOD
+Bootloader and configuration files
+EOD
diff --git a/release/packages/ucl/bsdinstall-all.ucl b/release/packages/ucl/bsdinstall-all.ucl
new file mode 100644
index 000000000000..4c4586dcc702
--- /dev/null
+++ b/release/packages/ucl/bsdinstall-all.ucl
@@ -0,0 +1,4 @@
+comment = "BSDInstall Utilities"
+desc = <<EOD
+BSDInstall Utilities
+EOD
diff --git a/release/packages/ucl/bsnmp-all.ucl b/release/packages/ucl/bsnmp-all.ucl
new file mode 100644
index 000000000000..9b80310c0617
--- /dev/null
+++ b/release/packages/ucl/bsnmp-all.ucl
@@ -0,0 +1,4 @@
+comment = "BSNMP Utilities"
+desc = <<EOD
+BSNMP Utilities
+EOD
diff --git a/release/packages/ucl/caroot-all.ucl b/release/packages/ucl/caroot-all.ucl
new file mode 100644
index 000000000000..151c1f18ae39
--- /dev/null
+++ b/release/packages/ucl/caroot-all.ucl
@@ -0,0 +1,4 @@
+comment = "SSL Certificates"
+desc = <<EOD
+SSL Certificates
+EOD
diff --git a/release/packages/ucl/caroot.ucl b/release/packages/ucl/caroot.ucl
new file mode 100644
index 000000000000..4d2b52d300fc
--- /dev/null
+++ b/release/packages/ucl/caroot.ucl
@@ -0,0 +1,10 @@
+deps {
+ "certctl": {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
+scripts: {
+ post-install = "/usr/sbin/certctl -D${PKG_ROOTDIR}/ rehash"
+ post-uninstall = "/usr/sbin/certctl -D${PKG_ROOTDIR}/ rehash"
+}
diff --git a/release/packages/ucl/ccdconfig-all.ucl b/release/packages/ucl/ccdconfig-all.ucl
new file mode 100644
index 000000000000..76ba9d64db61
--- /dev/null
+++ b/release/packages/ucl/ccdconfig-all.ucl
@@ -0,0 +1,5 @@
+comment = "Concatenated disk driver (ccd) configuration utility"
+desc = <<EOD
+ccdconfig(8) is used to configure the concatenated disk driver, ccd(4).
+ccdconfig(8) may also be started on boot using the "ccd" rc(8) service.
+EOD
diff --git a/release/packages/ucl/certctl-all.ucl b/release/packages/ucl/certctl-all.ucl
new file mode 100644
index 000000000000..b4bc5ae261c5
--- /dev/null
+++ b/release/packages/ucl/certctl-all.ucl
@@ -0,0 +1,4 @@
+comment = "SSL Certificate Utility"
+desc = <<EOD
+SSL Certificate Utility
+EOD
diff --git a/release/packages/ucl/certctl.ucl b/release/packages/ucl/certctl.ucl
new file mode 100644
index 000000000000..7f7adec83159
--- /dev/null
+++ b/release/packages/ucl/certctl.ucl
@@ -0,0 +1,6 @@
+deps {
+ "openssl": {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
diff --git a/release/packages/ucl/clang-all.ucl b/release/packages/ucl/clang-all.ucl
new file mode 100644
index 000000000000..3f79f0acb229
--- /dev/null
+++ b/release/packages/ucl/clang-all.ucl
@@ -0,0 +1,5 @@
+comment = "Clang Utilities"
+desc = <<EOD
+Clang Utilities
+EOD
+licenses = [ NCSA ]
diff --git a/release/packages/ucl/clang.ucl b/release/packages/ucl/clang.ucl
new file mode 100644
index 000000000000..956b769a1ee7
--- /dev/null
+++ b/release/packages/ucl/clang.ucl
@@ -0,0 +1,11 @@
+deps {
+ "lld" {
+ version = "${VERSION}"
+ origin = "base"
+ }
+
+ "libcompiler_rt-dev" {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
diff --git a/release/packages/ucl/clibs-all.ucl b/release/packages/ucl/clibs-all.ucl
new file mode 100644
index 000000000000..69ae018d4d1f
--- /dev/null
+++ b/release/packages/ucl/clibs-all.ucl
@@ -0,0 +1,4 @@
+comment = "Core C Libraries"
+desc = <<EOD
+Core C Libraries
+EOD
diff --git a/release/packages/clibs.ucl b/release/packages/ucl/clibs.ucl
index 093fbb60248a..093fbb60248a 100644
--- a/release/packages/clibs.ucl
+++ b/release/packages/ucl/clibs.ucl
diff --git a/release/packages/ucl/console-tools-all.ucl b/release/packages/ucl/console-tools-all.ucl
new file mode 100644
index 000000000000..53f31b2a9937
--- /dev/null
+++ b/release/packages/ucl/console-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "Console Utilities"
+desc = <<EOD
+Console Utilities
+EOD
diff --git a/release/packages/ucl/cron-all.ucl b/release/packages/ucl/cron-all.ucl
new file mode 100644
index 000000000000..d9edf6bfde52
--- /dev/null
+++ b/release/packages/ucl/cron-all.ucl
@@ -0,0 +1,4 @@
+comment = "cron(8) and crontab(1)"
+desc = <<EOD
+cron(8) and crontab(1)
+EOD
diff --git a/release/packages/ucl/csh-all.ucl b/release/packages/ucl/csh-all.ucl
new file mode 100644
index 000000000000..df4dc71f8dd5
--- /dev/null
+++ b/release/packages/ucl/csh-all.ucl
@@ -0,0 +1,4 @@
+comment = "C Shell"
+desc = <<EOD
+C Shell
+EOD
diff --git a/release/packages/ucl/ctf-tools-all.ucl b/release/packages/ucl/ctf-tools-all.ucl
new file mode 100644
index 000000000000..38ca769f6109
--- /dev/null
+++ b/release/packages/ucl/ctf-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "CTF Utilities"
+desc = <<EOD
+CTF Utilities
+EOD
diff --git a/release/packages/ucl/ctl-all.ucl b/release/packages/ucl/ctl-all.ucl
new file mode 100644
index 000000000000..d24ffabea1a0
--- /dev/null
+++ b/release/packages/ucl/ctl-all.ucl
@@ -0,0 +1,4 @@
+comment = "CAM Target Layer"
+desc = <<EOD
+The CAM Target Layer allows CAM to export storage targets, e.g. via iSCSI.
+EOD
diff --git a/release/packages/ucl/cxgbe-tools-all.ucl b/release/packages/ucl/cxgbe-tools-all.ucl
new file mode 100644
index 000000000000..e2f6132f7ef9
--- /dev/null
+++ b/release/packages/ucl/cxgbe-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "Chelsio cxbge Utilities"
+desc = <<EOD
+Chelsio cxbge Utilities
+EOD
diff --git a/release/packages/ucl/devd-all.ucl b/release/packages/ucl/devd-all.ucl
new file mode 100644
index 000000000000..dc7d162a1930
--- /dev/null
+++ b/release/packages/ucl/devd-all.ucl
@@ -0,0 +1,4 @@
+comment = "Devd Utility and scripts"
+desc = <<EOD
+Devd Utility and scripts
+EOD
diff --git a/release/packages/ucl/devmatch-all.ucl b/release/packages/ucl/devmatch-all.ucl
new file mode 100644
index 000000000000..02dc903fd422
--- /dev/null
+++ b/release/packages/ucl/devmatch-all.ucl
@@ -0,0 +1,4 @@
+comment = "Devmatch Utility"
+desc = <<EOD
+Devmatch Utility
+EOD
diff --git a/release/packages/ucl/dhclient-all.ucl b/release/packages/ucl/dhclient-all.ucl
new file mode 100644
index 000000000000..6785366aea5e
--- /dev/null
+++ b/release/packages/ucl/dhclient-all.ucl
@@ -0,0 +1,4 @@
+comment = "DHCP Client"
+desc = <<EOD
+DHCP Client
+EOD
diff --git a/release/packages/ucl/dma-all.ucl b/release/packages/ucl/dma-all.ucl
new file mode 100644
index 000000000000..e8824acf7a36
--- /dev/null
+++ b/release/packages/ucl/dma-all.ucl
@@ -0,0 +1,4 @@
+comment = "DMA Mail Agent Utilities"
+desc = <<EOD
+DMA Mail Agent Utilities
+EOD
diff --git a/release/packages/ucl/docs-all.ucl b/release/packages/ucl/docs-all.ucl
new file mode 100644
index 000000000000..7159d3f8f4ec
--- /dev/null
+++ b/release/packages/ucl/docs-all.ucl
@@ -0,0 +1,4 @@
+comment = "Documentation"
+desc = <<EOD
+Documentation
+EOD
diff --git a/release/packages/ucl/dtb-all.ucl b/release/packages/ucl/dtb-all.ucl
new file mode 100644
index 000000000000..cc5c1c60f062
--- /dev/null
+++ b/release/packages/ucl/dtb-all.ucl
@@ -0,0 +1,4 @@
+comment = "FreeBSD Devicetree Blobs"
+desc = <<EOD
+FreeBSD Devicetree Blobs
+EOD
diff --git a/release/packages/ucl/dtrace-all.ucl b/release/packages/ucl/dtrace-all.ucl
new file mode 100644
index 000000000000..fb36816123c5
--- /dev/null
+++ b/release/packages/ucl/dtrace-all.ucl
@@ -0,0 +1,4 @@
+comment = "Dtrace Utilities"
+desc = <<EOD
+Dtrace Utilities
+EOD
diff --git a/release/packages/ucl/dwatch-all.ucl b/release/packages/ucl/dwatch-all.ucl
new file mode 100644
index 000000000000..5f7e0fb764ce
--- /dev/null
+++ b/release/packages/ucl/dwatch-all.ucl
@@ -0,0 +1,4 @@
+comment = "Dwatch Utilities"
+desc = <<EOD
+Dwatch Utilities
+EOD
diff --git a/release/packages/ucl/ee-all.ucl b/release/packages/ucl/ee-all.ucl
new file mode 100644
index 000000000000..c003942ad3a9
--- /dev/null
+++ b/release/packages/ucl/ee-all.ucl
@@ -0,0 +1,4 @@
+comment = "Easy Editor Utilities"
+desc = <<EOD
+Easy Editor Utilities
+EOD
diff --git a/release/packages/ucl/efi-tools-all.ucl b/release/packages/ucl/efi-tools-all.ucl
new file mode 100644
index 000000000000..51d5e12189dd
--- /dev/null
+++ b/release/packages/ucl/efi-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "UEFI Utilities"
+desc = <<EOD
+UEFI Utilities
+EOD
diff --git a/release/packages/ucl/examples-all.ucl b/release/packages/ucl/examples-all.ucl
new file mode 100644
index 000000000000..93f0aee16187
--- /dev/null
+++ b/release/packages/ucl/examples-all.ucl
@@ -0,0 +1,4 @@
+comment = "Examples in /usr/share/examples"
+desc = <<EOD
+Examples in /usr/share/examples
+EOD
diff --git a/release/packages/ucl/fd-all.ucl b/release/packages/ucl/fd-all.ucl
new file mode 100644
index 000000000000..7092449174e3
--- /dev/null
+++ b/release/packages/ucl/fd-all.ucl
@@ -0,0 +1,4 @@
+comment = "Floppy disk support"
+desc = <<EOD
+Utilities for formatting and managing floppy disks supported by fdc(4).
+EOD
diff --git a/release/packages/ucl/fetch-all.ucl b/release/packages/ucl/fetch-all.ucl
new file mode 100644
index 000000000000..f9a3e03e6fa4
--- /dev/null
+++ b/release/packages/ucl/fetch-all.ucl
@@ -0,0 +1,4 @@
+comment = "Fetch Utility"
+desc = <<EOD
+Fetch Utility
+EOD
diff --git a/release/packages/ucl/firmware-iwm-all.ucl b/release/packages/ucl/firmware-iwm-all.ucl
new file mode 100644
index 000000000000..6fec27c15351
--- /dev/null
+++ b/release/packages/ucl/firmware-iwm-all.ucl
@@ -0,0 +1,4 @@
+comment = "iwm(4) firmwares"
+desc = <<EOD
+iwm(4) firmwares
+EOD
diff --git a/release/packages/ucl/ftp-all.ucl b/release/packages/ucl/ftp-all.ucl
new file mode 100644
index 000000000000..6275bc46e657
--- /dev/null
+++ b/release/packages/ucl/ftp-all.ucl
@@ -0,0 +1,4 @@
+comment = "FTP Utilities"
+desc = <<EOD
+FTP Utilities
+EOD
diff --git a/release/packages/ucl/ftpd-all.ucl b/release/packages/ucl/ftpd-all.ucl
new file mode 100644
index 000000000000..cbaa078123d5
--- /dev/null
+++ b/release/packages/ucl/ftpd-all.ucl
@@ -0,0 +1,4 @@
+comment = "FTP Daemon"
+desc = <<EOD
+FTP Daemon
+EOD
diff --git a/release/packages/ucl/fwget-all.ucl b/release/packages/ucl/fwget-all.ucl
new file mode 100644
index 000000000000..7a6f9dff5cc9
--- /dev/null
+++ b/release/packages/ucl/fwget-all.ucl
@@ -0,0 +1,4 @@
+comment = "FWGET Utility"
+desc = <<EOD
+FWGET Utility
+EOD
diff --git a/release/packages/ucl/games-all.ucl b/release/packages/ucl/games-all.ucl
new file mode 100644
index 000000000000..747638fe6a8f
--- /dev/null
+++ b/release/packages/ucl/games-all.ucl
@@ -0,0 +1,4 @@
+comment = "Games"
+desc = <<EOD
+Games
+EOD
diff --git a/release/packages/ucl/geom-all.ucl b/release/packages/ucl/geom-all.ucl
new file mode 100644
index 000000000000..6d80b4458f64
--- /dev/null
+++ b/release/packages/ucl/geom-all.ucl
@@ -0,0 +1,4 @@
+comment = "GEOM Utilitites"
+desc = <<EOD
+GEOM Utilitites
+EOD
diff --git a/release/packages/ucl/ggate-all.ucl b/release/packages/ucl/ggate-all.ucl
new file mode 100644
index 000000000000..0d0b984b440e
--- /dev/null
+++ b/release/packages/ucl/ggate-all.ucl
@@ -0,0 +1,4 @@
+comment = "GEOM Gate Utilities"
+desc = <<EOD
+GEOM Gate Utilities
+EOD
diff --git a/release/packages/ucl/hast-all.ucl b/release/packages/ucl/hast-all.ucl
new file mode 100644
index 000000000000..b2441ddb6866
--- /dev/null
+++ b/release/packages/ucl/hast-all.ucl
@@ -0,0 +1,4 @@
+comment = "Highly Available Storage daemon"
+desc = <<EOD
+Highly Available Storage daemon
+EOD
diff --git a/release/packages/ucl/hostapd-all.ucl b/release/packages/ucl/hostapd-all.ucl
new file mode 100644
index 000000000000..c2e0d0c0bd11
--- /dev/null
+++ b/release/packages/ucl/hostapd-all.ucl
@@ -0,0 +1,4 @@
+comment = "802.11 Access Point Daemon an Utilities"
+desc = <<EOD
+802.11 Access Point Daemon an Utilities
+EOD
diff --git a/release/packages/ucl/hyperv-tools-all.ucl b/release/packages/ucl/hyperv-tools-all.ucl
new file mode 100644
index 000000000000..e16fd5b4b053
--- /dev/null
+++ b/release/packages/ucl/hyperv-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "Microsoft HyperV Utilities"
+desc = <<EOD
+Microsoft HyperV Utilities
+EOD
diff --git a/release/packages/ucl/inetd-all.ucl b/release/packages/ucl/inetd-all.ucl
new file mode 100644
index 000000000000..731769bdc399
--- /dev/null
+++ b/release/packages/ucl/inetd-all.ucl
@@ -0,0 +1,4 @@
+comment = "Internet super-server"
+desc = <<EOD
+Internet super-server
+EOD
diff --git a/release/packages/ucl/ipf-all.ucl b/release/packages/ucl/ipf-all.ucl
new file mode 100644
index 000000000000..bd1bec5232de
--- /dev/null
+++ b/release/packages/ucl/ipf-all.ucl
@@ -0,0 +1,4 @@
+comment = "IP Filter (ipf) packet filter management tools"
+desc = <<EOD
+IP Filter (ipf) is a stateful packet filter for IPv4 and IPv6 networks.
+EOD
diff --git a/release/packages/ucl/ipfw-all.ucl b/release/packages/ucl/ipfw-all.ucl
new file mode 100644
index 000000000000..0884d48aa071
--- /dev/null
+++ b/release/packages/ucl/ipfw-all.ucl
@@ -0,0 +1,4 @@
+comment = "ipfw (IP firewall) management utilities"
+desc = <<EOD
+ipfw provides stateful packet filtering, NAT and traffic shaping for IP traffic.
+EOD
diff --git a/release/packages/ucl/iscsi-all.ucl b/release/packages/ucl/iscsi-all.ucl
new file mode 100644
index 000000000000..e81961cb40a5
--- /dev/null
+++ b/release/packages/ucl/iscsi-all.ucl
@@ -0,0 +1,6 @@
+comment = "iSCSI target, initiator, and management tools"
+desc = <<EOD
+iSCSI allows a block device to be exported from one system to another over a
+network. This package provides the iSCSI target and initiator and associated
+management tools.
+EOD
diff --git a/release/packages/ucl/jail-all.ucl b/release/packages/ucl/jail-all.ucl
new file mode 100644
index 000000000000..da844b500ad5
--- /dev/null
+++ b/release/packages/ucl/jail-all.ucl
@@ -0,0 +1,4 @@
+comment = "Jail Utilities"
+desc = <<EOD
+Jail Utilities
+EOD
diff --git a/release/packages/ucl/kerberos-all.ucl b/release/packages/ucl/kerberos-all.ucl
new file mode 100644
index 000000000000..6fb7f059296b
--- /dev/null
+++ b/release/packages/ucl/kerberos-all.ucl
@@ -0,0 +1,4 @@
+comment = "Kerberos Utilities"
+desc = <<EOD
+Kerberos Utilities
+EOD
diff --git a/release/packages/ucl/kerberos-lib-all.ucl b/release/packages/ucl/kerberos-lib-all.ucl
new file mode 100644
index 000000000000..ab769ee16f96
--- /dev/null
+++ b/release/packages/ucl/kerberos-lib-all.ucl
@@ -0,0 +1,4 @@
+comment = "Kerberos Libraries"
+desc = <<EOD
+Kerberos Libraries
+EOD
diff --git a/release/packages/ucl/kernel-all.ucl b/release/packages/ucl/kernel-all.ucl
new file mode 100644
index 000000000000..31671602a947
--- /dev/null
+++ b/release/packages/ucl/kernel-all.ucl
@@ -0,0 +1,4 @@
+comment = "FreeBSD ${KERNEL_NAME} Kernel ${KERNEL_FLAVOR}"
+desc = <<EOD
+FreeBSD ${KERNEL_NAME} Kernel ${KERNEL_FLAVOR}
+EOD
diff --git a/release/packages/ucl/lib9p-all.ucl b/release/packages/ucl/lib9p-all.ucl
new file mode 100644
index 000000000000..76a5b8de4596
--- /dev/null
+++ b/release/packages/ucl/lib9p-all.ucl
@@ -0,0 +1,5 @@
+comment = "9P network protocol library"
+desc = <<EOD
+lib9p implements the server side of the 9p2000, 9p2000.u and 9p2000.L revisions
+of the 9P protocol
+EOD
diff --git a/release/packages/ucl/libarchive-all.ucl b/release/packages/ucl/libarchive-all.ucl
new file mode 100644
index 000000000000..9b98404b3235
--- /dev/null
+++ b/release/packages/ucl/libarchive-all.ucl
@@ -0,0 +1,4 @@
+comment = "Archive handling library"
+desc = <<EOD
+libarchive allows applications to read and write archive files of various types.
+EOD
diff --git a/release/packages/ucl/libbegemot-all.ucl b/release/packages/ucl/libbegemot-all.ucl
new file mode 100644
index 000000000000..7a2f19df8e0e
--- /dev/null
+++ b/release/packages/ucl/libbegemot-all.ucl
@@ -0,0 +1,5 @@
+comment = "rpoll(3) interface for event-driven I/O"
+desc = <<EOD
+libbegemot provides rpoll(3), a simplified interface for handling event-driven
+I/O programming.
+EOD
diff --git a/release/packages/ucl/libblocksruntime-all.ucl b/release/packages/ucl/libblocksruntime-all.ucl
new file mode 100644
index 000000000000..818c32174a6c
--- /dev/null
+++ b/release/packages/ucl/libblocksruntime-all.ucl
@@ -0,0 +1,4 @@
+comment = "LLVM BlocksRuntime library"
+desc = <<EOD
+The LLVM libBlocksRuntime library.
+EOD
diff --git a/release/packages/ucl/libbsdstat-all.ucl b/release/packages/ucl/libbsdstat-all.ucl
new file mode 100644
index 000000000000..4db0059827a0
--- /dev/null
+++ b/release/packages/ucl/libbsdstat-all.ucl
@@ -0,0 +1,5 @@
+comment = "Periodic statistics library"
+desc = <<EOD
+libbsdstat is a library for managing and display periodically collected
+statistics.
+EOD
diff --git a/release/packages/ucl/libbsm-all.ucl b/release/packages/ucl/libbsm-all.ucl
new file mode 100644
index 000000000000..0a60ada09075
--- /dev/null
+++ b/release/packages/ucl/libbsm-all.ucl
@@ -0,0 +1,6 @@
+comment = "Basic Security Module (BSM) audit library"
+desc = <<EOD
+The libbsm library routines provide an interface to BSM audit record streams,
+allowing both the parsing of existing audit streams, as well as the creation of
+new audit records and streams.
+EOD
diff --git a/release/packages/ucl/libbz2-all.ucl b/release/packages/ucl/libbz2-all.ucl
new file mode 100644
index 000000000000..c8141bcb1d11
--- /dev/null
+++ b/release/packages/ucl/libbz2-all.ucl
@@ -0,0 +1,5 @@
+comment = "bzip2 compression library"
+desc = <<EOD
+libbz2 allows applications to compress and decompress data using the bzip2
+compression algorithm.
+EOD
diff --git a/release/packages/ucl/libcasper-all.ucl b/release/packages/ucl/libcasper-all.ucl
new file mode 100644
index 000000000000..b25a82a32050
--- /dev/null
+++ b/release/packages/ucl/libcasper-all.ucl
@@ -0,0 +1,5 @@
+comment = "Casper library"
+desc = <<EOD
+The libcasper library provides for the control of application capabilities
+through the casper process.
+EOD
diff --git a/release/packages/ucl/libcompat-all.ucl b/release/packages/ucl/libcompat-all.ucl
new file mode 100644
index 000000000000..a562f155dc5f
--- /dev/null
+++ b/release/packages/ucl/libcompat-all.ucl
@@ -0,0 +1,4 @@
+comment = "Compatibility library"
+desc = <<EOD
+libcompat provides implementations of some obsolete library functions.
+EOD
diff --git a/release/packages/ucl/libcompiler_rt-all.ucl b/release/packages/ucl/libcompiler_rt-all.ucl
new file mode 100644
index 000000000000..f21e629ac88c
--- /dev/null
+++ b/release/packages/ucl/libcompiler_rt-all.ucl
@@ -0,0 +1,4 @@
+comment = "LLVM compiler_rt library"
+desc = <<EOD
+The libcompiler_rt library from LLVM.
+EOD
diff --git a/release/packages/ucl/libcuse-all.ucl b/release/packages/ucl/libcuse-all.ucl
new file mode 100644
index 000000000000..de972d4b8d3a
--- /dev/null
+++ b/release/packages/ucl/libcuse-all.ucl
@@ -0,0 +1,5 @@
+comment = "Userland character device library"
+desc = <<EOD
+The libcuse library contains functions to create a character device in
+userspace.
+EOD
diff --git a/release/packages/ucl/libdwarf-all.ucl b/release/packages/ucl/libdwarf-all.ucl
new file mode 100644
index 000000000000..4226dbfee592
--- /dev/null
+++ b/release/packages/ucl/libdwarf-all.ucl
@@ -0,0 +1,6 @@
+comment = "DWARF access library"
+desc = <<EOD
+The DWARF Access Library provides functions that allow an application to read
+and write debugging information in object files. The format of debugging
+information accessible through this API is defined by the DWARF standard.
+EOD
diff --git a/release/packages/ucl/libevent1-all.ucl b/release/packages/ucl/libevent1-all.ucl
new file mode 100644
index 000000000000..511e077233d2
--- /dev/null
+++ b/release/packages/ucl/libevent1-all.ucl
@@ -0,0 +1,4 @@
+comment = "Private libevent1 library"
+desc = <<EOD
+A private library used by applications in the base system.
+EOD
diff --git a/release/packages/ucl/libexecinfo-all.ucl b/release/packages/ucl/libexecinfo-all.ucl
new file mode 100644
index 000000000000..8a0c110381be
--- /dev/null
+++ b/release/packages/ucl/libexecinfo-all.ucl
@@ -0,0 +1,5 @@
+comment = "NetBSD stack backtrace library"
+desc = <<EOD
+libexecinfo provides the backtrace(3) interface to allow an application to
+examine its current call stack.
+EOD
diff --git a/release/packages/ucl/libipt-all.ucl b/release/packages/ucl/libipt-all.ucl
new file mode 100644
index 000000000000..eb0ef6a32d40
--- /dev/null
+++ b/release/packages/ucl/libipt-all.ucl
@@ -0,0 +1,6 @@
+comment = "Intel(R) Processor Trace decoder library"
+desc = <<EOD
+The Intel Processor Trace (Intel PT) Decoder Library is Intel's reference
+implementation for decoding Intel PT. It can be used as a standalone library
+or it can be partially or fully integrated into your tool.
+EOD
diff --git a/release/packages/ucl/libldns-all.ucl b/release/packages/ucl/libldns-all.ucl
new file mode 100644
index 000000000000..55de2701bbb8
--- /dev/null
+++ b/release/packages/ucl/libldns-all.ucl
@@ -0,0 +1,6 @@
+comment="NLnet Labs LDNS library"
+desc = <<EOD
+The goal of ldns is to simplify DNS programming in C. ldns supports all
+low-level DNS and DNSSEC operations. It also defines a higher level API which
+allows a programmer to for instance create or sign packets.
+EOD
diff --git a/release/packages/ucl/liblzma-all.ucl b/release/packages/ucl/liblzma-all.ucl
new file mode 100644
index 000000000000..0b1bfcbcecc6
--- /dev/null
+++ b/release/packages/ucl/liblzma-all.ucl
@@ -0,0 +1,5 @@
+comment = "XZ LZMA library"
+desc = <<EOD
+liblzma allows applications to compress and decompress data using the XZ
+compression algorithm.
+EOD
diff --git a/release/packages/ucl/libmagic-all.ucl b/release/packages/ucl/libmagic-all.ucl
new file mode 100644
index 000000000000..2a29aacb260d
--- /dev/null
+++ b/release/packages/ucl/libmagic-all.ucl
@@ -0,0 +1,5 @@
+comment = "Magic number recognition library"
+desc = <<EOD
+libmagic allows an application to identity data using the magic(5) magic number
+database.
+EOD
diff --git a/release/packages/ucl/libopencsd-all.ucl b/release/packages/ucl/libopencsd-all.ucl
new file mode 100644
index 000000000000..af46292dceed
--- /dev/null
+++ b/release/packages/ucl/libopencsd-all.ucl
@@ -0,0 +1,5 @@
+comment = "ARM CoreSight Trace Decode Library"
+desc = <<EOD
+This library provides an API suitable for the decode of ARM CoreSight
+trace streams.
+EOD
diff --git a/release/packages/ucl/libpathconv-all.ucl b/release/packages/ucl/libpathconv-all.ucl
new file mode 100644
index 000000000000..872d34a24e6a
--- /dev/null
+++ b/release/packages/ucl/libpathconv-all.ucl
@@ -0,0 +1,5 @@
+comment = "Library for handling relative and absolute pathnames"
+desc = <<EOD
+libpathconv provides the abs2rel() and rel2abs() functions to convert between
+absolute and relative pathnames.
+EOD
diff --git a/release/packages/ucl/librpcsec_gss-all.ucl b/release/packages/ucl/librpcsec_gss-all.ucl
new file mode 100644
index 000000000000..67f481e9e9b5
--- /dev/null
+++ b/release/packages/ucl/librpcsec_gss-all.ucl
@@ -0,0 +1,5 @@
+comment = "RPC GSS-API authentication library"
+desc = <<EOD
+librpcsec_gss provides an API to allow applications to interact with the
+RPCSEC_GSS security mechanism.
+EOD
diff --git a/release/packages/ucl/librss-all.ucl b/release/packages/ucl/librss-all.ucl
new file mode 100644
index 000000000000..3c09025356a8
--- /dev/null
+++ b/release/packages/ucl/librss-all.ucl
@@ -0,0 +1,5 @@
+comment = "Receive-side scaling library"
+desc = <<EOD
+The librss library and the functions it provides are used for both fetching the
+system RSS configuration and interacting with RSS aware sockets.
+EOD
diff --git a/release/packages/ucl/libsdp-all.ucl b/release/packages/ucl/libsdp-all.ucl
new file mode 100644
index 000000000000..31f04e089470
--- /dev/null
+++ b/release/packages/ucl/libsdp-all.ucl
@@ -0,0 +1,5 @@
+comment = "Bluetooth Service Discovery Protocol library"
+desc = <<EOD
+libsdp allows applications to interact with the Bluetooth Service Discovery
+Protocol.
+EOD
diff --git a/release/packages/ucl/libsqlite3-all.ucl b/release/packages/ucl/libsqlite3-all.ucl
new file mode 100644
index 000000000000..55ac00863bf1
--- /dev/null
+++ b/release/packages/ucl/libsqlite3-all.ucl
@@ -0,0 +1,4 @@
+comment = "Private SQLite library"
+desc = <<EOD
+A private version of SQLite for use by applications in the base system.
+EOD
diff --git a/release/packages/ucl/libstdbuf-all.ucl b/release/packages/ucl/libstdbuf-all.ucl
new file mode 100644
index 000000000000..d85f2d3b70f2
--- /dev/null
+++ b/release/packages/ucl/libstdbuf-all.ucl
@@ -0,0 +1,6 @@
+comment = "Preloaded library to change standard streams initial buffering"
+desc = <<EOD
+The libstdbuf library is meant to be preloaded with the LD_PRELOAD environment
+variable to as to change the initial buffering of standard input, standard
+output and standard error streams.
+EOD
diff --git a/release/packages/ucl/libstdthreads-all.ucl b/release/packages/ucl/libstdthreads-all.ucl
new file mode 100644
index 000000000000..5af147ea5ca7
--- /dev/null
+++ b/release/packages/ucl/libstdthreads-all.ucl
@@ -0,0 +1,4 @@
+comment = "C11 threading library"
+desc = <<EOD
+libstdthreads provides the thread-control interface defined in the C99 standard.
+EOD
diff --git a/release/packages/ucl/libthread_db-all.ucl b/release/packages/ucl/libthread_db-all.ucl
new file mode 100644
index 000000000000..ba2164a3f211
--- /dev/null
+++ b/release/packages/ucl/libthread_db-all.ucl
@@ -0,0 +1,5 @@
+comment = "Library for interacting with threaded processes"
+desc = <<EOD
+libthread_db is used by the debugger to examine and interact with a
+multithreaded process being debugger.
+EOD
diff --git a/release/packages/ucl/libucl-all.ucl b/release/packages/ucl/libucl-all.ucl
new file mode 100644
index 000000000000..d04c2109df06
--- /dev/null
+++ b/release/packages/ucl/libucl-all.ucl
@@ -0,0 +1,5 @@
+comment = "Private Universal Configuration Library (UCL) library"
+desc = <<EOD
+A private library for reading and writing UCL files, for used by applications
+in the base system.
+EOD
diff --git a/release/packages/ucl/libufs-all.ucl b/release/packages/ucl/libufs-all.ucl
new file mode 100644
index 000000000000..d86a84bbd637
--- /dev/null
+++ b/release/packages/ucl/libufs-all.ucl
@@ -0,0 +1,8 @@
+comment = "Low-level access to UFS filesystems"
+desc = <<EOD
+The libufs library and the functions it provides are used for implementing
+utilities which need to access a UFS file system at a low level from userland.
+Facilities provided are used to implement utilities such as newfs(8) and
+dumpfs(8). The libufs library is designed to be simple, and to provide
+functions that are traditionally useful to have.
+EOD
diff --git a/release/packages/ucl/libvgl-all.ucl b/release/packages/ucl/libvgl-all.ucl
new file mode 100644
index 000000000000..fea63d807de0
--- /dev/null
+++ b/release/packages/ucl/libvgl-all.ucl
@@ -0,0 +1,13 @@
+comment = "Video Graphics Library"
+desc = <<EOD
+libvgl is a library that enables the programmer access to the graphics modes
+supported by the console driver (syscons). The library takes care of
+programming the actual video hardware, and provides a number of simple
+functions to do various graphic operations. There is also support for a mouse
+via the standard mouse system in FreeBSD, including the ability to
+transparently have a mouse pointer superimposed on the graphic image currently
+being worked on. The library takes care of screen switching by storing the
+current image in memory before switching to another virtual console, and
+restoring when the user switches back. This allows several graphic
+applications at once, but on different virtual consoles.
+EOD
diff --git a/release/packages/ucl/libvmmapi-all.ucl b/release/packages/ucl/libvmmapi-all.ucl
new file mode 100644
index 000000000000..976fb1bfce47
--- /dev/null
+++ b/release/packages/ucl/libvmmapi-all.ucl
@@ -0,0 +1,4 @@
+comment = "Front-end to vmm(4) virtualization driver"
+desc = <<EOD
+libvmmapi provides an interface for applications to access the vmm(4) driver.
+EOD
diff --git a/release/packages/ucl/liby-all.ucl b/release/packages/ucl/liby-all.ucl
new file mode 100644
index 000000000000..575aeda0a1ef
--- /dev/null
+++ b/release/packages/ucl/liby-all.ucl
@@ -0,0 +1,5 @@
+comment = "YACC library"
+desc = <<EOD
+liby provides default implementations of main() and yyerror() for use with
+applications which use yacc(1).
+EOD
diff --git a/release/packages/ucl/libyaml-all.ucl b/release/packages/ucl/libyaml-all.ucl
new file mode 100644
index 000000000000..f98a5a39362f
--- /dev/null
+++ b/release/packages/ucl/libyaml-all.ucl
@@ -0,0 +1,5 @@
+comment = "Private YAML library"
+desc = <<EOD
+The libprivateyaml library is used by the FreeBSD base system to parse YAML
+files. This library is not intended for use outside of the base system.
+EOD
diff --git a/release/packages/ucl/libzfs-all.ucl b/release/packages/ucl/libzfs-all.ucl
new file mode 100644
index 000000000000..bd53521f3aa0
--- /dev/null
+++ b/release/packages/ucl/libzfs-all.ucl
@@ -0,0 +1,5 @@
+comment = "ZFS filesystem library"
+desc = <<EOD
+libzfs allows applications to manage ZFS pools and filesystems. Several
+libraries which libzfs requires are also provided.
+EOD
diff --git a/release/packages/ucl/lld-all.ucl b/release/packages/ucl/lld-all.ucl
new file mode 100644
index 000000000000..03daf1b235e6
--- /dev/null
+++ b/release/packages/ucl/lld-all.ucl
@@ -0,0 +1,6 @@
+comment = "ELF linker from the LLVM project"
+desc = <<EOD
+ld.lld is the ELF linker provided by LLVM.
+EOD
+
+licenses = [ NCSA ]
diff --git a/release/packages/ucl/lldb-all.ucl b/release/packages/ucl/lldb-all.ucl
new file mode 100644
index 000000000000..da481c026981
--- /dev/null
+++ b/release/packages/ucl/lldb-all.ucl
@@ -0,0 +1,6 @@
+comment = "LLVM debugger"
+desc = <<EOD
+lldb is a source-level debugger from the LLVM project.
+EOD
+
+licenses = [ NCSA ]
diff --git a/release/packages/ucl/locales-all.ucl b/release/packages/ucl/locales-all.ucl
new file mode 100644
index 000000000000..6fc53ab10fca
--- /dev/null
+++ b/release/packages/ucl/locales-all.ucl
@@ -0,0 +1,4 @@
+comment = "Locale definitions"
+desc = <<EOD
+Provides the locale definitions (LC_*) for supported locales.
+EOD
diff --git a/release/packages/ucl/lp-all.ucl b/release/packages/ucl/lp-all.ucl
new file mode 100644
index 000000000000..c400038458d0
--- /dev/null
+++ b/release/packages/ucl/lp-all.ucl
@@ -0,0 +1,4 @@
+comment = "Printer subsystem"
+desc = <<EOD
+Printer subsystem
+EOD
diff --git a/release/packages/ucl/manuals-all.ucl b/release/packages/ucl/manuals-all.ucl
new file mode 100644
index 000000000000..9acfd90159ae
--- /dev/null
+++ b/release/packages/ucl/manuals-all.ucl
@@ -0,0 +1,4 @@
+comment = "Manual Pages"
+desc = <<EOD
+Manual Pages
+EOD
diff --git a/release/packages/ucl/mlx-tools-all.ucl b/release/packages/ucl/mlx-tools-all.ucl
new file mode 100644
index 000000000000..4af47252c71d
--- /dev/null
+++ b/release/packages/ucl/mlx-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "Mellanox Utilities"
+desc = <<EOD
+Mellanox Utilities
+EOD
diff --git a/release/packages/ucl/mtree-all.ucl b/release/packages/ucl/mtree-all.ucl
new file mode 100644
index 000000000000..b921c51a6afb
--- /dev/null
+++ b/release/packages/ucl/mtree-all.ucl
@@ -0,0 +1,4 @@
+comment = "MTREE Files"
+desc = <<EOD
+MTREE Files
+EOD
diff --git a/release/packages/ucl/natd-all.ucl b/release/packages/ucl/natd-all.ucl
new file mode 100644
index 000000000000..db5103c1d591
--- /dev/null
+++ b/release/packages/ucl/natd-all.ucl
@@ -0,0 +1,4 @@
+comment = "Network Address Translation (NAT) daemon for ipfw"
+desc = <<EOD
+natd provides userland NAT support for ipfw using divert(4) sockets.
+EOD
diff --git a/release/packages/ucl/netmap-all.ucl b/release/packages/ucl/netmap-all.ucl
new file mode 100644
index 000000000000..e0c0c65b8fb8
--- /dev/null
+++ b/release/packages/ucl/netmap-all.ucl
@@ -0,0 +1,4 @@
+comment = "Netmap Library and Utilities"
+desc = <<EOD
+Netmap Library and Utilities
+EOD
diff --git a/release/packages/ucl/newsyslog-all.ucl b/release/packages/ucl/newsyslog-all.ucl
new file mode 100644
index 000000000000..e52b34dbdcba
--- /dev/null
+++ b/release/packages/ucl/newsyslog-all.ucl
@@ -0,0 +1,4 @@
+comment = "Newsyslog Utility"
+desc = <<EOD
+Newsyslog Utility
+EOD
diff --git a/release/packages/ucl/nfs-all.ucl b/release/packages/ucl/nfs-all.ucl
new file mode 100644
index 000000000000..a53d2f028975
--- /dev/null
+++ b/release/packages/ucl/nfs-all.ucl
@@ -0,0 +1,4 @@
+comment = "NFS Utilities"
+desc = <<EOD
+NFS Utilities
+EOD
diff --git a/release/packages/ucl/ntp-all.ucl b/release/packages/ucl/ntp-all.ucl
new file mode 100644
index 000000000000..c01ae91c31cf
--- /dev/null
+++ b/release/packages/ucl/ntp-all.ucl
@@ -0,0 +1,4 @@
+comment = "Network Time Protocol server and client"
+desc = <<EOD
+Network Time Protocol server and client
+EOD
diff --git a/release/packages/ucl/nuageinit-all.ucl b/release/packages/ucl/nuageinit-all.ucl
new file mode 100644
index 000000000000..4d510b799fa7
--- /dev/null
+++ b/release/packages/ucl/nuageinit-all.ucl
@@ -0,0 +1,4 @@
+comment = "CloudInit support scripts"
+desc = <<EOD
+CloudInit support scripts
+EOD
diff --git a/release/packages/ucl/nvme-tools-all.ucl b/release/packages/ucl/nvme-tools-all.ucl
new file mode 100644
index 000000000000..5863af2d5e34
--- /dev/null
+++ b/release/packages/ucl/nvme-tools-all.ucl
@@ -0,0 +1,4 @@
+comment = "NVME Utilities"
+desc = <<EOD
+NVME Utilities
+EOD
diff --git a/release/packages/ucl/openssl-all.ucl b/release/packages/ucl/openssl-all.ucl
new file mode 100644
index 000000000000..8dd2da021f0a
--- /dev/null
+++ b/release/packages/ucl/openssl-all.ucl
@@ -0,0 +1,4 @@
+comment = "OpenSSL Utility"
+desc = <<EOD
+OpenSSL Utility
+EOD
diff --git a/release/packages/ucl/openssl-lib-all.ucl b/release/packages/ucl/openssl-lib-all.ucl
new file mode 100644
index 000000000000..c81dd44855cd
--- /dev/null
+++ b/release/packages/ucl/openssl-lib-all.ucl
@@ -0,0 +1,4 @@
+comment = "OpenSSL Libraries"
+desc = <<EOD
+OpenSSL Libraries
+EOD
diff --git a/release/packages/ucl/periodic-all.ucl b/release/packages/ucl/periodic-all.ucl
new file mode 100644
index 000000000000..569bf8d829c4
--- /dev/null
+++ b/release/packages/ucl/periodic-all.ucl
@@ -0,0 +1,4 @@
+comment = "Periodic Utility"
+desc = <<EOD
+Periodic Utility
+EOD
diff --git a/release/packages/ucl/periodic.ucl b/release/packages/ucl/periodic.ucl
new file mode 100644
index 000000000000..6f85d2ab744b
--- /dev/null
+++ b/release/packages/ucl/periodic.ucl
@@ -0,0 +1,6 @@
+deps {
+ "cron" {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
diff --git a/release/packages/ucl/pf-all.ucl b/release/packages/ucl/pf-all.ucl
new file mode 100644
index 000000000000..4b58fa4f6364
--- /dev/null
+++ b/release/packages/ucl/pf-all.ucl
@@ -0,0 +1,4 @@
+comment = "OpenBSD packet filter"
+desc = <<EOD
+pf is an advanced stateful packet filter developed by the OpenBSD project.
+EOD
diff --git a/release/packages/ucl/pkg-bootstrap-all.ucl b/release/packages/ucl/pkg-bootstrap-all.ucl
new file mode 100644
index 000000000000..9ca6ccd2af58
--- /dev/null
+++ b/release/packages/ucl/pkg-bootstrap-all.ucl
@@ -0,0 +1,4 @@
+comment = "pkg bootstrap Utility"
+desc = <<EOD
+pkg bootstrap Utility
+EOD
diff --git a/release/packages/ucl/ppp-all.ucl b/release/packages/ucl/ppp-all.ucl
new file mode 100644
index 000000000000..454e54b7b872
--- /dev/null
+++ b/release/packages/ucl/ppp-all.ucl
@@ -0,0 +1,5 @@
+comment = "Userland PPP implementation"
+desc = <<EOD
+ppp(8) is a userland implementations of the Point to Point Protocol for serial
+lines and Ethernet (PPPoE).
+EOD
diff --git a/release/packages/ucl/quotacheck-all.ucl b/release/packages/ucl/quotacheck-all.ucl
new file mode 100644
index 000000000000..18b2c3d9bd5c
--- /dev/null
+++ b/release/packages/ucl/quotacheck-all.ucl
@@ -0,0 +1,8 @@
+comment = "Filesystem quota consistency checker"
+desc = <<EOD
+The quotacheck utility examines each file system, builds a table of current
+disk usage, and compares this table against that recorded in the disk quota
+file for the file system. If any inconsistencies are detected, both the quota
+file and the current system copy of the incorrect quotas are updated (the
+latter only occurs if an active file system is checked).
+EOD
diff --git a/release/packages/ucl/rc-all.ucl b/release/packages/ucl/rc-all.ucl
new file mode 100644
index 000000000000..04ed0dafacf0
--- /dev/null
+++ b/release/packages/ucl/rc-all.ucl
@@ -0,0 +1,4 @@
+comment = "RC Scripts"
+desc = <<EOD
+RC Scripts
+EOD
diff --git a/release/packages/ucl/rcmds-all.ucl b/release/packages/ucl/rcmds-all.ucl
new file mode 100644
index 000000000000..db51d52ed246
--- /dev/null
+++ b/release/packages/ucl/rcmds-all.ucl
@@ -0,0 +1,7 @@
+comment = "BSD/SunOS remote status commands"
+desc = <<EOD
+The BSD/SunOS remote status commands, which can be used to query or interact
+with remote hosts over the network. This includes the command-line utilities
+rwho, ruptime, rup, rusers and rwall and the daemons rwhod, rpc.rstatd,
+rpc.rusersd, and rpc.rwalld.
+EOD
diff --git a/release/packages/ucl/rcmds.ucl b/release/packages/ucl/rcmds.ucl
new file mode 100644
index 000000000000..88a4916675dc
--- /dev/null
+++ b/release/packages/ucl/rcmds.ucl
@@ -0,0 +1,8 @@
+deps {
+ # The RPC daemons require rpcbind.
+ "utilities" {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
+
diff --git a/release/packages/ucl/rdma-all.ucl b/release/packages/ucl/rdma-all.ucl
new file mode 100644
index 000000000000..313c2b7d17e0
--- /dev/null
+++ b/release/packages/ucl/rdma-all.ucl
@@ -0,0 +1 @@
+comment = "RDMA Utilities"
diff --git a/release/packages/ucl/rescue-all.ucl b/release/packages/ucl/rescue-all.ucl
new file mode 100644
index 000000000000..da870079bbb7
--- /dev/null
+++ b/release/packages/ucl/rescue-all.ucl
@@ -0,0 +1,4 @@
+comment = "Rescue Utilities"
+desc = <<EOD
+Rescue Utilities
+EOD
diff --git a/release/packages/ucl/resolvconf-all.ucl b/release/packages/ucl/resolvconf-all.ucl
new file mode 100644
index 000000000000..a2d2e0debfa1
--- /dev/null
+++ b/release/packages/ucl/resolvconf-all.ucl
@@ -0,0 +1,4 @@
+comment = "Resolvconf Utility and scripts"
+desc = <<EOD
+Resolvconf Utility and scripts
+EOD
diff --git a/release/packages/ucl/runtime-all.ucl b/release/packages/ucl/runtime-all.ucl
new file mode 100644
index 000000000000..f614a3ef3d43
--- /dev/null
+++ b/release/packages/ucl/runtime-all.ucl
@@ -0,0 +1,4 @@
+comment = "FreeBSD Base System"
+desc = <<EOD
+FreeBSD Base System
+EOD
diff --git a/release/packages/runtime.ucl b/release/packages/ucl/runtime.ucl
index b04bc32f33cc..b04bc32f33cc 100644
--- a/release/packages/runtime.ucl
+++ b/release/packages/ucl/runtime.ucl
diff --git a/release/packages/ucl/sendmail-all.ucl b/release/packages/ucl/sendmail-all.ucl
new file mode 100644
index 000000000000..2711e33a31a8
--- /dev/null
+++ b/release/packages/ucl/sendmail-all.ucl
@@ -0,0 +1,4 @@
+comment = "Sendmail Utilities"
+desc = <<EOD
+Sendmail Utilities
+EOD
diff --git a/release/packages/ucl/smbutils-all.ucl b/release/packages/ucl/smbutils-all.ucl
new file mode 100644
index 000000000000..779179ca3875
--- /dev/null
+++ b/release/packages/ucl/smbutils-all.ucl
@@ -0,0 +1,4 @@
+comment = "SMB Utilities"
+desc = <<EOD
+SMB Utilities
+EOD
diff --git a/release/packages/ucl/src-all.ucl b/release/packages/ucl/src-all.ucl
new file mode 100644
index 000000000000..15b2b7d5b29d
--- /dev/null
+++ b/release/packages/ucl/src-all.ucl
@@ -0,0 +1,5 @@
+comment = "System userland source code"
+desc = <<EOD
+The source code used to rebuild the system, located in /usr/src.
+This package includes everything except the kernel source code.
+EOD
diff --git a/release/packages/ucl/src-sys-all.ucl b/release/packages/ucl/src-sys-all.ucl
new file mode 100644
index 000000000000..9b1c5b64bfbb
--- /dev/null
+++ b/release/packages/ucl/src-sys-all.ucl
@@ -0,0 +1,5 @@
+comment = "System kernel source code"
+desc = <<EOD
+The source code used to rebuild the system, located in /usr/src.
+This package includes the kernel source code.
+EOD
diff --git a/release/packages/ucl/ssh-all.ucl b/release/packages/ucl/ssh-all.ucl
new file mode 100644
index 000000000000..8159391eab08
--- /dev/null
+++ b/release/packages/ucl/ssh-all.ucl
@@ -0,0 +1,5 @@
+comment = "Secure Shell Utilities"
+desc = <<EOD
+Secure Shell Utilities
+EOD
+licenses = [ ISCL ]
diff --git a/release/packages/ucl/syscons-data-all.ucl b/release/packages/ucl/syscons-data-all.ucl
new file mode 100644
index 000000000000..9f59bfd60588
--- /dev/null
+++ b/release/packages/ucl/syscons-data-all.ucl
@@ -0,0 +1,4 @@
+comment = "syscons(4) fonts and keymaps"
+desc = <<EOD
+Fonts and keymaps for use with the legacy syscons(4) video console driver.
+EOD
diff --git a/release/packages/ucl/syslogd-all.ucl b/release/packages/ucl/syslogd-all.ucl
new file mode 100644
index 000000000000..0f82c31fdf0f
--- /dev/null
+++ b/release/packages/ucl/syslogd-all.ucl
@@ -0,0 +1,4 @@
+comment = "Syslog Daemon"
+desc = <<EOD
+Syslog Daemon
+EOD
diff --git a/release/packages/ucl/tcpd-all.ucl b/release/packages/ucl/tcpd-all.ucl
new file mode 100644
index 000000000000..13b7449af267
--- /dev/null
+++ b/release/packages/ucl/tcpd-all.ucl
@@ -0,0 +1,4 @@
+comment = "TCP Wrapper utilities"
+desc = <<EOD
+TCP Wrapper utilities
+EOD
diff --git a/release/packages/ucl/telnet-all.ucl b/release/packages/ucl/telnet-all.ucl
new file mode 100644
index 000000000000..e235b0d776eb
--- /dev/null
+++ b/release/packages/ucl/telnet-all.ucl
@@ -0,0 +1,4 @@
+comment = "Telnet client"
+desc = <<EOD
+Telnet client
+EOD
diff --git a/release/packages/ucl/tests-all.ucl b/release/packages/ucl/tests-all.ucl
new file mode 100644
index 000000000000..39bd365bee5b
--- /dev/null
+++ b/release/packages/ucl/tests-all.ucl
@@ -0,0 +1,4 @@
+comment = "Test Suite"
+desc = <<EOD
+Test Suite
+EOD
diff --git a/release/packages/ucl/toolchain-all.ucl b/release/packages/ucl/toolchain-all.ucl
new file mode 100644
index 000000000000..dd6517745722
--- /dev/null
+++ b/release/packages/ucl/toolchain-all.ucl
@@ -0,0 +1,4 @@
+comment = "Utilities for program development"
+desc = <<EOD
+Utilities for program development.
+EOD
diff --git a/release/packages/ucl/ufs-all.ucl b/release/packages/ucl/ufs-all.ucl
new file mode 100644
index 000000000000..48f9975e0dbd
--- /dev/null
+++ b/release/packages/ucl/ufs-all.ucl
@@ -0,0 +1,4 @@
+comment = "UFS Libraries and Utilities"
+desc = <<EOD
+UFS Libraries and Utilities
+EOD
diff --git a/release/packages/ucl/unbound-all.ucl b/release/packages/ucl/unbound-all.ucl
new file mode 100644
index 000000000000..700c9e4cf9d0
--- /dev/null
+++ b/release/packages/ucl/unbound-all.ucl
@@ -0,0 +1,5 @@
+comment = "Unbound DNS Resolver"
+desc = <<EOD
+Unbound DNS Resolver
+EOD
+licenses = [ BSD4CLAUSE ]
diff --git a/release/packages/ucl/utilities-all.ucl b/release/packages/ucl/utilities-all.ucl
new file mode 100644
index 000000000000..aeb82b0cfed5
--- /dev/null
+++ b/release/packages/ucl/utilities-all.ucl
@@ -0,0 +1,4 @@
+comment = "Non-vital programs and libraries"
+desc = <<EOD
+Non-vital programs and libraries
+EOD
diff --git a/release/packages/utilities.ucl b/release/packages/ucl/utilities.ucl
index 4eb98cae292a..4eb98cae292a 100644
--- a/release/packages/utilities.ucl
+++ b/release/packages/ucl/utilities.ucl
diff --git a/release/packages/ucl/vi-all.ucl b/release/packages/ucl/vi-all.ucl
new file mode 100644
index 000000000000..c2ad2f8e95eb
--- /dev/null
+++ b/release/packages/ucl/vi-all.ucl
@@ -0,0 +1,4 @@
+comment = "Vi Editor"
+desc = <<EOD
+Vi Editor
+EOD
diff --git a/release/packages/ucl/vt-data-all.ucl b/release/packages/ucl/vt-data-all.ucl
new file mode 100644
index 000000000000..4142b2eeae70
--- /dev/null
+++ b/release/packages/ucl/vt-data-all.ucl
@@ -0,0 +1,4 @@
+comment = "vt(4) fonts and keymaps"
+desc = <<EOD
+Fonts and keymaps for use with the vt(4) video console driver.
+EOD
diff --git a/release/packages/ucl/wpa-all.ucl b/release/packages/ucl/wpa-all.ucl
new file mode 100644
index 000000000000..e5ad7f36db95
--- /dev/null
+++ b/release/packages/ucl/wpa-all.ucl
@@ -0,0 +1,4 @@
+comment = "802.11 Supplicant"
+desc = <<EOD
+802.11 Supplicant
+EOD
diff --git a/release/packages/ucl/yp-all.ucl b/release/packages/ucl/yp-all.ucl
new file mode 100644
index 000000000000..9e17cd108d84
--- /dev/null
+++ b/release/packages/ucl/yp-all.ucl
@@ -0,0 +1,7 @@
+comment = "Yellow Pages (YP) / Network Information Service (NIS)"
+desc = <<EOD
+YP, also called NIS, is a network protocol for sharing name service
+information across machines on a network. This packages contains the YP
+server, YP management utilities, the YP-LDAP gateway (ypldap), YP client
+utilities and a sample Makefile for building the YP database.
+EOD
diff --git a/release/packages/ucl/zfs-all.ucl b/release/packages/ucl/zfs-all.ucl
new file mode 100644
index 000000000000..f4178acc481c
--- /dev/null
+++ b/release/packages/ucl/zfs-all.ucl
@@ -0,0 +1,4 @@
+comment = "ZFS Libraries and Utilities"
+desc = <<EOD
+ZFS Libraries and Utilities
+EOD
diff --git a/release/packages/ucl/zoneinfo-all.ucl b/release/packages/ucl/zoneinfo-all.ucl
new file mode 100644
index 000000000000..39991bf144e6
--- /dev/null
+++ b/release/packages/ucl/zoneinfo-all.ucl
@@ -0,0 +1,5 @@
+comment = "Timezone database"
+desc = <<EOD
+The timezone database allows applications to convert dates and times between
+UTC and local timezones.
+EOD
diff --git a/release/packages/unbound-all.ucl b/release/packages/unbound-all.ucl
deleted file mode 100644
index 78bb1f284ff2..000000000000
--- a/release/packages/unbound-all.ucl
+++ /dev/null
@@ -1 +0,0 @@
-licenses = [ BSD4CLAUSE ]
diff --git a/release/powerpc/mkisoimages.sh b/release/powerpc/mkisoimages.sh
index ba7c32f87bee..9d83390f1a4e 100644
--- a/release/powerpc/mkisoimages.sh
+++ b/release/powerpc/mkisoimages.sh
@@ -24,6 +24,9 @@
set -e
+scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
+
if [ "$1" = "-b" ]; then
MAKEFSARG="$4"
else
@@ -107,7 +110,7 @@ echo "/dev/iso9660/$LABEL / cd9660 ro 0 0" > "$BASEBITSDIR/etc/fstab"
if [ -n "${METALOG}" ]; then
echo "./etc/fstab type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$MAKEFSARG" "$@"
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -t cd9660 $bootable -o rockridge -o label="$LABEL" -o publisher="$publisher" "$NAME" "$MAKEFSARG" "$@"
rm -f "$BASEBITSDIR/etc/fstab"
if [ n "$bootable" ]; then
rm $BOOTBLOCK
diff --git a/release/riscv/make-memstick.sh b/release/riscv/make-memstick.sh
index 90ff98b394c7..0da59c29635b 100755
--- a/release/riscv/make-memstick.sh
+++ b/release/riscv/make-memstick.sh
@@ -17,6 +17,7 @@ if [ "$(uname -s)" = "FreeBSD" ]; then
fi
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
if [ $# -ne 2 ]; then
@@ -51,7 +52,7 @@ if [ -n "${METALOG}" ]; then
echo "./etc/rc.conf.local type=file uname=root gname=wheel mode=0644" >> ${metalogfilename}
MAKEFSARG=${metalogfilename}
fi
-makefs -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
+${MAKEFS} -D -N ${BASEBITSDIR}/etc -B little -o label=FreeBSD_Install -o version=2 ${2}.part ${MAKEFSARG}
rm ${BASEBITSDIR}/etc/fstab
rm ${BASEBITSDIR}/etc/rc.conf.local
if [ -n "${METALOG}" ]; then
@@ -62,7 +63,7 @@ fi
espfilename=$(mktemp /tmp/efiboot.XXXXXX)
make_esp_file ${espfilename} ${fat32min} ${BASEBITSDIR}/boot/loader.efi
-mkimg -s gpt \
+${MKIMG} -s gpt \
-p efi:=${espfilename} \
-p freebsd-ufs:=${2}.part \
-o ${2}
diff --git a/release/riscv/mkisoimages.sh b/release/riscv/mkisoimages.sh
index cb58178ed4b9..46b16f0ce08d 100644
--- a/release/riscv/mkisoimages.sh
+++ b/release/riscv/mkisoimages.sh
@@ -21,20 +21,9 @@
set -e
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
-if [ -z $ETDUMP ]; then
- ETDUMP=etdump
-fi
-
-if [ -z $MAKEFS ]; then
- MAKEFS=makefs
-fi
-
-if [ -z $MKIMG ]; then
- MKIMG=mkimg
-fi
-
if [ "$1" = "-b" ]; then
MAKEFSARG="$4"
else
diff --git a/release/scripts/tools.subr b/release/scripts/tools.subr
new file mode 100644
index 000000000000..e818f0a55410
--- /dev/null
+++ b/release/scripts/tools.subr
@@ -0,0 +1,13 @@
+#!/bin/sh
+#-
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2025 The FreeBSD Foundation
+#
+# This software was developed by Klara, Inc.
+# under sponsorship from the FreeBSD Foundation.
+#
+
+: ${ETDUMP:=etdump}
+: ${MAKEFS:=makefs}
+: ${MKIMG:=mkimg}
diff --git a/release/tools/vmimage.subr b/release/tools/vmimage.subr
index ce0ea03c096c..eb816018e9d3 100644
--- a/release/tools/vmimage.subr
+++ b/release/tools/vmimage.subr
@@ -6,6 +6,7 @@
#
scriptdir=$(dirname $(realpath $0))
+. ${scriptdir}/../scripts/tools.subr
. ${scriptdir}/../../tools/boot/install-boot.sh
export PATH="/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin"
@@ -209,11 +210,11 @@ buildfs() {
case "${VMFS}" in
ufs)
- cd ${DESTDIR} && makefs ${MAKEFSARGS} -o label=rootfs -o version=2 -o softupdates=1 \
+ cd ${DESTDIR} && ${MAKEFS} ${MAKEFSARGS} -o label=rootfs -o version=2 -o softupdates=1 \
${VMBASE} .${NO_ROOT:+/METALOG}
;;
zfs)
- cd ${DESTDIR} && makefs -t zfs ${MAKEFSARGS} \
+ cd ${DESTDIR} && ${MAKEFS} -t zfs ${MAKEFSARGS} \
-o poolname=zroot -o bootfs=zroot/ROOT/default -o rootpath=/ \
-o fs=zroot\;mountpoint=none \
-o fs=zroot/ROOT\;mountpoint=none \
@@ -342,7 +343,7 @@ vm_create_disk() {
buildfs
echo "Building final disk image... Please wait."
- mkimg -s ${PARTSCHEME} -f ${VMFORMAT} \
+ ${MKIMG} -s ${PARTSCHEME} -f ${VMFORMAT} \
${BOOTPARTS} \
${SWAPOPT} \
${CONFIG_DRIVE} \
diff --git a/sbin/kldstat/kldstat.c b/sbin/kldstat/kldstat.c
index 79c647576440..3a90f1c97eb4 100644
--- a/sbin/kldstat/kldstat.c
+++ b/sbin/kldstat/kldstat.c
@@ -35,7 +35,7 @@
#include <libutil.h>
#include <stdio.h>
#include <stdlib.h>
-#include <strings.h>
+#include <string.h>
#include <unistd.h>
#define PTR_WIDTH ((int)(sizeof(void *) * 2 + 2))
@@ -51,7 +51,7 @@ printmod(int modid)
{
struct module_stat stat;
- bzero(&stat, sizeof(stat));
+ memset(&stat, 0, sizeof(stat));
stat.version = sizeof(struct module_stat);
if (modstat(modid, &stat) < 0) {
warn("can't stat module id %d", modid);
diff --git a/sbin/mount/mount.8 b/sbin/mount/mount.8
index b584d71ea567..7bfc21ea41d5 100644
--- a/sbin/mount/mount.8
+++ b/sbin/mount/mount.8
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 30, 2025
+.Dd July 16, 2025
.Dt MOUNT 8
.Os
.Sh NAME
@@ -80,7 +80,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl a
All the file systems described in
@@ -573,7 +573,7 @@ support for a particular file system might be provided either on a static
.Xr acl 3 ,
.Xr getmntinfo 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr cd9660 4 ,
.Xr devfs 4 ,
.Xr ext2fs 4 ,
diff --git a/sbin/pfctl/parse.y b/sbin/pfctl/parse.y
index 9a917d1d8464..358fa909fc50 100644
--- a/sbin/pfctl/parse.y
+++ b/sbin/pfctl/parse.y
@@ -367,6 +367,7 @@ static struct node_fairq_opts fairq_opts;
static struct node_state_opt *keep_state_defaults = NULL;
static struct pfctl_watermarks syncookie_opts;
+int validate_range(uint8_t, uint16_t, uint16_t);
int disallow_table(struct node_host *, const char *);
int disallow_urpf_failed(struct node_host *, const char *);
int disallow_alias(struct node_host *, const char *);
@@ -3231,8 +3232,7 @@ logopts : logopt { $$ = $1; }
logopt : ALL { $$.log = PF_LOG_ALL; $$.logif = 0; }
| MATCHES { $$.log = PF_LOG_MATCHES; $$.logif = 0; }
- | USER { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
- | GROUP { $$.log = PF_LOG_SOCKET_LOOKUP; $$.logif = 0; }
+ | USER { $$.log = PF_LOG_USER; $$.logif = 0; }
| TO string {
const char *errstr;
u_int i;
@@ -3825,9 +3825,14 @@ port_item : portrange {
err(1, "port_item: calloc");
$$->port[0] = $1.a;
$$->port[1] = $1.b;
- if ($1.t)
+ if ($1.t) {
$$->op = PF_OP_RRG;
- else
+ if (validate_range($$->op, $$->port[0],
+ $$->port[1])) {
+ yyerror("invalid port range");
+ YYERROR;
+ }
+ } else
$$->op = PF_OP_EQ;
$$->next = NULL;
$$->tail = $$;
@@ -3844,6 +3849,10 @@ port_item : portrange {
$$->port[0] = $2.a;
$$->port[1] = $2.b;
$$->op = $1;
+ if (validate_range($$->op, $$->port[0], $$->port[1])) {
+ yyerror("invalid port range");
+ YYERROR;
+ }
$$->next = NULL;
$$->tail = $$;
}
@@ -3859,6 +3868,10 @@ port_item : portrange {
$$->port[0] = $1.a;
$$->port[1] = $3.a;
$$->op = $2;
+ if (validate_range($$->op, $$->port[0], $$->port[1])) {
+ yyerror("invalid port range");
+ YYERROR;
+ }
$$->next = NULL;
$$->tail = $$;
}
@@ -5197,6 +5210,19 @@ yyerror(const char *fmt, ...)
}
int
+validate_range(uint8_t op, uint16_t p1, uint16_t p2)
+{
+ uint16_t a = ntohs(p1);
+ uint16_t b = ntohs(p2);
+
+ if ((op == PF_OP_RRG && a > b) || /* 34:12, i.e. none */
+ (op == PF_OP_IRG && a >= b) || /* 34><12, i.e. none */
+ (op == PF_OP_XRG && a > b)) /* 34<>22, i.e. all */
+ return 1;
+ return 0;
+}
+
+int
disallow_table(struct node_host *h, const char *fmt)
{
for (; h != NULL; h = h->next)
@@ -5324,6 +5350,10 @@ filter_consistent(struct pfctl_rule *r, int anchor_call)
"synproxy state or modulate state");
problems++;
}
+ if ((r->keep_state == PF_STATE_SYNPROXY) && (r->direction != PF_IN))
+ fprintf(stderr, "%s:%d: warning: "
+ "synproxy used for inbound rules only, "
+ "ignored for outbound\n", file->name, yylval.lineno);
if (r->rule_flag & PFRULE_AFTO && r->rt) {
if (r->rt != PF_ROUTETO && r->rt != PF_REPLYTO) {
yyerror("dup-to "
@@ -6014,8 +6044,14 @@ apply_rdr_ports(struct pfctl_rule *r, struct pfctl_pool *rpool, struct redirspec
if (!rs->rport.b && rs->rport.t) {
rpool->proxy_port[1] = ntohs(rs->rport.a) +
(ntohs(r->dst.port[1]) - ntohs(r->dst.port[0]));
- } else
+ } else {
+ if (validate_range(rs->rport.t, rs->rport.a,
+ rs->rport.b)) {
+ yyerror("invalid rdr-to port range");
+ return (1);
+ }
r->rdr.proxy_port[1] = ntohs(rs->rport.b);
+ }
if (rs->pool_opts.staticport) {
yyerror("the 'static-port' option is only valid with nat rules");
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 271286deeda7..2015e0a09549 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -131,8 +131,8 @@ int pfctl_walk_get(int, struct pfioc_ruleset *, void *);
int pfctl_walk_anchors(int, int, const char *,
int(*)(int, struct pfioc_ruleset *, void *), void *);
struct pfr_anchors *
- pfctl_get_anchors(int, char *, int);
-int pfctl_recurse(int, int, char *,
+ pfctl_get_anchors(int, const char *, int);
+int pfctl_recurse(int, int, const char *,
int(*)(int, int, struct pfr_anchoritem *));
int pfctl_call_clearrules(int, int, struct pfr_anchoritem *);
int pfctl_call_cleartables(int, int, struct pfr_anchoritem *);
@@ -2988,20 +2988,23 @@ pfctl_show_anchors(int dev, int opts, char *anchor)
}
struct pfr_anchors *
-pfctl_get_anchors(int dev, char *anchor, int opts)
+pfctl_get_anchors(int dev, const char *anchor, int opts)
{
struct pfioc_ruleset pr;
static struct pfr_anchors anchors;
+ char anchorbuf[PATH_MAX];
char *n;
SLIST_INIT(&anchors);
memset(&pr, 0, sizeof(pr));
if (*anchor != '\0') {
- n = dirname(anchor);
+ strlcpy(anchorbuf, anchor, sizeof(anchorbuf));
+ n = dirname(anchorbuf);
if (n[0] != '.' && n[1] != '\0')
strlcpy(pr.path, n, sizeof(pr.path));
- n = basename(anchor);
+ strlcpy(anchorbuf, anchor, sizeof(anchorbuf));
+ n = basename(anchorbuf);
if (n != NULL)
strlcpy(pr.name, n, sizeof(pr.name));
}
@@ -3051,7 +3054,7 @@ pfctl_call_clearanchors(int dev, int opts, struct pfr_anchoritem *pfra)
}
int
-pfctl_recurse(int dev, int opts, char *anchorname,
+pfctl_recurse(int dev, int opts, const char *anchorname,
int(*walkf)(int, int, struct pfr_anchoritem *))
{
int rv = 0;
diff --git a/sbin/pfctl/pfctl_parser.c b/sbin/pfctl/pfctl_parser.c
index bd2c10c8080f..f2eb75135609 100644
--- a/sbin/pfctl/pfctl_parser.c
+++ b/sbin/pfctl/pfctl_parser.c
@@ -928,7 +928,7 @@ print_rule(struct pfctl_rule *r, const char *anchor_call, int verbose, int numer
printf("%sall", count++ ? ", " : "");
if (r->log & PF_LOG_MATCHES)
printf("%smatches", count++ ? ", " : "");
- if (r->log & PF_LOG_SOCKET_LOOKUP)
+ if (r->log & PF_LOG_USER)
printf("%suser", count++ ? ", " : "");
if (r->logif)
printf("%sto pflog%u", count++ ? ", " : "",
@@ -1483,7 +1483,8 @@ ifa_load(void)
err(1, "getifaddrs");
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (!(ifa->ifa_addr->sa_family == AF_INET ||
+ if (ifa->ifa_addr == NULL ||
+ !(ifa->ifa_addr->sa_family == AF_INET ||
ifa->ifa_addr->sa_family == AF_INET6 ||
ifa->ifa_addr->sa_family == AF_LINK))
continue;
diff --git a/sbin/pfctl/tests/files/pf0088.in b/sbin/pfctl/tests/files/pf0088.in
index 4700b6916b7e..a85aa84a30bb 100644
--- a/sbin/pfctl/tests/files/pf0088.in
+++ b/sbin/pfctl/tests/files/pf0088.in
@@ -16,7 +16,7 @@ pass to 10.0.0.2 keep state
block from 10.0.0.3 to 10.0.0.2
pass to 10.0.0.2 modulate state
block from 10.0.0.3 to 10.0.0.2
-pass to 10.0.0.2 synproxy state
+pass in to 10.0.0.2 synproxy state
pass out proto tcp from 10.0.0.4 to 10.0.0.5 keep state
diff --git a/sbin/pfctl/tests/files/pf0088.ok b/sbin/pfctl/tests/files/pf0088.ok
index 47251a4503dd..801056a4ab46 100644
--- a/sbin/pfctl/tests/files/pf0088.ok
+++ b/sbin/pfctl/tests/files/pf0088.ok
@@ -11,7 +11,7 @@ pass inet from any to 10.0.0.2 flags S/SA keep state
block drop inet from 10.0.0.3 to 10.0.0.2
pass inet from any to 10.0.0.2 flags S/SA modulate state
block drop inet from 10.0.0.3 to 10.0.0.2
-pass inet from any to 10.0.0.2 flags S/SA synproxy state
+pass in inet from any to 10.0.0.2 flags S/SA synproxy state
pass out inet proto tcp from 10.0.0.4 to 10.0.0.5 flags S/SA keep state
pass out inet proto tcp from 10.0.0.4 to 10.0.0.5 port = http flags S/SA keep state
pass out all flags S/SA keep state
diff --git a/sbin/pfctl/tests/files/pf1072.fail b/sbin/pfctl/tests/files/pf1072.fail
new file mode 100644
index 000000000000..06ef5ae457e5
--- /dev/null
+++ b/sbin/pfctl/tests/files/pf1072.fail
@@ -0,0 +1 @@
+invalid port range
diff --git a/sbin/pfctl/tests/files/pf1072.in b/sbin/pfctl/tests/files/pf1072.in
new file mode 100644
index 000000000000..e09e92388ce1
--- /dev/null
+++ b/sbin/pfctl/tests/files/pf1072.in
@@ -0,0 +1 @@
+pass in proto tcp from any port 500:100 to any
diff --git a/sbin/pfctl/tests/pfctl_test_list.inc b/sbin/pfctl/tests/pfctl_test_list.inc
index 51729bc9adad..3a68cc06ec74 100644
--- a/sbin/pfctl/tests/pfctl_test_list.inc
+++ b/sbin/pfctl/tests/pfctl_test_list.inc
@@ -180,3 +180,4 @@ PFCTL_TEST(1068, "max-pkt-rate")
PFCTL_TEST(1069, "max-pkt-size")
PFCTL_TEST_FAIL(1070, "include line number")
PFCTL_TEST(1071, "mask length on (lo0)")
+PFCTL_TEST_FAIL(1072, "Invalid port range")
diff --git a/sbin/route/route_netlink.c b/sbin/route/route_netlink.c
index 631c2860b547..ba22a2ec1e22 100644
--- a/sbin/route/route_netlink.c
+++ b/sbin/route/route_netlink.c
@@ -738,6 +738,7 @@ print_nlmsg(struct nl_helper *h, struct nlmsghdr *hdr, struct snl_msg_info *cinf
print_nlmsg_generic(h, hdr, cinfo);
}
+ fflush(stdout);
snl_clear_lb(&h->ss_cmd);
}
diff --git a/sbin/savecore/savecore.8 b/sbin/savecore/savecore.8
index 53d2360719dd..1fb79c51f98d 100644
--- a/sbin/savecore/savecore.8
+++ b/sbin/savecore/savecore.8
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 4, 2022
+.Dd July 16, 2025
.Dt SAVECORE 8
.Os
.Sh NAME
@@ -69,7 +69,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl C
Check to see if a dump exists,
@@ -193,7 +193,7 @@ is meant to be called near the end of the initialization file
.Xr zstd 1 ,
.Xr getbootfile 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr mem 4 ,
.Xr textdump 4 ,
.Xr tar 5 ,
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 5e60f00bc09f..505e83a67369 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -594,6 +594,7 @@ MAN= aac.4 \
tws.4 \
udp.4 \
udplite.4 \
+ ${_ufshci.4} \
unionfs.4 \
ure.4 \
vale.4 \
@@ -746,7 +747,6 @@ MLINKS+=lge.4 if_lge.4
MLINKS+=lo.4 loop.4
MLINKS+=lp.4 plip.4
MLINKS+=malo.4 if_malo.4
-MLINKS+=md.4 vn.4
MLINKS+=mem.4 kmem.4
MLINKS+=mfi.4 mfi_linux.4 \
mfi.4 mfip.4
@@ -938,6 +938,10 @@ MLINKS+=hwt.4 spe.4
.endif
.endif
+.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "aarch64"
+_ufshci.4= ufshci.4
+.endif
+
.if ${MACHINE_CPUARCH} == "amd64" || ${MACHINE_CPUARCH} == "i386" || \
${MACHINE_CPUARCH} == "aarch64"
_gve.4= gve.4
@@ -981,6 +985,7 @@ _ccd.4= ccd.4
.if ${MK_CDDL} != "no"
_dtrace_provs= dtrace_audit.4 \
dtrace_dtrace.4 \
+ dtrace_fbt.4 \
dtrace_io.4 \
dtrace_ip.4 \
dtrace_kinst.4 \
diff --git a/share/man/man4/dtrace_fbt.4 b/share/man/man4/dtrace_fbt.4
new file mode 100644
index 000000000000..3e35bb8c5bbc
--- /dev/null
+++ b/share/man/man4/dtrace_fbt.4
@@ -0,0 +1,332 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2025 Mateusz Piotrowski <0mp@FreeBSD.org>
+.\"
+.Dd July 16, 2025
+.Dt DTRACE_FBT 4
+.Os
+.Sh NAME
+.Nm dtrace_fbt
+.Nd a DTrace provider for dynamic kernel tracing based on function boundaries
+.Sh SYNOPSIS
+.Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:entry
+.Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:return
+.Sh DESCRIPTION
+The Function Boundary Tracing
+.Pq Nm fbt
+provider instruments the entry and return of almost every kernel function
+corresponding to an
+.Xr elf 5
+symbol in the kernel and loaded kernel modules.
+.Pp
+.Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:entry
+fires whenever the
+.Ar function
+is called.
+.Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:return
+fires when the
+.Ar function
+returns.
+.Pp
+The
+.Ar module
+in the probe description is either the name of the loaded kernel module
+or
+.Ql kernel
+for functions compiled into the kernel.
+.Ss Function Boundary Instrumentation
+The
+.Nm fbt
+will always instrument a function's entry, but
+its return will be intsrumented so long as it can find a
+.Ql ret
+instruction.
+.Pp
+In some cases,
+.Nm fbt
+cannot instrument a function's entry and/or return.
+Refer to subsection
+.Sx Frame Pointer
+for more details.
+.Ss Probe Arguments
+The arguments of the entry probe
+.Pq Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:entry
+are the arguments of the traced function call.
+.Bl -column -offset indent "Entry Probe Argument" "Definition"
+.It Sy Entry Probe Argument Ta Sy Definition
+.It Fa args[0] Ta Function's first argument, typed
+.Pq e.g., Xr malloc 9 Ap s Ft size_t Fa size
+.It Fa args[1] Ta Function's second argument, typed
+.Pq e.g., Xr malloc 9 Ap s Ft struct malloc_type Fa *type
+.It Fa args[2] Ta Function's third argument, typed
+.Pq e.g., Xr malloc 9 Ap s Ft int Fa flags
+.It Fa ... Ta ...
+.El
+.Pp
+The arguments of the return probe
+.Pq Nm fbt Ns Cm \&: Ns Ar module Ns Cm \&: Ns Ar function Ns Cm \&:return
+are
+.Fa args[0]
+.Po
+the offset of the firing return instruction within the function;
+useful to tell apart two different return statements in a single function
+.Pc
+and
+.Fa args[1]
+.Pq the return value, if any .
+.Bl -column -offset indent "Return Probe Argument" "Definition"
+.It Sy Return Probe Argument Ta Sy Definition
+.It Fa args[0] Ta Offset of the traced return instruction
+.It Fa args[1] Ta Function's return value
+.Po e.g., a kernel virtual address if returning from a successful
+.Xr malloc 9
+.Pc
+.El
+.Pp
+Subsection
+.Sx Example 2 : Getting Details About Probe's Arguments
+shows how to get probe's argument count and types directly with
+.Xr dtrace 1
+without having to resort to the reading function's source code
+or documentation.
+.Sh EXAMPLES
+.Ss Example 1 : Listing Available FBT Probes
+The following example shows how to list all the available
+.Nm fbt
+probes.
+.Bd -literal -offset 2n
+# dtrace -l -P fbt
+ ID PROVIDER MODULE FUNCTION NAME
+[...]
+31868 fbt kernel hammer_time entry
+31869 fbt kernel hammer_time return
+[...]
+.Ed
+.Pp
+Since
+.Fn hammer_time
+is a part of the kernel and not a separate loaded module, the
+.Ar module
+column displays
+.Ql kernel .
+.Ss Example 2 : Getting Details About Probe's Arguments
+The following example shows how to generate a program stability report of
+.Xr malloc 9 Ap s
+entry and return probes.
+Those reports are useful to view
+the probe's number of arguments and their types.
+.Bd -literal -offset 2n
+# dtrace -l -v -n fbt::malloc:entry
+[...]
+ Argument Types
+ args[0]: size_t
+ args[1]: struct malloc_type *
+ args[2]: int
+.Ed
+.Pp
+The count and types of
+.Nm fbt Ns Cm \&::malloc:entry
+arguments
+match the function signature of
+.Xr malloc 9 :
+.Va args[0]
+is
+.Ft size_t ,
+.Va args[1]
+is
+.Ft "struct malloc_type *" ,
+and
+.Va "args[2]"
+is
+.Ft int .
+.Bd -literal -offset 2n
+# dtrace -l -v -n fbt::malloc:return
+[...]
+ Argument Types
+ args[0]: int
+ args[1]: void *
+.Ed
+.Pp
+The
+.Cm return
+probe reports two arguments and their types:
+the return instruction offset
+.Pq the usual Ft int
+and the function's return value, which in this case is
+.Ft void * ,
+as
+.Xr malloc 9
+returns a kernel virtual address.
+.Ss Example 3 : Counting Kernel Slab Memory Allocation by Function
+.Bd -literal -offset 2n
+# dtrace -n 'fbt::kmem*:entry { @[probefunc] = count(); }'
+dtrace: description 'fbt::kmem*:entry ' matched 47 probes
+^C
+ kmem_alloc_contig 1
+ kmem_alloc_contig_domainset 1
+ kmem_cache_reap_active 1
+ kmem_alloc_contig_pages 2
+ kmem_free 2
+ kmem_std_destructor 19
+ kmem_std_constructor 26
+ kmem_cache_free 151
+ kmem_cache_alloc 181
+.Ed
+.Ss Example 4 : Counting Kernel Slab Memory Allocation by Calling Function
+.Bd -literal -offset 2n
+# dtrace -q -n 'fbt::kmem*:entry { @[caller] = count(); } END { printa("%40a %@16d\en", @); }'
+^C
+ kernel`contigmalloc+0x33 1
+ kernel`free+0xd3 1
+ kernel`kmem_alloc_contig+0x29 1
+kernel`kmem_alloc_contig_domainset+0x19a 1
+ zfs.ko`arc_reap_cb_check+0x16 1
+.Ed
+.Ss Example 5 : Counting Kernel malloc()'s by Calling Function
+.Bd -literal -offset 2n
+# dtrace -q -n 'fbt::malloc:entry { @[caller] = count(); } END { printa("%45a %@16d\en", @); }'
+^C
+ kernel`devclass_get_devices+0xa8 1
+ kernel`sys_ioctl+0xb7 1
+ dtrace.ko`dtrace_ioctl+0x15c1 1
+ dtrace.ko`dtrace_ioctl+0x972 2
+ dtrace.ko`dtrace_dof_create+0x35 2
+ kernel`kern_poll_kfds+0x2f0 4
+ kernel`kern_poll_kfds+0x28a 19
+.Ed
+.Ss Example 6 : Counting Kernel malloc()'s by Kernel Stack Trace
+.Bd -literal -offset 2n
+# dtrace -q -n 'fbt::malloc:entry { @[stack()] = count(); }'
+^C
+ dtrace.ko`dtrace_dof_create+0x35
+ dtrace.ko`dtrace_ioctl+0x827
+ kernel`devfs_ioctl+0xd1
+ kernel`VOP_IOCTL_APV+0x2a
+ kernel`vn_ioctl+0xb6
+ kernel`devfs_ioctl_f+0x1e
+ kernel`kern_ioctl+0x286
+ kernel`sys_ioctl+0x12f
+ kernel`amd64_syscall+0x169
+ kernel`0xffffffff81092b0b
+ 2
+.Ed
+.Ss Example 7 : Summarizing vmem_alloc()'s by Arena Name and Size Distribution
+.Bd -literal -offset 2n
+# dtrace -q -n 'fbt::vmem_alloc:entry { @[args[0]->vm_name] = quantize(arg1); }'
+^C
+
+ kernel arena dom
+ value ------------- Distribution ------------- count
+ 2048 | 0
+ 4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@ 4
+ 8192 |@@@@@@@@@@@@@ 2
+ 16384 | 0
+.Ed
+.Ss Example 8 : Measuring Total Time Spent Executing a Function
+This DTrace script measures the total time spent in
+.Fn vm_page*
+kernel functions.
+The
+.Fn quantize
+aggregation organizes the measurements into power-of-two buckets,
+providing a time distribution in nanoseconds for each function.
+.Bd -literal -offset 2n
+fbt::vm_page*:entry {
+ self->start = timestamp;
+}
+
+fbt::vm_page*:return /self->start/ {
+ @[probefunc] = quantize(timestamp - self->start);
+ self->start = 0;
+}
+.Ed
+.Sh SEE ALSO
+.Xr dtrace 1 ,
+.Xr dtrace_kinst 4 ,
+.Xr tracing 7
+.Rs
+.%A Brendan Gregg
+.%A Jim Mauro
+.%B DTrace: Dynamic Tracing in Oracle Solaris, Mac OS X and FreeBSD
+.%I Prentice Hall
+.%P pp. 898\(en903
+.%D 2011
+.%U https://www.brendangregg.com/dtracebook/
+.Re
+.Rs
+.%B The illumos Dynamic Tracing Guide
+.%O Chapter fbt Provider
+.%D 2008
+.%U https://illumos.org/books/dtrace/chp-fbt.html#chp-fbt
+.Re
+.Sh AUTHORS
+This manual page was written by
+.An Mateusz Piotrowski Aq Mt 0mp@FreeBSD.org .
+.Sh CAVEATS
+.Ss Stability and Portability
+.Nm fbt
+probes are by definition tightly coupled to kernel code; if the code underlying
+a script changes, the script may fail to run or may produce incorrect results.
+Scripts written for one version of
+.Fx
+might not work on others,
+and almost certainly will not work on other operating systems.
+.Pp
+Individual
+.Nm fbt
+probes often do not correspond nicely to logical system events.
+For example, consider a DTrace script which prints the destination
+address of every IP packet as the kernel hands them over
+to the network card driver (NIC).
+An
+.Nm fbt Ns -based
+implementation of such a script is a discouragingly difficult task:
+it involves instrumenting at least four different functions in different parts
+of the IPv4 and IPv6 code.
+At the same time, with the
+.Xr dtrace_ip 4
+provider the script is a simple one-liner:
+.Dl dtrace -n 'ip:::send {printf("%s", args[2]->ip_daddr);}'
+.Pp
+Make sure to review available
+.Xr dtrace 1
+providers first
+before implementing a custom script with the
+.Nm fbt
+provider.
+If none of the DTrace providers offer the desired probes,
+consider adding new statically-defined tracing probes
+.Pq Xr SDT 9 .
+.Ss Frame Pointer
+Inline functions are not instrumentable by
+.Nm fbt
+as they lack a frame pointer.
+A developer might explicitly disable inlining by adding the
+.Ql __noinline
+attribute to a function definition,
+but of course this requires a recompilation of the kernel.
+Building the kernel with
+.Fl fno-omit-frame-pointer
+is another way of preserving frame pointers.
+Note, that sometimes compilers will omit the frame pointer in leaf functions,
+even when configured with
+.Fl fno-omit-frame-pointer .
+.Pp
+Function returns via a tail call are also not instrumentable by
+.Nm fbt .
+As a result,
+a function might have an entry probe
+and a mix of instrumented and uninstrumentable returns.
+.Pp
+Use
+.Xr dtrace_kinst 4
+to trace arbitrary instructions inside kernel functions
+and work around some of the
+limitations
+of
+.Nm fbt .
+.Ss Tracing DTrace
+The
+.Nm fbt
+provider cannot attach to functions inside DTrace provider kernel modules.
diff --git a/share/man/man4/dtrace_kinst.4 b/share/man/man4/dtrace_kinst.4
index 9debbc1bd106..c2187689749b 100644
--- a/share/man/man4/dtrace_kinst.4
+++ b/share/man/man4/dtrace_kinst.4
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 27, 2023
+.Dd July 16, 2025
.Dt DTRACE_KINST 4
.Os
.Sh NAME
@@ -43,10 +43,13 @@ creates probes on-demand, meaning it searches for and parses the function's
instructions each time
.Xr dtrace 1
is run, and not at module load time.
-This is in contrast to FBT's load-time parsing, since
+This is in contrast to
+.Xr dtrace_fbt 4 Ap s
+load-time parsing, since
.Nm kinst
can potentially create thousands of probes for just a single function, instead
-of up to two (entry and return) in the case of FBT.
+of up to two (entry and return) in the case of
+.Xr dtrace_fbt 4 .
A result of this is that
.Cm dtrace -l -P kinst
will not match any probes.
@@ -79,7 +82,8 @@ Trace all instructions in
# dtrace -n 'kinst::amd64_syscall:'
.Ed
.Sh SEE ALSO
-.Xr dtrace 1
+.Xr dtrace 1 ,
+.Xr dtrace_fbt 4
.Sh HISTORY
The
.Nm kinst
diff --git a/share/man/man4/md.4 b/share/man/man4/md.4
index 0c99d61f8392..1da26ddda037 100644
--- a/share/man/man4/md.4
+++ b/share/man/man4/md.4
@@ -5,7 +5,7 @@
.\" this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
.\" ----------------------------------------------------------------------------
.\"
-.Dd January 8, 2020
+.Dd July 16, 2025
.Dt MD 4
.Os
.Sh NAME
@@ -158,7 +158,7 @@ installation process.
The
.Nm
driver did a hostile takeover of the
-.Xr vn 4
+.Sy vn
driver in
.Fx 5.0 .
.Sh AUTHORS
diff --git a/share/man/man4/mtw.4 b/share/man/man4/mtw.4
index 17722be73203..6aa59d848d36 100644
--- a/share/man/man4/mtw.4
+++ b/share/man/man4/mtw.4
@@ -24,23 +24,41 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd Feb 03, 2025
+.Dd May 3, 2025
.Dt MTW 4
.Os
.Sh NAME
-.Nm if_mtw
-.Nd "Mediatek MT7601U"
-.Ed
+.Nm mtw
+.Nd MediaTek MT7601U USB IEEE 802.11n wireless network driver
+.Sh SYNOPSIS
+.Cd device usb
+.Cd device mtw
+.Cd device wlan
+.Pp
+In
+.Xr rc.conf 5 :
+.Cd kld_list="if_mtw"
.Sh DESCRIPTION
-This module provides support for Mediatek MT7601U with the firmware from net/wifi-firmware-mtw-kmod
-
+This module provides support for
+MediaTek MT7601U USB wireless network adapters.
+If the appropriate hardware is detected,
+the driver will be automatically loaded with
+.Xr devmatch 8 .
+If driver autoloading is explicitly disabled, enable the module in
+.Xr rc.conf 5 .
+The
+.Nm
+driver can be configured at runtime with
+.Xr ifconfig 8
+or at boot with
+.Xr rc.conf 5 .
.Sh HARDWARE
The
.Nm
-driver supports Mediatek MT7601U
-based USB wireless network adapters including (but not all of them tested):
+driver supports MediaTek MT7601U based USB wireless network adapters
+including (but not all of them tested):
.Pp
-.Bl -column -compact
+.Bl -bullet -compact
.It
ASUS USB-N10 v2
.It
@@ -58,17 +76,43 @@ TP-LINK TL-WN727N v4 (tested working)
.It
Yealink WF40
.El
+.Sh FILES
+The
+.Nm
+driver requires firmware from
+.Pa ports/net/wifi-firmware-mt7601u-kmod .
+This firmware package will be installed automatically with
+.Xr fwget 8
+if the appropriate hardware is detected at installation or runtime.
.Sh SEE ALSO
-.Xr usb 4
-.Sh BUGS
+.Xr usb 4 ,
+.Xr wlan 4 ,
+.Xr networking 7 ,
+.Xr fwget 8 ,
+.Xr wpa_supplicant 8
+.Sh HISTORY
The
.Nm
-only works in station mode and monitor mode. The firmware does not always reinitialize when reloading the module, or when rebooting, without first unplugging the device.
-.Sh History
-The mtw driver first appeared in OpenBSD 7.1. The mtw driver was ported to FreeBSD in FreeBSD 15.0.
+driver first appeared in
+.Ox 7.1
+and
+.Fx 15.0 .
.Sh AUTHORS
.An -nosplit
-The mtw driver was written by
+The
+.Nm
+driver was written by
.An James Hastings Aq Mt hastings@openbsd.org
-ported to FreeBSD by
-.An Jesper Schmitz Mouridsen Aq Mt jsm@FreeBSD.org
+and ported to
+.Fx
+by
+.An Jesper Schmitz Mouridsen Aq Mt jsm@FreeBSD.org .
+.Sh BUGS
+.Nm
+only works in
+.Cm station
+mode and
+.Cm monitor
+mode.
+The firmware does not always reinitialize when reloading the module,
+or when rebooting, without first unplugging the device.
diff --git a/share/man/man4/sa.4 b/share/man/man4/sa.4
index 96b11ebe5360..699a940a34d1 100644
--- a/share/man/man4/sa.4
+++ b/share/man/man4/sa.4
@@ -457,7 +457,8 @@ One EOM notification will be sent, BPEW status will be set for one position
query, and then the driver state will be reset to normal.
.Sh SEE ALSO
.Xr mt 1 ,
-.Xr cam 4
+.Xr cam 4 ,
+.Xr mtio 4
.Sh AUTHORS
.An -nosplit
The
diff --git a/share/man/man4/snd_uaudio.4 b/share/man/man4/snd_uaudio.4
index 00329a6d8e40..7193c85fa4f0 100644
--- a/share/man/man4/snd_uaudio.4
+++ b/share/man/man4/snd_uaudio.4
@@ -1,3 +1,6 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
.\" $NetBSD: uaudio.4,v 1.15 2002/02/12 19:53:57 jdolecek Exp $
.\"
.\" Copyright (c) 1999 The NetBSD Foundation, Inc.
@@ -27,32 +30,30 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd February 15, 2025
+.Dd July 17, 2025
.Dt SND_UAUDIO 4
.Os
.Sh NAME
.Nm snd_uaudio
.Nd USB audio and MIDI device driver
.Sh SYNOPSIS
-To compile this driver into the kernel, place the following lines in your
-kernel configuration file:
-.Bd -ragged -offset indent
.Cd "device sound"
.Cd "device usb"
.Cd "device snd_uaudio"
-.Ed
.Pp
-Alternatively, to load the driver as a module at boot time, place the
-following line in
-.Xr loader.conf 5 :
-.Bd -literal -offset indent
-snd_uaudio_load="YES"
-.Ed
-.Sh DESCRIPTION
-The
-.Nm
-driver provides support for USB audio class devices and USB MIDI class devices.
+In
+.Xr rc.conf 5 :
+.Cd kld_list="snd_uaudio"
.Pp
+In
+.Xr sysctl.conf 5 :
+.Cd hw.usb.uaudio.buffer_ms
+.Cd hw.usb.uaudio.default_bits
+.Cd hw.usb.uaudio.default_channels
+.Cd hw.usb.uaudio.default_rate
+.Cd hw.usb.uaudio.handle_hid
+.Cd hw.usb.uaudio.debug
+.Sh DESCRIPTION
A USB audio device consists of a number of components: input terminals (e.g.\&
USB digital input), output terminals (e.g.\& speakers), and a number of units
in between (e.g.\& volume control).
@@ -68,6 +69,11 @@ sample rate and sample size.
Refer to the
.Ql USB Audio Class Specification
for more information.
+.Sh HARDWARE
+The
+.Nm
+driver provides support for USB audio class devices and
+USB MIDI class devices.
.Sh SYSCTL VARIABLES
The following settings can be entered at the
.Xr loader 8
diff --git a/share/man/man4/ufshci.4 b/share/man/man4/ufshci.4
new file mode 100644
index 000000000000..d722c9902b98
--- /dev/null
+++ b/share/man/man4/ufshci.4
@@ -0,0 +1,181 @@
+.\"
+.\" Copyright (c) 2025, Samsung Electronics Co., Ltd.
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" ufshci driver man page.
+.\"
+.\" Author: Jaeyoon Choi <j_yoon.choi@samsung.com>
+.\"
+.Dd July 17, 2025
+.Dt UFSHCI 4
+.Os
+.Sh NAME
+.Nm ufshci
+.Nd Universal Flash Storage Host Controller Interface driver
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following line in the kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device ufshci"
+.Ed
+.Pp
+Or, to load the driver as a module at boot, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+ufshci_load="YES"
+.Ed
+.Sh DESCRIPTION
+Universal Flash Storage (UFS) is a low-power, high-performance storage
+standard composed of a host controller and a single target device.
+.Pp
+The driver currently provides:
+.Bl -bullet
+.It
+Initialization of the host controller and the target device
+.It
+Handling of UFS Interconnect (UIC) commands
+.It
+Support for UTP Transfer Requests (UTR) and UTP Task Management Requests (UTMR)
+.It
+Support for the SCSI command set
+.It
+Operation in the legacy single-doorbell queue mode
+.It
+Support for the PCI Express bus
+.El
+.Pp
+After initialization, the controller is registered with the
+.Xr cam 4
+subsystem and its logical unit appears as the device node
+.Pa /dev/daX .
+.Pp
+The driver is under active development; upcoming work includes full
+UFS 4.1 feature coverage, additional power-management modes, and
+ACPI/FDT-based attach support.
+.Sh HARDWARE
+The
+.Nm
+driver supports both host controllers and devices implementing the
+Universal Flash Storage Host Controller Interface 4.1 and earlier.
+.Sh CONFIGURATION
+The
+.Nm
+driver currently operates with a single doorbell (one I/O-queue), so any
+tunables that change the queue count are ignored.
+When Multi-Circular Queue (MCQ) support is added and multiple queues
+become available, the following queue count tunable values will take effect:
+.Pp
+To force a single I/O queue pair shared by all CPUs, set the following
+tunable value in loader.conf(5):
+.Bd -literal -offset indent
+hw.ufshci.per_cpu_io_queues=0
+.Ed
+.Pp
+To assign more than one CPU per I/O queue pair, thereby reducing the
+number of MSI-X vectors consumed by the device, set the following tunable
+value in loader.conf(5):
+.Bd -literal -offset indent
+hw.ufshci.min_cpus_per_ioq=X
+.Ed
+.Pp
+To change the I/O command timeout value (in seconds), set the following tunable
+value in loader.conf(5):
+.Bd -literal -offset indent
+hw.ufshci.timeout_period=X
+.Ed
+.Pp
+To change the I/O command retry count, set the following tunable value in
+loader.conf(5):
+.Bd -literal -offset indent
+hw.ufshci.retry_count=X
+.Ed
+.Pp
+To force the driver to use legacy INTx interrupts, set the following tunable
+value in loader.conf(5):
+.br
+(Note: until MCQ support is available the driver always uses legacy INTx, so
+this value effectively remains 1)
+.Bd -literal -offset indent
+hw.ufshci.force_intx=1
+.Ed
+.Sh SYSCTL VARIABLES
+The following controller-level
+.Xr sysctl 8
+nodes are currently implemented:
+.Bl -tag -width indent
+.It Va dev.ufshci.0.num_failures
+(R) Number of command failures for the entire controller.
+.It Va dev.ufshci.0.num_retries
+(R) Number of command retries for the entire controller.
+.It Va dev.ufshci.0.num_intr_handler_calls
+(R) Number of times the interrupt handler has been called.
+.It Va dev.ufshci.0.num_cmds
+(R) Total number of commands issued by the controller.
+.It Va dev.ufshci.0.timeout_period
+(RW) Configured timeout period (in seconds).
+.It Va dev.ufshci.0.cap
+(R) Host controller capabilities register value.
+.It Va dev.ufshci.0.num_io_queues
+(R) Number of I/O-queue pairs.
+.It Va dev.ufshci.0.io_queue_mode
+(R) Indicates single doorbell mode or multi circular queue mode.
+.It Va dev.ufshci.0.minor_version
+(R) Host controller minor version.
+.It Va dev.ufshci.0.major_version
+(R) Host controller major version.
+.It Va dev.ufshci.0.utmrq.num_failures
+(R) Number of failed UTP task-management requests.
+.It Va dev.ufshci.0.utmrq.ioq.num_retries
+(R) Number of retried UTP task-management requests.
+.It Va dev.ufshci.0.utmrq.num_intr_handler_calls
+(R) Number of interrupt handler calls caused by UTP task-management requests.
+.It Va dev.ufshci.0.utmrq.num_cmds
+(R) Number of UTP task-management requests issued.
+.It Va dev.ufshci.0.utmrq.cq_head
+(R) Current location of the UTP task-management completion queue head.
+.It Va dev.ufshci.0.utmrq.sq_tail
+(R) Current location of the UTP task-management submission queue tail.
+.It Va dev.ufshci.0.utmrq.sq_head
+(R) Current location of the UTP task-management submission queue head.
+.It Va dev.ufshci.0.utmrq.num_trackers
+(R) Number of trackers in the UTP task-management queue.
+.It Va dev.ufshci.0.utmrq.num_entries
+(R) Number of entries in the UTP task-management queue.
+.It Va dev.ufshci.0.ioq.0.num_failures
+(R) Number of failed UTP transfer requests.
+.It Va dev.ufshci.0.ioq.0.num_retries
+(R) Number of retried UTP transfer requests.
+.It Va dev.ufshci.0.ioq.0.num_intr_handler_calls
+(R) Number of interrupt-handler calls caused by UTP transfer requests.
+.It Va dev.ufshci.0.ioq.0.num_cmds
+(R) Number of UTP transfer requests issued.
+.It Va dev.ufshci.0.ioq.0.cq_head
+(R) Current location of the UTP transfer completion queue head.
+.It Va dev.ufshci.0.ioq.0.sq_tail
+(R) Current location of the UTP transfer submission queue tail.
+.It Va dev.ufshci.0.ioq.0.sq_head
+(R) Current location of the UTP transfer submission queue head.
+.It Va dev.ufshci.0.ioq.0.num_trackers
+(R) Number of trackers in the UTP transfer queue.
+.It Va dev.ufshci.0.ioq.0.num_entries
+(R) Number of entries in the UTP transfer queue.
+.El
+.Sh SEE ALSO
+.Xr cam 4 ,
+.Xr pci 4 ,
+.Xr disk 9
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Fx 15.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was developed by Samsung Electronics and originally written by
+.An Jaeyoon Choi Aq Mt j_yoon.choi@samsung.com .
+.Pp
+This manual page was written by
+.An Jaeyoon Choi Aq Mt j_yoon.choi@samsung.com .
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index b5843d67e106..8954e872c231 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -27,7 +27,7 @@
.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd July 7, 2025
+.Dd July 9, 2025
.Dt PF.CONF 5
.Os
.Sh NAME
@@ -365,7 +365,7 @@ set timeout { adaptive.start 60000, adaptive.end 120000 }
set limit states 100000
.Ed
.Pp
-With 9000 state table entries, the timeout values are scaled to 50%
+With 90000 state table entries, the timeout values are scaled to 50%
(tcp.first 60, tcp.established 43200).
.It Ar set loginterface
Enable collection of packet and byte count statistics for the given
@@ -1387,7 +1387,7 @@ part of the new destination address according to the specified subnet.
It is possible to embed a complete IPv4 address into an IPv6 address
using a network prefix of /96 or smaller.
.Pp
-When a destination address is not specified it is assumed that the host
+When a destination address is not specified, it is assumed that the host
part is 32-bit long.
For IPv6 to IPv4 translation this would mean using only the lower 32
bits of the original IPv6 destination address.
@@ -2122,10 +2122,10 @@ options, or scrubbed with
will also not be recoverable from intermediate packets.
Such connections will stall and time out.
.It Xo Ar icmp-type Aq Ar type
-.Ar code Aq Ar code
+.Ar Op code Aq Ar code
.Xc
.It Xo Ar icmp6-type Aq Ar type
-.Ar code Aq Ar code
+.Ar Op code Aq Ar code
.Xc
This rule only applies to ICMP or ICMPv6 packets with the specified type
and code.
@@ -2574,6 +2574,7 @@ will not work if
.Xr pf 4
operates on a
.Xr bridge 4 .
+Also they act on incoming SYN packets only.
.Pp
Example:
.Bd -literal -offset indent
@@ -2783,8 +2784,8 @@ This means that it will not work on other protocols and will not match
a currently established connection.
.Pp
Caveat: operating system fingerprints are occasionally wrong.
-There are three problems: an attacker can trivially craft his packets to
-appear as any operating system he chooses;
+There are three problems: an attacker can trivially craft packets to
+appear as any operating system;
an operating system patch could change the stack behavior and no fingerprints
will match it until the database is updated;
and multiple operating systems may have the same fingerprint.
@@ -3111,7 +3112,7 @@ rule can also contain a filter ruleset in a brace-delimited block.
In that case, no separate loading of rules into the anchor
is required.
Brace delimited blocks may contain rules or other brace-delimited blocks.
-When an anchor is populated this way the anchor name becomes optional.
+When an anchor is populated this way, the anchor name becomes optional.
.Bd -literal -offset indent
anchor "external" on $ext_if {
block
diff --git a/share/man/man5/rc.conf.5 b/share/man/man5/rc.conf.5
index 2fd63e4f743d..de2181d638d1 100644
--- a/share/man/man5/rc.conf.5
+++ b/share/man/man5/rc.conf.5
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 21, 2025
+.Dd July 15, 2025
.Dt RC.CONF 5
.Os
.Sh NAME
@@ -1164,8 +1164,8 @@ and
is not found.
Multiple rules can be set as follows:
.Bd -literal
-pf_fallback_rules="\\
- block drop log all\\
+pf_fallback_rules="
+ block drop log all
pass in quick on em0"
.Pp
.Ed
diff --git a/share/man/man7/arch.7 b/share/man/man7/arch.7
index 918f9058c7aa..fe4e8055a8b1 100644
--- a/share/man/man7/arch.7
+++ b/share/man/man7/arch.7
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 12, 2025
+.Dd July 14, 2025
.Dt ARCH 7
.Os
.Sh NAME
diff --git a/share/man/man9/vnode.9 b/share/man/man9/vnode.9
index 5dd087725e92..d17492668298 100644
--- a/share/man/man9/vnode.9
+++ b/share/man/man9/vnode.9
@@ -24,7 +24,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 October 9, 2024
+.Dd July 15, 2025
.Dt VNODE 9
.Os
.Sh NAME
@@ -113,7 +113,7 @@ The
function declarations and definitions are generated from
.Pa sys/kern/vnode_if.src
by the
-.Pa sys/tools/vndoe_if.awk
+.Pa sys/tools/vnode_if.awk
script.
The interfaces are documented in their respective manual pages like
.Xr VOP_READ 9
diff --git a/share/misc/committers-src.dot b/share/misc/committers-src.dot
index 313f40ad8e51..0f9f8242c5c2 100644
--- a/share/misc/committers-src.dot
+++ b/share/misc/committers-src.dot
@@ -299,6 +299,7 @@ nork [label="Norikatsu Shigemura\nnork@FreeBSD.org\n2009/06/09"]
np [label="Navdeep Parhar\nnp@FreeBSD.org\n2009/06/05"]
nwhitehorn [label="Nathan Whitehorn\nnwhitehorn@FreeBSD.org\n2008/07/03"]
n_hibma [label="Nick Hibma\nn_hibma@FreeBSD.org\n1998/11/26"]
+obiwac [label="Aymeric Wibo\nobiwac@FreeBSD.org\n2025/07/15"]
obrien [label="David E. O'Brien\nobrien@FreeBSD.org\n1996/10/29"]
oh [label="Oskar Holmlund\noh@FreeBSD.org\n2021/04/21"]
olce [label="Olivier Certner\nolce@FreeBSD.org\n2023/12/01"]
@@ -711,6 +712,8 @@ joerg -> schweikh
jtl -> ngie
jtl -> thj
+jrm -> obiwac
+
julian -> glebius
julian -> davidxu
julian -> archie
@@ -799,6 +802,8 @@ mav -> eugen
mav -> freqlabs
mav -> ram
+mckusick -> obiwac
+
mdf -> gleb
mdodd -> jake
diff --git a/stand/common/dev_net.c b/stand/common/dev_net.c
index fc6b43ec7a40..964fa514cac5 100644
--- a/stand/common/dev_net.c
+++ b/stand/common/dev_net.c
@@ -66,10 +66,6 @@
#include "dev_net.h"
#include "bootstrap.h"
-#ifdef NETIF_DEBUG
-int debug = 0;
-#endif
-
static char *netdev_name;
static int netdev_sock = -1;
static int netdev_opens;
@@ -143,11 +139,8 @@ net_open(struct open_file *f, ...)
return (ENXIO);
}
netdev_name = strdup(devname);
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: netif_open() succeeded\n",
- __func__);
-#endif
+ DEBUG_PRINTF(1,("%s: netif_open() succeeded %#x\n",
+ __func__, rootip.s_addr));
}
/*
* If network params were not set by netif_open(), try to get
@@ -200,10 +193,7 @@ net_close(struct open_file *f)
{
struct devdesc *dev;
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: opens=%d\n", __func__, netdev_opens);
-#endif
+ DEBUG_PRINTF(1,("%s: opens=%d\n", __func__, netdev_opens));
dev = f->f_devdata;
dev->d_opendata = NULL;
@@ -216,10 +206,7 @@ net_cleanup(void)
{
if (netdev_sock >= 0) {
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: calling netif_close()\n", __func__);
-#endif
+ DEBUG_PRINTF(1,("%s: calling netif_close()\n", __func__));
rootip.s_addr = 0;
free(netdev_name);
netif_close(netdev_sock);
@@ -271,10 +258,7 @@ net_getparams(int sock)
bootp(sock);
if (myip.s_addr != 0)
goto exit;
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: BOOTP failed, trying RARP/RPC...\n", __func__);
-#endif
+ DEBUG_PRINTF(1,("%s: BOOTP failed, trying RARP/RPC...\n", __func__));
#endif
/*
@@ -292,10 +276,7 @@ net_getparams(int sock)
printf("%s: bootparam/whoami RPC failed\n", __func__);
return (EIO);
}
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: client name: %s\n", __func__, hostname);
-#endif
+ DEBUG_PRINTF(1,("%s: client name: %s\n", __func__, hostname));
/*
* Ignore the gateway from whoami (unreliable).
@@ -309,16 +290,12 @@ net_getparams(int sock)
}
if (smask) {
netmask = smask;
-#ifdef NETIF_DEBUG
- if (debug)
- printf("%s: subnet mask: %s\n", __func__,
- intoa(netmask));
-#endif
+ DEBUG_PRINTF(1,("%s: subnet mask: %s\n", __func__,
+ intoa(netmask)));
}
-#ifdef NETIF_DEBUG
- if (gateip.s_addr && debug)
- printf("%s: net gateway: %s\n", __func__, inet_ntoa(gateip));
-#endif
+ if (gateip.s_addr)
+ DEBUG_PRINTF(1,("%s: net gateway: %s\n", __func__,
+ inet_ntoa(gateip)));
/* Get the root server and pathname. */
if (bp_getfile(sock, "root", &rootip, rootpath)) {
@@ -329,12 +306,10 @@ exit:
if ((rootaddr = net_parse_rootpath()) != INADDR_NONE)
rootip.s_addr = rootaddr;
-#ifdef NETIF_DEBUG
- if (debug) {
- printf("%s: server addr: %s\n", __func__, inet_ntoa(rootip));
- printf("%s: server path: %s\n", __func__, rootpath);
- }
-#endif
+ DEBUG_PRINTF(1,("%s: proto: %d\n", __func__, netproto));
+ DEBUG_PRINTF(1,("%s: server addr: %s\n", __func__, inet_ntoa(rootip)));
+ DEBUG_PRINTF(1,("%s: server port: %d\n", __func__, rootport));
+ DEBUG_PRINTF(1,("%s: server path: %s\n", __func__, rootpath));
return (0);
}
@@ -410,6 +385,8 @@ net_parse_rootpath(void)
(void)strsep(&ptr, ":");
if (ptr != NULL) {
addr = inet_addr(rootpath);
+ DEBUG_PRINTF(1,("rootpath=%s addr=%#x\n",
+ rootpath, addr));
bcopy(ptr, rootpath, strlen(ptr) + 1);
}
} else {
diff --git a/stand/libsa/bootp.c b/stand/libsa/bootp.c
index d919bb59e843..ac37553c6d34 100644
--- a/stand/libsa/bootp.c
+++ b/stand/libsa/bootp.c
@@ -42,7 +42,6 @@
#include <string.h>
-#define BOOTP_DEBUGxx
#define SUPPORT_DHCP
#define DHCP_ENV_NOVENDOR 1 /* do not parse vendor options */
@@ -130,10 +129,7 @@ bootp(int sock)
} wbuf;
struct bootp *rbootp;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootp: socket=%d\n", sock);
-#endif
+ DEBUG_PRINTF(1, ("bootp: socket=%d\n", sock));
if (!bot)
bot = getsecs();
@@ -141,10 +137,7 @@ bootp(int sock)
printf("bootp: bad socket. %d\n", sock);
return;
}
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootp: d=%lx\n", (long)d);
-#endif
+ DEBUG_PRINTF(1, ("bootp: socktodesc=%lx\n", (long)d));
bp = &wbuf.wbootp;
bzero(bp, sizeof(*bp));
@@ -225,31 +218,20 @@ bootp(int sock)
netmask = htonl(IN_CLASSB_NET);
else
netmask = htonl(IN_CLASSC_NET);
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("'native netmask' is %s\n", intoa(netmask));
-#endif
+ DEBUG_PRINTF(1, ("'native netmask' is %s\n", intoa(netmask)));
}
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("mask: %s\n", intoa(netmask));
-#endif
+ DEBUG_PRINTF(1,("rootip: %s\n", inet_ntoa(rootip)));
+ DEBUG_PRINTF(1,("mask: %s\n", intoa(netmask)));
/* We need a gateway if root is on a different net */
if (!SAMENET(myip, rootip, netmask)) {
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("need gateway for root ip\n");
-#endif
+ DEBUG_PRINTF(1,("need gateway for root ip\n"));
}
/* Toss gateway if on a different net */
if (!SAMENET(myip, gateip, netmask)) {
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("gateway ip (%s) bad\n", inet_ntoa(gateip));
-#endif
+ DEBUG_PRINTF(1,("gateway ip (%s) bad\n", inet_ntoa(gateip)));
gateip.s_addr = 0;
}
@@ -264,18 +246,11 @@ bootpsend(struct iodesc *d, void *pkt, size_t len)
{
struct bootp *bp;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootpsend: d=%lx called.\n", (long)d);
-#endif
-
+ DEBUG_PRINTF(1,("bootpsend: d=%lx called.\n", (long)d));
bp = pkt;
bp->bp_secs = htons((u_short)(getsecs() - bot));
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootpsend: calling sendudp\n");
-#endif
+ DEBUG_PRINTF(1,("bootpsend: calling sendudp\n"));
return (sendudp(d, pkt, len));
}
@@ -288,34 +263,22 @@ bootprecv(struct iodesc *d, void **pkt, void **payload, time_t tleft,
struct bootp *bp;
void *ptr;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootp_recvoffer: called\n");
-#endif
+ DEBUG_PRINTF(1,("bootp_recvoffer: called\n"));
ptr = NULL;
n = readudp(d, &ptr, (void **)&bp, tleft);
if (n == -1 || n < sizeof(struct bootp) - BOOTP_VENDSIZE)
goto bad;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootprecv: checked. bp = %p, n = %zd\n", bp, n);
-#endif
+ DEBUG_PRINTF(1,("bootprecv: checked. bp = %p, n = %zd\n", bp, n));
+
if (bp->bp_xid != htonl(d->xid)) {
-#ifdef BOOTP_DEBUG
- if (debug) {
- printf("bootprecv: expected xid 0x%lx, got 0x%x\n",
- d->xid, ntohl(bp->bp_xid));
- }
-#endif
+ DEBUG_PRINTF(1,("bootprecv: expected xid 0x%lx, got 0x%x\n",
+ d->xid, ntohl(bp->bp_xid)));
goto bad;
}
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("bootprecv: got one!\n");
-#endif
+ DEBUG_PRINTF(1,("bootprecv: got one!\n"));
/* Suck out vendor info */
if (bcmp(vm_rfc1048, bp->bp_vend, sizeof(vm_rfc1048)) == 0) {
@@ -359,10 +322,7 @@ vend_rfc1048(u_char *cp, u_int len)
u_char tag;
const char *val;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("vend_rfc1048 bootp info. len=%d\n", len);
-#endif
+ DEBUG_PRINTF(1,("vend_rfc1048 bootp info. len=%d\n", len));
ep = cp + len;
/* Step over magic cookie */
@@ -443,10 +403,8 @@ vend_cmu(u_char *cp)
{
struct cmu_vend *vp;
-#ifdef BOOTP_DEBUG
- if (debug)
- printf("vend_cmu bootp info.\n");
-#endif
+ DEBUG_PRINTF(1,("vend_cmu bootp info.\n"));
+
vp = (struct cmu_vend *)cp;
if (vp->v_smask.s_addr != 0) {
diff --git a/stand/libsa/pkgfs.c b/stand/libsa/pkgfs.c
index 64ebdf033f14..32d488de5cfb 100644
--- a/stand/libsa/pkgfs.c
+++ b/stand/libsa/pkgfs.c
@@ -31,12 +31,6 @@
#include <string.h>
#include <zlib.h>
-#ifdef PKGFS_DEBUG
-#define DBG(x) printf x
-#else
-#define DBG(x)
-#endif
-
static int pkg_open(const char *, struct open_file *);
static int pkg_close(struct open_file *);
static int pkg_read(struct open_file *, void *, size_t, size_t *);
@@ -172,6 +166,9 @@ pkgfs_init(const char *pkgname, struct fs_ops *proto)
exclusive_file_system = NULL;
+ DEBUG_PRINTF(0, ("%s(%s: '%s') -> %d (error=%d)\n", __func__,
+ proto->fs_name, pkgname, fd, errno));
+
if (fd == -1)
return (errno);
@@ -239,7 +236,7 @@ pkg_open_follow(const char *fn, struct open_file *f, int lnks)
if (strcmp(fn, tf->tf_hdr.ut_name) == 0) {
f->f_fsdata = tf;
tf->tf_fp = 0; /* Reset the file pointer. */
- DBG(("%s: found %s type %c\n", __func__,
+ DEBUG_PRINTF(1, ("%s: found %s type %c\n", __func__,
fn, tf->tf_hdr.ut_typeflag[0]));
if (tf->tf_hdr.ut_typeflag[0] == '2') {
/* we have a symlink
@@ -275,6 +272,7 @@ pkg_close(struct open_file *f)
/*
* Free up the cache if we read all of the file.
*/
+ DEBUG_PRINTF(1, ("%s(%s)\n", __func__, tf->tf_hdr.ut_name));
if (tf->tf_fp == tf->tf_size && tf->tf_cachesz > 0) {
free(tf->tf_cache);
tf->tf_cachesz = 0;
@@ -297,6 +295,8 @@ pkg_read(struct open_file *f, void *buf, size_t size, size_t *res)
return (EBADF);
}
+ DEBUG_PRINTF(4, ("%s(%s,%zd)\n", __func__, tf->tf_hdr.ut_name, size));
+
if (tf->tf_cachesz == 0)
cache_data(tf, 1);
@@ -334,6 +334,8 @@ pkg_read(struct open_file *f, void *buf, size_t size, size_t *res)
tf->tf_fp = fp;
if (res != NULL)
*res = size;
+ DEBUG_PRINTF(4, ("%s(%s) res=%zd\n", __func__, tf->tf_hdr.ut_name,
+ (ssize_t)(tf->tf_size - tf->tf_fp)));
return ((sz == -1) ? errno : 0);
}
@@ -377,7 +379,7 @@ pkg_seek(struct open_file *f, off_t ofs, int whence)
return (tf->tf_fp);
}
}
- DBG(("%s: negative file seek (%jd)\n", __func__,
+ DEBUG_PRINTF(3, ("%s: negative file seek (%jd)\n", __func__,
(intmax_t)delta));
errno = ESPIPE;
return (-1);
@@ -511,26 +513,28 @@ cache_data(struct tarfile *tf, int force)
size_t sz;
if (tf == NULL) {
- DBG(("%s: no file to cache data for?\n", __func__));
+ DEBUG_PRINTF(5, ("%s: no file to cache data for?\n",
+ __func__));
errno = EINVAL;
return (-1);
}
pkg = tf->tf_pkg;
if (pkg == NULL) {
- DBG(("%s: no package associated with file?\n", __func__));
+ DEBUG_PRINTF(5, ("%s: no package associated with file?\n",
+ __func__));
errno = EINVAL;
return (-1);
}
if (tf->tf_cachesz > 0) {
- DBG(("%s: data already cached\n", __func__));
+ DEBUG_PRINTF(5, ("%s: data already cached\n", __func__));
errno = EINVAL;
return (-1);
}
if (tf->tf_ofs != pkg->pkg_ofs) {
- DBG(("%s: caching after force read of file %s?\n",
+ DEBUG_PRINTF(5, ("%s: caching after force read of file %s?\n",
__func__, tf->tf_hdr.ut_name));
errno = EINVAL;
return (-1);
@@ -548,7 +552,8 @@ cache_data(struct tarfile *tf, int force)
tf->tf_cache = malloc(sz);
if (tf->tf_cache == NULL) {
- DBG(("%s: could not allocate %d bytes\n", __func__, (int)sz));
+ DEBUG_PRINTF(5, ("%s: could not allocate %d bytes\n",
+ __func__, (int)sz));
errno = ENOMEM;
return (-1);
}
@@ -732,7 +737,7 @@ new_package(int fd, struct package **pp)
}
/*
- * Done parsing the ZIP header. Spkgt the inflation engine.
+ * Done parsing the ZIP header. Start the inflation engine.
*/
error = inflateInit2(&pkg->pkg_zs, -15);
if (error != Z_OK)
diff --git a/stand/libsa/stand.h b/stand/libsa/stand.h
index e1188fb73a26..8b7d93074ef2 100644
--- a/stand/libsa/stand.h
+++ b/stand/libsa/stand.h
@@ -558,4 +558,17 @@ void tslog_getbuf(void ** buf, size_t * len);
__END_DECLS
+/* define _DEBUG_LEVEL n or _DEBUG_LEVEL_VAR before include */
+#ifndef DEBUG_PRINTF
+# if defined(_DEBUG_LEVEL) || defined(_DEBUG_LEVEL_VAR)
+# ifndef _DEBUG_LEVEL_VAR
+# define _DEBUG_LEVEL_VAR _debug
+static int _debug = _DEBUG_LEVEL;
+# endif
+# define DEBUG_PRINTF(n, args) if (_DEBUG_LEVEL_VAR >= n) printf args
+# else
+# define DEBUG_PRINTF(n, args)
+# endif
+#endif
+
#endif /* STAND_H */
diff --git a/stand/libsa/zfs/zfsimpl.c b/stand/libsa/zfs/zfsimpl.c
index c7dc72561eff..971d71d098d3 100644
--- a/stand/libsa/zfs/zfsimpl.c
+++ b/stand/libsa/zfs/zfsimpl.c
@@ -1106,7 +1106,8 @@ vdev_insert(vdev_t *top_vdev, vdev_t *vdev)
}
static int
-vdev_from_nvlist(spa_t *spa, uint64_t top_guid, const nvlist_t *nvlist)
+vdev_from_nvlist(spa_t *spa, uint64_t top_guid, uint64_t txg,
+ const nvlist_t *nvlist)
{
vdev_t *top_vdev, *vdev;
nvlist_t **kids = NULL;
@@ -1120,6 +1121,7 @@ vdev_from_nvlist(spa_t *spa, uint64_t top_guid, const nvlist_t *nvlist)
return (rc);
top_vdev->v_spa = spa;
top_vdev->v_top = top_vdev;
+ top_vdev->v_txg = txg;
vdev_insert(spa->spa_root_vdev, top_vdev);
}
@@ -1163,7 +1165,7 @@ done:
static int
vdev_init_from_label(spa_t *spa, const nvlist_t *nvlist)
{
- uint64_t pool_guid, top_guid;
+ uint64_t pool_guid, top_guid, txg;
nvlist_t *vdevs;
int rc;
@@ -1171,13 +1173,15 @@ vdev_init_from_label(spa_t *spa, const nvlist_t *nvlist)
NULL, &pool_guid, NULL) ||
nvlist_find(nvlist, ZPOOL_CONFIG_TOP_GUID, DATA_TYPE_UINT64,
NULL, &top_guid, NULL) ||
+ nvlist_find(nvlist, ZPOOL_CONFIG_POOL_TXG, DATA_TYPE_UINT64,
+ NULL, &txg, NULL) != 0 ||
nvlist_find(nvlist, ZPOOL_CONFIG_VDEV_TREE, DATA_TYPE_NVLIST,
NULL, &vdevs, NULL)) {
printf("ZFS: can't find vdev details\n");
return (ENOENT);
}
- rc = vdev_from_nvlist(spa, top_guid, vdevs);
+ rc = vdev_from_nvlist(spa, top_guid, txg, vdevs);
nvlist_destroy(vdevs);
return (rc);
}
@@ -1267,6 +1271,21 @@ vdev_update_from_nvlist(uint64_t top_guid, const nvlist_t *nvlist)
return (rc);
}
+/*
+ * Shall not be called on root vdev, that is not linked into zfs_vdevs.
+ * See comment in vdev_create().
+ */
+static void
+vdev_free(struct vdev *vdev)
+{
+ struct vdev *kid, *safe;
+
+ STAILQ_FOREACH_SAFE(kid, &vdev->v_children, v_childlink, safe)
+ vdev_free(kid);
+ STAILQ_REMOVE(&zfs_vdevs, vdev, vdev, v_alllink);
+ free(vdev);
+}
+
static int
vdev_init_from_nvlist(spa_t *spa, const nvlist_t *nvlist)
{
@@ -1313,9 +1332,10 @@ vdev_init_from_nvlist(spa_t *spa, const nvlist_t *nvlist)
vdev = vdev_find(guid);
/*
* Top level vdev is missing, create it.
+ * XXXGL: how can this happen?
*/
if (vdev == NULL)
- rc = vdev_from_nvlist(spa, guid, kids[i]);
+ rc = vdev_from_nvlist(spa, guid, 0, kids[i]);
else
rc = vdev_update_from_nvlist(guid, kids[i]);
if (rc != 0)
@@ -2006,8 +2026,7 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv,
vdev_t *vdev;
nvlist_t *nvl;
uint64_t val;
- uint64_t guid;
- uint64_t pool_txg, pool_guid;
+ uint64_t guid, pool_guid, top_guid, txg;
const char *pool_name;
int rc, namelen;
@@ -2063,7 +2082,9 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv,
}
if (nvlist_find(nvl, ZPOOL_CONFIG_POOL_TXG, DATA_TYPE_UINT64,
- NULL, &pool_txg, NULL) != 0 ||
+ NULL, &txg, NULL) != 0 ||
+ nvlist_find(nvl, ZPOOL_CONFIG_TOP_GUID, DATA_TYPE_UINT64,
+ NULL, &top_guid, NULL) != 0 ||
nvlist_find(nvl, ZPOOL_CONFIG_POOL_GUID, DATA_TYPE_UINT64,
NULL, &pool_guid, NULL) != 0 ||
nvlist_find(nvl, ZPOOL_CONFIG_POOL_NAME, DATA_TYPE_STRING,
@@ -2098,9 +2119,22 @@ vdev_probe(vdev_phys_read_t *_read, vdev_phys_write_t *_write, void *priv,
nvlist_destroy(nvl);
return (ENOMEM);
}
+ } else {
+ struct vdev *kid;
+
+ STAILQ_FOREACH(kid, &spa->spa_root_vdev->v_children,
+ v_childlink)
+ if (kid->v_guid == top_guid && kid->v_txg < txg) {
+ printf("ZFS: pool %s vdev %s ignoring stale "
+ "label from txg 0x%jx, using 0x%jx@0x%jx\n",
+ spa->spa_name, kid->v_name,
+ kid->v_txg, guid, txg);
+ STAILQ_REMOVE(&spa->spa_root_vdev->v_children,
+ kid, vdev, v_childlink);
+ vdev_free(kid);
+ break;
+ }
}
- if (pool_txg > spa->spa_txg)
- spa->spa_txg = pool_txg;
/*
* Get the vdev tree and create our in-core copy of it.
diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S
index 6e51ebff298a..5bb877a174f7 100644
--- a/sys/amd64/amd64/apic_vector.S
+++ b/sys/amd64/amd64/apic_vector.S
@@ -49,12 +49,6 @@
#include <machine/specialreg.h>
#include <x86/apicreg.h>
-#ifdef SMP
-#define LK lock ;
-#else
-#define LK
-#endif
-
.text
SUPERALIGN_TEXT
/* End Of Interrupt to APIC */
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index 2c7777e608b9..b2bfe633adcc 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -497,8 +497,8 @@ struct kva_layout_s kva_layout_la57 = {
.kva_min = KV5ADDR(NPML5EPG / 2, 0, 0, 0, 0), /* == rec_pt */
.dmap_low = KV5ADDR(DMPML5I, 0, 0, 0, 0),
.dmap_high = KV5ADDR(DMPML5I + NDMPML5E, 0, 0, 0, 0),
- .lm_low = KV4ADDR(LMSPML4I, 0, 0, 0),
- .lm_high = KV4ADDR(LMEPML4I + 1, 0, 0, 0),
+ .lm_low = KV5ADDR(LMSPML5I, 0, 0, 0, 0),
+ .lm_high = KV5ADDR(LMEPML5I + 1, 0, 0, 0, 0),
.km_low = KV4ADDR(KPML4BASE, 0, 0, 0),
.km_high = KV4ADDR(KPML4BASE + NKPML4E - 1, NPDPEPG - 1,
NPDEPG - 1, NPTEPG - 1),
@@ -2475,6 +2475,7 @@ pmap_init(void)
struct pmap_preinit_mapping *ppim;
vm_page_t m, mpte;
pml4_entry_t *pml4e;
+ unsigned long lm_max;
int error, i, ret, skz63;
/* L1TF, reserve page @0 unconditionally */
@@ -2600,10 +2601,15 @@ pmap_init(void)
lm_ents = 8;
TUNABLE_INT_FETCH("vm.pmap.large_map_pml4_entries", &lm_ents);
- if (lm_ents > LMEPML4I - LMSPML4I + 1)
- lm_ents = LMEPML4I - LMSPML4I + 1;
+ lm_max = (kva_layout.lm_high - kva_layout.lm_low) / NBPML4;
+ if (lm_ents > lm_max) {
+ printf(
+ "pmap: shrinking large map from requested %d slots to %ld slots\n",
+ lm_ents, lm_max);
+ lm_ents = lm_max;
+ }
#ifdef KMSAN
- if (lm_ents > KMSANORIGPML4I - LMSPML4I) {
+ if (!la57 && lm_ents > KMSANORIGPML4I - LMSPML4I) {
printf(
"pmap: shrinking large map for KMSAN (%d slots to %ld slots)\n",
lm_ents, KMSANORIGPML4I - LMSPML4I);
@@ -2615,12 +2621,20 @@ pmap_init(void)
lm_ents, (u_long)lm_ents * (NBPML4 / 1024 / 1024 / 1024));
if (lm_ents != 0) {
large_vmem = vmem_create("large", kva_layout.lm_low,
- (vmem_size_t)kva_layout.lm_high - kva_layout.lm_low,
- PAGE_SIZE, 0, M_WAITOK);
+ (vmem_size_t)lm_ents * NBPML4, PAGE_SIZE, 0, M_WAITOK);
if (large_vmem == NULL) {
printf("pmap: cannot create large map\n");
lm_ents = 0;
}
+ if (la57) {
+ for (i = 0; i < howmany((vm_offset_t)NBPML4 *
+ lm_ents, NBPML5); i++) {
+ m = pmap_large_map_getptp_unlocked();
+ kernel_pmap->pm_pmltop[LMSPML5I + i] = X86_PG_V |
+ X86_PG_RW | X86_PG_A | X86_PG_M |
+ pg_nx | VM_PAGE_TO_PHYS(m);
+ }
+ }
for (i = 0; i < lm_ents; i++) {
m = pmap_large_map_getptp_unlocked();
pml4e = pmap_pml4e(kernel_pmap, kva_layout.lm_low +
@@ -7561,6 +7575,9 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde, u_int flags,
PG_RW = pmap_rw_bit(pmap);
KASSERT((newpde & (pmap_modified_bit(pmap) | PG_RW)) != PG_RW,
("pmap_enter_pde: newpde is missing PG_M"));
+ KASSERT((flags & (PMAP_ENTER_NOREPLACE | PMAP_ENTER_NORECLAIM)) !=
+ PMAP_ENTER_NORECLAIM,
+ ("pmap_enter_pde: flags is missing PMAP_ENTER_NOREPLACE"));
PG_V = pmap_valid_bit(pmap);
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
@@ -7689,6 +7706,14 @@ pmap_enter_pde(pmap_t pmap, vm_offset_t va, pd_entry_t newpde, u_int flags,
if (!pmap_pv_insert_pde(pmap, va, newpde, flags, lockp)) {
if (pdpg != NULL)
pmap_abort_ptp(pmap, va, pdpg);
+ else {
+ KASSERT(va >= VM_MAXUSER_ADDRESS &&
+ (*pde & (PG_PS | PG_V)) == PG_V,
+ ("pmap_enter_pde: invalid kernel PDE"));
+ mt = pmap_remove_pt_page(pmap, va);
+ KASSERT(mt != NULL,
+ ("pmap_enter_pde: missing kernel PTP"));
+ }
if (uwptpg != NULL) {
mt = pmap_remove_pt_page(pmap, va);
KASSERT(mt == uwptpg,
@@ -10752,19 +10777,28 @@ pmap_large_map_getptp(void)
static pdp_entry_t *
pmap_large_map_pdpe(vm_offset_t va)
{
+ pml4_entry_t *pml4;
vm_pindex_t pml4_idx;
vm_paddr_t mphys;
- pml4_idx = pmap_pml4e_index(va);
- KASSERT(LMSPML4I <= pml4_idx && pml4_idx < LMSPML4I + lm_ents,
- ("pmap_large_map_pdpe: va %#jx out of range idx %#jx LMSPML4I "
- "%#jx lm_ents %d",
- (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
- KASSERT((kernel_pml4[pml4_idx] & X86_PG_V) != 0,
- ("pmap_large_map_pdpe: invalid pml4 for va %#jx idx %#jx "
- "LMSPML4I %#jx lm_ents %d",
- (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
- mphys = kernel_pml4[pml4_idx] & PG_FRAME;
+ KASSERT(va >= kva_layout.lm_low && va < kva_layout.lm_low +
+ (vm_offset_t)NBPML4 * lm_ents, ("va %#lx not in large map", va));
+ if (la57) {
+ pml4 = pmap_pml4e(kernel_pmap, va);
+ mphys = *pml4 & PG_FRAME;
+ } else {
+ pml4_idx = pmap_pml4e_index(va);
+
+ KASSERT(LMSPML4I <= pml4_idx && pml4_idx < LMSPML4I + lm_ents,
+ ("pmap_large_map_pdpe: va %#jx out of range idx %#jx "
+ "LMSPML4I %#jx lm_ents %d",
+ (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
+ KASSERT((kernel_pml4[pml4_idx] & X86_PG_V) != 0,
+ ("pmap_large_map_pdpe: invalid pml4 for va %#jx idx %#jx "
+ "LMSPML4I %#jx lm_ents %d",
+ (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
+ mphys = kernel_pml4[pml4_idx] & PG_FRAME;
+ }
return ((pdp_entry_t *)PHYS_TO_DMAP(mphys) + pmap_pdpe_index(va));
}
@@ -12133,10 +12167,12 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
for (sva = 0, i = pmap_pml4e_index(sva); i < NPML4EPG; i++) {
switch (i) {
case PML4PML4I:
- sbuf_printf(sb, "\nRecursive map:\n");
+ if (!la57)
+ sbuf_printf(sb, "\nRecursive map:\n");
break;
case DMPML4I:
- sbuf_printf(sb, "\nDirect map:\n");
+ if (!la57)
+ sbuf_printf(sb, "\nDirect map:\n");
break;
#ifdef KASAN
case KASANPML4I:
@@ -12155,7 +12191,8 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
sbuf_printf(sb, "\nKernel map:\n");
break;
case LMSPML4I:
- sbuf_printf(sb, "\nLarge map:\n");
+ if (!la57)
+ sbuf_printf(sb, "\nLarge map:\n");
break;
}
diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h
index 08e96027a5ed..a0ca97f2d5a0 100644
--- a/sys/amd64/include/pmap.h
+++ b/sys/amd64/include/pmap.h
@@ -202,9 +202,14 @@
#define KMSANSHADPML4I (KPML4BASE - NKMSANSHADPML4E)
#define KMSANORIGPML4I (DMPML4I - NKMSANORIGPML4E)
-/* Large map: index of the first and max last pml4 entry */
+/*
+ * Large map: index of the first and max last pml4/la48 and pml5/la57
+ * entry.
+ */
#define LMSPML4I (PML4PML4I + 1)
#define LMEPML4I (KASANPML4I - 1)
+#define LMSPML5I (DMPML5I + NDMPML5E)
+#define LMEPML5I (LMSPML5I + 32 - 1) /* 32 slots for large map */
/*
* XXX doesn't really belong here I guess...
diff --git a/sys/amd64/include/vmparam.h b/sys/amd64/include/vmparam.h
index 59053665dc40..ef352e776af6 100644
--- a/sys/amd64/include/vmparam.h
+++ b/sys/amd64/include/vmparam.h
@@ -181,9 +181,9 @@
* 0x0100000000000000 - 0xf0ffffffffffffff does not exist (hole)
* 0xff00000000000000 - 0xff00ffffffffffff recursive page table (2048TB slot)
* 0xff01000000000000 - 0xff20ffffffffffff direct map (32 x 2048TB slots)
- * 0xff21000000000000 - 0xffff807fffffffff unused
- * 0xffff808000000000 - 0xffff847fffffffff large map (can be tuned up)
- * 0xffff848000000000 - 0xfffff77fffffffff unused (large map extends there)
+ * 0xff21000000000000 - 0xff40ffffffffffff large map
+ * 0xff41000000000000 - 0xffff7fffffffffff unused
+ * 0xffff800000000000 - 0xfffff5ffffffffff unused (start of kernel pml4 entry)
* 0xfffff60000000000 - 0xfffff7ffffffffff 2TB KMSAN origin map, optional
* 0xfffff78000000000 - 0xfffff7bfffffffff 512GB KASAN shadow map, optional
* 0xfffff80000000000 - 0xfffffbffffffffff 4TB unused
@@ -249,7 +249,7 @@
*/
#define PHYS_IN_DMAP(pa) (dmaplimit == 0 || (pa) < dmaplimit)
#define VIRT_IN_DMAP(va) \
- ((va) >= kva_layout.dmap_low && (va) < kva_layout.dmap_high)
+ ((va) >= kva_layout.dmap_low && (va) < kva_layout.dmap_low + dmaplimit)
#define PMAP_HAS_DMAP 1
#define PHYS_TO_DMAP(x) __extension__ ({ \
diff --git a/sys/amd64/pt/pt.c b/sys/amd64/pt/pt.c
new file mode 100644
index 000000000000..c7b75767680a
--- /dev/null
+++ b/sys/amd64/pt/pt.c
@@ -0,0 +1,978 @@
+/*
+ * Copyright (c) 2025 Bojan Novković <bnovkov@freebsd.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * hwt(4) Intel Processor Trace (PT) backend
+ *
+ * Driver Design Overview
+ *
+ * - Since PT is configured on a per-core basis, the driver uses
+ * 'smp_rendezvous' to start and disable tracing on each target core.
+ * - PT-specific resources are stored in a 'struct pt_ctx' context structure for
+ * each traced CPU core or thread. Upon initialization, a ToPA configuration
+ * is generated for each 'pt_ctx' structure using the HWT tracing buffers.
+ * The HWT tracing buffer is split into 4K ToPA entries. Currently, each
+ * 4K ToPA entry is configured to trigger an interrupt after it is filled.
+ * - The PT driver uses the XSAVE/XRSTOR PT extensions to load and save all
+ * relevant PT registers. Every time a traced thread is switched
+ * out or in, its state will be saved to or loaded from its corresponding
+ * 'pt_ctx' context.
+ * - When tracing starts, the PT hardware will start writing data into the
+ * tracing buffer. When a TOPA_INT entry is filled, it will trigger an
+ * interrupt before continuing. The interrupt handler will then fetch the
+ * last valid tracing buffer offset and enqueue a HWT_RECORD_BUFFER record.
+ * The driver is currently configured to use the NMI interrupt line.
+ * - The userspace PT backend waits for incoming HWT_RECORD_BUFFER records
+ * and uses the offsets to decode data from the tracing buffer.
+ *
+ * Future improvements and limitations
+ *
+ * - We currently configure the PT hardware to trigger an interrupt whenever
+ * a 4K ToPA entry is filled. While this is fine when tracing smaller
+ * functions or infrequent code paths, this will generate too much interrupt
+ * traffic when tracing hotter functions. A proper solution for this issue
+ * should estimate the amount of data generated by the current configuration
+ * and use it to determine interrupt frequency.
+ *
+ * - Support for more tracing options and PT features.
+ *
+ */
+
+#include <sys/systm.h>
+#include <sys/hwt.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/sdt.h>
+#include <sys/smp.h>
+#include <sys/taskqueue.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+
+#include <machine/atomic.h>
+#include <machine/cpufunc.h>
+#include <machine/fpu.h>
+#include <machine/smp.h>
+#include <machine/specialreg.h>
+
+#include <x86/apicvar.h>
+#include <x86/x86_var.h>
+
+#include <dev/hwt/hwt_context.h>
+#include <dev/hwt/hwt_vm.h>
+#include <dev/hwt/hwt_backend.h>
+#include <dev/hwt/hwt_config.h>
+#include <dev/hwt/hwt_cpu.h>
+#include <dev/hwt/hwt_record.h>
+#include <dev/hwt/hwt_thread.h>
+
+#include <amd64/pt/pt.h>
+
+#ifdef PT_DEBUG
+#define dprintf(fmt, ...) printf(fmt, ##__VA_ARGS__)
+#else
+#define dprintf(fmt, ...)
+#endif
+#define PT_SUPPORTED_FLAGS \
+ (RTIT_CTL_MTCEN | RTIT_CTL_CR3FILTER | RTIT_CTL_DIS_TNT | \
+ RTIT_CTL_USER | RTIT_CTL_OS | RTIT_CTL_BRANCHEN)
+#define PT_XSAVE_MASK (XFEATURE_ENABLED_X87 | XFEATURE_ENABLED_SSE)
+#define PT_XSTATE_BV (PT_XSAVE_MASK | XFEATURE_ENABLED_PT)
+#define PT_MAX_IP_RANGES 2
+
+#define PT_TOPA_MASK_PTRS 0x7f
+#define PT_TOPA_PAGE_MASK 0xffffff80
+#define PT_TOPA_PAGE_SHIFT 7
+
+#define CPUID_PT_LEAF 0x14
+
+MALLOC_DEFINE(M_PT, "pt", "Intel Processor Trace");
+
+SDT_PROVIDER_DEFINE(pt);
+SDT_PROBE_DEFINE(pt, , , topa__intr);
+
+TASKQUEUE_FAST_DEFINE_THREAD(pt);
+
+static void pt_send_buffer_record(void *arg, int pending __unused);
+static int pt_topa_intr(struct trapframe *tf);
+
+/*
+ * Intel Processor Trace XSAVE-managed state.
+ */
+struct pt_ext_area {
+ uint64_t rtit_ctl;
+ uint64_t rtit_output_base;
+ uint64_t rtit_output_mask_ptrs;
+ uint64_t rtit_status;
+ uint64_t rtit_cr3_match;
+ uint64_t rtit_addr0_a;
+ uint64_t rtit_addr0_b;
+ uint64_t rtit_addr1_a;
+ uint64_t rtit_addr1_b;
+};
+
+struct pt_buffer {
+ uint64_t *topa_hw; /* ToPA table entries. */
+ size_t size;
+ struct mtx lock; /* Lock for fields below. */
+ vm_offset_t offset;
+ uint64_t wrap_count;
+ int curpage;
+};
+
+struct pt_ctx {
+ int id;
+ struct pt_buffer buf; /* ToPA buffer metadata */
+ struct task task; /* ToPA buffer notification task */
+ struct hwt_context *hwt_ctx;
+ uint8_t *save_area; /* PT XSAVE area */
+};
+/* PT tracing contexts used for CPU mode. */
+static struct pt_ctx *pt_pcpu_ctx;
+
+enum pt_cpu_state {
+ PT_DISABLED = 0,
+ PT_STOPPED,
+ PT_ACTIVE
+};
+
+static struct pt_cpu {
+ struct pt_ctx *ctx; /* active PT tracing context */
+ enum pt_cpu_state state; /* used as part of trace stop protocol */
+} *pt_pcpu;
+
+/*
+ * PT-related CPUID bits.
+ */
+static struct pt_cpu_info {
+ uint32_t l0_eax;
+ uint32_t l0_ebx;
+ uint32_t l0_ecx;
+ uint32_t l1_eax;
+ uint32_t l1_ebx;
+ size_t xsave_area_size;
+ size_t xstate_hdr_offset;
+ size_t pt_xsave_offset;
+} pt_info __read_mostly;
+
+static bool initialized = false;
+static int cpu_mode_ctr = 0;
+
+static __inline enum pt_cpu_state
+pt_cpu_get_state(int cpu_id)
+{
+ return (atomic_load_int(&pt_pcpu[cpu_id].state));
+}
+
+static __inline void
+pt_cpu_set_state(int cpu_id, enum pt_cpu_state state)
+{
+ atomic_store_int(&pt_pcpu[cpu_id].state, state);
+}
+
+static __inline struct xstate_hdr *
+pt_ctx_get_xstate_hdr(struct pt_ctx *ctx)
+{
+ return ((struct xstate_hdr *)(ctx->save_area +
+ pt_info.xstate_hdr_offset));
+}
+
+
+static __inline struct pt_ext_area *
+pt_ctx_get_ext_area(struct pt_ctx *ctx)
+{
+ return ((struct pt_ext_area *)(ctx->save_area +
+ pt_info.pt_xsave_offset));
+}
+
+/*
+ * Updates current trace buffer offset from the
+ * ToPA MSRs. Records if the trace buffer wrapped.
+ */
+static __inline void
+pt_update_buffer(struct pt_buffer *buf)
+{
+ uint64_t reg;
+ int curpage;
+
+ /* Update buffer offset. */
+ reg = rdmsr(MSR_IA32_RTIT_OUTPUT_MASK_PTRS);
+ curpage = (reg & PT_TOPA_PAGE_MASK) >> PT_TOPA_PAGE_SHIFT;
+ mtx_lock_spin(&buf->lock);
+ /* Check if the output wrapped. */
+ if (buf->curpage > curpage)
+ buf->wrap_count++;
+ buf->curpage = curpage;
+ buf->offset = reg >> 32;
+ mtx_unlock_spin(&buf->lock);
+
+ dprintf("%s: wrap_cnt: %lu, curpage: %d, offset: %zu\n", __func__,
+ buf->wrap_count, buf->curpage, buf->offset);
+}
+
+static __inline void
+pt_fill_buffer_record(int id, struct pt_buffer *buf,
+ struct hwt_record_entry *rec)
+{
+ rec->record_type = HWT_RECORD_BUFFER;
+ rec->buf_id = id;
+ rec->curpage = buf->curpage;
+ rec->offset = buf->offset + (buf->wrap_count * buf->size);
+}
+
+/*
+ * Enables or disables tracing on curcpu
+ * using the XSAVE/XRSTOR PT extensions.
+ */
+static void
+pt_cpu_toggle_local(uint8_t *save_area, bool enable)
+{
+ u_long xcr0, cr0;
+ u_long xss;
+
+ cr0 = rcr0();
+ if (cr0 & CR0_TS)
+ clts();
+ xcr0 = rxcr(XCR0);
+ if ((xcr0 & PT_XSAVE_MASK) != PT_XSAVE_MASK)
+ load_xcr(XCR0, xcr0 | PT_XSAVE_MASK);
+ xss = rdmsr(MSR_IA32_XSS);
+ wrmsr(MSR_IA32_XSS, xss | XFEATURE_ENABLED_PT);
+
+ if (!enable) {
+ KASSERT((rdmsr(MSR_IA32_RTIT_CTL) & RTIT_CTL_TRACEEN) != 0,
+ ("%s: PT is disabled", __func__));
+ xsaves(save_area, XFEATURE_ENABLED_PT);
+ } else {
+ KASSERT((rdmsr(MSR_IA32_RTIT_CTL) & RTIT_CTL_TRACEEN) == 0,
+ ("%s: PT is enabled", __func__));
+ xrstors(save_area, XFEATURE_ENABLED_PT);
+ }
+ wrmsr(MSR_IA32_XSS, xss);
+ if ((xcr0 & PT_XSAVE_MASK) != PT_XSAVE_MASK)
+ load_xcr(XCR0, xcr0);
+ if (cr0 & CR0_TS)
+ load_cr0(cr0);
+}
+
+/*
+ * Starts PT tracing on 'curcpu'.
+ */
+static void
+pt_cpu_start(void *dummy)
+{
+ struct pt_cpu *cpu;
+
+ cpu = &pt_pcpu[curcpu];
+ MPASS(cpu->ctx != NULL);
+
+ dprintf("%s: curcpu %d\n", __func__, curcpu);
+ load_cr4(rcr4() | CR4_XSAVE);
+ wrmsr(MSR_IA32_RTIT_STATUS, 0);
+ pt_cpu_set_state(curcpu, PT_ACTIVE);
+ pt_cpu_toggle_local(cpu->ctx->save_area, true);
+}
+
+/*
+ * Stops PT tracing on 'curcpu'.
+ * Updates trace buffer offset to ensure
+ * any data generated between the last interrupt
+ * and the trace stop gets picked up by userspace.
+ */
+static void
+pt_cpu_stop(void *dummy)
+{
+ struct pt_cpu *cpu;
+ struct pt_ctx *ctx;
+
+ /* Shutdown may occur before PT gets properly configured. */
+ if (pt_cpu_get_state(curcpu) == PT_DISABLED)
+ return;
+
+ cpu = &pt_pcpu[curcpu];
+ ctx = cpu->ctx;
+ MPASS(ctx != NULL);
+ dprintf("%s: curcpu %d\n", __func__, curcpu);
+
+ pt_cpu_set_state(curcpu, PT_STOPPED);
+ pt_cpu_toggle_local(cpu->ctx->save_area, false);
+ pt_update_buffer(&ctx->buf);
+}
+
+/*
+ * Prepares the Table of Physical Addresses (ToPA) metadata for 'pt_ctx'.
+ * The HWT trace buffer is split into 4K ToPA table entries and used
+ * as a circular buffer, meaning that the last ToPA entry points to
+ * the first ToPA entry. Each entry is configured to raise an
+ * interrupt after being filled.
+ */
+static int
+pt_topa_prepare(struct pt_ctx *ctx, struct hwt_vm *vm)
+{
+ struct pt_buffer *buf;
+ size_t topa_size;
+ int i;
+
+ topa_size = TOPA_SIZE_4K;
+ buf = &ctx->buf;
+
+ KASSERT(buf->topa_hw == NULL,
+ ("%s: ToPA info already exists", __func__));
+ buf->topa_hw = mallocarray(vm->npages + 1, sizeof(uint64_t), M_PT,
+ M_ZERO | M_WAITOK);
+ dprintf("%s: ToPA virt addr %p\n", __func__, buf->topa_hw);
+ buf->size = vm->npages * PAGE_SIZE;
+ for (i = 0; i < vm->npages; i++) {
+ buf->topa_hw[i] = VM_PAGE_TO_PHYS(vm->pages[i]) | topa_size;
+ /*
+ * XXX: TOPA_INT should ideally be set according to
+ * expected amount of incoming trace data. Too few TOPA_INT
+ * entries will not trigger interrupts often enough when tracing
+ * smaller functions.
+ */
+ buf->topa_hw[i] |= TOPA_INT;
+ }
+ buf->topa_hw[vm->npages] = (uint64_t)vtophys(buf->topa_hw) | TOPA_END;
+
+ return (0);
+}
+
+/*
+ * Configures IP filtering for trace generation.
+ * A maximum of 2 ranges can be specified due to
+ * limitations imposed by the XSAVE/XRSTOR PT extensions.
+ */
+static int
+pt_configure_ranges(struct pt_ctx *ctx, struct pt_cpu_config *cfg)
+{
+ struct pt_ext_area *pt_ext;
+ int nranges_supp, n, error = 0;
+
+ pt_ext = pt_ctx_get_ext_area(ctx);
+ if (pt_info.l0_ebx & CPUPT_IPF) {
+ nranges_supp = (pt_info.l1_eax & CPUPT_NADDR_M) >>
+ CPUPT_NADDR_S;
+
+ if (nranges_supp > PT_IP_FILTER_MAX_RANGES)
+ nranges_supp = PT_IP_FILTER_MAX_RANGES;
+ n = cfg->nranges;
+ if (n > nranges_supp) {
+ printf("%s: %d IP filtering ranges requested, CPU "
+ "supports %d, truncating\n",
+ __func__, n, nranges_supp);
+ n = nranges_supp;
+ }
+
+ switch (n) {
+ case 2:
+ pt_ext->rtit_ctl |= (1UL << RTIT_CTL_ADDR_CFG_S(1));
+ pt_ext->rtit_addr1_a = cfg->ip_ranges[1].start;
+ pt_ext->rtit_addr1_b = cfg->ip_ranges[1].end;
+ case 1:
+ pt_ext->rtit_ctl |= (1UL << RTIT_CTL_ADDR_CFG_S(0));
+ pt_ext->rtit_addr0_a = cfg->ip_ranges[0].start;
+ pt_ext->rtit_addr0_b = cfg->ip_ranges[0].end;
+ break;
+ default:
+ error = (EINVAL);
+ break;
+ };
+ } else
+ error = (ENXIO);
+
+ return (error);
+}
+
+static int
+pt_init_ctx(struct pt_ctx *pt_ctx, struct hwt_vm *vm, int ctx_id)
+{
+
+ dprintf("%s: ctx id %d\n", __func__, ctx_id);
+
+ KASSERT(pt_ctx->buf.topa_hw == NULL,
+ ("%s: active ToPA buffer in context %p\n", __func__, pt_ctx));
+
+ memset(pt_ctx, 0, sizeof(struct pt_ctx));
+ mtx_init(&pt_ctx->buf.lock, "pttopa", NULL, MTX_SPIN);
+ pt_ctx->save_area = malloc_aligned(pt_info.xsave_area_size, 64,
+ M_PT, M_NOWAIT | M_ZERO);
+ if (pt_ctx->save_area == NULL)
+ return (ENOMEM);
+ dprintf("%s: preparing ToPA buffer\n", __func__);
+ if (pt_topa_prepare(pt_ctx, vm) != 0) {
+ dprintf("%s: failed to prepare ToPA buffer\n", __func__);
+ free(pt_ctx->save_area, M_PT);
+ return (ENOMEM);
+ }
+
+ pt_ctx->id = ctx_id;
+ TASK_INIT(&pt_ctx->task, 0, pt_send_buffer_record, pt_ctx);
+
+ return (0);
+}
+
+static void
+pt_deinit_ctx(struct pt_ctx *pt_ctx)
+{
+
+ if (pt_ctx->buf.topa_hw != NULL)
+ free(pt_ctx->buf.topa_hw, M_PT);
+ if (pt_ctx->save_area != NULL)
+ free(pt_ctx->save_area, M_PT);
+ memset(pt_ctx, 0, sizeof(*pt_ctx));
+ pt_ctx->buf.topa_hw = NULL;
+}
+
+/*
+ * HWT backend configuration method.
+ *
+ * Checks and translates the user-defined configuration to a
+ * set of PT tracing features. Uses the feature set to initialize
+ * the tracing context for the target CPU or thread.
+ */
+static int
+pt_backend_configure(struct hwt_context *ctx, int cpu_id, int thread_id)
+{
+ struct hwt_cpu *hwt_cpu;
+ struct hwt_thread *thr;
+ struct pt_ctx *pt_ctx;
+ struct pt_cpu_config *cfg;
+ struct pt_ext_area *pt_ext;
+ struct xstate_hdr *hdr;
+ int error;
+
+ dprintf("%s\n", __func__);
+
+ cfg = (struct pt_cpu_config *)ctx->config;
+ pt_ctx = NULL;
+
+ /* Clear any flags we don't support yet. */
+ cfg->rtit_ctl &= PT_SUPPORTED_FLAGS;
+ if (cfg->rtit_ctl & RTIT_CTL_MTCEN) {
+ if ((pt_info.l0_ebx & CPUPT_MTC) == 0) {
+ printf("%s: CPU does not support generating MTC "
+ "packets\n", __func__);
+ return (ENXIO);
+ }
+ }
+
+ if (cfg->rtit_ctl & RTIT_CTL_CR3FILTER) {
+ if ((pt_info.l0_ebx & CPUPT_CR3) == 0) {
+ printf("%s: CPU does not support CR3 filtering\n",
+ __func__);
+ return (ENXIO);
+ }
+ }
+
+ if (cfg->rtit_ctl & RTIT_CTL_DIS_TNT) {
+ if ((pt_info.l0_ebx & CPUPT_DIS_TNT) == 0) {
+ printf("%s: CPU does not support TNT\n", __func__);
+ return (ENXIO);
+ }
+ }
+ /* TODO: support for more config bits. */
+
+ if (ctx->mode == HWT_MODE_CPU) {
+ TAILQ_FOREACH(hwt_cpu, &ctx->cpus, next) {
+ if (hwt_cpu->cpu_id != cpu_id)
+ continue;
+ pt_ctx = &pt_pcpu_ctx[cpu_id];
+ break;
+ }
+ } else {
+ TAILQ_FOREACH(thr, &ctx->threads, next) {
+ if (thr->thread_id != thread_id)
+ continue;
+ KASSERT(thr->private != NULL,
+ ("%s: hwt thread private"
+ " not set, thr %p",
+ __func__, thr));
+ pt_ctx = (struct pt_ctx *)thr->private;
+ break;
+ }
+ }
+ if (pt_ctx == NULL)
+ return (ENOENT);
+
+ dprintf("%s: preparing MSRs\n", __func__);
+ pt_ext = pt_ctx_get_ext_area(pt_ctx);
+ hdr = pt_ctx_get_xstate_hdr(pt_ctx);
+
+ pt_ext->rtit_ctl |= cfg->rtit_ctl;
+ if (cfg->nranges != 0) {
+ dprintf("%s: preparing IPF ranges\n", __func__);
+ if ((error = pt_configure_ranges(pt_ctx, cfg)) != 0)
+ return (error);
+ }
+ pt_ctx->hwt_ctx = ctx;
+ pt_ext->rtit_ctl |= RTIT_CTL_TOPA;
+ pt_ext->rtit_output_base = (uint64_t)vtophys(pt_ctx->buf.topa_hw);
+ pt_ext->rtit_output_mask_ptrs = PT_TOPA_MASK_PTRS;
+ hdr->xstate_bv = XFEATURE_ENABLED_PT;
+ hdr->xstate_xcomp_bv = XFEATURE_ENABLED_PT |
+ XSTATE_XCOMP_BV_COMPACT;
+ pt_ext->rtit_ctl |= RTIT_CTL_TRACEEN;
+ pt_pcpu[cpu_id].ctx = pt_ctx;
+ pt_cpu_set_state(cpu_id, PT_STOPPED);
+
+ return (0);
+}
+
+/*
+ * hwt backend trace start operation. CPU affine.
+ */
+static void
+pt_backend_enable(struct hwt_context *ctx, int cpu_id)
+{
+ if (ctx->mode == HWT_MODE_CPU)
+ return;
+
+ KASSERT(curcpu == cpu_id,
+ ("%s: attempting to start PT on another cpu", __func__));
+ pt_cpu_start(NULL);
+ CPU_SET(cpu_id, &ctx->cpu_map);
+}
+
+/*
+ * hwt backend trace stop operation. CPU affine.
+ */
+static void
+pt_backend_disable(struct hwt_context *ctx, int cpu_id)
+{
+ struct pt_cpu *cpu;
+
+ if (ctx->mode == HWT_MODE_CPU)
+ return;
+
+ KASSERT(curcpu == cpu_id,
+ ("%s: attempting to disable PT on another cpu", __func__));
+ pt_cpu_stop(NULL);
+ CPU_CLR(cpu_id, &ctx->cpu_map);
+ cpu = &pt_pcpu[cpu_id];
+ cpu->ctx = NULL;
+}
+
+/*
+ * hwt backend trace start operation for remote CPUs.
+ */
+static int
+pt_backend_enable_smp(struct hwt_context *ctx)
+{
+
+ dprintf("%s\n", __func__);
+ if (ctx->mode == HWT_MODE_CPU &&
+ atomic_swap_32(&cpu_mode_ctr, 1) != 0)
+ return (-1);
+
+ KASSERT(ctx->mode == HWT_MODE_CPU,
+ ("%s: should only be used for CPU mode", __func__));
+ smp_rendezvous_cpus(ctx->cpu_map, NULL, pt_cpu_start, NULL, NULL);
+
+ return (0);
+}
+
+/*
+ * hwt backend trace stop operation for remote CPUs.
+ */
+static int
+pt_backend_disable_smp(struct hwt_context *ctx)
+{
+
+ dprintf("%s\n", __func__);
+ if (ctx->mode == HWT_MODE_CPU &&
+ atomic_swap_32(&cpu_mode_ctr, 0) == 0)
+ return (-1);
+
+ if (CPU_EMPTY(&ctx->cpu_map)) {
+ dprintf("%s: empty cpu map\n", __func__);
+ return (-1);
+ }
+ smp_rendezvous_cpus(ctx->cpu_map, NULL, pt_cpu_stop, NULL, NULL);
+
+ return (0);
+}
+
+/*
+ * HWT backend initialization method.
+ *
+ * Installs the ToPA interrupt handler and initializes
+ * the tracing contexts used for HWT_MODE_CPU.
+ */
+static int
+pt_backend_init(struct hwt_context *ctx)
+{
+ struct hwt_cpu *hwt_cpu;
+ int error;
+
+ dprintf("%s\n", __func__);
+ if (ctx->mode == HWT_MODE_CPU) {
+ TAILQ_FOREACH(hwt_cpu, &ctx->cpus, next) {
+ error = pt_init_ctx(&pt_pcpu_ctx[hwt_cpu->cpu_id],
+ hwt_cpu->vm, hwt_cpu->cpu_id);
+ if (error)
+ return (error);
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * HWT backend teardown method.
+ *
+ * Removes the ToPA interrupt handler, stops tracing on all active CPUs,
+ * and releases all previously allocated ToPA metadata.
+ */
+static int
+pt_backend_deinit(struct hwt_context *ctx)
+{
+ struct pt_ctx *pt_ctx;
+ struct hwt_thread *thr;
+ int cpu_id;
+
+ dprintf("%s\n", __func__);
+
+ pt_backend_disable_smp(ctx);
+ if (ctx->mode == HWT_MODE_THREAD) {
+ TAILQ_FOREACH(thr, &ctx->threads, next) {
+ KASSERT(thr->private != NULL,
+ ("%s: thr->private not set", __func__));
+ pt_ctx = (struct pt_ctx *)thr->private;
+ pt_deinit_ctx(pt_ctx);
+ }
+ } else {
+ CPU_FOREACH(cpu_id) {
+ if (!CPU_ISSET(cpu_id, &ctx->cpu_map))
+ continue;
+ if (pt_pcpu[cpu_id].ctx != NULL) {
+ KASSERT(pt_pcpu[cpu_id].ctx ==
+ &pt_pcpu_ctx[cpu_id],
+ ("%s: CPU mode tracing with non-cpu mode PT"
+ "context active",
+ __func__));
+ pt_pcpu[cpu_id].ctx = NULL;
+ }
+ pt_ctx = &pt_pcpu_ctx[cpu_id];
+ pt_deinit_ctx(pt_ctx);
+ memset(&pt_pcpu[cpu_id], 0, sizeof(struct pt_cpu));
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Fetches current offset into the tracing buffer.
+ */
+static int
+pt_backend_read(struct hwt_vm *vm, int *curpage, vm_offset_t *curpage_offset,
+ uint64_t *data)
+{
+ struct pt_buffer *buf;
+
+ if (vm->ctx->mode == HWT_MODE_THREAD)
+ buf = &((struct pt_ctx *)vm->thr->private)->buf;
+ else
+ buf = &pt_pcpu[vm->cpu->cpu_id].ctx->buf;
+ mtx_lock_spin(&buf->lock);
+ *curpage = buf->curpage;
+ *curpage_offset = buf->offset + (buf->wrap_count * vm->ctx->bufsize);
+ mtx_unlock_spin(&buf->lock);
+
+ return (0);
+}
+
+/*
+ * HWT thread creation hook.
+ * Allocates and associates a 'struct pt_ctx' for a given hwt thread.
+ */
+static int
+pt_backend_alloc_thread(struct hwt_thread *thr)
+{
+ struct pt_ctx *pt_ctx;
+ int error;
+
+ /* Omit M_WAITOK since this might get invoked a non-sleepable context */
+ pt_ctx = malloc(sizeof(*pt_ctx), M_PT, M_NOWAIT | M_ZERO);
+ if (pt_ctx == NULL)
+ return (ENOMEM);
+
+ error = pt_init_ctx(pt_ctx, thr->vm, thr->thread_id);
+ if (error)
+ return (error);
+
+ thr->private = pt_ctx;
+ return (0);
+}
+/*
+ * HWT thread teardown hook.
+ */
+static void
+pt_backend_free_thread(struct hwt_thread *thr)
+{
+ struct pt_ctx *ctx;
+
+ ctx = (struct pt_ctx *)thr->private;
+
+ pt_deinit_ctx(ctx);
+ free(ctx, M_PT);
+}
+
+static void
+pt_backend_dump(int cpu_id)
+{
+}
+
+static struct hwt_backend_ops pt_ops = {
+ .hwt_backend_init = pt_backend_init,
+ .hwt_backend_deinit = pt_backend_deinit,
+
+ .hwt_backend_configure = pt_backend_configure,
+
+ .hwt_backend_enable = pt_backend_enable,
+ .hwt_backend_disable = pt_backend_disable,
+
+#ifdef SMP
+ .hwt_backend_enable_smp = pt_backend_enable_smp,
+ .hwt_backend_disable_smp = pt_backend_disable_smp,
+#endif
+
+ .hwt_backend_read = pt_backend_read,
+ .hwt_backend_dump = pt_backend_dump,
+
+ .hwt_backend_thread_alloc = pt_backend_alloc_thread,
+ .hwt_backend_thread_free = pt_backend_free_thread,
+};
+
+static struct hwt_backend backend = {
+ .ops = &pt_ops,
+ .name = "pt",
+ .kva_req = 1,
+};
+
+/*
+ * Reads the latest valid trace buffer offset and enqueues
+ * a HWT_RECORD_BUFFER record.
+ * Used as a taskqueue routine from the ToPA interrupt handler.
+ */
+static void
+pt_send_buffer_record(void *arg, int pending __unused)
+{
+ struct hwt_record_entry record;
+ struct pt_ctx *ctx = (struct pt_ctx *)arg;
+
+ /* Prepare buffer record. */
+ mtx_lock_spin(&ctx->buf.lock);
+ pt_fill_buffer_record(ctx->id, &ctx->buf, &record);
+ mtx_unlock_spin(&ctx->buf.lock);
+ hwt_record_ctx(ctx->hwt_ctx, &record, M_ZERO | M_NOWAIT);
+}
+static void
+pt_topa_status_clear(void)
+{
+ uint64_t reg;
+
+ reg = rdmsr(MSR_IA_GLOBAL_STATUS_RESET);
+ reg &= ~GLOBAL_STATUS_FLAG_TRACETOPAPMI;
+ reg |= GLOBAL_STATUS_FLAG_TRACETOPAPMI;
+ wrmsr(MSR_IA_GLOBAL_STATUS_RESET, reg);
+}
+
+/*
+ * ToPA PMI handler.
+ *
+ * Invoked every time a ToPA entry marked with TOPA_INT is filled.
+ * Uses taskqueue to enqueue a buffer record for userspace.
+ * Re-enables the PC interrupt line as long as tracing is active.
+ */
+static int
+pt_topa_intr(struct trapframe *tf)
+{
+ struct pt_buffer *buf;
+ struct pt_ctx *ctx;
+ uint64_t reg;
+
+ SDT_PROBE0(pt, , , topa__intr);
+
+ if (pt_cpu_get_state(curcpu) != PT_ACTIVE) {
+ return (0);
+ }
+ reg = rdmsr(MSR_IA_GLOBAL_STATUS);
+ if ((reg & GLOBAL_STATUS_FLAG_TRACETOPAPMI) == 0) {
+ /* ACK spurious or leftover interrupt. */
+ pt_topa_status_clear();
+ return (1);
+ }
+
+ ctx = pt_pcpu[curcpu].ctx;
+ buf = &ctx->buf;
+ KASSERT(buf->topa_hw != NULL,
+ ("%s: ToPA PMI interrupt with invalid buffer", __func__));
+
+ pt_cpu_toggle_local(ctx->save_area, false);
+ pt_update_buffer(buf);
+ pt_topa_status_clear();
+ taskqueue_enqueue_flags(taskqueue_pt, &ctx->task,
+ TASKQUEUE_FAIL_IF_PENDING);
+
+ if (pt_cpu_get_state(curcpu) == PT_ACTIVE) {
+ pt_cpu_toggle_local(ctx->save_area, true);
+ lapic_reenable_pcint();
+ }
+ return (1);
+}
+
+/*
+ * Module initialization.
+ *
+ * Saves all PT-related cpuid info, registers itself as a HWT backend,
+ * and allocates metadata required to keep track of tracing operations
+ * on each CPU.
+ */
+static int
+pt_init(void)
+{
+ u_int cp[4];
+ int error;
+
+ dprintf("pt: Enumerating part 1\n");
+ cpuid_count(CPUID_PT_LEAF, 0, cp);
+ dprintf("pt: Maximum valid sub-leaf Index: %x\n", cp[0]);
+ dprintf("pt: ebx %x\n", cp[1]);
+ dprintf("pt: ecx %x\n", cp[2]);
+
+ pt_info.l0_eax = cp[0];
+ pt_info.l0_ebx = cp[1];
+ pt_info.l0_ecx = cp[2];
+
+ dprintf("pt: Enumerating part 2\n");
+ cpuid_count(CPUID_PT_LEAF, 1, cp);
+ dprintf("pt: eax %x\n", cp[0]);
+ dprintf("pt: ebx %x\n", cp[1]);
+
+ pt_info.l1_eax = cp[0];
+ pt_info.l1_ebx = cp[1];
+
+ error = hwt_backend_register(&backend);
+ if (error != 0) {
+ printf("pt: unable to register hwt backend, error %d\n", error);
+ return (error);
+ }
+ pt_pcpu = mallocarray(mp_ncpus, sizeof(struct pt_cpu), M_PT,
+ M_ZERO | M_WAITOK);
+ pt_pcpu_ctx = mallocarray(mp_ncpus, sizeof(struct pt_ctx), M_PT,
+ M_ZERO | M_WAITOK);
+
+ nmi_register_handler(pt_topa_intr);
+ if (!lapic_enable_pcint()) {
+ nmi_remove_handler(pt_topa_intr);
+ hwt_backend_unregister(&backend);
+ free(pt_pcpu, M_PT);
+ free(pt_pcpu_ctx, M_PT);
+ pt_pcpu = NULL;
+ pt_pcpu_ctx = NULL;
+ printf("pt: failed to setup interrupt line\n");
+ return (error);
+ }
+ initialized = true;
+
+ return (0);
+}
+
+/*
+ * Checks whether the CPU support Intel PT and
+ * initializes XSAVE area info.
+ *
+ * The driver relies on XSAVE/XRSTOR PT extensions,
+ * Table of Physical Addresses (ToPA) support, and
+ * support for multiple ToPA entries.
+ */
+static bool
+pt_supported(void)
+{
+ u_int cp[4];
+
+ if ((cpu_stdext_feature & CPUID_STDEXT_PROCTRACE) == 0) {
+ printf("pt: CPU does not support Intel Processor Trace\n");
+ return (false);
+ }
+ if ((cpu_feature2 & CPUID2_XSAVE) == 0) {
+ printf("pt: XSAVE is not supported\n");
+ return (false);
+ }
+ if (!xsave_extfeature_supported(XFEATURE_ENABLED_PT, true)) {
+ printf("pt: CPU does not support managing PT state using XSAVE\n");
+ return (false);
+ }
+ if (!xsave_extension_supported(CPUID_EXTSTATE_XSAVEC)) {
+ printf("pt: XSAVE compaction is not supported\n");
+ return (false);
+ }
+ if (!xsave_extension_supported(CPUID_EXTSTATE_XSAVES)) {
+ printf("pt: CPU does not support XSAVES/XRSTORS\n");
+ return (false);
+ }
+
+ /* Require ToPA support. */
+ cpuid_count(CPUID_PT_LEAF, 0, cp);
+ if ((cp[2] & CPUPT_TOPA) == 0) {
+ printf("pt: ToPA is not supported\n");
+ return (false);
+ }
+ if ((cp[2] & CPUPT_TOPA_MULTI) == 0) {
+ printf("pt: multiple ToPA outputs are not supported\n");
+ return (false);
+ }
+
+ pt_info.xstate_hdr_offset = xsave_area_hdr_offset();
+ pt_info.xsave_area_size = xsave_area_size(PT_XSTATE_BV, true, true);
+ pt_info.pt_xsave_offset = xsave_area_offset(PT_XSTATE_BV,
+ XFEATURE_ENABLED_PT, true, true);
+
+ return (true);
+}
+
+static void
+pt_deinit(void)
+{
+ if (!initialized)
+ return;
+ nmi_remove_handler(pt_topa_intr);
+ lapic_disable_pcint();
+ hwt_backend_unregister(&backend);
+ free(pt_pcpu, M_PT);
+ free(pt_pcpu_ctx, M_PT);
+ pt_pcpu = NULL;
+ initialized = false;
+}
+
+static int
+pt_modevent(module_t mod, int type, void *data)
+{
+ switch (type) {
+ case MOD_LOAD:
+ if (!pt_supported() || pt_init() != 0) {
+ return (ENXIO);
+ }
+ break;
+ case MOD_UNLOAD:
+ pt_deinit();
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+static moduledata_t pt_mod = { "intel_pt", pt_modevent, NULL };
+
+DECLARE_MODULE(intel_pt, pt_mod, SI_SUB_DRIVERS, SI_ORDER_FIRST);
+MODULE_DEPEND(intel_pt, hwt, 1, 1, 1);
+MODULE_VERSION(intel_pt, 1);
diff --git a/sys/amd64/pt/pt.h b/sys/amd64/pt/pt.h
new file mode 100644
index 000000000000..2423afdf22e9
--- /dev/null
+++ b/sys/amd64/pt/pt.h
@@ -0,0 +1,49 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2023 Bojan Novković <bnovkov@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.
+ */
+
+#ifndef _AMD64_PT_PT_H_
+#define _AMD64_PT_PT_H_
+
+#include <sys/types.h>
+
+#include <x86/include/specialreg.h>
+
+#define PT_IP_FILTER_MAX_RANGES (2) /* Intel SDM Vol. 3C, 33-29 */
+
+struct pt_cpu_config {
+ uint64_t rtit_ctl;
+ register_t cr3_filter;
+ int nranges;
+ struct ipf_range {
+ vm_offset_t start;
+ vm_offset_t end;
+ } ip_ranges[PT_IP_FILTER_MAX_RANGES];
+ uint32_t mtc_freq;
+ uint32_t cyc_thresh;
+ uint32_t psb_freq;
+};
+#endif /* !_AMD64_PT_PT_H_ */
diff --git a/sys/amd64/vmm/intel/vmx_support.S b/sys/amd64/vmm/intel/vmx_support.S
index f393f160b101..130130b64541 100644
--- a/sys/amd64/vmm/intel/vmx_support.S
+++ b/sys/amd64/vmm/intel/vmx_support.S
@@ -32,12 +32,6 @@
#include "vmx_assym.h"
-#ifdef SMP
-#define LK lock ;
-#else
-#define LK
-#endif
-
/* Be friendly to DTrace FBT's prologue/epilogue pattern matching */
#define VENTER push %rbp ; mov %rsp,%rbp
#define VLEAVE pop %rbp
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index a09da794e77d..459cc8ebe505 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -5709,6 +5709,9 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags,
PMAP_LOCK_ASSERT(pmap, MA_OWNED);
KASSERT(ADDR_IS_CANONICAL(va),
("%s: Address not in canonical form: %lx", __func__, va));
+ KASSERT((flags & (PMAP_ENTER_NOREPLACE | PMAP_ENTER_NORECLAIM)) !=
+ PMAP_ENTER_NORECLAIM,
+ ("pmap_enter_l2: flags is missing PMAP_ENTER_NOREPLACE"));
if ((l2 = pmap_alloc_l2(pmap, va, &l2pg, (flags &
PMAP_ENTER_NOSLEEP) != 0 ? NULL : lockp)) == NULL) {
@@ -5828,6 +5831,15 @@ pmap_enter_l2(pmap_t pmap, vm_offset_t va, pd_entry_t new_l2, u_int flags,
if (!pmap_pv_insert_l2(pmap, va, new_l2, flags, lockp)) {
if (l2pg != NULL)
pmap_abort_ptp(pmap, va, l2pg);
+ else {
+ KASSERT(ADDR_IS_KERNEL(va) &&
+ (pmap_load(l2) & ATTR_DESCR_MASK) ==
+ L2_TABLE,
+ ("pmap_enter_l2: invalid kernel L2E"));
+ mt = pmap_remove_pt_page(pmap, va);
+ KASSERT(mt != NULL,
+ ("pmap_enter_l2: missing kernel PTP"));
+ }
if (uwptpg != NULL) {
mt = pmap_remove_pt_page(pmap, va);
KASSERT(mt == uwptpg,
diff --git a/sys/arm64/broadcom/genet/if_genet.c b/sys/arm64/broadcom/genet/if_genet.c
index 0602f076b257..182b5582fb7c 100644
--- a/sys/arm64/broadcom/genet/if_genet.c
+++ b/sys/arm64/broadcom/genet/if_genet.c
@@ -349,7 +349,7 @@ gen_attach(device_t dev)
}
/* If address was not found, create one based on the hostid and name. */
- if (eaddr_found == 0)
+ if (!eaddr_found)
ether_gen_addr(sc->ifp, &eaddr);
/* Attach ethernet interface */
ether_ifattach(sc->ifp, eaddr.octet);
@@ -653,7 +653,7 @@ gen_bus_dma_teardown(struct gen_softc *sc)
error);
}
- if (sc->tx_buf_tag != NULL) {
+ if (sc->rx_buf_tag != NULL) {
for (i = 0; i < RX_DESC_COUNT; i++) {
error = bus_dmamap_destroy(sc->rx_buf_tag,
sc->rx_ring_ent[i].map);
diff --git a/sys/cddl/boot/zfs/zfsimpl.h b/sys/cddl/boot/zfs/zfsimpl.h
index 0ce38384abbf..83d964360343 100644
--- a/sys/cddl/boot/zfs/zfsimpl.h
+++ b/sys/cddl/boot/zfs/zfsimpl.h
@@ -2019,6 +2019,7 @@ typedef struct vdev {
vdev_list_t v_children; /* children of this vdev */
const char *v_name; /* vdev name */
uint64_t v_guid; /* vdev guid */
+ uint64_t v_txg; /* most recent transaction */
uint64_t v_id; /* index in parent */
uint64_t v_psize; /* physical device capacity */
int v_ashift; /* offset to block shift */
@@ -2048,7 +2049,6 @@ typedef struct spa {
STAILQ_ENTRY(spa) spa_link; /* link in global pool list */
char *spa_name; /* pool name */
uint64_t spa_guid; /* pool guid */
- uint64_t spa_txg; /* most recent transaction */
struct uberblock *spa_uberblock; /* best uberblock so far */
vdev_t *spa_root_vdev; /* toplevel vdev container */
objset_phys_t *spa_mos; /* MOS for this pool */
diff --git a/sys/conf/files b/sys/conf/files
index 74d251c2b608..dd0d390962f2 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3227,6 +3227,19 @@ dev/uart/uart_if.m optional uart
dev/uart/uart_subr.c optional uart
dev/uart/uart_tty.c optional uart
#
+# Universal Flash Storage Host Controller Interface drivers
+#
+dev/ufshci/ufshci.c optional ufshci
+dev/ufshci/ufshci_ctrlr.c optional ufshci
+dev/ufshci/ufshci_ctrlr_cmd.c optional ufshci
+dev/ufshci/ufshci_dev.c optional ufshci
+dev/ufshci/ufshci_pci.c optional ufshci
+dev/ufshci/ufshci_req_queue.c optional ufshci
+dev/ufshci/ufshci_req_sdb.c optional ufshci
+dev/ufshci/ufshci_sim.c optional ufshci
+dev/ufshci/ufshci_sysctl.c optional ufshci
+dev/ufshci/ufshci_uic_cmd.c optional ufshci
+#
# USB controller drivers
#
dev/usb/controller/musb_otg.c optional musb
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index 0584fc29d039..678d288c2d86 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -191,6 +191,10 @@ dev/ice/irdma_di_if.m optional ice pci \
compile-with "${NORMAL_M} -I$S/dev/ice"
dev/ice/ice_ddp_common.c optional ice pci \
compile-with "${NORMAL_C} -I$S/dev/ice"
+dev/ice/ice_iov.c optional ice pci pci_iov \
+ compile-with "${NORMAL_C} -I$S/dev/ice"
+dev/ice/ice_vf_mbx.c optional ice pci pci_iov \
+ compile-with "${NORMAL_C} -I$S/dev/ice"
ice_ddp.c optional ice_ddp \
compile-with "${AWK} -f $S/tools/fw_stub.awk ice_ddp.fw:ice_ddp:0x01032900 -mice_ddp -c${.TARGET}" \
no-ctfconvert no-implicit-rule before-depend local \
diff --git a/sys/dev/gpio/gpiobus.c b/sys/dev/gpio/gpiobus.c
index ab7f13177969..764bcb7e6ee8 100644
--- a/sys/dev/gpio/gpiobus.c
+++ b/sys/dev/gpio/gpiobus.c
@@ -110,10 +110,9 @@ gpio_alloc_intr_resource(device_t consumer_dev, int *rid, u_int alloc_flags,
res = bus_alloc_resource(consumer_dev, SYS_RES_IRQ, rid, irq, irq, 1,
alloc_flags);
if (res == NULL) {
- intr_free_intr_map_data((struct intr_map_data *)gpio_data);
+ intr_unmap_irq(irq);
return (NULL);
}
- rman_set_virtual(res, gpio_data);
return (res);
}
#else
@@ -866,6 +865,25 @@ gpiobus_alloc_resource(device_t bus, device_t child, int type, int *rid,
end, count, flags));
}
+static int
+gpiobus_release_resource(device_t dev, device_t child, struct resource *r)
+{
+ int err;
+#ifdef INTRNG
+ u_int irq;
+
+ irq = rman_get_start(r);
+ MPASS(irq == rman_get_end(r));
+#endif
+ err = bus_generic_rman_release_resource(dev, child, r);
+ if (err != 0)
+ return (err);
+#ifdef INTRNG
+ intr_unmap_irq(irq);
+#endif
+ return (0);
+}
+
static struct resource_list *
gpiobus_get_resource_list(device_t bus __unused, device_t child)
{
@@ -1060,7 +1078,7 @@ static device_method_t gpiobus_methods[] = {
DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
DEVMETHOD(bus_alloc_resource, gpiobus_alloc_resource),
- DEVMETHOD(bus_release_resource, bus_generic_rman_release_resource),
+ DEVMETHOD(bus_release_resource, gpiobus_release_resource),
DEVMETHOD(bus_activate_resource, bus_generic_rman_activate_resource),
DEVMETHOD(bus_deactivate_resource, bus_generic_rman_deactivate_resource),
DEVMETHOD(bus_get_resource_list, gpiobus_get_resource_list),
diff --git a/sys/dev/ice/ice_features.h b/sys/dev/ice/ice_features.h
index 821abe4806ca..5b23757b1c98 100644
--- a/sys/dev/ice/ice_features.h
+++ b/sys/dev/ice/ice_features.h
@@ -91,7 +91,9 @@ enum feat_list {
static inline void
ice_disable_unsupported_features(ice_bitmap_t __unused *bitmap)
{
+#ifndef PCI_IOV
ice_clear_bit(ICE_FEATURE_SRIOV, bitmap);
+#endif
#ifndef DEV_NETMAP
ice_clear_bit(ICE_FEATURE_NETMAP, bitmap);
#endif
diff --git a/sys/dev/ice/ice_iflib.h b/sys/dev/ice/ice_iflib.h
index 3a5dc201189a..e1d5307a9516 100644
--- a/sys/dev/ice/ice_iflib.h
+++ b/sys/dev/ice/ice_iflib.h
@@ -139,6 +139,9 @@ struct ice_irq_vector {
* @tc: traffic class queue belongs to
* @q_handle: qidx in tc; used in TXQ enable functions
*
+ * ice_iov.c requires the following parameters (when PCI_IOV is defined):
+ * @itr_idx: ITR index to use for this queue
+ *
* Other parameters may be iflib driver specific
*/
struct ice_tx_queue {
@@ -153,6 +156,9 @@ struct ice_tx_queue {
u32 me;
u16 q_handle;
u8 tc;
+#ifdef PCI_IOV
+ u8 itr_idx;
+#endif
/* descriptor writeback status */
qidx_t *tx_rsq;
@@ -175,6 +181,9 @@ struct ice_tx_queue {
* @stats: queue statistics
* @tc: traffic class queue belongs to
*
+ * ice_iov.c requires the following parameters (when PCI_IOV is defined):
+ * @itr_idx: ITR index to use for this queue
+ *
* Other parameters may be iflib driver specific
*/
struct ice_rx_queue {
@@ -187,6 +196,9 @@ struct ice_rx_queue {
struct ice_irq_vector *irqv;
u32 me;
u8 tc;
+#ifdef PCI_IOV
+ u8 itr_idx;
+#endif
struct if_irq que_irq;
};
@@ -332,6 +344,10 @@ struct ice_softc {
ice_declare_bitmap(feat_cap, ICE_FEATURE_COUNT);
ice_declare_bitmap(feat_en, ICE_FEATURE_COUNT);
+#ifdef PCI_IOV
+ struct ice_vf *vfs;
+ u16 num_vfs;
+#endif
struct ice_resmgr os_imgr;
/* For mirror interface */
struct ice_mirr_if *mirr_if;
diff --git a/sys/dev/ice/ice_iov.c b/sys/dev/ice/ice_iov.c
new file mode 100644
index 000000000000..c5a3e1060e44
--- /dev/null
+++ b/sys/dev/ice/ice_iov.c
@@ -0,0 +1,1856 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Intel Corporation
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * @file ice_iov.c
+ * @brief Virtualization support functions
+ *
+ * Contains functions for enabling and managing PCIe virtual function devices,
+ * including enabling new VFs, and managing VFs over the virtchnl interface.
+ */
+
+#include "ice_iov.h"
+
+static struct ice_vf *ice_iov_get_vf(struct ice_softc *sc, int vf_num);
+static void ice_iov_ready_vf(struct ice_softc *sc, struct ice_vf *vf);
+static void ice_reset_vf(struct ice_softc *sc, struct ice_vf *vf,
+ bool trigger_vflr);
+static void ice_iov_setup_intr_mapping(struct ice_softc *sc, struct ice_vf *vf);
+
+static void ice_vc_version_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_get_vf_res_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_add_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_del_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static bool ice_vc_isvalid_ring_len(u16 ring_len);
+static void ice_vc_cfg_vsi_qs_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_cfg_rss_key_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_set_rss_hena_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_enable_queues_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_notify_vf_link_state(struct ice_softc *sc, struct ice_vf *vf);
+static void ice_vc_disable_queues_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_cfg_irq_map_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_get_stats_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_eth_stats_to_virtchnl_eth_stats(struct ice_eth_stats *istats,
+ struct virtchnl_eth_stats *vstats);
+static void ice_vc_cfg_rss_lut_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_cfg_promisc_mode_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_add_vlan_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static void ice_vc_del_vlan_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf);
+static enum virtchnl_status_code ice_iov_err_to_virt_err(int ice_err);
+static int ice_vf_validate_mac(struct ice_vf *vf, const uint8_t *addr);
+
+/**
+ * ice_iov_attach - Initialize SR-IOV PF host support
+ * @sc: device softc structure
+ *
+ * Initialize SR-IOV PF host support at the end of the driver attach process.
+ *
+ * @pre Must be called from sleepable context (calls malloc() w/ M_WAITOK)
+ *
+ * @returns 0 if successful, or
+ * - ENOMEM if there is no memory for the PF/VF schemas or iov device
+ * - ENXIO if the device isn't PCI-E or doesn't support the same SR-IOV
+ * version as the kernel
+ * - ENOENT if the device doesn't have the SR-IOV capability
+ */
+int
+ice_iov_attach(struct ice_softc *sc)
+{
+ device_t dev = sc->dev;
+ nvlist_t *pf_schema, *vf_schema;
+ int error;
+
+ pf_schema = pci_iov_schema_alloc_node();
+ vf_schema = pci_iov_schema_alloc_node();
+
+ pci_iov_schema_add_unicast_mac(vf_schema, "mac-addr", 0, NULL);
+ pci_iov_schema_add_bool(vf_schema, "mac-anti-spoof",
+ IOV_SCHEMA_HASDEFAULT, TRUE);
+ pci_iov_schema_add_bool(vf_schema, "allow-set-mac",
+ IOV_SCHEMA_HASDEFAULT, FALSE);
+ pci_iov_schema_add_bool(vf_schema, "allow-promisc",
+ IOV_SCHEMA_HASDEFAULT, FALSE);
+ pci_iov_schema_add_uint16(vf_schema, "num-queues",
+ IOV_SCHEMA_HASDEFAULT, ICE_DEFAULT_VF_QUEUES);
+ pci_iov_schema_add_uint16(vf_schema, "mirror-src-vsi",
+ IOV_SCHEMA_HASDEFAULT, ICE_INVALID_MIRROR_VSI);
+ pci_iov_schema_add_uint16(vf_schema, "max-vlan-allowed",
+ IOV_SCHEMA_HASDEFAULT, ICE_DEFAULT_VF_VLAN_LIMIT);
+ pci_iov_schema_add_uint16(vf_schema, "max-mac-filters",
+ IOV_SCHEMA_HASDEFAULT, ICE_DEFAULT_VF_FILTER_LIMIT);
+
+ error = pci_iov_attach(dev, pf_schema, vf_schema);
+ if (error != 0) {
+ device_printf(dev,
+ "pci_iov_attach failed (error=%s)\n",
+ ice_err_str(error));
+ ice_clear_bit(ICE_FEATURE_SRIOV, sc->feat_en);
+ } else
+ ice_set_bit(ICE_FEATURE_SRIOV, sc->feat_en);
+
+ return (error);
+}
+
+/**
+ * ice_iov_detach - Teardown SR-IOV PF host support
+ * @sc: device softc structure
+ *
+ * Teardown SR-IOV PF host support at the start of the driver detach process.
+ *
+ * @returns 0 if successful or IOV support hasn't been setup, or
+ * - EBUSY if VFs still exist
+ */
+int
+ice_iov_detach(struct ice_softc *sc)
+{
+ device_t dev = sc->dev;
+ int error;
+
+ error = pci_iov_detach(dev);
+ if (error != 0) {
+ device_printf(dev,
+ "pci_iov_detach failed (error=%s)\n",
+ ice_err_str(error));
+ }
+
+ return (error);
+}
+
+/**
+ * ice_iov_init - Called by the OS before the first VF is created.
+ * @sc: device softc structure
+ * @num_vfs: number of VFs to setup resources for
+ * @params: configuration parameters for the PF
+ *
+ * @returns 0 if successful or an error code on failure
+ */
+int
+ice_iov_init(struct ice_softc *sc, uint16_t num_vfs, const nvlist_t *params __unused)
+{
+ /* Allocate array of VFs, for tracking */
+ sc->vfs = (struct ice_vf *)malloc(sizeof(struct ice_vf) * num_vfs, M_ICE, M_NOWAIT |
+ M_ZERO);
+ if (sc->vfs == NULL)
+ return (ENOMEM);
+
+ /* Initialize each VF with basic information */
+ for (int i = 0; i < num_vfs; i++)
+ sc->vfs[i].vf_num = i;
+
+ /* Save off number of configured VFs */
+ sc->num_vfs = num_vfs;
+
+ return (0);
+}
+
+/**
+ * ice_iov_get_vf - Get pointer to VF at given index
+ * @sc: device softc structure
+ * @vf_num: Index of VF to retrieve
+ *
+ * @remark will throw an assertion if vf_num is not in the
+ * range of allocated VFs
+ *
+ * @returns a pointer to the VF structure at the given index
+ */
+static struct ice_vf *
+ice_iov_get_vf(struct ice_softc *sc, int vf_num)
+{
+ MPASS(vf_num < sc->num_vfs);
+
+ return &sc->vfs[vf_num];
+}
+
+/**
+ * ice_iov_add_vf - Called by the OS for each VF to create
+ * @sc: device softc structure
+ * @vfnum: index of VF to configure
+ * @params: configuration parameters for the VF
+ *
+ * @returns 0 if successful or an error code on failure
+ */
+int
+ice_iov_add_vf(struct ice_softc *sc, uint16_t vfnum, const nvlist_t *params)
+{
+ struct ice_tx_queue *txq;
+ struct ice_rx_queue *rxq;
+ device_t dev = sc->dev;
+ struct ice_vsi *vsi;
+ struct ice_vf *vf;
+ int vf_num_queues;
+ const void *mac;
+ size_t size;
+ int error;
+ int i;
+
+ vf = ice_iov_get_vf(sc, vfnum);
+ vf->vf_flags = VF_FLAG_ENABLED;
+
+ /* This VF needs at least one VSI */
+ vsi = ice_alloc_vsi(sc, ICE_VSI_VF);
+ if (vsi == NULL)
+ return (ENOMEM);
+ vf->vsi = vsi;
+ vsi->vf_num = vfnum;
+
+ vf_num_queues = nvlist_get_number(params, "num-queues");
+ /* Validate and clamp value if invalid */
+ if (vf_num_queues < 1 || vf_num_queues > ICE_MAX_SCATTERED_QUEUES)
+ device_printf(dev, "Invalid num-queues (%d) for VF %d\n",
+ vf_num_queues, vf->vf_num);
+ if (vf_num_queues < 1) {
+ device_printf(dev, "Setting VF %d num-queues to 1\n", vf->vf_num);
+ vf_num_queues = 1;
+ } else if (vf_num_queues > ICE_MAX_SCATTERED_QUEUES) {
+ device_printf(dev, "Setting VF %d num-queues to %d\n",
+ vf->vf_num, ICE_MAX_SCATTERED_QUEUES);
+ vf_num_queues = ICE_MAX_SCATTERED_QUEUES;
+ }
+ vsi->qmap_type = ICE_RESMGR_ALLOC_SCATTERED;
+
+ /* Reserve VF queue allocation from PF queues */
+ ice_alloc_vsi_qmap(vsi, vf_num_queues, vf_num_queues);
+ vsi->num_tx_queues = vsi->num_rx_queues = vf_num_queues;
+
+ /* Assign Tx queues from PF space */
+ error = ice_resmgr_assign_scattered(&sc->tx_qmgr, vsi->tx_qmap,
+ vsi->num_tx_queues);
+ if (error) {
+ device_printf(sc->dev, "Unable to assign VF Tx queues: %s\n",
+ ice_err_str(error));
+ goto release_vsi;
+ }
+
+ /* Assign Rx queues from PF space */
+ error = ice_resmgr_assign_scattered(&sc->rx_qmgr, vsi->rx_qmap,
+ vsi->num_rx_queues);
+ if (error) {
+ device_printf(sc->dev, "Unable to assign VF Rx queues: %s\n",
+ ice_err_str(error));
+ goto release_vsi;
+ }
+
+ vsi->max_frame_size = ICE_MAX_FRAME_SIZE;
+
+ /* Allocate queue structure memory */
+ vsi->tx_queues = (struct ice_tx_queue *)
+ malloc(sizeof(struct ice_tx_queue) * vsi->num_tx_queues, M_ICE,
+ M_NOWAIT | M_ZERO);
+ if (!vsi->tx_queues) {
+ device_printf(sc->dev, "VF-%d: Unable to allocate Tx queue memory\n",
+ vfnum);
+ error = ENOMEM;
+ goto release_vsi;
+ }
+ for (i = 0, txq = vsi->tx_queues; i < vsi->num_tx_queues; i++, txq++) {
+ txq->me = i;
+ txq->vsi = vsi;
+ }
+
+ /* Allocate queue structure memory */
+ vsi->rx_queues = (struct ice_rx_queue *)
+ malloc(sizeof(struct ice_rx_queue) * vsi->num_rx_queues, M_ICE,
+ M_NOWAIT | M_ZERO);
+ if (!vsi->rx_queues) {
+ device_printf(sc->dev, "VF-%d: Unable to allocate Rx queue memory\n",
+ vfnum);
+ error = ENOMEM;
+ goto free_txqs;
+ }
+ for (i = 0, rxq = vsi->rx_queues; i < vsi->num_rx_queues; i++, rxq++) {
+ rxq->me = i;
+ rxq->vsi = vsi;
+ }
+
+ /* Allocate space to store the IRQ vector data */
+ vf->num_irq_vectors = vf_num_queues + 1;
+ vf->tx_irqvs = (struct ice_irq_vector *)
+ malloc(sizeof(struct ice_irq_vector) * (vf->num_irq_vectors),
+ M_ICE, M_NOWAIT);
+ if (!vf->tx_irqvs) {
+ device_printf(sc->dev,
+ "Unable to allocate TX irqv memory for VF-%d's %d vectors\n",
+ vfnum, vf->num_irq_vectors);
+ error = ENOMEM;
+ goto free_rxqs;
+ }
+ vf->rx_irqvs = (struct ice_irq_vector *)
+ malloc(sizeof(struct ice_irq_vector) * (vf->num_irq_vectors),
+ M_ICE, M_NOWAIT);
+ if (!vf->rx_irqvs) {
+ device_printf(sc->dev,
+ "Unable to allocate RX irqv memory for VF-%d's %d vectors\n",
+ vfnum, vf->num_irq_vectors);
+ error = ENOMEM;
+ goto free_txirqvs;
+ }
+
+ /* Assign VF interrupts from PF space */
+ if (!(vf->vf_imap =
+ (u16 *)malloc(sizeof(u16) * vf->num_irq_vectors,
+ M_ICE, M_NOWAIT))) {
+ device_printf(dev, "Unable to allocate VF-%d imap memory\n", vfnum);
+ error = ENOMEM;
+ goto free_rxirqvs;
+ }
+ error = ice_resmgr_assign_contiguous(&sc->dev_imgr, vf->vf_imap, vf->num_irq_vectors);
+ if (error) {
+ device_printf(dev, "Unable to assign VF-%d interrupt mapping: %s\n",
+ vfnum, ice_err_str(error));
+ goto free_imap;
+ }
+
+ if (nvlist_exists_binary(params, "mac-addr")) {
+ mac = nvlist_get_binary(params, "mac-addr", &size);
+ memcpy(vf->mac, mac, ETHER_ADDR_LEN);
+
+ if (nvlist_get_bool(params, "allow-set-mac"))
+ vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
+ } else
+ /*
+ * If the administrator has not specified a MAC address then
+ * we must allow the VF to choose one.
+ */
+ vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
+
+ if (nvlist_get_bool(params, "mac-anti-spoof"))
+ vf->vf_flags |= VF_FLAG_MAC_ANTI_SPOOF;
+
+ if (nvlist_get_bool(params, "allow-promisc"))
+ vf->vf_flags |= VF_FLAG_PROMISC_CAP;
+
+ vsi->mirror_src_vsi = nvlist_get_number(params, "mirror-src-vsi");
+
+ vf->vlan_limit = nvlist_get_number(params, "max-vlan-allowed");
+ vf->mac_filter_limit = nvlist_get_number(params, "max-mac-filters");
+
+ vf->vf_flags |= VF_FLAG_VLAN_CAP;
+
+ /* Create and setup VSI in HW */
+ error = ice_initialize_vsi(vsi);
+ if (error) {
+ device_printf(sc->dev, "Unable to initialize VF %d VSI: %s\n",
+ vfnum, ice_err_str(error));
+ goto release_imap;
+ }
+
+ /* Add the broadcast address */
+ error = ice_add_vsi_mac_filter(vsi, broadcastaddr);
+ if (error) {
+ device_printf(sc->dev, "Unable to add broadcast filter VF %d VSI: %s\n",
+ vfnum, ice_err_str(error));
+ goto release_imap;
+ }
+
+ ice_iov_ready_vf(sc, vf);
+
+ return (0);
+
+release_imap:
+ ice_resmgr_release_map(&sc->dev_imgr, vf->vf_imap,
+ vf->num_irq_vectors);
+free_imap:
+ free(vf->vf_imap, M_ICE);
+ vf->vf_imap = NULL;
+free_rxirqvs:
+ free(vf->rx_irqvs, M_ICE);
+ vf->rx_irqvs = NULL;
+free_txirqvs:
+ free(vf->tx_irqvs, M_ICE);
+ vf->tx_irqvs = NULL;
+free_rxqs:
+ free(vsi->rx_queues, M_ICE);
+ vsi->rx_queues = NULL;
+free_txqs:
+ free(vsi->tx_queues, M_ICE);
+ vsi->tx_queues = NULL;
+release_vsi:
+ ice_release_vsi(vsi);
+ vf->vsi = NULL;
+ return (error);
+}
+
+/**
+ * ice_iov_uninit - Called by the OS when VFs are destroyed
+ * @sc: device softc structure
+ */
+void
+ice_iov_uninit(struct ice_softc *sc)
+{
+ struct ice_vf *vf;
+ struct ice_vsi *vsi;
+
+ /* Release per-VF resources */
+ for (int i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+ vsi = vf->vsi;
+
+ /* Free VF interrupt reservation */
+ if (vf->vf_imap) {
+ free(vf->vf_imap, M_ICE);
+ vf->vf_imap = NULL;
+ }
+
+ /* Free queue interrupt mapping trackers */
+ if (vf->tx_irqvs) {
+ free(vf->tx_irqvs, M_ICE);
+ vf->tx_irqvs = NULL;
+ }
+ if (vf->rx_irqvs) {
+ free(vf->rx_irqvs, M_ICE);
+ vf->rx_irqvs = NULL;
+ }
+
+ if (!vsi)
+ continue;
+
+ /* Free VSI queues */
+ if (vsi->tx_queues) {
+ free(vsi->tx_queues, M_ICE);
+ vsi->tx_queues = NULL;
+ }
+ if (vsi->rx_queues) {
+ free(vsi->rx_queues, M_ICE);
+ vsi->rx_queues = NULL;
+ }
+
+ ice_release_vsi(vsi);
+ vf->vsi = NULL;
+ }
+
+ /* Release memory used for VF tracking */
+ if (sc->vfs) {
+ free(sc->vfs, M_ICE);
+ sc->vfs = NULL;
+ }
+ sc->num_vfs = 0;
+}
+
+/**
+ * ice_iov_handle_vflr - Process VFLR event
+ * @sc: device softc structure
+ *
+ * Identifys which VFs have been reset and re-configure
+ * them.
+ */
+void
+ice_iov_handle_vflr(struct ice_softc *sc)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct ice_vf *vf;
+ u32 reg, reg_idx, bit_idx;
+
+ for (int i = 0; i < sc->num_vfs; i++) {
+ vf = &sc->vfs[i];
+
+ reg_idx = (hw->func_caps.vf_base_id + vf->vf_num) / 32;
+ bit_idx = (hw->func_caps.vf_base_id + vf->vf_num) % 32;
+ reg = rd32(hw, GLGEN_VFLRSTAT(reg_idx));
+ if (reg & BIT(bit_idx))
+ ice_reset_vf(sc, vf, false);
+ }
+}
+
+/**
+ * ice_iov_ready_vf - Setup VF interrupts and mark it as ready
+ * @sc: device softc structure
+ * @vf: driver's VF structure for the VF to update
+ *
+ * Clears VF reset triggering bit, sets up the PF<->VF interrupt
+ * mapping and marks the VF as active in the HW so that the VF
+ * driver can use it.
+ */
+static void
+ice_iov_ready_vf(struct ice_softc *sc, struct ice_vf *vf)
+{
+ struct ice_hw *hw = &sc->hw;
+ u32 reg;
+
+ /* Clear the triggering bit */
+ reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_num));
+ reg &= ~VPGEN_VFRTRIG_VFSWR_M;
+ wr32(hw, VPGEN_VFRTRIG(vf->vf_num), reg);
+
+ /* Setup VF interrupt allocation and mapping */
+ ice_iov_setup_intr_mapping(sc, vf);
+
+ /* Indicate to the VF that reset is done */
+ wr32(hw, VFGEN_RSTAT(vf->vf_num), VIRTCHNL_VFR_VFACTIVE);
+
+ ice_flush(hw);
+}
+
+/**
+ * ice_reset_vf - Perform a hardware reset (VFR) on a VF
+ * @sc: device softc structure
+ * @vf: driver's VF structure for VF to be reset
+ * @trigger_vflr: trigger a reset or only handle already executed reset
+ *
+ * Performs a VFR for the given VF. This function busy waits until the
+ * reset completes in the HW, notifies the VF that the reset is done
+ * by setting a bit in a HW register, then returns.
+ *
+ * @remark This also sets up the PF<->VF interrupt mapping and allocations in
+ * the hardware after the hardware reset is finished, via
+ * ice_iov_setup_intr_mapping()
+ */
+static void
+ice_reset_vf(struct ice_softc *sc, struct ice_vf *vf, bool trigger_vflr)
+{
+ u16 global_vf_num, reg_idx, bit_idx;
+ struct ice_hw *hw = &sc->hw;
+ int status;
+ u32 reg;
+ int i;
+
+ global_vf_num = vf->vf_num + hw->func_caps.vf_base_id;
+
+ if (trigger_vflr) {
+ reg = rd32(hw, VPGEN_VFRTRIG(vf->vf_num));
+ reg |= VPGEN_VFRTRIG_VFSWR_M;
+ wr32(hw, VPGEN_VFRTRIG(vf->vf_num), reg);
+ }
+
+ /* clear the VFLR bit for the VF in a GLGEN_VFLRSTAT register */
+ reg_idx = (global_vf_num) / 32;
+ bit_idx = (global_vf_num) % 32;
+ wr32(hw, GLGEN_VFLRSTAT(reg_idx), BIT(bit_idx));
+ ice_flush(hw);
+
+ /* Wait until there are no pending PCI transactions */
+ wr32(hw, PF_PCI_CIAA,
+ ICE_PCIE_DEV_STATUS | (global_vf_num << PF_PCI_CIAA_VF_NUM_S));
+
+ for (i = 0; i < ICE_PCI_CIAD_WAIT_COUNT; i++) {
+ reg = rd32(hw, PF_PCI_CIAD);
+ if (!(reg & PCIEM_STA_TRANSACTION_PND))
+ break;
+
+ DELAY(ICE_PCI_CIAD_WAIT_DELAY_US);
+ }
+ if (i == ICE_PCI_CIAD_WAIT_COUNT)
+ device_printf(sc->dev,
+ "VF-%d PCI transactions stuck\n", vf->vf_num);
+
+ /* Disable TX queues, which is required during VF reset */
+ status = ice_dis_vsi_txq(hw->port_info, vf->vsi->idx, 0, 0, NULL, NULL,
+ NULL, ICE_VF_RESET, vf->vf_num, NULL);
+ if (status)
+ device_printf(sc->dev,
+ "%s: Failed to disable LAN Tx queues: err %s aq_err %s\n",
+ __func__, ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+
+ /* Then check for the VF reset to finish in HW */
+ for (i = 0; i < ICE_VPGEN_VFRSTAT_WAIT_COUNT; i++) {
+ reg = rd32(hw, VPGEN_VFRSTAT(vf->vf_num));
+ if ((reg & VPGEN_VFRSTAT_VFRD_M))
+ break;
+
+ DELAY(ICE_VPGEN_VFRSTAT_WAIT_DELAY_US);
+ }
+ if (i == ICE_VPGEN_VFRSTAT_WAIT_COUNT)
+ device_printf(sc->dev,
+ "VF-%d Reset is stuck\n", vf->vf_num);
+
+ ice_iov_ready_vf(sc, vf);
+}
+
+/**
+ * ice_vc_get_vf_res_msg - Handle VIRTCHNL_OP_GET_VF_RESOURCES msg from VF
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ * @msg_buf: raw message buffer from the VF
+ *
+ * Receives a message from the VF listing its supported capabilities, and
+ * replies to the VF with information about what resources the PF has
+ * allocated for the VF.
+ *
+ * @remark This always replies to the VF with a success status; it does not
+ * fail. It's up to the VF driver to reject or complain about the PF's response.
+ */
+static void
+ice_vc_get_vf_res_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_vf_resource *vf_res;
+ struct virtchnl_vsi_resource *vsi_res;
+ u16 vf_res_len;
+ u32 vf_caps;
+
+ /* XXX: Only support one VSI per VF, so this size doesn't need adjusting */
+ vf_res_len = sizeof(struct virtchnl_vf_resource);
+ vf_res = (struct virtchnl_vf_resource *)malloc(vf_res_len, M_ICE,
+ M_WAITOK | M_ZERO);
+
+ vf_res->num_vsis = 1;
+ vf_res->num_queue_pairs = vf->vsi->num_tx_queues;
+ vf_res->max_vectors = vf_res->num_queue_pairs + 1;
+
+ vf_res->rss_key_size = ICE_GET_SET_RSS_KEY_EXTEND_KEY_SIZE;
+ vf_res->rss_lut_size = ICE_VSIQF_HLUT_ARRAY_SIZE;
+ vf_res->max_mtu = 0;
+
+ vf_res->vf_cap_flags = VF_BASE_MODE_OFFLOADS;
+ if (msg_buf != NULL) {
+ vf_caps = *((u32 *)(msg_buf));
+
+ if (vf_caps & VIRTCHNL_VF_CAP_ADV_LINK_SPEED)
+ vf_res->vf_cap_flags |= VIRTCHNL_VF_CAP_ADV_LINK_SPEED;
+
+ if (vf_caps & VIRTCHNL_VF_OFFLOAD_WB_ON_ITR)
+ vf_res->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_WB_ON_ITR;
+ }
+
+ vsi_res = &vf_res->vsi_res[0];
+ vsi_res->vsi_id = vf->vsi->idx;
+ vsi_res->num_queue_pairs = vf->vsi->num_tx_queues;
+ vsi_res->vsi_type = VIRTCHNL_VSI_SRIOV;
+ vsi_res->qset_handle = 0;
+ if (!ETHER_IS_ZERO(vf->mac))
+ memcpy(vsi_res->default_mac_addr, vf->mac, ETHER_ADDR_LEN);
+
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_GET_VF_RESOURCES,
+ VIRTCHNL_STATUS_SUCCESS, (u8 *)vf_res, vf_res_len, NULL);
+
+ free(vf_res, M_ICE);
+}
+
+/**
+ * ice_vc_version_msg - Handle VIRTCHNL_OP_VERSION msg from VF
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ * @msg_buf: raw message buffer from the VF
+ *
+ * Receives a version message from the VF, and responds to the VF with
+ * the version number that the PF will use.
+ *
+ * @remark This always replies to the VF with a success status; it does not
+ * fail.
+ */
+static void
+ice_vc_version_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct virtchnl_version_info *recv_vf_version;
+ struct ice_hw *hw = &sc->hw;
+ device_t dev = sc->dev;
+
+ recv_vf_version = (struct virtchnl_version_info *)msg_buf;
+
+ /* VFs running the 1.0 API expect to get 1.0 back */
+ if (VF_IS_V10(recv_vf_version)) {
+ vf->version.major = 1;
+ vf->version.minor = VIRTCHNL_VERSION_MINOR_NO_VF_CAPS;
+ } else {
+ vf->version.major = VIRTCHNL_VERSION_MAJOR;
+ vf->version.minor = VIRTCHNL_VERSION_MINOR;
+
+ if ((recv_vf_version->major != VIRTCHNL_VERSION_MAJOR) ||
+ (recv_vf_version->minor != VIRTCHNL_VERSION_MINOR))
+ device_printf(dev,
+ "%s: VF-%d requested version (%d.%d) differs from PF version (%d.%d)\n",
+ __func__, vf->vf_num,
+ recv_vf_version->major, recv_vf_version->minor,
+ VIRTCHNL_VERSION_MAJOR, VIRTCHNL_VERSION_MINOR);
+ }
+
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_VERSION,
+ VIRTCHNL_STATUS_SUCCESS, (u8 *)&vf->version, sizeof(vf->version),
+ NULL);
+}
+
+/**
+ * ice_vf_validate_mac - Validate MAC address before adding it
+ * @vf: VF tracking structure
+ * @addr: MAC address to validate
+ *
+ * Validate a MAC address before adding it to a VF during the handling
+ * of a VIRTCHNL_OP_ADD_ETH_ADDR operation. Notably, this also checks if
+ * the VF is allowed to set its own arbitrary MAC addresses.
+ *
+ * Returns 0 if MAC address is valid for the given vf
+ */
+static int
+ice_vf_validate_mac(struct ice_vf *vf, const uint8_t *addr)
+{
+
+ if (ETHER_IS_ZERO(addr) || ETHER_IS_BROADCAST(addr))
+ return (EINVAL);
+
+ /*
+ * If the VF is not allowed to change its MAC address, don't let it
+ * set a MAC filter for an address that is not a multicast address and
+ * is not its assigned MAC.
+ */
+ if (!(vf->vf_flags & VF_FLAG_SET_MAC_CAP) &&
+ !(ETHER_IS_MULTICAST(addr) || !bcmp(addr, vf->mac, ETHER_ADDR_LEN)))
+ return (EPERM);
+
+ return (0);
+}
+
+/**
+ * ice_vc_add_eth_addr_msg - Handle VIRTCHNL_OP_ADD_ETH_ADDR msg from VF
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ * @msg_buf: raw message buffer from the VF
+ *
+ * Receives a list of MAC addresses from the VF and adds those addresses
+ * to the VSI's filter list.
+ */
+static void
+ice_vc_add_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct virtchnl_ether_addr_list *addr_list;
+ struct ice_hw *hw = &sc->hw;
+ u16 added_addr_cnt = 0;
+ int error = 0;
+
+ addr_list = (struct virtchnl_ether_addr_list *)msg_buf;
+
+ if (addr_list->num_elements >
+ (vf->mac_filter_limit - vf->mac_filter_cnt)) {
+ v_status = VIRTCHNL_STATUS_ERR_NO_MEMORY;
+ goto done;
+ }
+
+ for (int i = 0; i < addr_list->num_elements; i++) {
+ u8 *addr = addr_list->list[i].addr;
+
+ /* The type flag is currently ignored; every MAC address is
+ * treated as the LEGACY type
+ */
+
+ error = ice_vf_validate_mac(vf, addr);
+ if (error == EPERM) {
+ device_printf(sc->dev,
+ "%s: VF-%d: Not permitted to add MAC addr for VSI %d\n",
+ __func__, vf->vf_num, vf->vsi->idx);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ continue;
+ } else if (error) {
+ device_printf(sc->dev,
+ "%s: VF-%d: Did not add invalid MAC addr for VSI %d\n",
+ __func__, vf->vf_num, vf->vsi->idx);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ continue;
+ }
+
+ error = ice_add_vsi_mac_filter(vf->vsi, addr);
+ if (error) {
+ device_printf(sc->dev,
+ "%s: VF-%d: Error adding MAC addr for VSI %d\n",
+ __func__, vf->vf_num, vf->vsi->idx);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ continue;
+ }
+ /* Don't count VF's MAC against its MAC filter limit */
+ if (memcmp(addr, vf->mac, ETHER_ADDR_LEN))
+ added_addr_cnt++;
+ }
+
+ vf->mac_filter_cnt += added_addr_cnt;
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_ADD_ETH_ADDR,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_del_eth_addr_msg - Handle VIRTCHNL_OP_DEL_ETH_ADDR msg from VF
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ * @msg_buf: raw message buffer from the VF
+ *
+ * Receives a list of MAC addresses from the VF and removes those addresses
+ * from the VSI's filter list.
+ */
+static void
+ice_vc_del_eth_addr_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct virtchnl_ether_addr_list *addr_list;
+ struct ice_hw *hw = &sc->hw;
+ u16 deleted_addr_cnt = 0;
+ int error = 0;
+
+ addr_list = (struct virtchnl_ether_addr_list *)msg_buf;
+
+ for (int i = 0; i < addr_list->num_elements; i++) {
+ error = ice_remove_vsi_mac_filter(vf->vsi, addr_list->list[i].addr);
+ if (error) {
+ device_printf(sc->dev,
+ "%s: VF-%d: Error removing MAC addr for VSI %d\n",
+ __func__, vf->vf_num, vf->vsi->idx);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ continue;
+ }
+ /* Don't count VF's MAC against its MAC filter limit */
+ if (memcmp(addr_list->list[i].addr, vf->mac, ETHER_ADDR_LEN))
+ deleted_addr_cnt++;
+ }
+
+ if (deleted_addr_cnt >= vf->mac_filter_cnt)
+ vf->mac_filter_cnt = 0;
+ else
+ vf->mac_filter_cnt -= deleted_addr_cnt;
+
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_DEL_ETH_ADDR,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_add_vlan_msg - Handle VIRTCHNL_OP_ADD_VLAN msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Adds the VLANs in msg_buf to the VF's VLAN filter list.
+ */
+static void
+ice_vc_add_vlan_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_vlan_filter_list *vlan_list;
+ int status = 0;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+
+ vlan_list = (struct virtchnl_vlan_filter_list *)msg_buf;
+
+ if (vlan_list->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ vf->vf_num, vsi->idx, vlan_list->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ if (vlan_list->num_elements > (vf->vlan_limit - vf->vlan_cnt)) {
+ v_status = VIRTCHNL_STATUS_ERR_NO_MEMORY;
+ goto done;
+ }
+
+ status = ice_add_vlan_hw_filters(vsi, vlan_list->vlan_id,
+ vlan_list->num_elements);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Failure adding VLANs to VSI %d, err %s aq_err %s\n",
+ vf->vf_num, vsi->idx, ice_status_str(status),
+ ice_aq_str(sc->hw.adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+
+ vf->vlan_cnt += vlan_list->num_elements;
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_ADD_VLAN,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_del_vlan_msg - Handle VIRTCHNL_OP_DEL_VLAN msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Removes the VLANs in msg_buf from the VF's VLAN filter list.
+ */
+static void
+ice_vc_del_vlan_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_vlan_filter_list *vlan_list;
+ int status = 0;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+
+ vlan_list = (struct virtchnl_vlan_filter_list *)msg_buf;
+
+ if (vlan_list->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ vf->vf_num, vsi->idx, vlan_list->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ status = ice_remove_vlan_hw_filters(vsi, vlan_list->vlan_id,
+ vlan_list->num_elements);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Failure deleting VLANs from VSI %d, err %s aq_err %s\n",
+ vf->vf_num, vsi->idx, ice_status_str(status),
+ ice_aq_str(sc->hw.adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+
+ if (vlan_list->num_elements >= vf->vlan_cnt)
+ vf->vlan_cnt = 0;
+ else
+ vf->vlan_cnt -= vlan_list->num_elements;
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_DEL_VLAN,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_validate_ring_len - Check to see if a descriptor ring length is valid
+ * @ring_len: length of ring
+ *
+ * Check whether a ring size value is valid.
+ *
+ * @returns true if given ring size is valid
+ */
+static bool
+ice_vc_isvalid_ring_len(u16 ring_len)
+{
+ return (ring_len >= ICE_MIN_DESC_COUNT &&
+ ring_len <= ICE_MAX_DESC_COUNT &&
+ !(ring_len % ICE_DESC_COUNT_INCR));
+}
+
+/**
+ * ice_vc_cfg_vsi_qs_msg - Handle VIRTCHNL_OP_CONFIG_VSI_QUEUES msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ */
+static void
+ice_vc_cfg_vsi_qs_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ device_t dev = sc->dev;
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_vsi_queue_config_info *vqci;
+ struct virtchnl_queue_pair_info *vqpi;
+ enum virtchnl_status_code status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+ struct ice_tx_queue *txq;
+ struct ice_rx_queue *rxq;
+ int i, error = 0;
+
+ vqci = (struct virtchnl_vsi_queue_config_info *)msg_buf;
+
+ if (vqci->num_queue_pairs > vf->vsi->num_tx_queues &&
+ vqci->num_queue_pairs > vf->vsi->num_rx_queues) {
+ status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ ice_vsi_disable_tx(vf->vsi);
+ ice_control_all_rx_queues(vf->vsi, false);
+
+ /*
+ * Clear TX and RX queues config in case VF
+ * requests different number of queues.
+ */
+ for (i = 0; i < vsi->num_tx_queues; i++) {
+ txq = &vsi->tx_queues[i];
+
+ txq->desc_count = 0;
+ txq->tx_paddr = 0;
+ txq->tc = 0;
+ }
+
+ for (i = 0; i < vsi->num_rx_queues; i++) {
+ rxq = &vsi->rx_queues[i];
+
+ rxq->desc_count = 0;
+ rxq->rx_paddr = 0;
+ }
+
+ vqpi = vqci->qpair;
+ for (i = 0; i < vqci->num_queue_pairs; i++, vqpi++) {
+ /* Initial parameter validation */
+ if (vqpi->txq.vsi_id != vf->vsi->idx ||
+ vqpi->rxq.vsi_id != vf->vsi->idx ||
+ vqpi->txq.queue_id != vqpi->rxq.queue_id ||
+ vqpi->txq.headwb_enabled ||
+ vqpi->rxq.splithdr_enabled ||
+ vqpi->rxq.crc_disable ||
+ !(ice_vc_isvalid_ring_len(vqpi->txq.ring_len)) ||
+ !(ice_vc_isvalid_ring_len(vqpi->rxq.ring_len))) {
+ status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ /* Copy parameters into VF's queue/VSI structs */
+ txq = &vsi->tx_queues[vqpi->txq.queue_id];
+
+ txq->desc_count = vqpi->txq.ring_len;
+ txq->tx_paddr = vqpi->txq.dma_ring_addr;
+ txq->q_handle = vqpi->txq.queue_id;
+ txq->tc = 0;
+
+ rxq = &vsi->rx_queues[vqpi->rxq.queue_id];
+
+ rxq->desc_count = vqpi->rxq.ring_len;
+ rxq->rx_paddr = vqpi->rxq.dma_ring_addr;
+ vsi->mbuf_sz = vqpi->rxq.databuffer_size;
+ }
+
+ /* Configure TX queues in HW */
+ error = ice_cfg_vsi_for_tx(vsi);
+ if (error) {
+ device_printf(dev,
+ "VF-%d: Unable to configure VSI for Tx: %s\n",
+ vf->vf_num, ice_err_str(error));
+ status = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
+ goto done;
+ }
+
+ /* Configure RX queues in HW */
+ error = ice_cfg_vsi_for_rx(vsi);
+ if (error) {
+ device_printf(dev,
+ "VF-%d: Unable to configure VSI for Rx: %s\n",
+ vf->vf_num, ice_err_str(error));
+ status = VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
+ ice_vsi_disable_tx(vsi);
+ goto done;
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_CONFIG_VSI_QUEUES,
+ status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_cfg_rss_key_msg - Handle VIRTCHNL_OP_CONFIG_RSS_KEY msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Sets the RSS key for the given VF, using the contents of msg_buf.
+ */
+static void
+ice_vc_cfg_rss_key_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_aqc_get_set_rss_keys keydata =
+ { .standard_rss_key = {0}, .extended_hash_key = {0} };
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_rss_key *vrk;
+ int status = 0;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+
+ vrk = (struct virtchnl_rss_key *)msg_buf;
+
+ if (vrk->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ vf->vf_num, vsi->idx, vrk->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ if ((vrk->key_len >
+ (ICE_AQC_GET_SET_RSS_KEY_DATA_RSS_KEY_SIZE +
+ ICE_AQC_GET_SET_RSS_KEY_DATA_HASH_KEY_SIZE)) ||
+ vrk->key_len == 0) {
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ memcpy(&keydata, vrk->key, vrk->key_len);
+
+ status = ice_aq_set_rss_key(hw, vsi->idx, &keydata);
+ if (status) {
+ device_printf(sc->dev,
+ "ice_aq_set_rss_key status %s, error %s\n",
+ ice_status_str(status), ice_aq_str(hw->adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_CONFIG_RSS_KEY,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_cfg_rss_lut_msg - Handle VIRTCHNL_OP_CONFIG_RSS_LUT msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Adds the LUT from the VF in msg_buf to the PF via an admin queue call.
+ */
+static void
+ice_vc_cfg_rss_lut_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_rss_lut *vrl;
+ int status = 0;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_aq_get_set_rss_lut_params lut_params = {};
+ struct ice_vsi *vsi = vf->vsi;
+
+ vrl = (struct virtchnl_rss_lut *)msg_buf;
+
+ if (vrl->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ vf->vf_num, vsi->idx, vrl->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ if (vrl->lut_entries > ICE_VSIQF_HLUT_ARRAY_SIZE) {
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ lut_params.vsi_handle = vsi->idx;
+ lut_params.lut_size = vsi->rss_table_size;
+ lut_params.lut_type = vsi->rss_lut_type;
+ lut_params.lut = vrl->lut;
+ lut_params.global_lut_id = 0;
+
+ status = ice_aq_set_rss_lut(hw, &lut_params);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Cannot set RSS lut, err %s aq_err %s\n",
+ vf->vf_num, ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_CONFIG_RSS_LUT,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_set_rss_hena_msg - Handle VIRTCHNL_OP_SET_RSS_HENA msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Adds the VF's hena (hash enable) bits as flow types to the PF's RSS flow
+ * type list.
+ */
+static void
+ice_vc_set_rss_hena_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_rss_hena *vrh;
+ int status = 0;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+
+ MPASS(vsi != NULL);
+
+ vrh = (struct virtchnl_rss_hena *)msg_buf;
+
+ /*
+ * Remove existing configuration to make sure only requested
+ * config is applied and allow VFs to disable RSS completly.
+ */
+ status = ice_rem_vsi_rss_cfg(hw, vsi->idx);
+ if (vrh->hena) {
+ /*
+ * Problem with removing config is not fatal, when new one
+ * is requested. Warn about it but try to apply new config
+ * anyway.
+ */
+ if (status)
+ device_printf(sc->dev,
+ "ice_rem_vsi_rss_cfg status %s, error %s\n",
+ ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ status = ice_add_avf_rss_cfg(hw, vsi->idx, vrh->hena);
+ if (status)
+ device_printf(sc->dev,
+ "ice_add_avf_rss_cfg status %s, error %s\n",
+ ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ }
+ v_status = ice_iov_err_to_virt_err(status);
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_SET_RSS_HENA,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_enable_queues_msg - Handle VIRTCHNL_OP_ENABLE_QUEUES msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Enables VF queues selected in msg_buf for Tx/Rx traffic.
+ *
+ * @remark Only actually operates on Rx queues; Tx queues are enabled in
+ * CONFIG_VSI_QUEUES message handler.
+ */
+static void
+ice_vc_enable_queues_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_queue_select *vqs;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+ int bit, error = 0;
+
+ vqs = (struct virtchnl_queue_select *)msg_buf;
+
+ if (vqs->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "%s: VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ __func__, vf->vf_num, vsi->idx, vqs->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ if (!vqs->rx_queues && !vqs->tx_queues) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message queue masks are empty\n",
+ __func__, vf->vf_num);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ /* Validate rx_queue mask */
+ bit = fls(vqs->rx_queues);
+ if (bit > vsi->num_rx_queues) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message's rx_queues map (0x%08x) has invalid bit set (%d)\n",
+ __func__, vf->vf_num, vqs->rx_queues, bit);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ /* Tx ring enable is handled in an earlier message. */
+ for_each_set_bit(bit, &vqs->rx_queues, 32) {
+ error = ice_control_rx_queue(vsi, bit, true);
+ if (error) {
+ device_printf(sc->dev,
+ "Unable to enable Rx ring %d for receive: %s\n",
+ bit, ice_err_str(error));
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_ENABLE_QUEUES,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_disable_queues_msg - Handle VIRTCHNL_OP_DISABLE_QUEUES msg
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Disables all VF queues for the VF's VSI.
+ *
+ * @remark Unlike the ENABLE_QUEUES handler, this operates on both
+ * Tx and Rx queues
+ */
+static void
+ice_vc_disable_queues_msg(struct ice_softc *sc, struct ice_vf *vf,
+ u8 *msg_buf __unused)
+{
+ struct ice_hw *hw = &sc->hw;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+ int error = 0;
+
+ error = ice_control_all_rx_queues(vsi, false);
+ if (error) {
+ device_printf(sc->dev,
+ "Unable to disable Rx rings for transmit: %s\n",
+ ice_err_str(error));
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ error = ice_vsi_disable_tx(vsi);
+ if (error) {
+ /* Already prints an error message */
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_DISABLE_QUEUES,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_cfg_irq_map_msg - Handle VIRTCHNL_OP_CFG_IRQ_MAP msg from VF
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Configures the interrupt vectors described in the message in msg_buf. The
+ * VF needs to send this message during init, so that queues can be allowed
+ * to generate interrupts.
+ */
+static void
+ice_vc_cfg_irq_map_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+#define ICE_VIRTCHNL_QUEUE_MAP_SIZE 16
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_irq_map_info *vimi;
+ struct virtchnl_vector_map *vvm;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ struct ice_vsi *vsi = vf->vsi;
+ u16 vector;
+
+ vimi = (struct virtchnl_irq_map_info *)msg_buf;
+
+ if (vimi->num_vectors > vf->num_irq_vectors) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message has more vectors (%d) than configured for VF (%d)\n",
+ __func__, vf->vf_num, vimi->num_vectors, vf->num_irq_vectors);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ vvm = vimi->vecmap;
+ /* Save off information from message */
+ for (int i = 0; i < vimi->num_vectors; i++, vvm++) {
+ struct ice_tx_queue *txq;
+ struct ice_rx_queue *rxq;
+ int bit;
+
+ if (vvm->vsi_id != vf->vsi->idx) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message's VSI ID (%d) does not match VF's (%d) for vector %d\n",
+ __func__, vf->vf_num, vvm->vsi_id, vf->vsi->idx, i);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ /* vvm->vector_id is relative to VF space */
+ vector = vvm->vector_id;
+
+ if (vector >= vf->num_irq_vectors) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message's vector ID (%d) is greater than VF's max ID (%d)\n",
+ __func__, vf->vf_num, vector, vf->num_irq_vectors - 1);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ /* The Misc/Admin Queue vector doesn't need mapping */
+ if (vector == 0)
+ continue;
+
+ /* coverity[address_of] */
+ for_each_set_bit(bit, &vvm->txq_map, ICE_VIRTCHNL_QUEUE_MAP_SIZE) {
+ if (bit >= vsi->num_tx_queues) {
+ device_printf(sc->dev,
+ "%s: VF-%d: txq map has invalid bit set\n",
+ __func__, vf->vf_num);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ vf->tx_irqvs[vector].me = vector;
+
+ txq = &vsi->tx_queues[bit];
+ txq->irqv = &vf->tx_irqvs[vector];
+ txq->itr_idx = vvm->txitr_idx;
+ }
+ /* coverity[address_of] */
+ for_each_set_bit(bit, &vvm->rxq_map, ICE_VIRTCHNL_QUEUE_MAP_SIZE) {
+ if (bit >= vsi->num_rx_queues) {
+ device_printf(sc->dev,
+ "%s: VF-%d: rxq map has invalid bit set\n",
+ __func__, vf->vf_num);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+ vf->rx_irqvs[vector].me = vector;
+
+ rxq = &vsi->rx_queues[bit];
+ rxq->irqv = &vf->rx_irqvs[vector];
+ rxq->itr_idx = vvm->rxitr_idx;
+ }
+ }
+
+ /* Write to T/RQCTL registers to actually map vectors to queues */
+ for (int i = 0; i < vf->vsi->num_rx_queues; i++)
+ if (vsi->rx_queues[i].irqv != NULL)
+ ice_configure_rxq_interrupt(hw, vsi->rx_qmap[i],
+ vsi->rx_queues[i].irqv->me, vsi->rx_queues[i].itr_idx);
+
+ for (int i = 0; i < vf->vsi->num_tx_queues; i++)
+ if (vsi->tx_queues[i].irqv != NULL)
+ ice_configure_txq_interrupt(hw, vsi->tx_qmap[i],
+ vsi->tx_queues[i].irqv->me, vsi->tx_queues[i].itr_idx);
+
+ ice_flush(hw);
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_CONFIG_IRQ_MAP,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_eth_stats_to_virtchnl_eth_stats - Convert stats for virtchnl
+ * @istats: VSI stats from HW to convert
+ * @vstats: stats struct to copy to
+ *
+ * This function copies all known stats in struct virtchnl_eth_stats from the
+ * input struct ice_eth_stats to an output struct virtchnl_eth_stats.
+ *
+ * @remark These two structure types currently have the same definition up to
+ * the size of struct virtchnl_eth_stats (on FreeBSD), but that could change
+ * in the future.
+ */
+static void
+ice_eth_stats_to_virtchnl_eth_stats(struct ice_eth_stats *istats,
+ struct virtchnl_eth_stats *vstats)
+{
+ vstats->rx_bytes = istats->rx_bytes;
+ vstats->rx_unicast = istats->rx_unicast;
+ vstats->rx_multicast = istats->rx_multicast;
+ vstats->rx_broadcast = istats->rx_broadcast;
+ vstats->rx_discards = istats->rx_discards;
+ vstats->rx_unknown_protocol = istats->rx_unknown_protocol;
+ vstats->tx_bytes = istats->tx_bytes;
+ vstats->tx_unicast = istats->tx_unicast;
+ vstats->tx_multicast = istats->tx_multicast;
+ vstats->tx_broadcast = istats->tx_broadcast;
+ vstats->tx_discards = istats->tx_discards;
+ vstats->tx_errors = istats->tx_errors;
+}
+
+/**
+ * ice_vc_get_stats_msg - Handle VIRTCHNL_OP_GET_STATS msg
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ * @msg_buf: raw message buffer from the VF
+ *
+ * Updates the VF's VSI stats and sends those stats back to the VF.
+ */
+static void
+ice_vc_get_stats_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct virtchnl_queue_select *vqs;
+ struct virtchnl_eth_stats stats;
+ struct ice_vsi *vsi = vf->vsi;
+ struct ice_hw *hw = &sc->hw;
+
+ vqs = (struct virtchnl_queue_select *)msg_buf;
+
+ if (vqs->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "%s: VF-%d: message has invalid VSI ID %d (VF has VSI ID %d)\n",
+ __func__, vf->vf_num, vqs->vsi_id, vsi->idx);
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_GET_STATS,
+ VIRTCHNL_STATUS_ERR_PARAM, NULL, 0, NULL);
+ }
+
+ ice_update_vsi_hw_stats(vf->vsi);
+ ice_eth_stats_to_virtchnl_eth_stats(&vsi->hw_stats.cur, &stats);
+
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_GET_STATS,
+ VIRTCHNL_STATUS_SUCCESS, (u8 *)&stats,
+ sizeof(struct virtchnl_eth_stats), NULL);
+}
+
+/**
+ * ice_vc_cfg_promisc_mode_msg - Handle VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE
+ * @sc: PF's softc structure
+ * @vf: VF tracking structure
+ * @msg_buf: message buffer from VF
+ *
+ * Configures the promiscuous modes for the given VSI in msg_buf.
+ */
+static void
+ice_vc_cfg_promisc_mode_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct virtchnl_promisc_info *vpi;
+ enum virtchnl_status_code v_status = VIRTCHNL_STATUS_SUCCESS;
+ int status = 0;
+ struct ice_vsi *vsi = vf->vsi;
+ ice_declare_bitmap(old_promisc_mask, ICE_PROMISC_MAX);
+ ice_declare_bitmap(req_promisc_mask, ICE_PROMISC_MAX);
+ ice_declare_bitmap(clear_promisc_mask, ICE_PROMISC_MAX);
+ ice_declare_bitmap(set_promisc_mask, ICE_PROMISC_MAX);
+ ice_declare_bitmap(old_req_xor_mask, ICE_PROMISC_MAX);
+ u16 vid;
+
+ vpi = (struct virtchnl_promisc_info *)msg_buf;
+
+ /* Check to see if VF has permission to configure promiscuous mode */
+ if (!(vf->vf_flags & VF_FLAG_PROMISC_CAP)) {
+ device_printf(sc->dev,
+ "VF-%d: attempted to configure promiscuous mode\n",
+ vf->vf_num);
+ /* Don't reply to VF with an error */
+ goto done;
+ }
+
+ if (vpi->vsi_id != vsi->idx) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid VSI ID (expected %d, got %d)\n",
+ vf->vf_num, vsi->idx, vpi->vsi_id);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+ }
+
+ if (vpi->flags & ~ICE_VIRTCHNL_VALID_PROMISC_FLAGS) {
+ device_printf(sc->dev,
+ "VF-%d: Message has invalid promiscuous flags set (valid 0x%02x, got 0x%02x)\n",
+ vf->vf_num, ICE_VIRTCHNL_VALID_PROMISC_FLAGS,
+ vpi->flags);
+ v_status = VIRTCHNL_STATUS_ERR_PARAM;
+ goto done;
+
+ }
+
+ ice_zero_bitmap(req_promisc_mask, ICE_PROMISC_MAX);
+ /* Convert virtchnl flags to ice AQ promiscuous mode flags */
+ if (vpi->flags & FLAG_VF_UNICAST_PROMISC) {
+ ice_set_bit(ICE_PROMISC_UCAST_TX, req_promisc_mask);
+ ice_set_bit(ICE_PROMISC_UCAST_RX, req_promisc_mask);
+ }
+ if (vpi->flags & FLAG_VF_MULTICAST_PROMISC) {
+ ice_set_bit(ICE_PROMISC_MCAST_TX, req_promisc_mask);
+ ice_set_bit(ICE_PROMISC_MCAST_RX, req_promisc_mask);
+ }
+
+ status = ice_get_vsi_promisc(hw, vsi->idx, old_promisc_mask, &vid);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Failed to get promiscuous mode mask for VSI %d, err %s aq_err %s\n",
+ vf->vf_num, vsi->idx,
+ ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+
+ /* Figure out what got added and what got removed */
+ ice_zero_bitmap(old_req_xor_mask, ICE_PROMISC_MAX);
+ ice_xor_bitmap(old_req_xor_mask, old_promisc_mask, req_promisc_mask, ICE_PROMISC_MAX);
+ ice_and_bitmap(clear_promisc_mask, old_req_xor_mask, old_promisc_mask, ICE_PROMISC_MAX);
+ ice_and_bitmap(set_promisc_mask, old_req_xor_mask, req_promisc_mask, ICE_PROMISC_MAX);
+
+ if (ice_is_any_bit_set(clear_promisc_mask, ICE_PROMISC_MAX)) {
+ status = ice_clear_vsi_promisc(hw, vsi->idx,
+ clear_promisc_mask, 0);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Failed to clear promiscuous mode for VSI %d, err %s aq_err %s\n",
+ vf->vf_num, vsi->idx,
+ ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+ }
+
+ if (ice_is_any_bit_set(set_promisc_mask, ICE_PROMISC_MAX)) {
+ status = ice_set_vsi_promisc(hw, vsi->idx, set_promisc_mask, 0);
+ if (status) {
+ device_printf(sc->dev,
+ "VF-%d: Failed to set promiscuous mode for VSI %d, err %s aq_err %s\n",
+ vf->vf_num, vsi->idx,
+ ice_status_str(status),
+ ice_aq_str(hw->adminq.sq_last_status));
+ v_status = ice_iov_err_to_virt_err(status);
+ goto done;
+ }
+ }
+
+done:
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE,
+ v_status, NULL, 0, NULL);
+}
+
+/**
+ * ice_vc_notify_all_vfs_link_state - Notify all VFs of PF link state
+ * @sc: device private structure
+ *
+ * Sends a message to all VFs about the status of the PF's link
+ * state. For more details, @see ice_vc_notify_vf_link_state.
+ */
+void
+ice_vc_notify_all_vfs_link_state(struct ice_softc *sc)
+{
+ for (int i = 0; i < sc->num_vfs; i++)
+ ice_vc_notify_vf_link_state(sc, &sc->vfs[i]);
+}
+
+/**
+ * ice_vc_notify_vf_link_state - Notify VF of PF link state
+ * @sc: device private structure
+ * @vf: VF tracking structure
+ *
+ * Sends an event message to the specified VF with information about
+ * the current link state from the PF's port. This includes whether
+ * link is up or down, and the link speed in 100Mbps units.
+ */
+static void
+ice_vc_notify_vf_link_state(struct ice_softc *sc, struct ice_vf *vf)
+{
+ struct virtchnl_pf_event event = {};
+ struct ice_hw *hw = &sc->hw;
+
+ event.event = VIRTCHNL_EVENT_LINK_CHANGE;
+ event.severity = PF_EVENT_SEVERITY_INFO;
+ event.event_data.link_event_adv.link_status = sc->link_up;
+ event.event_data.link_event_adv.link_speed =
+ (u32)ice_conv_link_speed_to_virtchnl(true,
+ hw->port_info->phy.link_info.link_speed);
+
+ ice_aq_send_msg_to_vf(hw, vf->vf_num, VIRTCHNL_OP_EVENT,
+ VIRTCHNL_STATUS_SUCCESS, (u8 *)&event, sizeof(event), NULL);
+}
+
+/**
+ * ice_vc_handle_vf_msg - Handle a message from a VF
+ * @sc: device private structure
+ * @event: event received from the HW MBX queue
+ *
+ * Called whenever an event is received from a VF on the HW mailbox queue.
+ * Responsible for handling these messages as well as responding to the
+ * VF afterwards, depending on the received message type.
+ */
+void
+ice_vc_handle_vf_msg(struct ice_softc *sc, struct ice_rq_event_info *event)
+{
+ struct ice_hw *hw = &sc->hw;
+ device_t dev = sc->dev;
+ struct ice_vf *vf;
+ int err = 0;
+
+ u32 v_opcode = event->desc.cookie_high;
+ u16 v_id = event->desc.retval;
+ u8 *msg = event->msg_buf;
+ u16 msglen = event->msg_len;
+
+ if (v_id >= sc->num_vfs) {
+ device_printf(dev, "%s: Received msg from invalid VF-%d: opcode %d, len %d\n",
+ __func__, v_id, v_opcode, msglen);
+ return;
+ }
+
+ vf = &sc->vfs[v_id];
+
+ /* Perform basic checks on the msg */
+ err = virtchnl_vc_validate_vf_msg(&vf->version, v_opcode, msg, msglen);
+ if (err) {
+ device_printf(dev, "%s: Received invalid msg from VF-%d: opcode %d, len %d, error %d\n",
+ __func__, vf->vf_num, v_opcode, msglen, err);
+ ice_aq_send_msg_to_vf(hw, v_id, v_opcode, VIRTCHNL_STATUS_ERR_PARAM, NULL, 0, NULL);
+ return;
+ }
+
+ switch (v_opcode) {
+ case VIRTCHNL_OP_VERSION:
+ ice_vc_version_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_RESET_VF:
+ ice_reset_vf(sc, vf, true);
+ break;
+ case VIRTCHNL_OP_GET_VF_RESOURCES:
+ ice_vc_get_vf_res_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_ADD_ETH_ADDR:
+ ice_vc_add_eth_addr_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_DEL_ETH_ADDR:
+ ice_vc_del_eth_addr_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_ADD_VLAN:
+ ice_vc_add_vlan_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_DEL_VLAN:
+ ice_vc_del_vlan_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_VSI_QUEUES:
+ ice_vc_cfg_vsi_qs_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_RSS_KEY:
+ ice_vc_cfg_rss_key_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_RSS_LUT:
+ ice_vc_cfg_rss_lut_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_SET_RSS_HENA:
+ ice_vc_set_rss_hena_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_ENABLE_QUEUES:
+ ice_vc_enable_queues_msg(sc, vf, msg);
+ ice_vc_notify_vf_link_state(sc, vf);
+ break;
+ case VIRTCHNL_OP_DISABLE_QUEUES:
+ ice_vc_disable_queues_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_IRQ_MAP:
+ ice_vc_cfg_irq_map_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_GET_STATS:
+ ice_vc_get_stats_msg(sc, vf, msg);
+ break;
+ case VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
+ ice_vc_cfg_promisc_mode_msg(sc, vf, msg);
+ break;
+ default:
+ device_printf(dev, "%s: Received unknown msg from VF-%d: opcode %d, len %d\n",
+ __func__, vf->vf_num, v_opcode, msglen);
+ ice_aq_send_msg_to_vf(hw, v_id, v_opcode,
+ VIRTCHNL_STATUS_ERR_NOT_SUPPORTED, NULL, 0, NULL);
+ break;
+ }
+}
+
+/**
+ * ice_iov_setup_intr_mapping - Setup interrupt config for a VF
+ * @sc: device softc structure
+ * @vf: driver's VF structure for VF to be configured
+ *
+ * Before a VF can be used, and after a VF reset, the PF must configure
+ * the VF's interrupt allocation registers. This includes allocating
+ * interrupts from the PF's interrupt pool to the VF using the
+ * VPINT_ALLOC(_PCI) registers, and setting up a mapping from PF vectors
+ * to VF vectors in GLINT_VECT2FUNC.
+ *
+ * As well, this sets up queue allocation registers and maps the mailbox
+ * interrupt for the VF.
+ */
+static void
+ice_iov_setup_intr_mapping(struct ice_softc *sc, struct ice_vf *vf)
+{
+ struct ice_hw *hw = &sc->hw;
+ struct ice_vsi *vsi = vf->vsi;
+ u16 v;
+
+ /* Calculate indices for register ops below */
+ u16 vf_first_irq_idx = vf->vf_imap[0];
+ u16 vf_last_irq_idx = (vf_first_irq_idx + vf->num_irq_vectors) - 1;
+ u16 abs_vf_first_irq_idx = hw->func_caps.common_cap.msix_vector_first_id +
+ vf_first_irq_idx;
+ u16 abs_vf_last_irq_idx = (abs_vf_first_irq_idx + vf->num_irq_vectors) - 1;
+ u16 abs_vf_num = vf->vf_num + hw->func_caps.vf_base_id;
+
+ /* Map out VF interrupt allocation in global device space. Both
+ * VPINT_ALLOC and VPINT_ALLOC_PCI use the same values.
+ */
+ wr32(hw, VPINT_ALLOC(vf->vf_num),
+ (((abs_vf_first_irq_idx << VPINT_ALLOC_FIRST_S) & VPINT_ALLOC_FIRST_M) |
+ ((abs_vf_last_irq_idx << VPINT_ALLOC_LAST_S) & VPINT_ALLOC_LAST_M) |
+ VPINT_ALLOC_VALID_M));
+ wr32(hw, VPINT_ALLOC_PCI(vf->vf_num),
+ (((abs_vf_first_irq_idx << VPINT_ALLOC_PCI_FIRST_S) & VPINT_ALLOC_PCI_FIRST_M) |
+ ((abs_vf_last_irq_idx << VPINT_ALLOC_PCI_LAST_S) & VPINT_ALLOC_PCI_LAST_M) |
+ VPINT_ALLOC_PCI_VALID_M));
+
+ /* Create inverse mapping of vectors to PF/VF combinations */
+ for (v = vf_first_irq_idx; v <= vf_last_irq_idx; v++)
+ {
+ wr32(hw, GLINT_VECT2FUNC(v),
+ (((abs_vf_num << GLINT_VECT2FUNC_VF_NUM_S) & GLINT_VECT2FUNC_VF_NUM_M) |
+ ((hw->pf_id << GLINT_VECT2FUNC_PF_NUM_S) & GLINT_VECT2FUNC_PF_NUM_M)));
+ }
+
+ /* Map mailbox interrupt to MSI-X index 0. Disable ITR for it, too. */
+ wr32(hw, VPINT_MBX_CTL(abs_vf_num),
+ ((0 << VPINT_MBX_CTL_MSIX_INDX_S) & VPINT_MBX_CTL_MSIX_INDX_M) |
+ ((0x3 << VPINT_MBX_CTL_ITR_INDX_S) & VPINT_MBX_CTL_ITR_INDX_M) |
+ VPINT_MBX_CTL_CAUSE_ENA_M);
+
+ /* Mark the TX queue mapping registers as valid */
+ wr32(hw, VPLAN_TXQ_MAPENA(vf->vf_num), VPLAN_TXQ_MAPENA_TX_ENA_M);
+
+ /* Indicate to HW that VF has scattered queue allocation */
+ wr32(hw, VPLAN_TX_QBASE(vf->vf_num), VPLAN_TX_QBASE_VFQTABLE_ENA_M);
+ for (int i = 0; i < vsi->num_tx_queues; i++) {
+ wr32(hw, VPLAN_TX_QTABLE(i, vf->vf_num),
+ (vsi->tx_qmap[i] << VPLAN_TX_QTABLE_QINDEX_S) & VPLAN_TX_QTABLE_QINDEX_M);
+ }
+
+ /* Mark the RX queue mapping registers as valid */
+ wr32(hw, VPLAN_RXQ_MAPENA(vf->vf_num), VPLAN_RXQ_MAPENA_RX_ENA_M);
+ wr32(hw, VPLAN_RX_QBASE(vf->vf_num), VPLAN_RX_QBASE_VFQTABLE_ENA_M);
+ for (int i = 0; i < vsi->num_rx_queues; i++) {
+ wr32(hw, VPLAN_RX_QTABLE(i, vf->vf_num),
+ (vsi->rx_qmap[i] << VPLAN_RX_QTABLE_QINDEX_S) & VPLAN_RX_QTABLE_QINDEX_M);
+ }
+}
+
+/**
+ * ice_err_to_virt err - translate ice errors into virtchnl errors
+ * @ice_err: status returned from ice function
+ */
+static enum virtchnl_status_code
+ice_iov_err_to_virt_err(int ice_err)
+{
+ switch (ice_err) {
+ case 0:
+ return VIRTCHNL_STATUS_SUCCESS;
+ case ICE_ERR_BAD_PTR:
+ case ICE_ERR_INVAL_SIZE:
+ case ICE_ERR_DEVICE_NOT_SUPPORTED:
+ case ICE_ERR_PARAM:
+ case ICE_ERR_CFG:
+ return VIRTCHNL_STATUS_ERR_PARAM;
+ case ICE_ERR_NO_MEMORY:
+ return VIRTCHNL_STATUS_ERR_NO_MEMORY;
+ case ICE_ERR_NOT_READY:
+ case ICE_ERR_RESET_FAILED:
+ case ICE_ERR_FW_API_VER:
+ case ICE_ERR_AQ_ERROR:
+ case ICE_ERR_AQ_TIMEOUT:
+ case ICE_ERR_AQ_FULL:
+ case ICE_ERR_AQ_NO_WORK:
+ case ICE_ERR_AQ_EMPTY:
+ return VIRTCHNL_STATUS_ERR_ADMIN_QUEUE_ERROR;
+ default:
+ return VIRTCHNL_STATUS_ERR_NOT_SUPPORTED;
+ }
+}
diff --git a/sys/dev/ice/ice_iov.h b/sys/dev/ice/ice_iov.h
new file mode 100644
index 000000000000..c4fb3e932e3f
--- /dev/null
+++ b/sys/dev/ice/ice_iov.h
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Intel Corporation
+ * 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 Intel Corporation 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.
+ */
+
+/**
+ * @file ice_iov.h
+ * @brief header for IOV functionality
+ *
+ * This header includes definitions used to implement device Virtual Functions
+ * for the ice driver.
+ */
+
+#ifndef _ICE_IOV_H_
+#define _ICE_IOV_H_
+
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <sys/nv.h>
+#include <sys/iov_schema.h>
+#include <sys/param.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pcireg.h>
+
+#include <dev/pci/pci_iov.h>
+
+#include "ice_iflib.h"
+#include "ice_vf_mbx.h"
+
+/**
+ * @enum ice_vf_flags
+ * @brief VF state flags
+ *
+ * Used to indicate the status of a PF's VF, as well as indicating what each VF
+ * is capabile of. Intended to be modified only using atomic operations, so
+ * they can be read and modified in places that aren't locked.
+ *
+ * Used in struct ice_vf's vf_flags field.
+ */
+enum ice_vf_flags {
+ VF_FLAG_ENABLED = BIT(0),
+ VF_FLAG_SET_MAC_CAP = BIT(1),
+ VF_FLAG_VLAN_CAP = BIT(2),
+ VF_FLAG_PROMISC_CAP = BIT(3),
+ VF_FLAG_MAC_ANTI_SPOOF = BIT(4),
+};
+
+/**
+ * @struct ice_vf
+ * @brief PF's VF software context
+ *
+ * Represents the state and options for a VF spawned from a PF.
+ */
+struct ice_vf {
+ struct ice_vsi *vsi;
+ u32 vf_flags;
+
+ u8 mac[ETHER_ADDR_LEN];
+ u16 vf_num;
+ struct virtchnl_version_info version;
+
+ u16 mac_filter_limit;
+ u16 mac_filter_cnt;
+ u16 vlan_limit;
+ u16 vlan_cnt;
+
+ u16 num_irq_vectors;
+ u16 *vf_imap;
+ struct ice_irq_vector *tx_irqvs;
+ struct ice_irq_vector *rx_irqvs;
+};
+
+#define ICE_PCIE_DEV_STATUS 0xAA
+
+#define ICE_PCI_CIAD_WAIT_COUNT 100
+#define ICE_PCI_CIAD_WAIT_DELAY_US 1
+#define ICE_VPGEN_VFRSTAT_WAIT_COUNT 100
+#define ICE_VPGEN_VFRSTAT_WAIT_DELAY_US 20
+
+#define ICE_VIRTCHNL_VALID_PROMISC_FLAGS (FLAG_VF_UNICAST_PROMISC | \
+ FLAG_VF_MULTICAST_PROMISC)
+
+#define ICE_DEFAULT_VF_VLAN_LIMIT 64
+#define ICE_DEFAULT_VF_FILTER_LIMIT 16
+
+int ice_iov_attach(struct ice_softc *sc);
+int ice_iov_detach(struct ice_softc *sc);
+
+int ice_iov_init(struct ice_softc *sc, uint16_t num_vfs, const nvlist_t *params);
+int ice_iov_add_vf(struct ice_softc *sc, uint16_t vfnum, const nvlist_t *params);
+void ice_iov_uninit(struct ice_softc *sc);
+
+void ice_iov_handle_vflr(struct ice_softc *sc);
+
+void ice_vc_handle_vf_msg(struct ice_softc *sc, struct ice_rq_event_info *event);
+void ice_vc_notify_all_vfs_link_state(struct ice_softc *sc);
+
+#endif /* _ICE_IOV_H_ */
+
diff --git a/sys/dev/ice/ice_lib.c b/sys/dev/ice/ice_lib.c
index d44ae5f37750..442111e5ffaf 100644
--- a/sys/dev/ice/ice_lib.c
+++ b/sys/dev/ice/ice_lib.c
@@ -42,6 +42,9 @@
#include "ice_lib.h"
#include "ice_iflib.h"
+#ifdef PCI_IOV
+#include "ice_iov.h"
+#endif
#include <dev/pci/pcivar.h>
#include <dev/pci/pcireg.h>
#include <machine/resource.h>
@@ -741,6 +744,12 @@ ice_initialize_vsi(struct ice_vsi *vsi)
case ICE_VSI_VMDQ2:
ctx.flags = ICE_AQ_VSI_TYPE_VMDQ2;
break;
+#ifdef PCI_IOV
+ case ICE_VSI_VF:
+ ctx.flags = ICE_AQ_VSI_TYPE_VF;
+ ctx.vf_num = vsi->vf_num;
+ break;
+#endif
default:
return (ENODEV);
}
@@ -1607,6 +1616,12 @@ ice_setup_tx_ctx(struct ice_tx_queue *txq, struct ice_tlan_ctx *tlan_ctx, u16 pf
case ICE_VSI_VMDQ2:
tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VMQ;
break;
+#ifdef PCI_IOV
+ case ICE_VSI_VF:
+ tlan_ctx->vmvf_type = ICE_TLAN_CTX_VMVF_TYPE_VF;
+ tlan_ctx->vmvf_num = hw->func_caps.vf_base_id + vsi->vf_num;
+ break;
+#endif
default:
return (ENODEV);
}
@@ -1660,6 +1675,10 @@ ice_cfg_vsi_for_tx(struct ice_vsi *vsi)
struct ice_tlan_ctx tlan_ctx = { 0 };
struct ice_tx_queue *txq = &vsi->tx_queues[i];
+ /* Last configured queue */
+ if (txq->desc_count == 0)
+ break;
+
pf_q = vsi->tx_qmap[txq->me];
qg->txqs[0].txq_id = htole16(pf_q);
@@ -1788,6 +1807,10 @@ ice_cfg_vsi_for_rx(struct ice_vsi *vsi)
for (i = 0; i < vsi->num_rx_queues; i++) {
MPASS(vsi->mbuf_sz > 0);
+ /* Last configured queue */
+ if (vsi->rx_queues[i].desc_count == 0)
+ break;
+
err = ice_setup_rx_ctx(&vsi->rx_queues[i]);
if (err)
return err;
@@ -2257,6 +2280,11 @@ ice_process_ctrlq_event(struct ice_softc *sc, const char *qname,
case ice_aqc_opc_get_link_status:
ice_process_link_event(sc, event);
break;
+#ifdef PCI_IOV
+ case ice_mbx_opc_send_msg_to_pf:
+ ice_vc_handle_vf_msg(sc, event);
+ break;
+#endif
case ice_aqc_opc_fw_logs_event:
ice_handle_fw_log_event(sc, &event->desc, event->msg_buf);
break;
diff --git a/sys/dev/ice/ice_lib.h b/sys/dev/ice/ice_lib.h
index b6b23ec82161..308b2bda2790 100644
--- a/sys/dev/ice/ice_lib.h
+++ b/sys/dev/ice/ice_lib.h
@@ -611,6 +611,10 @@ struct ice_vsi {
u16 mirror_src_vsi;
u16 rule_mir_ingress;
u16 rule_mir_egress;
+
+#ifdef PCI_IOV
+ u8 vf_num; /* Index of owning VF, if applicable */
+#endif
};
/**
diff --git a/sys/dev/ice/ice_vf_mbx.c b/sys/dev/ice/ice_vf_mbx.c
new file mode 100644
index 000000000000..387a1c6739a6
--- /dev/null
+++ b/sys/dev/ice/ice_vf_mbx.c
@@ -0,0 +1,471 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Intel Corporation
+ * 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 Intel Corporation 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 "ice_common.h"
+#include "ice_hw_autogen.h"
+#include "ice_vf_mbx.h"
+
+/**
+ * ice_aq_send_msg_to_vf
+ * @hw: pointer to the hardware structure
+ * @vfid: VF ID to send msg
+ * @v_opcode: opcodes for VF-PF communication
+ * @v_retval: return error code
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ * @cd: pointer to command details
+ *
+ * Send message to VF driver (0x0802) using mailbox
+ * queue and asynchronously sending message via
+ * ice_sq_send_cmd() function
+ */
+int
+ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
+ u8 *msg, u16 msglen, struct ice_sq_cd *cd)
+{
+ struct ice_aqc_pf_vf_msg *cmd;
+ struct ice_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_mbx_opc_send_msg_to_vf);
+
+ cmd = &desc.params.virt;
+ cmd->id = CPU_TO_LE32(vfid);
+
+ desc.cookie_high = CPU_TO_LE32(v_opcode);
+ desc.cookie_low = CPU_TO_LE32(v_retval);
+
+ if (msglen)
+ desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
+
+ return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd);
+}
+
+/**
+ * ice_aq_send_msg_to_pf
+ * @hw: pointer to the hardware structure
+ * @v_opcode: opcodes for VF-PF communication
+ * @v_retval: return error code
+ * @msg: pointer to the msg buffer
+ * @msglen: msg length
+ * @cd: pointer to command details
+ *
+ * Send message to PF driver using mailbox queue. By default, this
+ * message is sent asynchronously, i.e. ice_sq_send_cmd()
+ * does not wait for completion before returning.
+ */
+int
+ice_aq_send_msg_to_pf(struct ice_hw *hw, enum virtchnl_ops v_opcode,
+ int v_retval, u8 *msg, u16 msglen,
+ struct ice_sq_cd *cd)
+{
+ struct ice_aq_desc desc;
+
+ ice_fill_dflt_direct_cmd_desc(&desc, ice_mbx_opc_send_msg_to_pf);
+ desc.cookie_high = CPU_TO_LE32(v_opcode);
+ desc.cookie_low = CPU_TO_LE32(v_retval);
+
+ if (msglen)
+ desc.flags |= CPU_TO_LE16(ICE_AQ_FLAG_RD);
+
+ return ice_sq_send_cmd(hw, &hw->mailboxq, &desc, msg, msglen, cd);
+}
+
+static const u32 ice_legacy_aq_to_vc_speed[] = {
+ VIRTCHNL_LINK_SPEED_100MB, /* BIT(0) */
+ VIRTCHNL_LINK_SPEED_100MB,
+ VIRTCHNL_LINK_SPEED_1GB,
+ VIRTCHNL_LINK_SPEED_1GB,
+ VIRTCHNL_LINK_SPEED_1GB,
+ VIRTCHNL_LINK_SPEED_10GB,
+ VIRTCHNL_LINK_SPEED_20GB,
+ VIRTCHNL_LINK_SPEED_25GB,
+ VIRTCHNL_LINK_SPEED_40GB,
+ VIRTCHNL_LINK_SPEED_40GB,
+ VIRTCHNL_LINK_SPEED_40GB,
+};
+
+/**
+ * ice_conv_link_speed_to_virtchnl
+ * @adv_link_support: determines the format of the returned link speed
+ * @link_speed: variable containing the link_speed to be converted
+ *
+ * Convert link speed supported by HW to link speed supported by virtchnl.
+ * If adv_link_support is true, then return link speed in Mbps. Else return
+ * link speed as a VIRTCHNL_LINK_SPEED_* casted to a u32. Note that the caller
+ * needs to cast back to an enum virtchnl_link_speed in the case where
+ * adv_link_support is false, but when adv_link_support is true the caller can
+ * expect the speed in Mbps.
+ */
+u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed)
+{
+ /* convert a BIT() value into an array index */
+ u16 index = (u16)(ice_fls(link_speed) - 1);
+
+ if (adv_link_support)
+ return ice_get_link_speed(index);
+ else if (index < ARRAY_SIZE(ice_legacy_aq_to_vc_speed))
+ /* Virtchnl speeds are not defined for every speed supported in
+ * the hardware. To maintain compatibility with older AVF
+ * drivers, while reporting the speed the new speed values are
+ * resolved to the closest known virtchnl speeds
+ */
+ return ice_legacy_aq_to_vc_speed[index];
+
+ return VIRTCHNL_LINK_SPEED_UNKNOWN;
+}
+
+/* The mailbox overflow detection algorithm helps to check if there
+ * is a possibility of a malicious VF transmitting too many MBX messages to the
+ * PF.
+ * 1. The mailbox snapshot structure, ice_mbx_snapshot, is initialized during
+ * driver initialization in ice_init_hw() using ice_mbx_init_snapshot().
+ * The struct ice_mbx_snapshot helps to track and traverse a static window of
+ * messages within the mailbox queue while looking for a malicious VF.
+ *
+ * 2. When the caller starts processing its mailbox queue in response to an
+ * interrupt, the structure ice_mbx_snapshot is expected to be cleared before
+ * the algorithm can be run for the first time for that interrupt. This
+ * requires calling ice_mbx_reset_snapshot() as well as calling
+ * ice_mbx_reset_vf_info() for each VF tracking structure.
+ *
+ * 3. For every message read by the caller from the MBX Queue, the caller must
+ * call the detection algorithm's entry function ice_mbx_vf_state_handler().
+ * Before every call to ice_mbx_vf_state_handler() the struct ice_mbx_data is
+ * filled as it is required to be passed to the algorithm.
+ *
+ * 4. Every time a message is read from the MBX queue, a tracking structure
+ * for the VF must be passed to the state handler. The boolean output
+ * report_malvf from ice_mbx_vf_state_handler() serves as an indicator to the
+ * caller whether it must report this VF as malicious or not.
+ *
+ * 5. When a VF is identified to be malicious, the caller can send a message
+ * to the system administrator.
+ *
+ * 6. The PF is responsible for maintaining the struct ice_mbx_vf_info
+ * structure for each VF. The PF should clear the VF tracking structure if the
+ * VF is reset. When a VF is shut down and brought back up, we will then
+ * assume that the new VF is not malicious and may report it again if we
+ * detect it again.
+ *
+ * 7. The function ice_mbx_reset_snapshot() is called to reset the information
+ * in ice_mbx_snapshot for every new mailbox interrupt handled.
+ */
+#define ICE_RQ_DATA_MASK(rq_data) ((rq_data) & PF_MBX_ARQH_ARQH_M)
+/* Using the highest value for an unsigned 16-bit value 0xFFFF to indicate that
+ * the max messages check must be ignored in the algorithm
+ */
+#define ICE_IGNORE_MAX_MSG_CNT 0xFFFF
+
+/**
+ * ice_mbx_reset_snapshot - Initialize mailbox snapshot structure
+ * @snap: pointer to the mailbox snapshot
+ */
+static void ice_mbx_reset_snapshot(struct ice_mbx_snapshot *snap)
+{
+ struct ice_mbx_vf_info *vf_info;
+
+ /* Clear mbx_buf in the mailbox snaphot structure and setting the
+ * mailbox snapshot state to a new capture.
+ */
+ ice_memset(&snap->mbx_buf, 0, sizeof(snap->mbx_buf), ICE_NONDMA_MEM);
+ snap->mbx_buf.state = ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
+
+ /* Reset message counts for all VFs to zero */
+ LIST_FOR_EACH_ENTRY(vf_info, &snap->mbx_vf, ice_mbx_vf_info, list_entry)
+ vf_info->msg_count = 0;
+}
+
+/**
+ * ice_mbx_traverse - Pass through mailbox snapshot
+ * @hw: pointer to the HW struct
+ * @new_state: new algorithm state
+ *
+ * Traversing the mailbox static snapshot without checking
+ * for malicious VFs.
+ */
+static void
+ice_mbx_traverse(struct ice_hw *hw,
+ enum ice_mbx_snapshot_state *new_state)
+{
+ struct ice_mbx_snap_buffer_data *snap_buf;
+ u32 num_iterations;
+
+ snap_buf = &hw->mbx_snapshot.mbx_buf;
+
+ /* As mailbox buffer is circular, applying a mask
+ * on the incremented iteration count.
+ */
+ num_iterations = ICE_RQ_DATA_MASK(++snap_buf->num_iterations);
+
+ /* Checking either of the below conditions to exit snapshot traversal:
+ * Condition-1: If the number of iterations in the mailbox is equal to
+ * the mailbox head which would indicate that we have reached the end
+ * of the static snapshot.
+ * Condition-2: If the maximum messages serviced in the mailbox for a
+ * given interrupt is the highest possible value then there is no need
+ * to check if the number of messages processed is equal to it. If not
+ * check if the number of messages processed is greater than or equal
+ * to the maximum number of mailbox entries serviced in current work item.
+ */
+ if (num_iterations == snap_buf->head ||
+ (snap_buf->max_num_msgs_mbx < ICE_IGNORE_MAX_MSG_CNT &&
+ ++snap_buf->num_msg_proc >= snap_buf->max_num_msgs_mbx))
+ *new_state = ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT;
+}
+
+/**
+ * ice_mbx_detect_malvf - Detect malicious VF in snapshot
+ * @hw: pointer to the HW struct
+ * @vf_info: mailbox tracking structure for a VF
+ * @new_state: new algorithm state
+ * @is_malvf: boolean output to indicate if VF is malicious
+ *
+ * This function tracks the number of asynchronous messages
+ * sent per VF and marks the VF as malicious if it exceeds
+ * the permissible number of messages to send.
+ */
+static int
+ice_mbx_detect_malvf(struct ice_hw *hw, struct ice_mbx_vf_info *vf_info,
+ enum ice_mbx_snapshot_state *new_state,
+ bool *is_malvf)
+{
+ /* increment the message count for this VF */
+ vf_info->msg_count++;
+
+ if (vf_info->msg_count >= ICE_ASYNC_VF_MSG_THRESHOLD)
+ *is_malvf = true;
+
+ /* continue to iterate through the mailbox snapshot */
+ ice_mbx_traverse(hw, new_state);
+
+ return 0;
+}
+
+/**
+ * ice_e830_mbx_vf_dec_trig - Decrements the VF mailbox queue counter
+ * @hw: pointer to the HW struct
+ * @event: pointer to the control queue receive event
+ *
+ * This function triggers to decrement the counter
+ * MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT when the driver replenishes
+ * the buffers at the PF mailbox queue.
+ */
+void ice_e830_mbx_vf_dec_trig(struct ice_hw *hw,
+ struct ice_rq_event_info *event)
+{
+ u16 vfid = LE16_TO_CPU(event->desc.retval);
+
+ wr32(hw, E830_MBX_VF_DEC_TRIG(vfid), 1);
+}
+
+/**
+ * ice_mbx_vf_clear_cnt_e830 - Clear the VF mailbox queue count
+ * @hw: pointer to the HW struct
+ * @vf_id: VF ID in the PF space
+ *
+ * This function clears the counter MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT, and should
+ * be called when a VF is created and on VF reset.
+ */
+void ice_mbx_vf_clear_cnt_e830(struct ice_hw *hw, u16 vf_id)
+{
+ u32 reg = rd32(hw, E830_MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT(vf_id));
+
+ wr32(hw, E830_MBX_VF_DEC_TRIG(vf_id), reg);
+}
+
+/**
+ * ice_mbx_vf_state_handler - Handle states of the overflow algorithm
+ * @hw: pointer to the HW struct
+ * @mbx_data: pointer to structure containing mailbox data
+ * @vf_info: mailbox tracking structure for the VF in question
+ * @report_malvf: boolean output to indicate whether VF should be reported
+ *
+ * The function serves as an entry point for the malicious VF
+ * detection algorithm by handling the different states and state
+ * transitions of the algorithm:
+ * New snapshot: This state is entered when creating a new static
+ * snapshot. The data from any previous mailbox snapshot is
+ * cleared and a new capture of the mailbox head and tail is
+ * logged. This will be the new static snapshot to detect
+ * asynchronous messages sent by VFs. On capturing the snapshot
+ * and depending on whether the number of pending messages in that
+ * snapshot exceed the watermark value, the state machine enters
+ * traverse or detect states.
+ * Traverse: If pending message count is below watermark then iterate
+ * through the snapshot without any action on VF.
+ * Detect: If pending message count exceeds watermark traverse
+ * the static snapshot and look for a malicious VF.
+ */
+int
+ice_mbx_vf_state_handler(struct ice_hw *hw, struct ice_mbx_data *mbx_data,
+ struct ice_mbx_vf_info *vf_info, bool *report_malvf)
+{
+ struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
+ struct ice_mbx_snap_buffer_data *snap_buf;
+ struct ice_ctl_q_info *cq = &hw->mailboxq;
+ enum ice_mbx_snapshot_state new_state;
+ int status = 0;
+ bool is_malvf = false;
+
+ if (!report_malvf || !mbx_data || !vf_info)
+ return ICE_ERR_BAD_PTR;
+
+ *report_malvf = false;
+
+ /* When entering the mailbox state machine assume that the VF
+ * is not malicious until detected.
+ */
+ /* Checking if max messages allowed to be processed while servicing current
+ * interrupt is not less than the defined AVF message threshold.
+ */
+ if (mbx_data->max_num_msgs_mbx <= ICE_ASYNC_VF_MSG_THRESHOLD)
+ return ICE_ERR_INVAL_SIZE;
+
+ /* The watermark value should not be lesser than the threshold limit
+ * set for the number of asynchronous messages a VF can send to mailbox
+ * nor should it be greater than the maximum number of messages in the
+ * mailbox serviced in current interrupt.
+ */
+ if (mbx_data->async_watermark_val < ICE_ASYNC_VF_MSG_THRESHOLD ||
+ mbx_data->async_watermark_val > mbx_data->max_num_msgs_mbx)
+ return ICE_ERR_PARAM;
+
+ new_state = ICE_MAL_VF_DETECT_STATE_INVALID;
+ snap_buf = &snap->mbx_buf;
+
+ switch (snap_buf->state) {
+ case ICE_MAL_VF_DETECT_STATE_NEW_SNAPSHOT:
+ /* Clear any previously held data in mailbox snapshot structure. */
+ ice_mbx_reset_snapshot(snap);
+
+ /* Collect the pending ARQ count, number of messages processed and
+ * the maximum number of messages allowed to be processed from the
+ * Mailbox for current interrupt.
+ */
+ snap_buf->num_pending_arq = mbx_data->num_pending_arq;
+ snap_buf->num_msg_proc = mbx_data->num_msg_proc;
+ snap_buf->max_num_msgs_mbx = mbx_data->max_num_msgs_mbx;
+
+ /* Capture a new static snapshot of the mailbox by logging the
+ * head and tail of snapshot and set num_iterations to the tail
+ * value to mark the start of the iteration through the snapshot.
+ */
+ snap_buf->head = ICE_RQ_DATA_MASK(cq->rq.next_to_clean +
+ mbx_data->num_pending_arq);
+ snap_buf->tail = ICE_RQ_DATA_MASK(cq->rq.next_to_clean - 1);
+ snap_buf->num_iterations = snap_buf->tail;
+
+ /* Pending ARQ messages returned by ice_clean_rq_elem
+ * is the difference between the head and tail of the
+ * mailbox queue. Comparing this value against the watermark
+ * helps to check if we potentially have malicious VFs.
+ */
+ if (snap_buf->num_pending_arq >=
+ mbx_data->async_watermark_val) {
+ new_state = ICE_MAL_VF_DETECT_STATE_DETECT;
+ status = ice_mbx_detect_malvf(hw, vf_info, &new_state, &is_malvf);
+ } else {
+ new_state = ICE_MAL_VF_DETECT_STATE_TRAVERSE;
+ ice_mbx_traverse(hw, &new_state);
+ }
+ break;
+
+ case ICE_MAL_VF_DETECT_STATE_TRAVERSE:
+ new_state = ICE_MAL_VF_DETECT_STATE_TRAVERSE;
+ ice_mbx_traverse(hw, &new_state);
+ break;
+
+ case ICE_MAL_VF_DETECT_STATE_DETECT:
+ new_state = ICE_MAL_VF_DETECT_STATE_DETECT;
+ status = ice_mbx_detect_malvf(hw, vf_info, &new_state, &is_malvf);
+ break;
+
+ default:
+ new_state = ICE_MAL_VF_DETECT_STATE_INVALID;
+ status = ICE_ERR_CFG;
+ }
+
+ snap_buf->state = new_state;
+
+ /* Only report VFs as malicious the first time we detect it */
+ if (is_malvf && !vf_info->malicious) {
+ vf_info->malicious = 1;
+ *report_malvf = true;
+ }
+
+ return status;
+}
+
+/**
+ * ice_mbx_clear_malvf - Clear VF mailbox info
+ * @vf_info: the mailbox tracking structure for a VF
+ *
+ * In case of a VF reset, this function shall be called to clear the VF's
+ * current mailbox tracking state.
+ */
+void ice_mbx_clear_malvf(struct ice_mbx_vf_info *vf_info)
+{
+ vf_info->malicious = 0;
+ vf_info->msg_count = 0;
+}
+
+/**
+ * ice_mbx_init_vf_info - Initialize a new VF mailbox tracking info
+ * @hw: pointer to the hardware structure
+ * @vf_info: the mailbox tracking info structure for a VF
+ *
+ * Initialize a VF mailbox tracking info structure and insert it into the
+ * snapshot list.
+ *
+ * If you remove the VF, you must also delete the associated VF info structure
+ * from the linked list.
+ */
+void ice_mbx_init_vf_info(struct ice_hw *hw, struct ice_mbx_vf_info *vf_info)
+{
+ struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
+
+ ice_mbx_clear_malvf(vf_info);
+ LIST_ADD(&vf_info->list_entry, &snap->mbx_vf);
+}
+
+/**
+ * ice_mbx_init_snapshot - Initialize mailbox snapshot data
+ * @hw: pointer to the hardware structure
+ *
+ * Clear the mailbox snapshot structure and initialize the VF mailbox list.
+ */
+void ice_mbx_init_snapshot(struct ice_hw *hw)
+{
+ struct ice_mbx_snapshot *snap = &hw->mbx_snapshot;
+
+ INIT_LIST_HEAD(&snap->mbx_vf);
+ ice_mbx_reset_snapshot(snap);
+}
diff --git a/sys/dev/ice/ice_vf_mbx.h b/sys/dev/ice/ice_vf_mbx.h
new file mode 100644
index 000000000000..3b185ac89c11
--- /dev/null
+++ b/sys/dev/ice/ice_vf_mbx.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/* Copyright (c) 2025, Intel Corporation
+ * 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 Intel Corporation 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.
+ */
+
+#ifndef _ICE_VF_MBX_H_
+#define _ICE_VF_MBX_H_
+
+#include "ice_type.h"
+#include "ice_controlq.h"
+
+/* Defining the mailbox message threshold as 63 asynchronous
+ * pending messages. Normal VF functionality does not require
+ * sending more than 63 asynchronous pending message.
+ */
+
+ /* Threshold value should be used to initialize
+ * MBX_VF_IN_FLIGHT_MSGS_AT_PF_CNT register.
+ */
+#define ICE_ASYNC_VF_MSG_THRESHOLD 63
+
+int
+ice_aq_send_msg_to_pf(struct ice_hw *hw, enum virtchnl_ops v_opcode,
+ int v_retval, u8 *msg, u16 msglen,
+ struct ice_sq_cd *cd);
+int
+ice_aq_send_msg_to_vf(struct ice_hw *hw, u16 vfid, u32 v_opcode, u32 v_retval,
+ u8 *msg, u16 msglen, struct ice_sq_cd *cd);
+
+u32 ice_conv_link_speed_to_virtchnl(bool adv_link_support, u16 link_speed);
+
+void ice_e830_mbx_vf_dec_trig(struct ice_hw *hw,
+ struct ice_rq_event_info *event);
+void ice_mbx_vf_clear_cnt_e830(struct ice_hw *hw, u16 vf_id);
+int
+ice_mbx_vf_state_handler(struct ice_hw *hw, struct ice_mbx_data *mbx_data,
+ struct ice_mbx_vf_info *vf_info, bool *report_malvf);
+void ice_mbx_clear_malvf(struct ice_mbx_vf_info *vf_info);
+void ice_mbx_init_vf_info(struct ice_hw *hw, struct ice_mbx_vf_info *vf_info);
+void ice_mbx_init_snapshot(struct ice_hw *hw);
+#endif /* _ICE_VF_MBX_H_ */
diff --git a/sys/dev/ice/if_ice_iflib.c b/sys/dev/ice/if_ice_iflib.c
index e60ee0f1c5c3..1469d2916465 100644
--- a/sys/dev/ice/if_ice_iflib.c
+++ b/sys/dev/ice/if_ice_iflib.c
@@ -42,6 +42,9 @@
#include "ice_drv_info.h"
#include "ice_switch.h"
#include "ice_sched.h"
+#ifdef PCI_IOV
+#include "ice_iov.h"
+#endif
#include <sys/module.h>
#include <sys/sockio.h>
@@ -85,6 +88,12 @@ static int ice_if_suspend(if_ctx_t ctx);
static int ice_if_resume(if_ctx_t ctx);
static bool ice_if_needs_restart(if_ctx_t ctx, enum iflib_restart_event event);
static void ice_init_link(struct ice_softc *sc);
+#ifdef PCI_IOV
+static int ice_if_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params);
+static void ice_if_iov_uninit(if_ctx_t ctx);
+static int ice_if_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params);
+static void ice_if_vflr_handle(if_ctx_t ctx);
+#endif
static int ice_setup_mirror_vsi(struct ice_mirr_if *mif);
static int ice_wire_mirror_intrs(struct ice_mirr_if *mif);
static void ice_free_irqvs_subif(struct ice_mirr_if *mif);
@@ -158,6 +167,11 @@ static device_method_t ice_methods[] = {
DEVMETHOD(device_shutdown, iflib_device_shutdown),
DEVMETHOD(device_suspend, iflib_device_suspend),
DEVMETHOD(device_resume, iflib_device_resume),
+#ifdef PCI_IOV
+ DEVMETHOD(pci_iov_init, iflib_device_iov_init),
+ DEVMETHOD(pci_iov_uninit, iflib_device_iov_uninit),
+ DEVMETHOD(pci_iov_add_vf, iflib_device_iov_add_vf),
+#endif
DEVMETHOD_END
};
@@ -198,6 +212,12 @@ static device_method_t ice_iflib_methods[] = {
DEVMETHOD(ifdi_suspend, ice_if_suspend),
DEVMETHOD(ifdi_resume, ice_if_resume),
DEVMETHOD(ifdi_needs_restart, ice_if_needs_restart),
+#ifdef PCI_IOV
+ DEVMETHOD(ifdi_iov_vf_add, ice_if_iov_vf_add),
+ DEVMETHOD(ifdi_iov_init, ice_if_iov_init),
+ DEVMETHOD(ifdi_iov_uninit, ice_if_iov_uninit),
+ DEVMETHOD(ifdi_vflr_handle, ice_if_vflr_handle),
+#endif
DEVMETHOD_END
};
@@ -733,6 +753,9 @@ ice_update_link_status(struct ice_softc *sc, bool update_media)
iflib_link_state_change(sc->ctx, LINK_STATE_DOWN, 0);
ice_rdma_link_change(sc, LINK_STATE_DOWN, 0);
}
+#ifdef PCI_IOV
+ ice_vc_notify_all_vfs_link_state(sc);
+#endif
update_media = true;
}
@@ -831,6 +854,14 @@ ice_if_attach_post(if_ctx_t ctx)
ice_add_device_sysctls(sc);
+#ifdef PCI_IOV
+ if (ice_is_bit_set(sc->feat_cap, ICE_FEATURE_SRIOV)) {
+ err = ice_iov_attach(sc);
+ if (err == ENOMEM)
+ return (err);
+ }
+#endif /* PCI_IOV */
+
/* Get DCBX/LLDP state and start DCBX agent */
ice_init_dcb_setup(sc);
@@ -953,6 +984,11 @@ ice_if_detach(if_ctx_t ctx)
ice_destroy_mirror_interface(sc);
ice_rdma_pf_detach(sc);
+#ifdef PCI_IOV
+ if (ice_is_bit_set(sc->feat_cap, ICE_FEATURE_SRIOV))
+ ice_iov_detach(sc);
+#endif /* PCI_IOV */
+
/* Free allocated media types */
ifmedia_removeall(sc->media);
@@ -1676,6 +1712,11 @@ ice_if_msix_intr_assign(if_ctx_t ctx, int msix)
/* For future interrupt assignments */
sc->last_rid = rid + sc->irdma_vectors;
+#ifdef PCI_IOV
+ /* Create soft IRQ for handling VF resets */
+ iflib_softirq_alloc_generic(ctx, NULL, IFLIB_INTR_IOV, sc, 0, "iov");
+#endif
+
return (0);
fail:
for (; i >= 0; i--, vector--)
@@ -2277,7 +2318,12 @@ ice_transition_recovery_mode(struct ice_softc *sc)
ice_rdma_pf_detach(sc);
ice_clear_bit(ICE_FEATURE_RDMA, sc->feat_cap);
+#ifdef PCI_IOV
+ if (ice_test_and_clear_bit(ICE_FEATURE_SRIOV, sc->feat_en))
+ ice_iov_detach(sc);
+#else
ice_clear_bit(ICE_FEATURE_SRIOV, sc->feat_en);
+#endif /* PCI_IOV */
ice_clear_bit(ICE_FEATURE_SRIOV, sc->feat_cap);
ice_vsi_del_txqs_ctx(vsi);
@@ -2325,7 +2371,12 @@ ice_transition_safe_mode(struct ice_softc *sc)
ice_rdma_pf_detach(sc);
ice_clear_bit(ICE_FEATURE_RDMA, sc->feat_cap);
+#ifdef PCI_IOV
+ if (ice_test_and_clear_bit(ICE_FEATURE_SRIOV, sc->feat_en))
+ ice_iov_detach(sc);
+#else
ice_clear_bit(ICE_FEATURE_SRIOV, sc->feat_en);
+#endif /* PCI_IOV */
ice_clear_bit(ICE_FEATURE_SRIOV, sc->feat_cap);
ice_clear_bit(ICE_FEATURE_RSS, sc->feat_cap);
@@ -2410,6 +2461,15 @@ ice_if_update_admin_status(if_ctx_t ctx)
/* Check and update link status */
ice_update_link_status(sc, false);
+#ifdef PCI_IOV
+ /*
+ * Schedule VFs' reset handler after global resets
+ * and other events were processed.
+ */
+ if (ice_testandclear_state(&sc->state, ICE_STATE_VFLR_PENDING))
+ iflib_iov_intr_deferred(ctx);
+#endif
+
/*
* If there are still messages to process, we need to reschedule
* ourselves. Otherwise, we can just re-enable the interrupt. We'll be
@@ -3349,6 +3409,78 @@ ice_init_link(struct ice_softc *sc)
}
+#ifdef PCI_IOV
+/**
+ * ice_if_iov_init - iov init handler for iflib
+ * @ctx: iflib context pointer
+ * @num_vfs: number of VFs to create
+ * @params: configuration parameters for the PF
+ *
+ * Configure the driver for SR-IOV mode. Used to setup things like memory
+ * before any VFs are created.
+ *
+ * @remark This is a wrapper for ice_iov_init
+ */
+static int
+ice_if_iov_init(if_ctx_t ctx, uint16_t num_vfs, const nvlist_t *params)
+{
+ struct ice_softc *sc = (struct ice_softc *)iflib_get_softc(ctx);
+
+ return ice_iov_init(sc, num_vfs, params);
+}
+
+/**
+ * ice_if_iov_uninit - iov uninit handler for iflib
+ * @ctx: iflib context pointer
+ *
+ * Destroys VFs and frees their memory and resources.
+ *
+ * @remark This is a wrapper for ice_iov_uninit
+ */
+static void
+ice_if_iov_uninit(if_ctx_t ctx)
+{
+ struct ice_softc *sc = (struct ice_softc *)iflib_get_softc(ctx);
+
+ ice_iov_uninit(sc);
+}
+
+/**
+ * ice_if_iov_vf_add - iov add vf handler for iflib
+ * @ctx: iflib context pointer
+ * @vfnum: index of VF to configure
+ * @params: configuration parameters for the VF
+ *
+ * Sets up the VF given by the vfnum index. This is called by the OS
+ * for each VF created by the PF driver after it is spawned.
+ *
+ * @remark This is a wrapper for ice_iov_vf_add
+ */
+static int
+ice_if_iov_vf_add(if_ctx_t ctx, uint16_t vfnum, const nvlist_t *params)
+{
+ struct ice_softc *sc = (struct ice_softc *)iflib_get_softc(ctx);
+
+ return ice_iov_add_vf(sc, vfnum, params);
+}
+
+/**
+ * ice_if_vflr_handle - iov VFLR handler
+ * @ctx: iflib context pointer
+ *
+ * Performs the necessar teardown or setup required for a VF after
+ * a VFLR is initiated.
+ *
+ * @remark This is a wrapper for ice_iov_handle_vflr
+ */
+static void
+ice_if_vflr_handle(if_ctx_t ctx)
+{
+ struct ice_softc *sc = (struct ice_softc *)iflib_get_softc(ctx);
+ ice_iov_handle_vflr(sc);
+}
+#endif /* PCI_IOV */
+
extern struct if_txrx ice_subif_txrx;
/**
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c
index 741a7c013f7d..29dc0c880e3a 100644
--- a/sys/dev/md/md.c
+++ b/sys/dev/md/md.c
@@ -11,9 +11,9 @@
*/
/*-
- * The following functions are based on the vn(4) driver: mdstart_swap(),
- * mdstart_vnode(), mdcreate_swap(), mdcreate_vnode() and mddestroy(),
- * and as such under the following copyright:
+ * The following functions are based on the historical vn(4) driver:
+ * mdstart_swap(), mdstart_vnode(), mdcreate_swap(), mdcreate_vnode()
+ * and mddestroy(), and as such under the following copyright:
*
* Copyright (c) 1988 University of Utah.
* Copyright (c) 1990, 1993
diff --git a/sys/dev/mgb/if_mgb.c b/sys/dev/mgb/if_mgb.c
index 1240d0f84415..409f34167df0 100644
--- a/sys/dev/mgb/if_mgb.c
+++ b/sys/dev/mgb/if_mgb.c
@@ -1435,7 +1435,7 @@ mgb_hw_teardown(struct mgb_softc *sc)
/* Stop MAC */
CSR_CLEAR_REG(sc, MGB_MAC_RX, MGB_MAC_ENBL);
- CSR_WRITE_REG(sc, MGB_MAC_TX, MGB_MAC_ENBL);
+ CSR_CLEAR_REG(sc, MGB_MAC_TX, MGB_MAC_ENBL);
if ((err = mgb_wait_for_bits(sc, MGB_MAC_RX, MGB_MAC_DSBL, 0)))
return (err);
if ((err = mgb_wait_for_bits(sc, MGB_MAC_TX, MGB_MAC_DSBL, 0)))
diff --git a/sys/dev/mlx5/mlx5_accel/ipsec.h b/sys/dev/mlx5/mlx5_accel/ipsec.h
index 361b9f72d873..c3f3a2372482 100644
--- a/sys/dev/mlx5/mlx5_accel/ipsec.h
+++ b/sys/dev/mlx5/mlx5_accel/ipsec.h
@@ -260,8 +260,8 @@ int mlx5e_accel_ipsec_fs_rx_tables_create(struct mlx5e_priv *priv);
void mlx5e_accel_ipsec_fs_rx_catchall_rules_destroy(struct mlx5e_priv *priv);
int mlx5e_accel_ipsec_fs_rx_catchall_rules(struct mlx5e_priv *priv);
int mlx5_accel_ipsec_rx_tag_add(if_t ifp, struct mlx5e_rq_mbuf *mr);
-void mlx5e_accel_ipsec_handle_rx_cqe(struct mbuf *mb, struct mlx5_cqe64 *cqe,
- struct mlx5e_rq_mbuf *mr);
+void mlx5e_accel_ipsec_handle_rx_cqe(if_t ifp, struct mbuf *mb,
+ struct mlx5_cqe64 *cqe, struct mlx5e_rq_mbuf *mr);
static inline int mlx5e_accel_ipsec_flow(struct mlx5_cqe64 *cqe)
{
@@ -269,12 +269,12 @@ static inline int mlx5e_accel_ipsec_flow(struct mlx5_cqe64 *cqe)
}
static inline void
-mlx5e_accel_ipsec_handle_rx(struct mbuf *mb, struct mlx5_cqe64 *cqe,
+mlx5e_accel_ipsec_handle_rx(if_t ifp, struct mbuf *mb, struct mlx5_cqe64 *cqe,
struct mlx5e_rq_mbuf *mr)
{
u32 ipsec_meta_data = be32_to_cpu(cqe->ft_metadata);
if (MLX5_IPSEC_METADATA_MARKER(ipsec_meta_data))
- mlx5e_accel_ipsec_handle_rx_cqe(mb, cqe, mr);
+ mlx5e_accel_ipsec_handle_rx_cqe(ifp, mb, cqe, mr);
}
#endif /* __MLX5_ACCEL_IPSEC_H__ */
diff --git a/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_rxtx.c b/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_rxtx.c
index 0883cfb2d510..5dccb8bc2b87 100644
--- a/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_rxtx.c
+++ b/sys/dev/mlx5/mlx5_accel/mlx5_ipsec_rxtx.c
@@ -24,11 +24,14 @@
*
*/
+#include "opt_ipsec.h"
+
#include <sys/mbuf.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netipsec/keydb.h>
#include <netipsec/ipsec_offload.h>
+#include <netipsec/xform.h>
#include <dev/mlx5/qp.h>
#include <dev/mlx5/mlx5_en/en.h>
#include <dev/mlx5/mlx5_accel/ipsec.h>
@@ -48,7 +51,8 @@ mlx5_accel_ipsec_rx_tag_add(if_t ifp, struct mlx5e_rq_mbuf *mr)
return (0);
mtag = (struct ipsec_accel_in_tag *)m_tag_get(
- PACKET_TAG_IPSEC_ACCEL_IN, sizeof(*mtag), M_NOWAIT);
+ PACKET_TAG_IPSEC_ACCEL_IN, sizeof(struct ipsec_accel_in_tag) -
+ __offsetof(struct ipsec_accel_in_tag, xh), M_NOWAIT);
if (mtag == NULL)
return (-ENOMEM);
mr->ipsec_mtag = mtag;
@@ -56,8 +60,8 @@ mlx5_accel_ipsec_rx_tag_add(if_t ifp, struct mlx5e_rq_mbuf *mr)
}
void
-mlx5e_accel_ipsec_handle_rx_cqe(struct mbuf *mb, struct mlx5_cqe64 *cqe,
- struct mlx5e_rq_mbuf *mr)
+mlx5e_accel_ipsec_handle_rx_cqe(if_t ifp, struct mbuf *mb,
+ struct mlx5_cqe64 *cqe, struct mlx5e_rq_mbuf *mr)
{
struct ipsec_accel_in_tag *mtag;
u32 drv_spi;
@@ -65,10 +69,12 @@ mlx5e_accel_ipsec_handle_rx_cqe(struct mbuf *mb, struct mlx5_cqe64 *cqe,
drv_spi = MLX5_IPSEC_METADATA_HANDLE(be32_to_cpu(cqe->ft_metadata));
mtag = mr->ipsec_mtag;
WARN_ON(mtag == NULL);
- mr->ipsec_mtag = NULL;
if (mtag != NULL) {
mtag->drv_spi = drv_spi;
- m_tag_prepend(mb, &mtag->tag);
+ if (ipsec_accel_fill_xh(ifp, drv_spi, &mtag->xh)) {
+ m_tag_prepend(mb, &mtag->tag);
+ mr->ipsec_mtag = NULL;
+ }
}
}
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c
index 4de451f1b039..89d2010656c5 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c
@@ -659,7 +659,8 @@ mlx5e_tls_rx_set_params(void *ctx, struct inpcb *inp, const struct tls_session_p
return (EINVAL);
MLX5_SET64(sw_tls_rx_cntx, ctx, param.initial_record_number, tls_sn_he);
- MLX5_SET(sw_tls_rx_cntx, ctx, param.resync_tcp_sn, tcp_sn_he);
+ MLX5_SET(sw_tls_rx_cntx, ctx, param.resync_tcp_sn, 0);
+ MLX5_SET(sw_tls_rx_cntx, ctx, progress.next_record_tcp_sn, tcp_sn_he);
return (0);
}
diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c b/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
index 6b53db6fea23..eb569488631a 100644
--- a/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
+++ b/sys/dev/mlx5/mlx5_en/mlx5_en_rx.c
@@ -467,7 +467,7 @@ mlx5e_build_rx_mbuf(struct mlx5_cqe64 *cqe, struct mlx5e_rq *rq,
break;
}
- mlx5e_accel_ipsec_handle_rx(mb, cqe, mr);
+ mlx5e_accel_ipsec_handle_rx(ifp, mb, cqe, mr);
}
static inline void
diff --git a/sys/dev/qlnx/qlnxe/qlnx_os.c b/sys/dev/qlnx/qlnxe/qlnx_os.c
index 05ec69a70dfe..9d23d5df1d2b 100644
--- a/sys/dev/qlnx/qlnxe/qlnx_os.c
+++ b/sys/dev/qlnx/qlnxe/qlnx_os.c
@@ -30,6 +30,8 @@
* Author : David C Somayajulu, Cavium, Inc., San Jose, CA 95131.
*/
+#include "opt_inet.h"
+
#include <sys/cdefs.h>
#include "qlnx_os.h"
#include "bcm_osal.h"
@@ -2778,7 +2780,7 @@ qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data)
if (!p_ptt) {
QL_DPRINT1(ha, "ecore_ptt_acquire failed\n");
- ret = -1;
+ ret = ERESTART;
break;
}
@@ -2789,7 +2791,7 @@ qlnx_ioctl(if_t ifp, u_long cmd, caddr_t data)
ecore_ptt_release(p_hwfn, p_ptt);
if (ret) {
- ret = -1;
+ ret = ENODEV;
break;
}
diff --git a/sys/dev/random/fortuna.c b/sys/dev/random/fortuna.c
index c4282c723a44..8363de99a60a 100644
--- a/sys/dev/random/fortuna.c
+++ b/sys/dev/random/fortuna.c
@@ -341,6 +341,13 @@ random_fortuna_process_event(struct harvest_event *event)
u_int pl;
RANDOM_RESEED_LOCK();
+ /*
+ * Run SP 800-90B health tests on the source if so configured.
+ */
+ if (!random_harvest_healthtest(event)) {
+ RANDOM_RESEED_UNLOCK();
+ return;
+ }
/*-
* FS&K - P_i = P_i|<harvested stuff>
* Accumulate the event into the appropriate pool
diff --git a/sys/dev/random/random_harvestq.c b/sys/dev/random/random_harvestq.c
index 395310b115fb..c7762967c4fb 100644
--- a/sys/dev/random/random_harvestq.c
+++ b/sys/dev/random/random_harvestq.c
@@ -88,6 +88,8 @@ static void random_sources_feed(void);
static __read_mostly bool epoch_inited;
static __read_mostly epoch_t rs_epoch;
+static const char *random_source_descr[ENTROPYSOURCE];
+
/*
* How many events to queue up. We create this many items in
* an 'empty' queue, then transfer them to the 'harvest' queue with
@@ -299,6 +301,230 @@ random_sources_feed(void)
explicit_bzero(entropy, sizeof(entropy));
}
+/*
+ * State used for conducting NIST SP 800-90B health tests on entropy sources.
+ */
+static struct health_test_softc {
+ uint32_t ht_rct_value[HARVESTSIZE + 1];
+ u_int ht_rct_count; /* number of samples with the same value */
+ u_int ht_rct_limit; /* constant after init */
+
+ uint32_t ht_apt_value[HARVESTSIZE + 1];
+ u_int ht_apt_count; /* number of samples with the same value */
+ u_int ht_apt_seq; /* sequence number of the last sample */
+ u_int ht_apt_cutoff; /* constant after init */
+
+ uint64_t ht_total_samples;
+ bool ondemand; /* Set to true to restart the state machine */
+ enum {
+ INIT = 0, /* initial state */
+ DISABLED, /* health checking is disabled */
+ STARTUP, /* doing startup tests, samples are discarded */
+ STEADY, /* steady-state operation */
+ FAILED, /* health check failed, discard samples */
+ } ht_state;
+} healthtest[ENTROPYSOURCE];
+
+#define RANDOM_SELFTEST_STARTUP_SAMPLES 1024 /* 4.3, requirement 4 */
+#define RANDOM_SELFTEST_APT_WINDOW 512 /* 4.4.2 */
+
+static void
+copy_event(uint32_t dst[static HARVESTSIZE + 1],
+ const struct harvest_event *event)
+{
+ memset(dst, 0, sizeof(uint32_t) * (HARVESTSIZE + 1));
+ memcpy(dst, event->he_entropy, event->he_size);
+ dst[HARVESTSIZE] = event->he_somecounter;
+}
+
+static void
+random_healthtest_rct_init(struct health_test_softc *ht,
+ const struct harvest_event *event)
+{
+ ht->ht_rct_count = 1;
+ copy_event(ht->ht_rct_value, event);
+}
+
+/*
+ * Apply the repitition count test to a sample.
+ *
+ * Return false if the test failed, i.e., we observed >= C consecutive samples
+ * with the same value, and true otherwise.
+ */
+static bool
+random_healthtest_rct_next(struct health_test_softc *ht,
+ const struct harvest_event *event)
+{
+ uint32_t val[HARVESTSIZE + 1];
+
+ copy_event(val, event);
+ if (memcmp(val, ht->ht_rct_value, sizeof(ht->ht_rct_value)) != 0) {
+ ht->ht_rct_count = 1;
+ memcpy(ht->ht_rct_value, val, sizeof(ht->ht_rct_value));
+ return (true);
+ } else {
+ ht->ht_rct_count++;
+ return (ht->ht_rct_count < ht->ht_rct_limit);
+ }
+}
+
+static void
+random_healthtest_apt_init(struct health_test_softc *ht,
+ const struct harvest_event *event)
+{
+ ht->ht_apt_count = 1;
+ ht->ht_apt_seq = 1;
+ copy_event(ht->ht_apt_value, event);
+}
+
+static bool
+random_healthtest_apt_next(struct health_test_softc *ht,
+ const struct harvest_event *event)
+{
+ uint32_t val[HARVESTSIZE + 1];
+
+ if (ht->ht_apt_seq == 0) {
+ random_healthtest_apt_init(ht, event);
+ return (true);
+ }
+
+ copy_event(val, event);
+ if (memcmp(val, ht->ht_apt_value, sizeof(ht->ht_apt_value)) == 0) {
+ ht->ht_apt_count++;
+ if (ht->ht_apt_count >= ht->ht_apt_cutoff)
+ return (false);
+ }
+
+ ht->ht_apt_seq++;
+ if (ht->ht_apt_seq == RANDOM_SELFTEST_APT_WINDOW)
+ ht->ht_apt_seq = 0;
+
+ return (true);
+}
+
+/*
+ * Run the health tests for the given event. This is assumed to be called from
+ * a serialized context.
+ */
+bool
+random_harvest_healthtest(const struct harvest_event *event)
+{
+ struct health_test_softc *ht;
+
+ ht = &healthtest[event->he_source];
+
+ /*
+ * Was on-demand testing requested? Restart the state machine if so,
+ * restarting the startup tests.
+ */
+ if (atomic_load_bool(&ht->ondemand)) {
+ atomic_store_bool(&ht->ondemand, false);
+ ht->ht_state = INIT;
+ }
+
+ switch (ht->ht_state) {
+ case __predict_false(INIT):
+ /* Store the first sample and initialize test state. */
+ random_healthtest_rct_init(ht, event);
+ random_healthtest_apt_init(ht, event);
+ ht->ht_total_samples = 0;
+ ht->ht_state = STARTUP;
+ return (false);
+ case DISABLED:
+ /* No health testing for this source. */
+ return (true);
+ case STEADY:
+ case STARTUP:
+ ht->ht_total_samples++;
+ if (random_healthtest_rct_next(ht, event) &&
+ random_healthtest_apt_next(ht, event)) {
+ if (ht->ht_state == STARTUP &&
+ ht->ht_total_samples >=
+ RANDOM_SELFTEST_STARTUP_SAMPLES) {
+ printf(
+ "random: health test passed for source %s\n",
+ random_source_descr[event->he_source]);
+ ht->ht_state = STEADY;
+ }
+ return (ht->ht_state == STEADY);
+ }
+ ht->ht_state = FAILED;
+ printf(
+ "random: health test failed for source %s, discarding samples\n",
+ random_source_descr[event->he_source]);
+ /* FALLTHROUGH */
+ case FAILED:
+ return (false);
+ }
+}
+
+static bool nist_healthtest_enabled = false;
+SYSCTL_BOOL(_kern_random, OID_AUTO, nist_healthtest_enabled,
+ CTLFLAG_RDTUN, &nist_healthtest_enabled, 0,
+ "Enable NIST SP 800-90B health tests for noise sources");
+
+static void
+random_healthtest_init(enum random_entropy_source source)
+{
+ struct health_test_softc *ht;
+
+ ht = &healthtest[source];
+ KASSERT(ht->ht_state == INIT,
+ ("%s: health test state is %d for source %d",
+ __func__, ht->ht_state, source));
+
+ /*
+ * If health-testing is enabled, validate all sources except CACHED and
+ * VMGENID: they are deterministic sources used only a small, fixed
+ * number of times, so statistical testing is not applicable.
+ */
+ if (!nist_healthtest_enabled ||
+ source == RANDOM_CACHED || source == RANDOM_PURE_VMGENID) {
+ ht->ht_state = DISABLED;
+ return;
+ }
+
+ /*
+ * Set cutoff values for the two tests, assuming that each sample has
+ * min-entropy of 1 bit and allowing for an error rate of 1 in 2^{34}.
+ * With a sample rate of RANDOM_KTHREAD_HZ, we expect to see an false
+ * positive once in ~54.5 years.
+ *
+ * The RCT limit comes from the formula in section 4.4.1.
+ *
+ * The APT cutoff is calculated using the formula in section 4.4.2
+ * footnote 10 with the window size changed from 512 to 511, since the
+ * test as written counts the number of samples equal to the first
+ * sample in the window, and thus tests W-1 samples.
+ */
+ ht->ht_rct_limit = 35;
+ ht->ht_apt_cutoff = 330;
+}
+
+static int
+random_healthtest_ondemand(SYSCTL_HANDLER_ARGS)
+{
+ u_int mask, source;
+ int error;
+
+ mask = 0;
+ error = sysctl_handle_int(oidp, &mask, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+
+ while (mask != 0) {
+ source = ffs(mask) - 1;
+ if (source < nitems(healthtest))
+ atomic_store_bool(&healthtest[source].ondemand, true);
+ mask &= ~(1u << source);
+ }
+ return (0);
+}
+SYSCTL_PROC(_kern_random, OID_AUTO, nist_healthtest_ondemand,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, 0,
+ random_healthtest_ondemand, "I",
+ "Re-run NIST SP 800-90B startup health tests for a noise source");
+
static int
random_check_uint_harvestmask(SYSCTL_HANDLER_ARGS)
{
@@ -362,7 +588,8 @@ static const char *random_source_descr[ENTROPYSOURCE] = {
[RANDOM_SWI] = "SWI",
[RANDOM_FS_ATIME] = "FS_ATIME",
[RANDOM_UMA] = "UMA",
- [RANDOM_CALLOUT] = "CALLOUT", /* ENVIRONMENTAL_END */
+ [RANDOM_CALLOUT] = "CALLOUT",
+ [RANDOM_RANDOMDEV] = "RANDOMDEV", /* ENVIRONMENTAL_END */
[RANDOM_PURE_OCTEON] = "PURE_OCTEON", /* PURE_START */
[RANDOM_PURE_SAFE] = "PURE_SAFE",
[RANDOM_PURE_GLXSB] = "PURE_GLXSB",
@@ -424,6 +651,9 @@ random_harvestq_init(void *unused __unused)
hc_source_mask = almost_everything_mask;
RANDOM_HARVEST_INIT_LOCK();
harvest_context.hc_active_buf = 0;
+
+ for (int i = 0; i < ENTROPYSOURCE; i++)
+ random_healthtest_init(i);
}
SYSINIT(random_device_h_init, SI_SUB_RANDOM, SI_ORDER_THIRD, random_harvestq_init, NULL);
diff --git a/sys/dev/random/random_harvestq.h b/sys/dev/random/random_harvestq.h
index 7804bf52aa4f..1d462500df85 100644
--- a/sys/dev/random/random_harvestq.h
+++ b/sys/dev/random/random_harvestq.h
@@ -49,4 +49,6 @@ random_get_cyclecount(void)
return ((uint32_t)get_cyclecount());
}
+bool random_harvest_healthtest(const struct harvest_event *event);
+
#endif /* SYS_DEV_RANDOM_RANDOM_HARVESTQ_H_INCLUDED */
diff --git a/sys/dev/random/randomdev.c b/sys/dev/random/randomdev.c
index 9d1c7b1167c8..ced4dd8067d9 100644
--- a/sys/dev/random/randomdev.c
+++ b/sys/dev/random/randomdev.c
@@ -312,7 +312,7 @@ randomdev_accumulate(uint8_t *buf, u_int count)
for (i = 0; i < RANDOM_KEYSIZE_WORDS; i += sizeof(event.he_entropy)/sizeof(event.he_entropy[0])) {
event.he_somecounter = random_get_cyclecount();
event.he_size = sizeof(event.he_entropy);
- event.he_source = RANDOM_CACHED;
+ event.he_source = RANDOM_RANDOMDEV;
event.he_destination = destination++; /* Harmless cheating */
memcpy(event.he_entropy, entropy_data + i, sizeof(event.he_entropy));
p_random_alg_context->ra_event_processor(&event);
diff --git a/sys/dev/ufshci/ufshci_private.h b/sys/dev/ufshci/ufshci_private.h
index cac743884ee6..ac58d44102a0 100644
--- a/sys/dev/ufshci/ufshci_private.h
+++ b/sys/dev/ufshci/ufshci_private.h
@@ -149,6 +149,8 @@ struct ufshci_hw_queue {
bus_dmamap_t queuemem_map;
bus_addr_t req_queue_addr;
+ bus_addr_t *ucd_bus_addr;
+
uint32_t num_entries;
uint32_t num_trackers;
@@ -198,8 +200,6 @@ struct ufshci_req_queue {
bus_dma_tag_t dma_tag_payload;
bus_dmamap_t ucdmem_map;
-
- bus_addr_t ucd_addr;
};
struct ufshci_device {
diff --git a/sys/dev/ufshci/ufshci_req_sdb.c b/sys/dev/ufshci/ufshci_req_sdb.c
index 4670281d367a..b1f303afaef5 100644
--- a/sys/dev/ufshci/ufshci_req_sdb.c
+++ b/sys/dev/ufshci/ufshci_req_sdb.c
@@ -48,6 +48,29 @@ ufshci_req_sdb_cmd_desc_destroy(struct ufshci_req_queue *req_queue)
}
}
+static void
+ufshci_ucd_map(void *arg, bus_dma_segment_t *seg, int nseg, int error)
+{
+ struct ufshci_hw_queue *hwq = arg;
+ int i;
+
+ if (error != 0) {
+ printf("ufshci: Failed to map UCD, error = %d\n", error);
+ return;
+ }
+
+ if (hwq->num_trackers != nseg) {
+ printf(
+ "ufshci: Failed to map UCD, num_trackers = %d, nseg = %d\n",
+ hwq->num_trackers, nseg);
+ return;
+ }
+
+ for (i = 0; i < nseg; i++) {
+ hwq->ucd_bus_addr[i] = seg[i].ds_addr;
+ }
+}
+
static int
ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
uint32_t num_entries, struct ufshci_controller *ctrlr)
@@ -55,7 +78,6 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
struct ufshci_hw_queue *hwq = &req_queue->hwq[UFSHCI_SDB_Q];
struct ufshci_tracker *tr;
size_t ucd_allocsz, payload_allocsz;
- uint64_t ucdmem_phys;
uint8_t *ucdmem;
int i, error;
@@ -71,10 +93,11 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
* Allocate physical memory for UTP Command Descriptor (UCD)
* Note: UFSHCI UCD format is restricted to 128-byte alignment.
*/
- error = bus_dma_tag_create(bus_get_dma_tag(ctrlr->dev), 128,
- ctrlr->page_size, BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL,
- ucd_allocsz, howmany(ucd_allocsz, ctrlr->page_size),
- ctrlr->page_size, 0, NULL, NULL, &req_queue->dma_tag_ucd);
+ error = bus_dma_tag_create(bus_get_dma_tag(ctrlr->dev), 128, 0,
+ BUS_SPACE_MAXADDR, BUS_SPACE_MAXADDR, NULL, NULL, ucd_allocsz,
+ howmany(ucd_allocsz, sizeof(struct ufshci_utp_cmd_desc)),
+ sizeof(struct ufshci_utp_cmd_desc), 0, NULL, NULL,
+ &req_queue->dma_tag_ucd);
if (error != 0) {
ufshci_printf(ctrlr, "request cmd desc tag create failed %d\n",
error);
@@ -88,7 +111,7 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
}
if (bus_dmamap_load(req_queue->dma_tag_ucd, req_queue->ucdmem_map,
- ucdmem, ucd_allocsz, ufshci_single_map, &ucdmem_phys, 0) != 0) {
+ ucdmem, ucd_allocsz, ufshci_ucd_map, hwq, 0) != 0) {
ufshci_printf(ctrlr, "failed to load cmd desc memory\n");
bus_dmamem_free(req_queue->dma_tag_ucd, req_queue->ucd,
req_queue->ucdmem_map);
@@ -96,7 +119,6 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
}
req_queue->ucd = (struct ufshci_utp_cmd_desc *)ucdmem;
- req_queue->ucd_addr = ucdmem_phys;
/*
* Allocate physical memory for PRDT
@@ -128,10 +150,9 @@ ufshci_req_sdb_cmd_desc_construct(struct ufshci_req_queue *req_queue,
tr->slot_state = UFSHCI_SLOT_STATE_FREE;
tr->ucd = (struct ufshci_utp_cmd_desc *)ucdmem;
- tr->ucd_bus_addr = ucdmem_phys;
+ tr->ucd_bus_addr = hwq->ucd_bus_addr[i];
ucdmem += sizeof(struct ufshci_utp_cmd_desc);
- ucdmem_phys += sizeof(struct ufshci_utp_cmd_desc);
hwq->act_tr[i] = tr;
}
@@ -175,6 +196,11 @@ ufshci_req_sdb_construct(struct ufshci_controller *ctrlr,
req_queue->hwq = malloc(sizeof(struct ufshci_hw_queue), M_UFSHCI,
M_ZERO | M_NOWAIT);
hwq = &req_queue->hwq[UFSHCI_SDB_Q];
+ hwq->num_entries = req_queue->num_entries;
+ hwq->num_trackers = req_queue->num_trackers;
+ req_queue->hwq->ucd_bus_addr = malloc(sizeof(bus_addr_t) *
+ req_queue->num_trackers,
+ M_UFSHCI, M_ZERO | M_NOWAIT);
mtx_init(&hwq->qlock, "ufshci req_queue lock", NULL, MTX_DEF);
@@ -277,6 +303,7 @@ ufshci_req_sdb_destroy(struct ufshci_controller *ctrlr,
if (mtx_initialized(&hwq->qlock))
mtx_destroy(&hwq->qlock);
+ free(req_queue->hwq->ucd_bus_addr, M_UFSHCI);
free(req_queue->hwq, M_UFSHCI);
}
diff --git a/sys/fs/fdescfs/fdesc_vnops.c b/sys/fs/fdescfs/fdesc_vnops.c
index 676ea5de12b8..58a22b8bdc50 100644
--- a/sys/fs/fdescfs/fdesc_vnops.c
+++ b/sys/fs/fdescfs/fdesc_vnops.c
@@ -547,6 +547,8 @@ fdesc_readdir(struct vop_readdir_args *ap)
fmp = VFSTOFDESC(ap->a_vp->v_mount);
if (ap->a_ncookies != NULL)
*ap->a_ncookies = 0;
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = 0;
off = (int)uio->uio_offset;
if (off != uio->uio_offset || off < 0 || (u_int)off % UIO_MX != 0 ||
@@ -559,7 +561,12 @@ fdesc_readdir(struct vop_readdir_args *ap)
fcnt = i - 2; /* The first two nodes are `.' and `..' */
FILEDESC_SLOCK(fdp);
- while (i < fdp->fd_nfiles + 2 && uio->uio_resid >= UIO_MX) {
+ while (uio->uio_resid >= UIO_MX) {
+ if (i >= fdp->fd_nfiles + 2) {
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = 1;
+ break;
+ }
bzero((caddr_t)dp, UIO_MX);
switch (i) {
case 0: /* `.' */
diff --git a/sys/fs/msdosfs/msdosfs_conv.c b/sys/fs/msdosfs/msdosfs_conv.c
index da4848169173..208b64930e61 100644
--- a/sys/fs/msdosfs/msdosfs_conv.c
+++ b/sys/fs/msdosfs/msdosfs_conv.c
@@ -797,19 +797,24 @@ mbsadjpos(const char **instr, size_t inlen, size_t outlen, int weight, int flag,
static u_char *
dos2unixchr(u_char *outbuf, const u_char **instr, size_t *ilen, int lower, struct msdosfsmount *pmp)
{
- u_char c, *outp;
- size_t len, olen;
+ u_char c, *outp, *outp1;
+ size_t i, len, olen;
outp = outbuf;
if (pmp->pm_flags & MSDOSFSMNT_KICONV && msdosfs_iconv) {
olen = len = 4;
+ outp1 = outp;
if (lower & (LCASE_BASE | LCASE_EXT))
msdosfs_iconv->convchr_case(pmp->pm_d2u, (const char **)instr,
ilen, (char **)&outp, &olen, KICONV_LOWER);
else
msdosfs_iconv->convchr(pmp->pm_d2u, (const char **)instr,
ilen, (char **)&outp, &olen);
+ for (i = 0; i < outp - outp1; i++) {
+ if (outp1[i] == '/')
+ outp1[i] = '?';
+ }
len -= olen;
/*
@@ -826,6 +831,8 @@ dos2unixchr(u_char *outbuf, const u_char **instr, size_t *ilen, int lower, struc
c = dos2unix[c];
if (lower & (LCASE_BASE | LCASE_EXT))
c = u2l[c];
+ if (c == '/')
+ c = '?';
*outp++ = c;
outbuf[1] = '\0';
}
diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 4c498e96a3c0..a957315aaa12 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -647,7 +647,8 @@ nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
NFSATTRBIT_TIMECREATE))
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE);
(void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
- &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
+ &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL,
+ false, false, false);
break;
}
}
@@ -2646,7 +2647,8 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
- struct statfs *pnfssf)
+ struct statfs *pnfssf, bool xattrsupp, bool has_hiddensystem,
+ bool has_namedattr)
{
int bitpos, retnum = 0;
u_int32_t *tl;
@@ -2660,10 +2662,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
struct nfsfsinfo fsinf;
struct timespec temptime;
NFSACL_T *aclp, *naclp = NULL;
- size_t atsiz;
- bool xattrsupp;
short irflag;
- long has_pathconf;
#ifdef QUOTA
struct dqblk dqb;
uid_t savuid;
@@ -2747,18 +2746,6 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
}
}
- /* Check to see if Extended Attributes are supported. */
- xattrsupp = false;
- if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
- if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
- error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
- "xxx", NULL, &atsiz, cred, p);
- NFSVOPUNLOCK(vp);
- if (error != EOPNOTSUPP)
- xattrsupp = true;
- }
- }
-
/*
* Put out the attribute bitmap for the ones being filled in
* and get the field for the number of attributes returned.
@@ -2780,11 +2767,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
}
- if (cred == NULL || p == NULL || vp == NULL ||
- VOP_PATHCONF(vp, _PC_HAS_HIDDENSYSTEM,
- &has_pathconf) != 0)
- has_pathconf = 0;
- if (has_pathconf == 0) {
+ if (!has_hiddensystem) {
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
}
@@ -2828,10 +2811,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
break;
case NFSATTRBIT_NAMEDATTR:
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
- if (VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR,
- &has_pathconf) != 0)
- has_pathconf = 0;
- if (has_pathconf != 0)
+ if (has_namedattr)
*tl = newnfs_true;
else
*tl = newnfs_false;
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index 3b6c1ec90c06..54f60a753c50 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -395,8 +395,9 @@ int nfsrv_putopbit(struct nfsrv_descript *, nfsopbit_t *);
void nfsrv_wcc(struct nfsrv_descript *, int, struct nfsvattr *, int,
struct nfsvattr *);
int nfsv4_fillattr(struct nfsrv_descript *, struct mount *, vnode_t, NFSACL_T *,
- struct vattr *, fhandle_t *, int, nfsattrbit_t *,
- struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t, struct statfs *);
+ struct vattr *, fhandle_t *, int, nfsattrbit_t *, struct ucred *,
+ NFSPROC_T *, int, int, int, int, uint64_t, struct statfs *, bool, bool,
+ bool);
void nfsrv_fillattr(struct nfsrv_descript *, struct nfsvattr *);
struct mbuf *nfsrv_adj(struct mbuf *, int, int);
void nfsrv_postopattr(struct nfsrv_descript *, int, struct nfsvattr *);
@@ -735,7 +736,8 @@ int nfsvno_updfilerev(vnode_t, struct nfsvattr *, struct nfsrv_descript *,
NFSPROC_T *);
int nfsvno_fillattr(struct nfsrv_descript *, struct mount *, vnode_t,
struct nfsvattr *, fhandle_t *, int, nfsattrbit_t *,
- struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t);
+ struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t, bool, bool,
+ bool);
int nfsrv_sattr(struct nfsrv_descript *, vnode_t, struct nfsvattr *, nfsattrbit_t *,
NFSACL_T *, NFSPROC_T *);
int nfsv4_sattr(struct nfsrv_descript *, vnode_t, struct nfsvattr *, nfsattrbit_t *,
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index e0e66baca44d..2f3c59b68518 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -5436,7 +5436,8 @@ nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
NFSZERO_ATTRBIT(&attrbits);
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
(void) nfsv4_fillattr(nd, vp->v_mount, vp, aclp, NULL, NULL, 0,
- &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
+ &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL, false, false,
+ false);
error = nfscl_request(nd, vp, p, cred);
if (error)
return (error);
diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c
index 1ae5ed1a75ca..99a781640c53 100644
--- a/sys/fs/nfsclient/nfs_clstate.c
+++ b/sys/fs/nfsclient/nfs_clstate.c
@@ -3701,7 +3701,7 @@ nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p)
if (!error)
(void) nfsv4_fillattr(nd, NULL, NULL, NULL, &va,
NULL, 0, &rattrbits, NULL, p, 0, 0, 0, 0,
- (uint64_t)0, NULL);
+ (uint64_t)0, NULL, false, false, false);
break;
case NFSV4OP_CBRECALL:
NFSCL_DEBUG(4, "cbrecall\n");
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 43ee0383669f..4f0d5946d6b9 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -2112,7 +2112,8 @@ int
nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp,
struct nfsvattr *nvap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
struct ucred *cred, struct thread *p, int isdgram, int reterr,
- int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
+ int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
+ bool xattrsupp, bool has_hiddensystem, bool has_namedattr)
{
struct statfs *sf;
int error;
@@ -2131,7 +2132,7 @@ nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp,
}
error = nfsv4_fillattr(nd, mp, vp, NULL, &nvap->na_vattr, fhp, rderror,
attrbitp, cred, p, isdgram, reterr, supports_nfsv4acls, at_root,
- mounted_on_fileno, sf);
+ mounted_on_fileno, sf, xattrsupp, has_hiddensystem, has_namedattr);
free(sf, M_TEMP);
NFSEXITCODE2(0, nd);
return (error);
@@ -2448,7 +2449,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
struct nfsvattr nva, at, *nvap = &nva;
struct mbuf *mb0, *mb1;
struct nfsreferral *refp;
- int nlen, r, error = 0, getret = 1, usevget = 1;
+ int nlen, r, error = 0, getret = 1, ret, usevget = 1;
int siz, cnt, fullsiz, eofflag, ncookies, entrycnt;
caddr_t bpos0, bpos1;
u_int64_t off, toff, verf __unused;
@@ -2462,6 +2463,9 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
uint64_t mounted_on_fileno;
struct thread *p = curthread;
int bextpg0, bextpg1, bextpgsiz0, bextpgsiz1;
+ size_t atsiz;
+ long pathval;
+ bool has_hiddensystem, has_namedattr, xattrsupp;
if (nd->nd_repstat) {
nfsrv_postopattr(nd, getret, &at);
@@ -2936,9 +2940,32 @@ again:
*tl++ = newnfs_true;
txdr_hyper(*cookiep, tl);
dirlen += nfsm_strtom(nd, dp->d_name, nlen);
+ xattrsupp = false;
+ has_hiddensystem = false;
+ has_namedattr = false;
if (nvp != NULL) {
supports_nfsv4acls =
nfs_supportsnfsv4acls(nvp);
+ if (NFSISSET_ATTRBIT(&attrbits,
+ NFSATTRBIT_XATTRSUPPORT)) {
+ ret = VOP_GETEXTATTR(nvp,
+ EXTATTR_NAMESPACE_USER,
+ "xxx", NULL, &atsiz,
+ nd->nd_cred, p);
+ xattrsupp = ret != EOPNOTSUPP;
+ }
+ if (VOP_PATHCONF(nvp,
+ _PC_HAS_HIDDENSYSTEM, &pathval) !=
+ 0)
+ pathval = 0;
+ has_hiddensystem = pathval > 0;
+ pathval = 0;
+ if (NFSISSET_ATTRBIT(&attrbits,
+ NFSATTRBIT_NAMEDATTR) &&
+ VOP_PATHCONF(nvp, _PC_HAS_NAMEDATTR,
+ &pathval) != 0)
+ pathval = 0;
+ has_namedattr = pathval > 0;
NFSVOPUNLOCK(nvp);
} else
supports_nfsv4acls = 0;
@@ -2958,13 +2985,15 @@ again:
nvp, nvap, &nfh, r, &rderrbits,
nd->nd_cred, p, isdgram, 0,
supports_nfsv4acls, at_root,
- mounted_on_fileno);
+ mounted_on_fileno, xattrsupp,
+ has_hiddensystem, has_namedattr);
} else {
dirlen += nfsvno_fillattr(nd, new_mp,
nvp, nvap, &nfh, r, &attrbits,
nd->nd_cred, p, isdgram, 0,
supports_nfsv4acls, at_root,
- mounted_on_fileno);
+ mounted_on_fileno, xattrsupp,
+ has_hiddensystem, has_namedattr);
}
if (nvp != NULL)
vrele(nvp);
@@ -6356,7 +6385,7 @@ nfsrv_setacldsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p,
* the same type (VREG).
*/
nfsv4_fillattr(nd, NULL, vp, aclp, NULL, NULL, 0, &attrbits, NULL,
- NULL, 0, 0, 0, 0, 0, NULL);
+ NULL, 0, 0, 0, 0, 0, NULL, false, false, false);
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
if (error != 0) {
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index f7564ade401b..9eebcda548c6 100644
--- a/sys/fs/nfsserver/nfs_nfsdserv.c
+++ b/sys/fs/nfsserver/nfs_nfsdserv.c
@@ -241,7 +241,7 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
{
struct nfsvattr nva;
fhandle_t fh;
- int at_root = 0, error = 0, supports_nfsv4acls;
+ int at_root = 0, error = 0, ret, supports_nfsv4acls;
struct nfsreferral *refp;
nfsattrbit_t attrbits, tmpbits;
struct mount *mp;
@@ -250,6 +250,9 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
uint64_t mounted_on_fileno = 0;
accmode_t accmode;
struct thread *p = curthread;
+ size_t atsiz;
+ long pathval;
+ bool has_hiddensystem, has_namedattr, xattrsupp;
if (nd->nd_repstat)
goto out;
@@ -307,6 +310,26 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
&nva, &attrbits, p);
if (nd->nd_repstat == 0) {
supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
+ xattrsupp = false;
+ if (NFSISSET_ATTRBIT(&attrbits,
+ NFSATTRBIT_XATTRSUPPORT)) {
+ ret = VOP_GETEXTATTR(vp,
+ EXTATTR_NAMESPACE_USER,
+ "xxx", NULL, &atsiz, nd->nd_cred,
+ p);
+ xattrsupp = ret != EOPNOTSUPP;
+ }
+ if (VOP_PATHCONF(vp, _PC_HAS_HIDDENSYSTEM,
+ &pathval) != 0)
+ pathval = 0;
+ has_hiddensystem = pathval > 0;
+ pathval = 0;
+ if (NFSISSET_ATTRBIT(&attrbits,
+ NFSATTRBIT_NAMEDATTR) &&
+ VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR,
+ &pathval) != 0)
+ pathval = 0;
+ has_namedattr = pathval > 0;
mp = vp->v_mount;
if (nfsrv_enable_crossmntpt != 0 &&
vp->v_type == VDIR &&
@@ -340,7 +363,9 @@ nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
(void)nfsvno_fillattr(nd, mp, vp, &nva,
&fh, 0, &attrbits, nd->nd_cred, p,
isdgram, 1, supports_nfsv4acls,
- at_root, mounted_on_fileno);
+ at_root, mounted_on_fileno,
+ xattrsupp, has_hiddensystem,
+ has_namedattr);
vfs_unbusy(mp);
}
vrele(vp);
@@ -4353,9 +4378,10 @@ nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
int error = 0;
NFSNAMEICNDSET(&cn, nd->nd_cred, LOOKUP, OPENNAMED | ISLASTCN |
- NOFOLLOW);
+ NOFOLLOW | LOCKLEAF);
cn.cn_nameptr = ".";
cn.cn_namelen = 1;
+ cn.cn_lkflags = LK_SHARED;
NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
if (*tl == newnfs_true)
cn.cn_flags |= CREATENAMED;
@@ -4374,6 +4400,8 @@ nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
if (nd->nd_repstat == ENOATTR)
nd->nd_repstat = NFSERR_NOENT;
}
+ if (nd->nd_repstat == 0)
+ NFSVOPUNLOCK(*vpp);
vput(dp);
NFSEXITCODE2(0, nd);
diff --git a/sys/fs/p9fs/p9fs_vnops.c b/sys/fs/p9fs/p9fs_vnops.c
index 56bf766ef801..227e2b93883e 100644
--- a/sys/fs/p9fs/p9fs_vnops.c
+++ b/sys/fs/p9fs/p9fs_vnops.c
@@ -1784,6 +1784,9 @@ p9fs_readdir(struct vop_readdir_args *ap)
return (EBADF);
}
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = 0;
+
io_buffer = uma_zalloc(p9fs_io_buffer_zone, M_WAITOK);
/* We haven't reached the end yet. read more. */
@@ -1801,8 +1804,11 @@ p9fs_readdir(struct vop_readdir_args *ap)
count = p9_client_readdir(vofid, (char *)io_buffer,
diroffset, count);
- if (count == 0)
+ if (count == 0) {
+ if (ap->a_eofflag != NULL)
+ *ap->a_eofflag = 1;
break;
+ }
if (count < 0) {
error = EIO;
diff --git a/sys/fs/udf/ecma167-udf.h b/sys/fs/udf/ecma167-udf.h
index 839bbec08254..19e114763cac 100644
--- a/sys/fs/udf/ecma167-udf.h
+++ b/sys/fs/udf/ecma167-udf.h
@@ -243,7 +243,7 @@ struct part_map_spare {
uint8_t n_st; /* Number of Sparing Tables */
uint8_t reserved1;
uint32_t st_size;
- uint32_t st_loc[1];
+ uint32_t st_loc[];
} __packed;
union udf_pmap {
@@ -266,7 +266,7 @@ struct udf_sparing_table {
uint16_t rt_l; /* Relocation Table len */
uint8_t reserved[2];
uint32_t seq_num;
- struct spare_map_entry entries[1];
+ struct spare_map_entry entries[];
} __packed;
/* Partition Descriptor [3/10.5] */
diff --git a/sys/fs/udf/udf_vfsops.c b/sys/fs/udf/udf_vfsops.c
index c7438147c0a0..c5ef1f686093 100644
--- a/sys/fs/udf/udf_vfsops.c
+++ b/sys/fs/udf/udf_vfsops.c
@@ -81,6 +81,7 @@
#include <sys/fcntl.h>
#include <sys/iconv.h>
#include <sys/kernel.h>
+#include <sys/limits.h>
#include <sys/malloc.h>
#include <sys/mount.h>
#include <sys/namei.h>
@@ -729,7 +730,7 @@ udf_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp)
struct ifid *ifhp;
struct vnode *nvp;
struct udf_node *np;
- off_t fsize;
+ uint64_t fsize;
int error;
ifhp = (struct ifid *)fhp;
@@ -741,6 +742,10 @@ udf_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp)
np = VTON(nvp);
fsize = le64toh(np->fentry->inf_len);
+ if (fsize > OFF_MAX) {
+ *vpp = NULLVP;
+ return (EIO);
+ }
*vpp = nvp;
vnode_create_vobject(*vpp, fsize, curthread);
diff --git a/sys/fs/udf/udf_vnops.c b/sys/fs/udf/udf_vnops.c
index 88bf4917a851..37889241e8c3 100644
--- a/sys/fs/udf/udf_vnops.c
+++ b/sys/fs/udf/udf_vnops.c
@@ -39,6 +39,7 @@
#include <sys/conf.h>
#include <sys/buf.h>
#include <sys/iconv.h>
+#include <sys/limits.h>
#include <sys/mount.h>
#include <sys/vnode.h>
#include <sys/dirent.h>
@@ -182,11 +183,14 @@ udf_access(struct vop_access_args *a)
}
static int
-udf_open(struct vop_open_args *ap) {
+udf_open(struct vop_open_args *ap)
+{
struct udf_node *np = VTON(ap->a_vp);
- off_t fsize;
+ uint64_t fsize;
fsize = le64toh(np->fentry->inf_len);
+ if (fsize > OFF_MAX)
+ return (EIO);
vnode_create_vobject(ap->a_vp, fsize, ap->a_td);
return 0;
}
@@ -314,12 +318,13 @@ udf_getattr(struct vop_getattr_args *a)
* that directories consume at least one logical block,
* make it appear so.
*/
- if (fentry->logblks_rec != 0) {
- vap->va_size =
- le64toh(fentry->logblks_rec) * node->udfmp->bsize;
- } else {
+ vap->va_size = le64toh(fentry->logblks_rec);
+ if (vap->va_size == 0)
vap->va_size = node->udfmp->bsize;
- }
+ else if (vap->va_size > UINT64_MAX / node->udfmp->bsize)
+ vap->va_size = UINT64_MAX;
+ else
+ vap->va_size *= node->udfmp->bsize;
} else {
vap->va_size = le64toh(fentry->inf_len);
}
@@ -446,6 +451,7 @@ udf_read(struct vop_read_args *ap)
struct buf *bp;
uint8_t *data;
daddr_t lbn, rablock;
+ uint64_t len;
off_t diff, fsize;
ssize_t n;
int error = 0;
@@ -471,7 +477,12 @@ udf_read(struct vop_read_args *ap)
return (error);
}
- fsize = le64toh(node->fentry->inf_len);
+ len = le64toh(node->fentry->inf_len);
+ if (len > OFF_MAX) {
+ /* too big, just cap to the requested length */
+ len = uio->uio_resid;
+ }
+ fsize = len;
udfmp = node->udfmp;
do {
lbn = lblkno(udfmp, uio->uio_offset);
@@ -783,6 +794,7 @@ udf_readdir(struct vop_readdir_args *a)
struct udf_uiodir uiodir;
struct udf_dirstream *ds;
uint64_t *cookies = NULL;
+ uint64_t len;
int ncookies;
int error = 0;
@@ -811,8 +823,12 @@ udf_readdir(struct vop_readdir_args *a)
* Iterate through the file id descriptors. Give the parent dir
* entry special attention.
*/
- ds = udf_opendir(node, uio->uio_offset, le64toh(node->fentry->inf_len),
- node->udfmp);
+ len = le64toh(node->fentry->inf_len);
+ if (len > INT_MAX) {
+ /* too big, just cap to INT_MAX */
+ len = INT_MAX;
+ }
+ ds = udf_opendir(node, uio->uio_offset, len, node->udfmp);
while ((fid = udf_getfid(ds)) != NULL) {
/* XXX Should we return an error on a bad fid? */
@@ -904,7 +920,8 @@ udf_readlink(struct vop_readlink_args *ap)
struct udf_node *node;
void *buf;
char *cp;
- int error, len, root;
+ uint64_t len;
+ int error, root;
/*
* A symbolic link in UDF is a list of variable-length path
@@ -914,6 +931,8 @@ udf_readlink(struct vop_readlink_args *ap)
vp = ap->a_vp;
node = VTON(vp);
len = le64toh(node->fentry->inf_len);
+ if (len > MAXPATHLEN)
+ return (EIO);
buf = malloc(len, M_DEVBUF, M_WAITOK);
iov[0].iov_len = len;
iov[0].iov_base = buf;
@@ -1116,13 +1135,14 @@ udf_lookup(struct vop_cachedlookup_args *a)
struct udf_mnt *udfmp;
struct fileid_desc *fid = NULL;
struct udf_dirstream *ds;
+ uint64_t fsize;
u_long nameiop;
u_long flags;
char *nameptr;
long namelen;
ino_t id = 0;
int offset, error = 0;
- int fsize, lkflags, ltype, numdirpasses;
+ int lkflags, ltype, numdirpasses;
dvp = a->a_dvp;
node = VTON(dvp);
@@ -1133,6 +1153,10 @@ udf_lookup(struct vop_cachedlookup_args *a)
nameptr = a->a_cnp->cn_nameptr;
namelen = a->a_cnp->cn_namelen;
fsize = le64toh(node->fentry->inf_len);
+ if (fsize > INT_MAX) {
+ /* too big, just cap to INT_MAX */
+ fsize = INT_MAX;
+ }
/*
* If this is a LOOKUP and we've already partially searched through
diff --git a/sys/i386/i386/pmap.c b/sys/i386/i386/pmap.c
index 5065b7e61ee8..b44f5e08bbcf 100644
--- a/sys/i386/i386/pmap.c
+++ b/sys/i386/i386/pmap.c
@@ -876,14 +876,16 @@ __CONCAT(PMTYPE, init_pat)(void)
#ifdef PMAP_PAE_COMP
static void *
-pmap_pdpt_allocf(uma_zone_t zone, vm_size_t bytes, int domain, uint8_t *flags,
- int wait)
+pmap_pdpt_allocf(uma_zone_t zone, vm_size_t bytes, int domain, uint8_t *sflagsp,
+ int flags)
{
/* Inform UMA that this allocator uses kernel_map/object. */
- *flags = UMA_SLAB_KERNEL;
+ *sflagsp = UMA_SLAB_KERNEL;
+ /* contig allocations cannot be NEVERFREED */
+ flags &= ~M_NEVERFREED;
return ((void *)kmem_alloc_contig_domainset(DOMAINSET_FIXED(domain),
- bytes, wait, 0x0ULL, 0xffffffffULL, 1, 0, VM_MEMATTR_DEFAULT));
+ bytes, flags, 0x0ULL, 0xffffffffULL, 1, 0, VM_MEMATTR_DEFAULT));
}
#endif
diff --git a/sys/kern/subr_asan.c b/sys/kern/subr_asan.c
index 0edb631d1475..464efda1e91a 100644
--- a/sys/kern/subr_asan.c
+++ b/sys/kern/subr_asan.c
@@ -263,8 +263,7 @@ kasan_mark(const void *addr, size_t size, size_t redzsize, uint8_t code)
if (__predict_false(!kasan_enabled))
return;
- if ((vm_offset_t)addr >= DMAP_MIN_ADDRESS &&
- (vm_offset_t)addr < DMAP_MAX_ADDRESS)
+ if (kasan_md_unsupported((vm_offset_t)addr))
return;
KASSERT((vm_offset_t)addr >= VM_MIN_KERNEL_ADDRESS &&
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index 94e44d888181..b472aaea89e6 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -2309,6 +2309,12 @@ sys_exterrctl(struct thread *td, struct exterrctl_args *uap)
return (EINVAL);
td->td_pflags2 &= ~TDP2_UEXTERR;
return (0);
+ case EXTERRCTL_UD:
+ /*
+ * Important: this code must always return EINVAL and never any
+ * extended error, for testing purposes.
+ */
+ /* FALLTHROUGH */
default:
return (EINVAL);
}
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index 3d455b3874cc..89c1d779f04c 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -332,7 +332,8 @@ SDT_PROBE_DEFINE2(vfs, namecache, evict_negative, done, "struct vnode *",
"char *");
SDT_PROBE_DEFINE1(vfs, namecache, symlink, alloc__fail, "size_t");
-SDT_PROBE_DEFINE3(vfs, fplookup, lookup, done, "struct nameidata", "int", "bool");
+SDT_PROBE_DEFINE3(vfs, fplookup, lookup, done, "struct nameidata *", "int",
+ "enum cache_fpl_status");
SDT_PROBE_DECLARE(vfs, namei, lookup, entry);
SDT_PROBE_DECLARE(vfs, namei, lookup, return);
@@ -6420,15 +6421,11 @@ out:
cache_fpl_smr_assert_not_entered(&fpl);
cache_fpl_assert_status(&fpl);
*status = fpl.status;
- if (SDT_PROBES_ENABLED()) {
- SDT_PROBE3(vfs, fplookup, lookup, done, ndp, fpl.line, fpl.status);
- if (fpl.status == CACHE_FPL_STATUS_HANDLED)
- SDT_PROBE4(vfs, namei, lookup, return, error, ndp->ni_vp, true,
- ndp);
- }
-
+ SDT_PROBE3(vfs, fplookup, lookup, done, ndp, fpl.line, fpl.status);
if (__predict_true(fpl.status == CACHE_FPL_STATUS_HANDLED)) {
MPASS(error != CACHE_FPL_FAILED);
+ SDT_PROBE4(vfs, namei, lookup, return, error, ndp->ni_vp, true,
+ ndp);
if (error != 0) {
cache_fpl_cleanup_cnp(fpl.cnp);
MPASS(fpl.dvp == NULL);
diff --git a/sys/kern/vfs_inotify.c b/sys/kern/vfs_inotify.c
index 2b42228465a4..d3cd0d1f9832 100644
--- a/sys/kern/vfs_inotify.c
+++ b/sys/kern/vfs_inotify.c
@@ -371,7 +371,7 @@ inotify_unlink_watch_locked(struct inotify_softc *sc, struct inotify_watch *watc
TAILQ_REMOVE(&vp->v_pollinfo->vpi_inotify, watch, vlink);
if (TAILQ_EMPTY(&vp->v_pollinfo->vpi_inotify))
- vn_irflag_unset_locked(vp, VIRF_INOTIFY);
+ vn_irflag_unset(vp, VIRF_INOTIFY);
}
/*
@@ -675,7 +675,8 @@ vn_inotify(struct vnode *vp, struct vnode *dvp, struct componentname *cnp,
struct vattr va;
int error;
- error = VOP_GETATTR(vp, &va, cnp->cn_cred);
+ error = VOP_GETATTR(vp, &va,
+ cnp->cn_cred);
if (error == 0 && va.va_nlink != 0)
selfevent = 0;
}
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 9922796f8a1d..7cb6e2124326 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -326,6 +326,7 @@ SUBDIR= \
proto \
pseudofs \
${_pst} \
+ ${_pt} \
pty \
puc \
pwm \
@@ -842,6 +843,7 @@ _iwx= iwx
_ixl= ixl
_nvdimm= nvdimm
_pms= pms
+_pt= pt
_qat= qat
.if ${MK_SOURCELESS_UCODE} != "no"
_qatfw= qatfw
diff --git a/sys/modules/ice/Makefile b/sys/modules/ice/Makefile
index 91f20193d878..9f9c9f602cda 100644
--- a/sys/modules/ice/Makefile
+++ b/sys/modules/ice/Makefile
@@ -13,6 +13,7 @@ SRCS += opt_inet.h opt_inet6.h opt_rss.h opt_iflib.h
SRCS += ice_lib.c ice_osdep.c ice_resmgr.c ice_strings.c
SRCS += ice_iflib_recovery_txrx.c ice_iflib_txrx.c if_ice_iflib.c
SRCS += ice_fw_logging.c ice_ddp_common.c
+SRCS.PCI_IOV += pci_iov_if.h ice_iov.c ice_vf_mbx.c
# RDMA Client interface
# TODO: Is this the right way to compile this?
diff --git a/sys/modules/pt/Makefile b/sys/modules/pt/Makefile
new file mode 100644
index 000000000000..416b072face9
--- /dev/null
+++ b/sys/modules/pt/Makefile
@@ -0,0 +1,8 @@
+
+.PATH: ${SRCTOP}/sys/amd64/pt
+
+KMOD= pt
+SRCS= pt.c pt.h device_if.h bus_if.h
+SRCS+= opt_hwpmc_hooks.h opt_kstack_pages.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/qlnx/qlnxe/Makefile b/sys/modules/qlnx/qlnxe/Makefile
index 3d8415cf0e57..2a44ae6ddde5 100644
--- a/sys/modules/qlnx/qlnxe/Makefile
+++ b/sys/modules/qlnx/qlnxe/Makefile
@@ -58,6 +58,7 @@ SRCS+=qlnx_rdma.c
SRCS+=qlnx_ioctl.c
SRCS+=qlnx_os.c
+SRCS+=opt_inet.h
SRCS+= ${LINUXKPI_GENSRCS}
diff --git a/sys/net/ethernet.h b/sys/net/ethernet.h
index cf4f75bd0b6c..01485cf26e06 100644
--- a/sys/net/ethernet.h
+++ b/sys/net/ethernet.h
@@ -62,6 +62,8 @@ struct ether_header {
u_char ether_shost[ETHER_ADDR_LEN];
u_short ether_type;
} __packed;
+_Static_assert(sizeof(struct ether_header) == ETHER_HDR_LEN,
+ "size of struct ether_header is wrong");
/*
* Structure of a 48-bit Ethernet address.
@@ -69,6 +71,8 @@ struct ether_header {
struct ether_addr {
u_char octet[ETHER_ADDR_LEN];
} __packed;
+_Static_assert(sizeof(struct ether_addr) == ETHER_ADDR_LEN,
+ "size of struct ether_addr is wrong");
#define ETHER_IS_MULTICAST(addr) (*(addr) & 0x01) /* is address mcast/bcast? */
#define ETHER_IS_IPV6_MULTICAST(addr) \
@@ -112,6 +116,8 @@ struct ether_vlan_header {
uint16_t evl_tag;
uint16_t evl_proto;
} __packed;
+_Static_assert(sizeof(struct ether_vlan_header) == ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN,
+ "size of struct ether_vlan_header is wrong");
#define EVL_VLID_MASK 0x0FFF
#define EVL_PRI_MASK 0xE000
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c
index 7be4dfac23e7..3ae0c01c0efc 100644
--- a/sys/net/if_ethersubr.c
+++ b/sys/net/if_ethersubr.c
@@ -92,11 +92,6 @@
#include <crypto/sha1.h>
-#ifdef CTASSERT
-CTASSERT(sizeof (struct ether_header) == ETHER_ADDR_LEN * 2 + 2);
-CTASSERT(sizeof (struct ether_addr) == ETHER_ADDR_LEN);
-#endif
-
VNET_DEFINE(pfil_head_t, link_pfil_head); /* Packet filter hooks */
/* netgraph node hooks for ng_ether(4) */
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 1f2011634695..452a8eb4024b 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1370,7 +1370,6 @@ struct pf_kruleset {
struct pf_krulequeue queues[2];
struct {
struct pf_krulequeue *ptr;
- struct pf_krule **ptr_array;
u_int32_t rcount;
u_int32_t ticket;
int open;
diff --git a/sys/net80211/ieee80211_hostap.c b/sys/net80211/ieee80211_hostap.c
index c5a478533313..9074878e17e4 100644
--- a/sys/net80211/ieee80211_hostap.c
+++ b/sys/net80211/ieee80211_hostap.c
@@ -2214,12 +2214,9 @@ hostap_recv_mgmt(struct ieee80211_node *ni, struct mbuf *m0,
/* VHT */
if (IEEE80211_IS_CHAN_VHT(ni->ni_chan) &&
- vhtcap != NULL &&
- vhtinfo != NULL) {
- /* XXX TODO; see below */
- net80211_vap_printf(vap, "%s: VHT TODO!\n", __func__);
+ vhtcap != NULL) {
ieee80211_vht_node_init(ni);
- ieee80211_vht_update_cap(ni, vhtcap, vhtinfo);
+ ieee80211_vht_update_cap(ni, vhtcap);
} else if (ni->ni_flags & IEEE80211_NODE_VHT)
ieee80211_vht_node_cleanup(ni);
diff --git a/sys/net80211/ieee80211_ht.c b/sys/net80211/ieee80211_ht.c
index 5ec80e3646b8..c28f124648a1 100644
--- a/sys/net80211/ieee80211_ht.c
+++ b/sys/net80211/ieee80211_ht.c
@@ -1952,6 +1952,11 @@ do { \
_RETURN_CHAN_BITS(0);
/*
+ * TODO: should we bail out if there's no htinfo?
+ * Or just treat it as if we can't do the HT20/HT40 check?
+ */
+
+ /*
* The original code was based on
* 802.11ac-2013, Table 8-183x-VHT Operation Information subfields.
* 802.11-2020, Table 9-274-VHT Operation Information subfields
@@ -1962,8 +1967,12 @@ do { \
*/
htinfo = (const struct ieee80211_ie_htinfo *)ni->ni_ies.htinfo_ie;
- ht40 = ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH) ==
- IEEE80211_HTINFO_TXWIDTH_2040);
+ if (htinfo != NULL)
+ ht40 = ((htinfo->hi_byte1 & IEEE80211_HTINFO_TXWIDTH) ==
+ IEEE80211_HTINFO_TXWIDTH_2040);
+ else
+ ht40 = false;
+
can_vht160 = can_vht80p80 = can_vht80 = false;
/* 20 Mhz */
diff --git a/sys/net80211/ieee80211_vht.c b/sys/net80211/ieee80211_vht.c
index e91977f1ef98..de0b691d4d2a 100644
--- a/sys/net80211/ieee80211_vht.c
+++ b/sys/net80211/ieee80211_vht.c
@@ -838,12 +838,10 @@ ieee80211_add_vhtinfo(uint8_t *frm, struct ieee80211_node *ni)
}
void
-ieee80211_vht_update_cap(struct ieee80211_node *ni, const uint8_t *vhtcap_ie,
- const uint8_t *vhtop_ie)
+ieee80211_vht_update_cap(struct ieee80211_node *ni, const uint8_t *vhtcap_ie)
{
ieee80211_parse_vhtcap(ni, vhtcap_ie);
- ieee80211_parse_vhtopmode(ni, vhtop_ie);
}
static struct ieee80211_channel *
diff --git a/sys/net80211/ieee80211_vht.h b/sys/net80211/ieee80211_vht.h
index 2964de63c343..a1529df4a85b 100644
--- a/sys/net80211/ieee80211_vht.h
+++ b/sys/net80211/ieee80211_vht.h
@@ -52,8 +52,7 @@ uint8_t * ieee80211_add_vhtinfo(uint8_t *frm, struct ieee80211_node *);
uint8_t *ieee80211_add_vhtcap_ch(uint8_t *, struct ieee80211vap *,
struct ieee80211_channel *);
-void ieee80211_vht_update_cap(struct ieee80211_node *,
- const uint8_t *, const uint8_t *);
+void ieee80211_vht_update_cap(struct ieee80211_node *, const uint8_t *);
struct ieee80211_channel *
ieee80211_vht_adjust_channel(struct ieee80211com *,
diff --git a/sys/netinet/tcp_hpts.c b/sys/netinet/tcp_hpts.c
index 91f8251589e4..b60cdf45af52 100644
--- a/sys/netinet/tcp_hpts.c
+++ b/sys/netinet/tcp_hpts.c
@@ -433,38 +433,40 @@ static void
tcp_hpts_log(struct tcp_hpts_entry *hpts, struct tcpcb *tp, struct timeval *tv,
int slots_to_run, int idx, bool from_callout)
{
- union tcp_log_stackspecific log;
- /*
- * Unused logs are
- * 64 bit - delRate, rttProp, bw_inuse
- * 16 bit - cwnd_gain
- * 8 bit - bbr_state, bbr_substate, inhpts;
- */
- memset(&log, 0, sizeof(log));
- log.u_bbr.flex1 = hpts->p_nxt_slot;
- log.u_bbr.flex2 = hpts->p_cur_slot;
- log.u_bbr.flex3 = hpts->p_prev_slot;
- log.u_bbr.flex4 = idx;
- log.u_bbr.flex5 = hpts->p_curtick;
- log.u_bbr.flex6 = hpts->p_on_queue_cnt;
- log.u_bbr.flex7 = hpts->p_cpu;
- log.u_bbr.flex8 = (uint8_t)from_callout;
- log.u_bbr.inflight = slots_to_run;
- log.u_bbr.applimited = hpts->overidden_sleep;
- log.u_bbr.delivered = hpts->saved_curtick;
- log.u_bbr.timeStamp = tcp_tv_to_usectick(tv);
- log.u_bbr.epoch = hpts->saved_curslot;
- log.u_bbr.lt_epoch = hpts->saved_prev_slot;
- log.u_bbr.pkts_out = hpts->p_delayed_by;
- log.u_bbr.lost = hpts->p_hpts_sleep_time;
- log.u_bbr.pacing_gain = hpts->p_cpu;
- log.u_bbr.pkt_epoch = hpts->p_runningslot;
- log.u_bbr.use_lt_bw = 1;
- TCP_LOG_EVENTP(tp, NULL,
- &tptosocket(tp)->so_rcv,
- &tptosocket(tp)->so_snd,
- BBR_LOG_HPTSDIAG, 0,
- 0, &log, false, tv);
+ if (hpts_does_tp_logging && tcp_bblogging_on(tp)) {
+ union tcp_log_stackspecific log;
+ /*
+ * Unused logs are
+ * 64 bit - delRate, rttProp, bw_inuse
+ * 16 bit - cwnd_gain
+ * 8 bit - bbr_state, bbr_substate, inhpts;
+ */
+ memset(&log, 0, sizeof(log));
+ log.u_bbr.flex1 = hpts->p_nxt_slot;
+ log.u_bbr.flex2 = hpts->p_cur_slot;
+ log.u_bbr.flex3 = hpts->p_prev_slot;
+ log.u_bbr.flex4 = idx;
+ log.u_bbr.flex5 = hpts->p_curtick;
+ log.u_bbr.flex6 = hpts->p_on_queue_cnt;
+ log.u_bbr.flex7 = hpts->p_cpu;
+ log.u_bbr.flex8 = (uint8_t)from_callout;
+ log.u_bbr.inflight = slots_to_run;
+ log.u_bbr.applimited = hpts->overidden_sleep;
+ log.u_bbr.delivered = hpts->saved_curtick;
+ log.u_bbr.timeStamp = tcp_tv_to_usectick(tv);
+ log.u_bbr.epoch = hpts->saved_curslot;
+ log.u_bbr.lt_epoch = hpts->saved_prev_slot;
+ log.u_bbr.pkts_out = hpts->p_delayed_by;
+ log.u_bbr.lost = hpts->p_hpts_sleep_time;
+ log.u_bbr.pacing_gain = hpts->p_cpu;
+ log.u_bbr.pkt_epoch = hpts->p_runningslot;
+ log.u_bbr.use_lt_bw = 1;
+ TCP_LOG_EVENTP(tp, NULL,
+ &tptosocket(tp)->so_rcv,
+ &tptosocket(tp)->so_snd,
+ BBR_LOG_HPTSDIAG, 0,
+ 0, &log, false, tv);
+ }
}
static void
@@ -1353,10 +1355,7 @@ again:
}
CURVNET_SET(inp->inp_vnet);
/* Lets do any logging that we might want to */
- if (hpts_does_tp_logging && tcp_bblogging_on(tp)) {
- tcp_hpts_log(hpts, tp, &tv, slots_to_run, i,
- from_callout);
- }
+ tcp_hpts_log(hpts, tp, &tv, slots_to_run, i, from_callout);
if (tp->t_fb_ptr != NULL) {
kern_prefetch(tp->t_fb_ptr, &did_prefetch);
@@ -1487,7 +1486,7 @@ no_run:
}
void
-__tcp_set_hpts(struct tcpcb *tp, int32_t line)
+tcp_set_hpts(struct tcpcb *tp)
{
struct tcp_hpts_entry *hpts;
int failed;
diff --git a/sys/netinet/tcp_hpts.h b/sys/netinet/tcp_hpts.h
index b097a2b98db9..f5856ed8e688 100644
--- a/sys/netinet/tcp_hpts.h
+++ b/sys/netinet/tcp_hpts.h
@@ -149,8 +149,7 @@ uint32_t tcp_hpts_insert_diag(struct tcpcb *tp, uint32_t slot, int32_t line,
#define tcp_hpts_insert(inp, slot) \
tcp_hpts_insert_diag((inp), (slot), __LINE__, NULL)
-void __tcp_set_hpts(struct tcpcb *tp, int32_t line);
-#define tcp_set_hpts(a) __tcp_set_hpts(a, __LINE__)
+void tcp_set_hpts(struct tcpcb *tp);
void tcp_set_inp_to_drop(struct inpcb *inp, uint16_t reason);
@@ -165,25 +164,25 @@ extern int32_t tcp_min_hptsi_time;
* The following functions should also be available
* to userspace as well.
*/
-static __inline uint32_t
+static inline uint32_t
tcp_tv_to_hptstick(const struct timeval *sv)
{
return ((sv->tv_sec * 100000) + (sv->tv_usec / HPTS_TICKS_PER_SLOT));
}
-static __inline uint32_t
+static inline uint32_t
tcp_tv_to_usectick(const struct timeval *sv)
{
return ((uint32_t) ((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec));
}
-static __inline uint32_t
+static inline uint32_t
tcp_tv_to_mssectick(const struct timeval *sv)
{
return ((uint32_t) ((sv->tv_sec * HPTS_MSEC_IN_SEC) + (sv->tv_usec/HPTS_USEC_IN_MSEC)));
}
-static __inline uint64_t
+static inline uint64_t
tcp_tv_to_lusectick(const struct timeval *sv)
{
return ((uint64_t)((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec));
@@ -199,7 +198,7 @@ get_hpts_min_sleep_time(void)
return (tcp_min_hptsi_time + HPTS_TICKS_PER_SLOT);
}
-static __inline uint32_t
+static inline uint32_t
tcp_gethptstick(struct timeval *sv)
{
struct timeval tv;
@@ -210,7 +209,7 @@ tcp_gethptstick(struct timeval *sv)
return (tcp_tv_to_hptstick(sv));
}
-static __inline uint64_t
+static inline uint64_t
tcp_get_u64_usecs(struct timeval *tv)
{
struct timeval tvd;
@@ -221,7 +220,7 @@ tcp_get_u64_usecs(struct timeval *tv)
return (tcp_tv_to_lusectick(tv));
}
-static __inline uint32_t
+static inline uint32_t
tcp_get_usecs(struct timeval *tv)
{
struct timeval tvd;
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 7c032e13f37a..1f60c0e07b13 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1055,6 +1055,8 @@ findpcb:
* socket appended to the listen queue in SYN_RECEIVED state.
*/
if ((thflags & (TH_RST|TH_ACK|TH_SYN)) == TH_ACK) {
+ int result;
+
/*
* Parse the TCP options here because
* syncookies need access to the reflected
@@ -1064,8 +1066,8 @@ findpcb:
/*
* NB: syncache_expand() doesn't unlock inp.
*/
- rstreason = syncache_expand(&inc, &to, th, &so, m, port);
- if (rstreason < 0) {
+ result = syncache_expand(&inc, &to, th, &so, m, port);
+ if (result < 0) {
/*
* A failing TCP MD5 signature comparison
* must result in the segment being dropped
@@ -1073,7 +1075,7 @@ findpcb:
* to the sender.
*/
goto dropunlock;
- } else if (rstreason == 0) {
+ } else if (result == 0) {
/*
* No syncache entry, or ACK was not for our
* SYN/ACK. Do our protection against double
@@ -1515,7 +1517,9 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
struct tcpopt to;
int tfo_syn;
u_int maxseg = 0;
+ bool no_data;
+ no_data = (tlen == 0);
thflags = tcp_get_flags(th);
tp->sackhint.last_sack_ack = 0;
sack_changed = SACK_NOCHANGE;
@@ -1754,7 +1758,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
tp->ts_recent = to.to_tsval;
}
- if (tlen == 0) {
+ if (no_data) {
if (SEQ_GT(th->th_ack, tp->snd_una) &&
SEQ_LEQ(th->th_ack, tp->snd_max) &&
!IN_RECOVERY(tp->t_flags) &&
@@ -2557,7 +2561,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
if (SEQ_LEQ(th->th_ack, tp->snd_una)) {
maxseg = tcp_maxseg(tp);
- if (tlen == 0 &&
+ if (no_data &&
(tiwin == tp->snd_wnd ||
(tp->t_flags & TF_SACK_PERMIT))) {
/*
@@ -3113,8 +3117,7 @@ step6:
(tp->snd_wl1 == th->th_seq && (SEQ_LT(tp->snd_wl2, th->th_ack) ||
(tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd))))) {
/* keep track of pure window updates */
- if (tlen == 0 &&
- tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
+ if (no_data && tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
TCPSTAT_INC(tcps_rcvwinupd);
tp->snd_wnd = tiwin;
tp->snd_wl1 = th->th_seq;
diff --git a/sys/netinet/tcp_log_buf.c b/sys/netinet/tcp_log_buf.c
index 75d693bc019b..e24790ece43d 100644
--- a/sys/netinet/tcp_log_buf.c
+++ b/sys/netinet/tcp_log_buf.c
@@ -2878,7 +2878,7 @@ tcp_log_sendfile(struct socket *so, off_t offset, size_t nbytes, int flags)
/* double check log state now that we have the lock */
if (inp->inp_flags & INP_DROPPED)
goto done;
- if (tp->_t_logstate != TCP_LOG_STATE_OFF) {
+ if (tcp_bblogging_on(tp)) {
struct timeval tv;
tcp_log_eventspecific_t log;
diff --git a/sys/netinet/tcp_log_buf.h b/sys/netinet/tcp_log_buf.h
index fef32e16b2e4..3e7eef8a1cda 100644
--- a/sys/netinet/tcp_log_buf.h
+++ b/sys/netinet/tcp_log_buf.h
@@ -539,12 +539,12 @@ struct tcpcb;
NULL, NULL, 0, NULL); \
} while (0)
#endif /* TCP_LOG_FORCEVERBOSE */
+/* Assumes/requires the caller has already checked tcp_bblogging_on(tp). */
#define TCP_LOG_EVENTP(tp, th, rxbuf, txbuf, eventid, errornum, len, stackinfo, th_hostorder, tv) \
do { \
- if (tcp_bblogging_on(tp)) \
- tcp_log_event(tp, th, rxbuf, txbuf, eventid, \
- errornum, len, stackinfo, th_hostorder, \
- NULL, NULL, 0, tv); \
+ KASSERT(tcp_bblogging_on(tp), ("bblogging is off")); \
+ tcp_log_event(tp, th, rxbuf, txbuf, eventid, errornum, len, \
+ stackinfo, th_hostorder, NULL, NULL, 0, tv); \
} while (0)
#ifdef TCP_BLACKBOX
diff --git a/sys/netinet6/mld6.c b/sys/netinet6/mld6.c
index 06fe9e8820c9..a825658bd9ee 100644
--- a/sys/netinet6/mld6.c
+++ b/sys/netinet6/mld6.c
@@ -234,17 +234,20 @@ static SYSCTL_NODE(_net_inet6_mld, OID_AUTO, ifinfo,
CTLFLAG_RD | CTLFLAG_MPSAFE, sysctl_mld_ifinfo,
"Per-interface MLDv2 state");
-static int mld_v1enable = 1;
-SYSCTL_INT(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_RWTUN,
- &mld_v1enable, 0, "Enable fallback to MLDv1");
+VNET_DEFINE_STATIC(bool, mld_v1enable) = true;
+#define V_mld_v1enable VNET(mld_v1enable)
+SYSCTL_BOOL(_net_inet6_mld, OID_AUTO, v1enable, CTLFLAG_VNET | CTLFLAG_RWTUN,
+ &VNET_NAME(mld_v1enable), 0, "Enable fallback to MLDv1");
-static int mld_v2enable = 1;
-SYSCTL_INT(_net_inet6_mld, OID_AUTO, v2enable, CTLFLAG_RWTUN,
- &mld_v2enable, 0, "Enable MLDv2");
+VNET_DEFINE_STATIC(bool, mld_v2enable) = true;
+#define V_mld_v2enable VNET(mld_v2enable)
+SYSCTL_BOOL(_net_inet6_mld, OID_AUTO, v2enable, CTLFLAG_VNET | CTLFLAG_RWTUN,
+ &VNET_NAME(mld_v2enable), 0, "Enable MLDv2");
-static int mld_use_allow = 1;
-SYSCTL_INT(_net_inet6_mld, OID_AUTO, use_allow, CTLFLAG_RWTUN,
- &mld_use_allow, 0, "Use ALLOW/BLOCK for RFC 4604 SSM joins/leaves");
+VNET_DEFINE_STATIC(bool, mld_use_allow) = true;
+#define V_mld_use_allow VNET(mld_use_allow)
+SYSCTL_BOOL(_net_inet6_mld, OID_AUTO, use_allow, CTLFLAG_VNET | CTLFLAG_RWTUN,
+ &VNET_NAME(mld_use_allow), 0, "Use ALLOW/BLOCK for RFC 4604 SSM joins/leaves");
/*
* Packed Router Alert option structure declaration.
@@ -481,7 +484,7 @@ mld_domifattach(struct ifnet *ifp)
mbufq_init(&mli->mli_gq, MLD_MAX_RESPONSE_PACKETS);
if ((ifp->if_flags & IFF_MULTICAST) == 0)
mli->mli_flags |= MLIF_SILENT;
- if (mld_use_allow)
+ if (V_mld_use_allow)
mli->mli_flags |= MLIF_USEALLOW;
MLD_LOCK();
@@ -614,7 +617,7 @@ mld_v1_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
is_general_query = 0;
- if (!mld_v1enable) {
+ if (!V_mld_v1enable) {
CTR3(KTR_MLD, "ignore v1 query %s on ifp %p(%s)",
ip6_sprintf(ip6tbuf, &mld->mld_addr),
ifp, if_name(ifp));
@@ -790,7 +793,7 @@ mld_v2_input_query(struct ifnet *ifp, const struct ip6_hdr *ip6,
NET_EPOCH_ASSERT();
- if (!mld_v2enable) {
+ if (!V_mld_v2enable) {
CTR3(KTR_MLD, "ignore v2 query src %s on ifp %p(%s)",
ip6_sprintf(ip6tbuf, &ip6->ip6_src),
ifp, if_name(ifp));
@@ -1076,7 +1079,7 @@ mld_v1_input_report(struct ifnet *ifp, const struct ip6_hdr *ip6,
NET_EPOCH_ASSERT();
- if (!mld_v1enable) {
+ if (!V_mld_v1enable) {
CTR3(KTR_MLD, "ignore v1 report %s on ifp %p(%s)",
ip6_sprintf(ip6tbuf, &mld->mld_addr),
ifp, if_name(ifp));
diff --git a/sys/netinet6/raw_ip6.c b/sys/netinet6/raw_ip6.c
index 0379ef7c789a..c90a1213bd66 100644
--- a/sys/netinet6/raw_ip6.c
+++ b/sys/netinet6/raw_ip6.c
@@ -765,8 +765,7 @@ rip6_bind(struct socket *so, struct sockaddr *nam, struct thread *td)
}
if (ifa != NULL &&
((struct in6_ifaddr *)ifa)->ia6_flags &
- (IN6_IFF_ANYCAST|IN6_IFF_NOTREADY|
- IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
+ (IN6_IFF_NOTREADY|IN6_IFF_DETACHED|IN6_IFF_DEPRECATED)) {
NET_EPOCH_EXIT(et);
return (EADDRNOTAVAIL);
}
diff --git a/sys/netipsec/ipsec.c b/sys/netipsec/ipsec.c
index 6bacc68b7441..92d0201b398a 100644
--- a/sys/netipsec/ipsec.c
+++ b/sys/netipsec/ipsec.c
@@ -636,8 +636,10 @@ ipsec4_in_reject1(const struct mbuf *m, struct ip *ip1, struct inpcb *inp)
#ifdef IPSEC_OFFLOAD
tag = ipsec_accel_input_tag_lookup(m);
- if (tag != NULL)
- return (0);
+ if (tag != NULL) {
+ tag->tag.m_tag_id = PACKET_TAG_IPSEC_IN_DONE;
+ __DECONST(struct mbuf *, m)->m_flags |= M_DECRYPTED;
+ }
#endif
if (ip1 == NULL) {
diff --git a/sys/netipsec/ipsec_offload.c b/sys/netipsec/ipsec_offload.c
index 467d5ded1d7a..8a09d5f37b4a 100644
--- a/sys/netipsec/ipsec_offload.c
+++ b/sys/netipsec/ipsec_offload.c
@@ -94,6 +94,7 @@ struct ifp_handle_sav {
size_t hdr_ext_size;
uint64_t cnt_octets;
uint64_t cnt_allocs;
+ struct xform_history xfh;
};
#define IFP_HS_HANDLED 0x00000001
@@ -159,6 +160,8 @@ static void ipsec_accel_drv_sa_lifetime_update_impl(struct secasvar *sav,
static int ipsec_accel_drv_sa_lifetime_fetch_impl(struct secasvar *sav,
if_t ifp, u_int drv_spi, uint64_t *octets, uint64_t *allocs);
static void ipsec_accel_ifdetach_event(void *arg, struct ifnet *ifp);
+static bool ipsec_accel_fill_xh_impl(if_t ifp, uint32_t drv_spi,
+ struct xform_history *xh);
static void
ipsec_accel_init(void *arg)
@@ -185,6 +188,7 @@ ipsec_accel_init(void *arg)
ipsec_accel_drv_sa_lifetime_update_impl;
ipsec_accel_drv_sa_lifetime_fetch_p =
ipsec_accel_drv_sa_lifetime_fetch_impl;
+ ipsec_accel_fill_xh_p = ipsec_accel_fill_xh_impl;
pctrie_init(&drv_spi_pctrie);
ipsec_accel_ifdetach_event_tag = EVENTHANDLER_REGISTER(
ifnet_departure_event, ipsec_accel_ifdetach_event, NULL,
@@ -209,6 +213,7 @@ ipsec_accel_fini(void *arg)
ipsec_accel_on_ifdown_p = NULL;
ipsec_accel_drv_sa_lifetime_update_p = NULL;
ipsec_accel_drv_sa_lifetime_fetch_p = NULL;
+ ipsec_accel_fill_xh_p = NULL;
ipsec_accel_sync_imp();
clean_unrhdr(drv_spi_unr); /* avoid panic, should go later */
clear_unrhdr(drv_spi_unr);
@@ -412,6 +417,10 @@ ipsec_accel_handle_sav(struct secasvar *sav, struct ifnet *ifp,
ihs->ifdata = priv;
ihs->flags = flags;
ihs->hdr_ext_size = esp_hdrsiz(sav);
+ memcpy(&ihs->xfh.dst, &sav->sah->saidx.dst, sizeof(ihs->xfh.dst));
+ ihs->xfh.spi = sav->spi;
+ ihs->xfh.proto = sav->sah->saidx.proto;
+ ihs->xfh.mode = sav->sah->saidx.mode;
mtx_lock(&ipsec_accel_sav_tmp);
CK_LIST_FOREACH(i, &sav->accel_ifps, sav_link) {
if (i->ifp == ifp) {
@@ -1162,4 +1171,20 @@ ipsec_accel_key_setaccelif_impl(struct secasvar *sav)
return (m);
}
+static bool
+ipsec_accel_fill_xh_impl(if_t ifp, uint32_t drv_spi, struct xform_history *xh)
+{
+ struct ifp_handle_sav *i;
+
+ if (drv_spi < IPSEC_ACCEL_DRV_SPI_MIN ||
+ drv_spi > IPSEC_ACCEL_DRV_SPI_MAX)
+ return (false);
+
+ i = DRVSPI_SA_PCTRIE_LOOKUP(&drv_spi_pctrie, drv_spi);
+ if (i == NULL)
+ return (false);
+ memcpy(xh, &i->xfh, sizeof(*xh));
+ return (true);
+}
+
#endif /* IPSEC_OFFLOAD */
diff --git a/sys/netipsec/ipsec_offload.h b/sys/netipsec/ipsec_offload.h
index 904fe6252396..ae60eaa8ae78 100644
--- a/sys/netipsec/ipsec_offload.h
+++ b/sys/netipsec/ipsec_offload.h
@@ -30,6 +30,7 @@
#include <sys/errno.h>
#include <net/if.h>
#include <net/if_var.h>
+#include <netipsec/xform.h>
struct secpolicy;
struct secasvar;
@@ -42,6 +43,7 @@ struct ipsec_accel_out_tag {
struct ipsec_accel_in_tag {
struct m_tag tag;
+ struct xform_history xh; /* Must be first to mimic IPSEC_IN_DONE */
uint16_t drv_spi;
};
@@ -66,6 +68,8 @@ extern void (*ipsec_accel_drv_sa_lifetime_update_p)(struct secasvar *sav,
if_t ifp, u_int drv_spi, uint64_t octets, uint64_t allocs);
extern int (*ipsec_accel_drv_sa_lifetime_fetch_p)(struct secasvar *sav,
if_t ifp, u_int drv_spi, uint64_t *octets, uint64_t *allocs);
+extern bool (*ipsec_accel_fill_xh_p)(if_t ifp, uint32_t drv_spi,
+ struct xform_history *xh);
#ifdef IPSEC_OFFLOAD
/*
@@ -158,6 +162,16 @@ ipsec_accel_key_setaccelif(struct secasvar *sav)
return (NULL);
}
+static inline bool
+ipsec_accel_fill_xh(if_t ifp, uint32_t drv_spi, struct xform_history *xh)
+{
+ bool (*p)(if_t ifp, uint32_t drv_spi, struct xform_history *xh);
+
+ p = atomic_load_ptr(&ipsec_accel_fill_xh_p);
+ if (p != NULL)
+ return (p(ifp, drv_spi, xh));
+ return (false);
+}
#else
#define ipsec_accel_sa_newkey(a)
@@ -168,6 +182,7 @@ ipsec_accel_key_setaccelif(struct secasvar *sav)
#define ipsec_accel_sync()
#define ipsec_accel_is_accel_sav(a)
#define ipsec_accel_key_setaccelif(a)
+#define ipsec_accel_fill_xh(a, b, c) (false)
#endif
void ipsec_accel_forget_sav_impl(struct secasvar *sav);
@@ -180,6 +195,7 @@ bool ipsec_accel_output(struct ifnet *ifp, struct mbuf *m,
struct inpcb *inp, struct secpolicy *sp, struct secasvar *sav, int af,
int mtu, int *hwassist);
void ipsec_accel_forget_sav(struct secasvar *sav);
+struct xform_history;
#else
#define ipsec_accel_input(a, b, c) (ENXIO)
#define ipsec_accel_output(a, b, c, d, e, f, g, h) ({ \
diff --git a/sys/netipsec/key.c b/sys/netipsec/key.c
index ae67d83c6d13..4ba1b49c24f0 100644
--- a/sys/netipsec/key.c
+++ b/sys/netipsec/key.c
@@ -114,6 +114,8 @@ void (*ipsec_accel_drv_sa_lifetime_update_p)(struct secasvar *sav, if_t ifp,
u_int drv_spi, uint64_t octets, uint64_t allocs);
int (*ipsec_accel_drv_sa_lifetime_fetch_p)(struct secasvar *sav, if_t ifp,
u_int drv_spi, uint64_t *octets, uint64_t *allocs);
+bool (*ipsec_accel_fill_xh_p)(if_t ifp, uint32_t drv_spi,
+ struct xform_history *xh);
#endif
#define FULLMASK 0xff
diff --git a/sys/netlink/netlink_message_parser.h b/sys/netlink/netlink_message_parser.h
index 8492ecb3021b..720317ed74f3 100644
--- a/sys/netlink/netlink_message_parser.h
+++ b/sys/netlink/netlink_message_parser.h
@@ -209,7 +209,8 @@ int nlattr_get_nested(struct nlattr *nla, struct nl_pstate *npt,
int nlattr_get_nested_ptr(struct nlattr *nla, struct nl_pstate *npt,
const void *arg, void *target);
-bool nlmsg_report_err_msg(struct nl_pstate *npt, const char *fmt, ...);
+bool nlmsg_report_err_msg(struct nl_pstate *npt, const char *fmt, ...)
+ __printflike(2, 3);
#define NLMSG_REPORT_ERR_MSG(_npt, _fmt, ...) { \
nlmsg_report_err_msg(_npt, _fmt, ## __VA_ARGS__); \
diff --git a/sys/netpfil/pf/if_pflog.c b/sys/netpfil/pf/if_pflog.c
index 0a84f9d680ac..cb96d2fcc44c 100644
--- a/sys/netpfil/pf/if_pflog.c
+++ b/sys/netpfil/pf/if_pflog.c
@@ -284,9 +284,9 @@ pflog_packet(uint8_t action, u_int8_t reason,
* state lock, since this leads to unsafe LOR.
* These conditions are very very rare, however.
*/
- if (trigger->log & PF_LOG_SOCKET_LOOKUP && !pd->lookup.done && lookupsafe)
+ if (trigger->log & PF_LOG_USER && !pd->lookup.done && lookupsafe)
pd->lookup.done = pf_socket_lookup(pd);
- if (pd->lookup.done > 0)
+ if (trigger->log & PF_LOG_USER && pd->lookup.done > 0)
hdr.uid = pd->lookup.uid;
else
hdr.uid = -1;
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 2391edaf1a5a..4e03584b8f85 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -532,6 +532,7 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
struct pf_kpooladdr *rpool_first;
int error;
uint8_t rt = 0;
+ int n = 0;
PF_RULES_RASSERT();
@@ -557,10 +558,12 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
*/
if (sp->pfs_1301.rule != htonl(-1) && sp->pfs_1301.anchor == htonl(-1) &&
(flags & (PFSYNC_SI_IOCTL | PFSYNC_SI_CKSUM)) && ntohl(sp->pfs_1301.rule) <
- pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount)
- r = pf_main_ruleset.rules[
- PF_RULESET_FILTER].active.ptr_array[ntohl(sp->pfs_1301.rule)];
- else
+ pf_main_ruleset.rules[PF_RULESET_FILTER].active.rcount) {
+ TAILQ_FOREACH(r, pf_main_ruleset.rules[
+ PF_RULESET_FILTER].active.ptr, entries)
+ if (ntohl(sp->pfs_1301.rule) == n++)
+ break;
+ } else
r = &V_pf_default_rule;
/*
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index a410fe570c39..009f7e4d78b1 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -6219,7 +6219,7 @@ pf_create_state(struct pf_krule *r, struct pf_test_ctx *ctx,
if (ctx->tag > 0)
s->tag = ctx->tag;
if (pd->proto == IPPROTO_TCP && (tcp_get_flags(th) & (TH_SYN|TH_ACK)) ==
- TH_SYN && r->keep_state == PF_STATE_SYNPROXY) {
+ TH_SYN && r->keep_state == PF_STATE_SYNPROXY && pd->dir == PF_IN) {
pf_set_protostate(s, PF_PEER_SRC, PF_TCPS_PROXY_SRC);
pf_undo_nat(ctx->nr, pd, bip_sum);
s->src.seqhi = arc4random();
@@ -9068,6 +9068,9 @@ pf_route(struct pf_krule *r, struct ifnet *oifp,
goto bad;
}
+ if (r->rt == PF_DUPTO)
+ skip_test = true;
+
if (pd->dir == PF_IN && !skip_test) {
if (pf_test(AF_INET, PF_OUT, PFIL_FWD, ifp, &m0, inp,
&pd->act) != PF_PASS) {
@@ -9370,6 +9373,9 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp,
goto bad;
}
+ if (r->rt == PF_DUPTO)
+ skip_test = true;
+
if (pd->dir == PF_IN && !skip_test) {
if (pf_test(AF_INET6, PF_OUT, PFIL_FWD | PF_PFIL_NOREFRAGMENT,
ifp, &m0, inp, &pd->act) != PF_PASS) {
@@ -10058,6 +10064,8 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
pd->didx = (dir == PF_IN) ? 1 : 0;
pd->af = pd->naf = af;
+ PF_RULES_ASSERT();
+
TAILQ_INIT(&pd->sctp_multihome_jobs);
if (default_actions != NULL)
memcpy(&pd->act, default_actions, sizeof(pd->act));
@@ -10133,6 +10141,12 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
}
h = mtod(pd->m, struct ip6_hdr *);
+ if (pd->m->m_pkthdr.len <
+ sizeof(struct ip6_hdr) + ntohs(h->ip6_plen)) {
+ *action = PF_DROP;
+ REASON_SET(reason, PFRES_SHORT);
+ return (-1);
+ }
if (pf_walk_header6(pd, h, reason) != PF_PASS) {
*action = PF_DROP;
@@ -10471,35 +10485,30 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
PF_RULES_RLOCK_TRACKER;
KASSERT(dir == PF_IN || dir == PF_OUT, ("%s: bad direction %d\n", __func__, dir));
M_ASSERTPKTHDR(*m0);
+ NET_EPOCH_ASSERT();
if (!V_pf_status.running)
return (PF_PASS);
- PF_RULES_RLOCK();
-
kif = (struct pfi_kkif *)ifp->if_pf_kif;
if (__predict_false(kif == NULL)) {
DPFPRINTF(PF_DEBUG_URGENT,
("%s: kif == NULL, if_xname %s\n",
__func__, ifp->if_xname));
- PF_RULES_RUNLOCK();
return (PF_DROP);
}
if (kif->pfik_flags & PFI_IFLAG_SKIP) {
- PF_RULES_RUNLOCK();
return (PF_PASS);
}
if ((*m0)->m_flags & M_SKIP_FIREWALL) {
- PF_RULES_RUNLOCK();
return (PF_PASS);
}
if (__predict_false(! M_WRITABLE(*m0))) {
*m0 = m_unshare(*m0, M_NOWAIT);
if (*m0 == NULL) {
- PF_RULES_RUNLOCK();
return (PF_DROP);
}
}
@@ -10512,12 +10521,10 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
ifp = ifnet_byindexgen(pd.pf_mtag->if_index,
pd.pf_mtag->if_idxgen);
if (ifp == NULL || ifp->if_flags & IFF_DYING) {
- PF_RULES_RUNLOCK();
m_freem(*m0);
*m0 = NULL;
return (PF_PASS);
}
- PF_RULES_RUNLOCK();
(ifp->if_output)(ifp, *m0, sintosa(&pd.pf_mtag->dst), NULL);
*m0 = NULL;
return (PF_PASS);
@@ -10532,11 +10539,12 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
/* But only once. We may see the packet multiple times (e.g.
* PFIL_IN/PFIL_OUT). */
pf_dummynet_flag_remove(pd.m, pd.pf_mtag);
- PF_RULES_RUNLOCK();
return (PF_PASS);
}
+ PF_RULES_RLOCK();
+
if (pf_setup_pdesc(af, dir, &pd, m0, &action, &reason,
kif, default_actions) == -1) {
if (action != PF_PASS)
diff --git a/sys/netpfil/pf/pf.h b/sys/netpfil/pf/pf.h
index db353d185368..cfff58064922 100644
--- a/sys/netpfil/pf/pf.h
+++ b/sys/netpfil/pf/pf.h
@@ -140,7 +140,7 @@ enum { PF_ADDR_ADDRMASK, PF_ADDR_NOROUTE, PF_ADDR_DYNIFTL,
#define PF_LOG 0x01
#define PF_LOG_ALL 0x02
-#define PF_LOG_SOCKET_LOOKUP 0x04
+#define PF_LOG_USER 0x04
#define PF_LOG_FORCE 0x08
#define PF_LOG_MATCHES 0x10
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index c14211edf10f..5c69c395c5fc 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -1359,7 +1359,7 @@ static int
pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
{
struct pf_kruleset *rs;
- struct pf_krule *rule, **old_array, *old_rule;
+ struct pf_krule *rule, *old_rule;
struct pf_krulequeue *old_rules;
struct pf_krule_global *old_tree;
int error;
@@ -1384,13 +1384,10 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
/* Swap rules, keep the old. */
old_rules = rs->rules[rs_num].active.ptr;
old_rcount = rs->rules[rs_num].active.rcount;
- old_array = rs->rules[rs_num].active.ptr_array;
old_tree = rs->rules[rs_num].active.tree;
rs->rules[rs_num].active.ptr =
rs->rules[rs_num].inactive.ptr;
- rs->rules[rs_num].active.ptr_array =
- rs->rules[rs_num].inactive.ptr_array;
rs->rules[rs_num].active.tree =
rs->rules[rs_num].inactive.tree;
rs->rules[rs_num].active.rcount =
@@ -1420,7 +1417,6 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
}
rs->rules[rs_num].inactive.ptr = old_rules;
- rs->rules[rs_num].inactive.ptr_array = old_array;
rs->rules[rs_num].inactive.tree = NULL; /* important for pf_ioctl_addrule */
rs->rules[rs_num].inactive.rcount = old_rcount;
@@ -1433,9 +1429,6 @@ pf_commit_rules(u_int32_t ticket, int rs_num, char *anchor)
while ((rule = TAILQ_FIRST(old_rules)) != NULL)
pf_unlink_rule_locked(old_rules, rule);
PF_UNLNKDRULES_UNLOCK();
- if (rs->rules[rs_num].inactive.ptr_array)
- free(rs->rules[rs_num].inactive.ptr_array, M_TEMP);
- rs->rules[rs_num].inactive.ptr_array = NULL;
rs->rules[rs_num].inactive.rcount = 0;
rs->rules[rs_num].inactive.open = 0;
pf_remove_if_empty_kruleset(rs);
@@ -1458,24 +1451,11 @@ pf_setup_pfsync_matching(struct pf_kruleset *rs)
if (rs_cnt == PF_RULESET_SCRUB)
continue;
- if (rs->rules[rs_cnt].inactive.ptr_array)
- free(rs->rules[rs_cnt].inactive.ptr_array, M_TEMP);
- rs->rules[rs_cnt].inactive.ptr_array = NULL;
-
if (rs->rules[rs_cnt].inactive.rcount) {
- rs->rules[rs_cnt].inactive.ptr_array =
- mallocarray(rs->rules[rs_cnt].inactive.rcount,
- sizeof(struct pf_rule **),
- M_TEMP, M_NOWAIT);
-
- if (!rs->rules[rs_cnt].inactive.ptr_array)
- return (ENOMEM);
- }
-
- TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
- entries) {
- pf_hash_rule_rolling(&ctx, rule);
- (rs->rules[rs_cnt].inactive.ptr_array)[rule->nr] = rule;
+ TAILQ_FOREACH(rule, rs->rules[rs_cnt].inactive.ptr,
+ entries) {
+ pf_hash_rule_rolling(&ctx, rule);
+ }
}
}
@@ -2061,6 +2041,47 @@ pf_ioctl_getrules(struct pfioc_rule *pr)
return (0);
}
+static int
+pf_rule_checkaf(struct pf_krule *r)
+{
+ switch (r->af) {
+ case 0:
+ if (r->rule_flag & PFRULE_AFTO)
+ return (EPFNOSUPPORT);
+ break;
+ case AF_INET:
+ if ((r->rule_flag & PFRULE_AFTO) && r->naf != AF_INET6)
+ return (EPFNOSUPPORT);
+ break;
+#ifdef INET6
+ case AF_INET6:
+ if ((r->rule_flag & PFRULE_AFTO) && r->naf != AF_INET)
+ return (EPFNOSUPPORT);
+ break;
+#endif /* INET6 */
+ default:
+ return (EPFNOSUPPORT);
+ }
+
+ if ((r->rule_flag & PFRULE_AFTO) == 0 && r->naf != 0)
+ return (EPFNOSUPPORT);
+
+ return (0);
+}
+
+static int
+pf_validate_range(uint8_t op, uint16_t port[2])
+{
+ uint16_t a = ntohs(port[0]);
+ uint16_t b = ntohs(port[1]);
+
+ if ((op == PF_OP_RRG && a > b) || /* 34:12, i.e. none */
+ (op == PF_OP_IRG && a >= b) || /* 34><12, i.e. none */
+ (op == PF_OP_XRG && a > b)) /* 34<>22, i.e. all */
+ return 1;
+ return 0;
+}
+
int
pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
uint32_t pool_ticket, const char *anchor, const char *anchor_call,
@@ -2080,6 +2101,13 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
#define ERROUT(x) ERROUT_FUNCTION(errout, x)
+ if ((error = pf_rule_checkaf(rule)))
+ ERROUT(error);
+ if (pf_validate_range(rule->src.port_op, rule->src.port))
+ ERROUT(EINVAL);
+ if (pf_validate_range(rule->dst.port_op, rule->dst.port))
+ ERROUT(EINVAL);
+
if (rule->ifname[0])
kif = pf_kkif_create(M_WAITOK);
if (rule->rcv_ifname[0])
@@ -3569,7 +3597,7 @@ DIOCADDRULENV_error:
error = pf_rule_to_krule(&pr->rule, rule);
if (error != 0) {
pf_krule_free(rule);
- break;
+ goto fail;
}
pr->anchor[sizeof(pr->anchor) - 1] = '\0';
@@ -3728,11 +3756,11 @@ DIOCGETRULENV_error:
if (pcr->action < PF_CHANGE_ADD_HEAD ||
pcr->action > PF_CHANGE_GET_TICKET) {
error = EINVAL;
- break;
+ goto fail;
}
if (pcr->rule.return_icmp >> 8 > ICMP_MAXTYPE) {
error = EINVAL;
- break;
+ goto fail;
}
if (pcr->action != PF_CHANGE_REMOVE) {
@@ -3740,9 +3768,13 @@ DIOCGETRULENV_error:
error = pf_rule_to_krule(&pcr->rule, newrule);
if (error != 0) {
pf_krule_free(newrule);
- break;
+ goto fail;
}
+ if ((error = pf_rule_checkaf(newrule))) {
+ pf_krule_free(newrule);
+ goto fail;
+ }
if (newrule->ifname[0])
kif = pf_kkif_create(M_WAITOK);
pf_counter_u64_init(&newrule->evaluations, M_WAITOK);
@@ -3890,7 +3922,7 @@ DIOCGETRULENV_error:
pf_free_rule(newrule);
PF_RULES_WUNLOCK();
PF_CONFIG_UNLOCK();
- break;
+ goto fail;
}
newrule->nat.cur = TAILQ_FIRST(&newrule->nat.list);
@@ -3917,7 +3949,7 @@ DIOCGETRULENV_error:
PF_RULES_WUNLOCK();
PF_CONFIG_UNLOCK();
error = EINVAL;
- break;
+ goto fail;
}
}
@@ -3935,7 +3967,7 @@ DIOCGETRULENV_error:
PF_RULES_WUNLOCK();
PF_CONFIG_UNLOCK();
error = EEXIST;
- break;
+ goto fail;
}
if (oldrule == NULL)
@@ -3991,7 +4023,7 @@ DIOCCHANGERULE_error:
if (sp->timeout >= PFTM_MAX) {
error = EINVAL;
- break;
+ goto fail;
}
if (V_pfsync_state_import_ptr != NULL) {
PF_RULES_RLOCK();
@@ -4011,7 +4043,7 @@ DIOCCHANGERULE_error:
s = pf_find_state_byid(ps->state.id, ps->state.creatorid);
if (s == NULL) {
error = ENOENT;
- break;
+ goto fail;
}
pfsync_state_export((union pfsync_state_union*)&ps->state,
@@ -4090,7 +4122,7 @@ DIOCGETSTATES_retry:
error = copyout(pstore, out,
sizeof(struct pfsync_state_1301) * count);
if (error)
- break;
+ goto fail;
out = ps->ps_states + nr;
}
DIOCGETSTATES_full:
@@ -4110,7 +4142,7 @@ DIOCGETSTATES_full:
if (ps->ps_req_version > PF_STATE_VERSION) {
error = ENOTSUP;
- break;
+ goto fail;
}
if (ps->ps_len <= 0) {
@@ -4168,7 +4200,7 @@ DIOCGETSTATESV2_retry:
error = copyout(pstore, out,
sizeof(struct pf_state_export) * count);
if (error)
- break;
+ goto fail;
out = ps->ps_states + nr;
}
DIOCGETSTATESV2_full:
@@ -4274,12 +4306,12 @@ DIOCGETSTATESV2_full:
if (psp->ifname[0] == '\0') {
error = EINVAL;
- break;
+ goto fail;
}
error = pf_user_strcpy(ps.ifname, psp->ifname, IFNAMSIZ);
if (error != 0)
- break;
+ goto fail;
ifp = ifunit(ps.ifname);
if (ifp != NULL) {
psp->baudrate32 =
@@ -4340,7 +4372,7 @@ DIOCGETSTATESV2_full:
altq = malloc(sizeof(*altq), M_PFALTQ, M_WAITOK | M_ZERO);
error = pf_import_kaltq(pa, altq, IOCPARM_LEN(cmd));
if (error)
- break;
+ goto fail;
altq->local_flags = 0;
PF_RULES_WLOCK();
@@ -4348,7 +4380,7 @@ DIOCGETSTATESV2_full:
PF_RULES_WUNLOCK();
free(altq, M_PFALTQ);
error = EBUSY;
- break;
+ goto fail;
}
/*
@@ -4360,7 +4392,7 @@ DIOCGETSTATESV2_full:
PF_RULES_WUNLOCK();
error = EBUSY;
free(altq, M_PFALTQ);
- break;
+ goto fail;
}
altq->altq_disc = NULL;
TAILQ_FOREACH(a, V_pf_altq_ifs_inactive, entries) {
@@ -4380,7 +4412,7 @@ DIOCGETSTATESV2_full:
if (error) {
PF_RULES_WUNLOCK();
free(altq, M_PFALTQ);
- break;
+ goto fail;
}
if (altq->qname[0] != 0)
@@ -4418,13 +4450,13 @@ DIOCGETSTATESV2_full:
if (pa->ticket != V_ticket_altqs_active) {
PF_RULES_RUNLOCK();
error = EBUSY;
- break;
+ goto fail;
}
altq = pf_altq_get_nth_active(pa->nr);
if (altq == NULL) {
PF_RULES_RUNLOCK();
error = EBUSY;
- break;
+ goto fail;
}
pf_export_kaltq(altq, pa, IOCPARM_LEN(cmd));
PF_RULES_RUNLOCK();
@@ -4448,20 +4480,20 @@ DIOCGETSTATESV2_full:
if (pq->ticket != V_ticket_altqs_active) {
PF_RULES_RUNLOCK();
error = EBUSY;
- break;
+ goto fail;
}
nbytes = pq->nbytes;
altq = pf_altq_get_nth_active(pq->nr);
if (altq == NULL) {
PF_RULES_RUNLOCK();
error = EBUSY;
- break;
+ goto fail;
}
if ((altq->local_flags & PFALTQ_FLAG_IF_REMOVED) != 0) {
PF_RULES_RUNLOCK();
error = ENXIO;
- break;
+ goto fail;
}
PF_RULES_RUNLOCK();
if (cmd == DIOCGETQSTATSV0)
@@ -4530,30 +4562,30 @@ DIOCGETSTATESV2_full:
if (pca->action < PF_CHANGE_ADD_HEAD ||
pca->action > PF_CHANGE_REMOVE) {
error = EINVAL;
- break;
+ goto fail;
}
if (pca->addr.addr.type != PF_ADDR_ADDRMASK &&
pca->addr.addr.type != PF_ADDR_DYNIFTL &&
pca->addr.addr.type != PF_ADDR_TABLE) {
error = EINVAL;
- break;
+ goto fail;
}
if (pca->addr.addr.p.dyn != NULL) {
error = EINVAL;
- break;
+ goto fail;
}
if (pca->action != PF_CHANGE_REMOVE) {
#ifndef INET
if (pca->af == AF_INET) {
error = EAFNOSUPPORT;
- break;
+ goto fail;
}
#endif /* INET */
#ifndef INET6
if (pca->af == AF_INET6) {
error = EAFNOSUPPORT;
- break;
+ goto fail;
}
#endif /* INET6 */
newpa = malloc(sizeof(*newpa), M_PFRULE, M_WAITOK);
@@ -4676,7 +4708,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != 0) {
error = ENODEV;
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_clr_tables(&io->pfrio_table, &io->pfrio_ndel,
@@ -4692,13 +4724,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_table))) {
error = ENOMEM;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_table);
@@ -4707,7 +4739,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
free(pfrts, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_add_tables(pfrts, io->pfrio_size,
@@ -4724,13 +4756,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_table))) {
error = ENOMEM;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_table);
@@ -4739,7 +4771,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
free(pfrts, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_del_tables(pfrts, io->pfrio_size,
@@ -4757,14 +4789,14 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
- break;
+ goto fail;
}
PF_RULES_RLOCK();
n = pfr_table_count(&io->pfrio_table, io->pfrio_flags);
if (n < 0) {
PF_RULES_RUNLOCK();
error = EINVAL;
- break;
+ goto fail;
}
io->pfrio_size = min(io->pfrio_size, n);
@@ -4775,7 +4807,7 @@ DIOCCHANGEADDR_error:
if (pfrts == NULL) {
error = ENOMEM;
PF_RULES_RUNLOCK();
- break;
+ goto fail;
}
error = pfr_get_tables(&io->pfrio_table, pfrts,
&io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
@@ -4794,7 +4826,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
error = ENODEV;
- break;
+ goto fail;
}
PF_TABLE_STATS_LOCK();
PF_RULES_RLOCK();
@@ -4803,7 +4835,7 @@ DIOCCHANGEADDR_error:
PF_RULES_RUNLOCK();
PF_TABLE_STATS_UNLOCK();
error = EINVAL;
- break;
+ goto fail;
}
io->pfrio_size = min(io->pfrio_size, n);
@@ -4814,7 +4846,7 @@ DIOCCHANGEADDR_error:
error = ENOMEM;
PF_RULES_RUNLOCK();
PF_TABLE_STATS_UNLOCK();
- break;
+ goto fail;
}
error = pfr_get_tstats(&io->pfrio_table, pfrtstats,
&io->pfrio_size, io->pfrio_flags | PFR_FLAG_USERIOCTL);
@@ -4833,7 +4865,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 || io->pfrio_size > pf_ioctl_maxcount ||
@@ -4842,7 +4874,7 @@ DIOCCHANGEADDR_error:
* size, so we didn't fail on overly large requests.
* Keep doing so. */
io->pfrio_size = pf_ioctl_maxcount;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_table);
@@ -4851,7 +4883,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
free(pfrts, M_TEMP);
- break;
+ goto fail;
}
PF_TABLE_STATS_LOCK();
@@ -4872,7 +4904,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
- break;
+ goto fail;
}
PF_RULES_RLOCK();
@@ -4880,7 +4912,7 @@ DIOCCHANGEADDR_error:
if (n < 0) {
PF_RULES_RUNLOCK();
error = EINVAL;
- break;
+ goto fail;
}
io->pfrio_size = min(io->pfrio_size, n);
@@ -4892,7 +4924,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
free(pfrts, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_set_tflags(pfrts, io->pfrio_size,
@@ -4908,7 +4940,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != 0) {
error = ENODEV;
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_clr_addrs(&io->pfrio_table, &io->pfrio_ndel,
@@ -4924,13 +4956,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -4938,7 +4970,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_add_addrs(&io->pfrio_table, pfras,
@@ -4958,13 +4990,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -4972,7 +5004,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_del_addrs(&io->pfrio_table, pfras,
@@ -4992,17 +5024,17 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 || io->pfrio_size2 < 0) {
error = EINVAL;
- break;
+ goto fail;
}
count = max(io->pfrio_size, io->pfrio_size2);
if (count > pf_ioctl_maxcount ||
WOULD_OVERFLOW(count, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = count * sizeof(struct pfr_addr);
pfras = mallocarray(count, sizeof(struct pfr_addr), M_TEMP,
@@ -5010,7 +5042,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_set_addrs(&io->pfrio_table, pfras,
@@ -5031,13 +5063,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -5059,13 +5091,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_astats)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_astats))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_astats);
pfrastats = mallocarray(io->pfrio_size,
@@ -5087,13 +5119,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -5101,7 +5133,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_clr_astats(&io->pfrio_table, pfras,
@@ -5121,13 +5153,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -5135,7 +5167,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_RLOCK();
error = pfr_tst_addrs(&io->pfrio_table, pfras,
@@ -5155,13 +5187,13 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_addr)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfrio_size < 0 ||
io->pfrio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfrio_size, sizeof(struct pfr_addr))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = io->pfrio_size * sizeof(struct pfr_addr);
pfras = mallocarray(io->pfrio_size, sizeof(struct pfr_addr),
@@ -5169,7 +5201,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfras, totlen);
if (error) {
free(pfras, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
error = pfr_ina_define(&io->pfrio_table, pfras,
@@ -5204,13 +5236,13 @@ DIOCCHANGEADDR_error:
if (io->esize != sizeof(*ioe)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->size < 0 ||
io->size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = sizeof(struct pfioc_trans_e) * io->size;
ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
@@ -5218,7 +5250,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->array, ioes, totlen);
if (error) {
free(ioes, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
@@ -5285,13 +5317,13 @@ DIOCCHANGEADDR_error:
if (io->esize != sizeof(*ioe)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->size < 0 ||
io->size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = sizeof(struct pfioc_trans_e) * io->size;
ioes = mallocarray(io->size, sizeof(struct pfioc_trans_e),
@@ -5299,7 +5331,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->array, ioes, totlen);
if (error) {
free(ioes, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
for (i = 0, ioe = ioes; i < io->size; i++, ioe++) {
@@ -5368,14 +5400,14 @@ DIOCCHANGEADDR_error:
if (io->esize != sizeof(*ioe)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->size < 0 ||
io->size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->size, sizeof(struct pfioc_trans_e))) {
error = EINVAL;
- break;
+ goto fail;
}
totlen = sizeof(struct pfioc_trans_e) * io->size;
@@ -5384,7 +5416,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->array, ioes, totlen);
if (error) {
free(ioes, M_TEMP);
- break;
+ goto fail;
}
PF_RULES_WLOCK();
/* First makes sure everything will succeed. */
@@ -5525,7 +5557,7 @@ DIOCCHANGEADDR_error:
if (psn->psn_len == 0) {
psn->psn_len = sizeof(struct pf_src_node) * nr;
- break;
+ goto fail;
}
nr = 0;
@@ -5550,7 +5582,7 @@ DIOCCHANGEADDR_error:
sizeof(struct pf_src_node) * nr);
if (error) {
free(pstore, M_TEMP);
- break;
+ goto fail;
}
psn->psn_len = sizeof(struct pf_src_node) * nr;
free(pstore, M_TEMP);
@@ -5606,14 +5638,14 @@ DIOCCHANGEADDR_error:
if (io->pfiio_esize != sizeof(struct pfi_kif)) {
error = ENODEV;
- break;
+ goto fail;
}
if (io->pfiio_size < 0 ||
io->pfiio_size > pf_ioctl_maxcount ||
WOULD_OVERFLOW(io->pfiio_size, sizeof(struct pfi_kif))) {
error = EINVAL;
- break;
+ goto fail;
}
io->pfiio_name[sizeof(io->pfiio_name) - 1] = '\0';
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index 26f7ab41eef4..9c7863bb301e 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -1012,10 +1012,13 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
if (rpool->proxy_port[1]) {
uint32_t tmp_nport;
+ uint16_t div;
- tmp_nport = ((ntohs(pd->ndport) - ntohs(r->dst.port[0])) %
- (rpool->proxy_port[1] - rpool->proxy_port[0] +
- 1)) + rpool->proxy_port[0];
+ div = r->rdr.proxy_port[1] - r->rdr.proxy_port[0] + 1;
+ div = (div == 0) ? 1 : div;
+
+ tmp_nport = ((ntohs(pd->ndport) - ntohs(r->dst.port[0])) % div) +
+ rpool->proxy_port[0];
/* Wrap around if necessary. */
if (tmp_nport > 65535)
diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c
index e3f3ab9025f7..9c0151b7da2b 100644
--- a/sys/netpfil/pf/pf_table.c
+++ b/sys/netpfil/pf/pf_table.c
@@ -819,10 +819,10 @@ pfr_create_kentry(struct pfr_addr *ad, bool counters)
static void
pfr_destroy_kentries(struct pfr_kentryworkq *workq)
{
- struct pfr_kentry *p, *q;
+ struct pfr_kentry *p;
- for (p = SLIST_FIRST(workq); p != NULL; p = q) {
- q = SLIST_NEXT(p, pfrke_workq);
+ while ((p = SLIST_FIRST(workq)) != NULL) {
+ SLIST_REMOVE_HEAD(workq, pfrke_workq);
pfr_destroy_kentry(p);
}
}
@@ -1680,8 +1680,7 @@ pfr_ina_commit(struct pfr_table *trs, u_int32_t ticket, int *nadd,
}
if (!(flags & PFR_FLAG_DUMMY)) {
- for (p = SLIST_FIRST(&workq); p != NULL; p = q) {
- q = SLIST_NEXT(p, pfrkt_workq);
+ SLIST_FOREACH_SAFE(p, &workq, pfrkt_workq, q) {
pfr_commit_ktable(p, tzero);
}
rs->topen = 0;
@@ -1710,7 +1709,7 @@ pfr_commit_ktable(struct pfr_ktable *kt, time_t tzero)
} else if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE) {
/* kt might contain addresses */
struct pfr_kentryworkq addrq, addq, changeq, delq, garbageq;
- struct pfr_kentry *p, *q, *next;
+ struct pfr_kentry *p, *q;
struct pfr_addr ad;
pfr_enqueue_addrs(shadow, &addrq, NULL, 0);
@@ -1720,7 +1719,8 @@ pfr_commit_ktable(struct pfr_ktable *kt, time_t tzero)
SLIST_INIT(&delq);
SLIST_INIT(&garbageq);
pfr_clean_node_mask(shadow, &addrq);
- SLIST_FOREACH_SAFE(p, &addrq, pfrke_workq, next) {
+ while ((p = SLIST_FIRST(&addrq)) != NULL) {
+ SLIST_REMOVE_HEAD(&addrq, pfrke_workq);
pfr_copyout_addr(&ad, p);
q = pfr_lookup_addr(kt, &ad, 1);
if (q != NULL) {
@@ -1864,8 +1864,7 @@ pfr_setflags_ktables(struct pfr_ktableworkq *workq)
{
struct pfr_ktable *p, *q;
- for (p = SLIST_FIRST(workq); p; p = q) {
- q = SLIST_NEXT(p, pfrkt_workq);
+ SLIST_FOREACH_SAFE(p, workq, pfrkt_workq, q) {
pfr_setflags_ktable(p, p->pfrkt_nflags);
}
}
@@ -2015,10 +2014,10 @@ pfr_create_ktable(struct pfr_table *tbl, time_t tzero, int attachruleset)
static void
pfr_destroy_ktables(struct pfr_ktableworkq *workq, int flushaddr)
{
- struct pfr_ktable *p, *q;
+ struct pfr_ktable *p;
- for (p = SLIST_FIRST(workq); p; p = q) {
- q = SLIST_NEXT(p, pfrkt_workq);
+ while ((p = SLIST_FIRST(workq)) != NULL) {
+ SLIST_REMOVE_HEAD(workq, pfrkt_workq);
pfr_destroy_ktable(p, flushaddr);
}
}
diff --git a/sys/rpc/clnt_rc.c b/sys/rpc/clnt_rc.c
index 9e87af578885..44b63e38a8e6 100644
--- a/sys/rpc/clnt_rc.c
+++ b/sys/rpc/clnt_rc.c
@@ -198,6 +198,12 @@ clnt_reconnect_connect(CLIENT *cl)
newclient = clnt_vc_create(so,
(struct sockaddr *) &rc->rc_addr, rc->rc_prog, rc->rc_vers,
rc->rc_sendsz, rc->rc_recvsz, rc->rc_intr);
+ /*
+ * CLSET_FD_CLOSE must be done now, in case rpctls_connect()
+ * fails just below.
+ */
+ if (newclient != NULL)
+ CLNT_CONTROL(newclient, CLSET_FD_CLOSE, 0);
if (rc->rc_tls && newclient != NULL) {
CURVNET_SET(so->so_vnet);
stat = rpctls_connect(newclient, rc->rc_tlscertname, so,
@@ -236,7 +242,6 @@ clnt_reconnect_connect(CLIENT *cl)
goto out;
}
- CLNT_CONTROL(newclient, CLSET_FD_CLOSE, 0);
CLNT_CONTROL(newclient, CLSET_CONNECT, &one);
CLNT_CONTROL(newclient, CLSET_TIMEOUT, &rc->rc_timeout);
CLNT_CONTROL(newclient, CLSET_RETRY_TIMEOUT, &rc->rc_retry);
diff --git a/sys/rpc/rpcsec_gss/rpcsec_gss.c b/sys/rpc/rpcsec_gss/rpcsec_gss.c
index 62c71937a185..983dd251f81f 100644
--- a/sys/rpc/rpcsec_gss/rpcsec_gss.c
+++ b/sys/rpc/rpcsec_gss/rpcsec_gss.c
@@ -67,6 +67,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/hash.h>
+#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/kobj.h>
#include <sys/lock.h>
@@ -772,6 +773,17 @@ rpc_gss_init(AUTH *auth, rpc_gss_options_ret_t *options_ret)
gd->gd_cred.gc_seq = 0;
/*
+ * XXX Threads from inside jails can get here via calls
+ * to clnt_vc_call()->AUTH_REFRESH()->rpc_gss_refresh()
+ * but the NFS mount is always done outside of the
+ * jails in vnet0. Since the thread credentials won't
+ * necessarily have cr_prison == vnet0 and this function
+ * has no access to the socket, using vnet0 seems the
+ * only option. This is broken if NFS mounts are enabled
+ * within vnet prisons.
+ */
+ KGSS_CURVNET_SET_QUIET(vnet0);
+ /*
* For KerberosV, if there is a client principal name, that implies
* that this is a host based initiator credential in the default
* keytab file. For this case, it is necessary to do a
@@ -994,12 +1006,14 @@ out:
gss_delete_sec_context(&min_stat, &gd->gd_ctx,
GSS_C_NO_BUFFER);
}
+ KGSS_CURVNET_RESTORE();
mtx_lock(&gd->gd_lock);
gd->gd_state = RPCSEC_GSS_START;
wakeup(gd);
mtx_unlock(&gd->gd_lock);
return (FALSE);
}
+ KGSS_CURVNET_RESTORE();
mtx_lock(&gd->gd_lock);
gd->gd_state = RPCSEC_GSS_ESTABLISHED;
diff --git a/sys/rpc/rpcsec_tls/rpctls_impl.c b/sys/rpc/rpcsec_tls/rpctls_impl.c
index 93fe283e65fd..51fe270b13d9 100644
--- a/sys/rpc/rpcsec_tls/rpctls_impl.c
+++ b/sys/rpc/rpcsec_tls/rpctls_impl.c
@@ -240,6 +240,14 @@ rpctls_rpc_failed(struct upsock *ups, struct socket *so)
* failed to do the handshake.
*/
mtx_unlock(&rpctls_lock);
+ /*
+ * Do a shutdown on the socket, since the daemon is
+ * probably stuck in SSL_accept() or SSL_connect() trying to
+ * read the socket. Do not soclose() the socket, since the
+ * daemon will close() the socket after SSL_accept()
+ * returns an error.
+ */
+ soshutdown(so, SHUT_RD);
}
}
diff --git a/sys/sys/exterrvar.h b/sys/sys/exterrvar.h
index 15557c614f88..7bf1d264ff5e 100644
--- a/sys/sys/exterrvar.h
+++ b/sys/sys/exterrvar.h
@@ -21,6 +21,7 @@
#define EXTERRCTL_ENABLE 1
#define EXTERRCTL_DISABLE 2
+#define EXTERRCTL_UD 3
#define EXTERRCTLF_FORCE 0x00000001
diff --git a/sys/sys/inotify.h b/sys/sys/inotify.h
index 65dc5dba43f3..d1f23d5898bb 100644
--- a/sys/sys/inotify.h
+++ b/sys/sys/inotify.h
@@ -107,11 +107,18 @@ void vn_inotify_revoke(struct vnode *);
} while (0)
/* Log an inotify event using a specific name for the vnode. */
-#define INOTIFY_NAME(vp, dvp, cnp, ev) do { \
+#define INOTIFY_NAME_LOCK(vp, dvp, cnp, ev, lock) do { \
if (__predict_false((vn_irflag_read(vp) & VIRF_INOTIFY) != 0 || \
- (vn_irflag_read(dvp) & VIRF_INOTIFY) != 0)) \
+ (vn_irflag_read(dvp) & VIRF_INOTIFY) != 0)) { \
+ if (lock) \
+ vn_lock((vp), LK_SHARED | LK_RETRY); \
VOP_INOTIFY((vp), (dvp), (cnp), (ev), 0); \
+ if (lock) \
+ VOP_UNLOCK(vp); \
+ } \
} while (0)
+#define INOTIFY_NAME(vp, dvp, cnp, ev) \
+ INOTIFY_NAME_LOCK((vp), (dvp), (cnp), (ev), false)
extern __uint32_t inotify_rename_cookie;
@@ -126,7 +133,8 @@ extern __uint32_t inotify_rename_cookie;
VOP_INOTIFY((vp), (tdvp), (tcnp), IN_MOVED_TO, cookie); \
} \
if ((tvp) != NULL) \
- INOTIFY_NAME((tvp), (tdvp), (tcnp), _IN_MOVE_DELETE); \
+ INOTIFY_NAME_LOCK((tvp), (tdvp), (tcnp), \
+ _IN_MOVE_DELETE, true); \
} while (0)
#define INOTIFY_REVOKE(vp) do { \
diff --git a/sys/sys/param.h b/sys/sys/param.h
index af116d6e3f7a..bd739eacae6f 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -74,7 +74,7 @@
* cannot include sys/param.h and should only be updated here.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1500051
+#define __FreeBSD_version 1500053
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/sys/random.h b/sys/sys/random.h
index 254ba9451d0a..5abf762cd200 100644
--- a/sys/sys/random.h
+++ b/sys/sys/random.h
@@ -85,7 +85,8 @@ enum random_entropy_source {
RANDOM_FS_ATIME,
RANDOM_UMA, /* Special!! UMA/SLAB Allocator */
RANDOM_CALLOUT,
- RANDOM_ENVIRONMENTAL_END = RANDOM_CALLOUT,
+ RANDOM_RANDOMDEV,
+ RANDOM_ENVIRONMENTAL_END = RANDOM_RANDOMDEV,
/* Fast hardware random-number sources from here on. */
RANDOM_PURE_START,
RANDOM_PURE_OCTEON = RANDOM_PURE_START,
diff --git a/sys/vm/swap_pager.c b/sys/vm/swap_pager.c
index 86b75a2d7989..d6bd06226d04 100644
--- a/sys/vm/swap_pager.c
+++ b/sys/vm/swap_pager.c
@@ -384,8 +384,8 @@ swap_release_by_cred(vm_ooffset_t decr, struct ucred *cred)
#endif
}
-static int swap_pager_full = 2; /* swap space exhaustion (task killing) */
-static int swap_pager_almost_full = 1; /* swap space exhaustion (w/hysteresis)*/
+static bool swap_pager_full = true; /* swap space exhaustion (task killing) */
+static bool swap_pager_almost_full = true; /* swap space exhaustion (w/hysteresis) */
static struct mtx swbuf_mtx; /* to sync nsw_wcount_async */
static int nsw_wcount_async; /* limit async write buffers */
static int nsw_wcount_async_max;/* assigned maximum */
@@ -642,14 +642,14 @@ swp_sizecheck(void)
{
if (swap_pager_avail < nswap_lowat) {
- if (swap_pager_almost_full == 0) {
+ if (!swap_pager_almost_full) {
printf("swap_pager: out of swap space\n");
- swap_pager_almost_full = 1;
+ swap_pager_almost_full = true;
}
} else {
- swap_pager_full = 0;
+ swap_pager_full = false;
if (swap_pager_avail > nswap_hiwat)
- swap_pager_almost_full = 0;
+ swap_pager_almost_full = false;
}
}
@@ -958,11 +958,10 @@ swp_pager_getswapspace(int *io_npages)
swp_sizecheck();
swdevhd = TAILQ_NEXT(sp, sw_list);
} else {
- if (swap_pager_full != 2) {
+ if (!swap_pager_full) {
printf("swp_pager_getswapspace(%d): failed\n",
*io_npages);
- swap_pager_full = 2;
- swap_pager_almost_full = 1;
+ swap_pager_full = swap_pager_almost_full = true;
}
swdevhd = NULL;
}
@@ -2863,10 +2862,8 @@ swapoff_one(struct swdevt *sp, struct ucred *cred, u_int flags)
sp->sw_id = NULL;
TAILQ_REMOVE(&swtailq, sp, sw_list);
nswapdev--;
- if (nswapdev == 0) {
- swap_pager_full = 2;
- swap_pager_almost_full = 1;
- }
+ if (nswapdev == 0)
+ swap_pager_full = swap_pager_almost_full = true;
if (swdevhd == sp)
swdevhd = NULL;
mtx_unlock(&sw_dev_mtx);
diff --git a/sys/vm/vm_pagequeue.h b/sys/vm/vm_pagequeue.h
index cbbd27389662..9bd3b389fb60 100644
--- a/sys/vm/vm_pagequeue.h
+++ b/sys/vm/vm_pagequeue.h
@@ -260,9 +260,9 @@ struct vm_domain {
u_int vmd_inactive_shortage; /* Per-thread shortage. */
blockcount_t vmd_inactive_running; /* Number of inactive threads. */
blockcount_t vmd_inactive_starting; /* Number of threads started. */
- volatile u_int vmd_addl_shortage; /* Shortage accumulator. */
- volatile u_int vmd_inactive_freed; /* Successful inactive frees. */
- volatile u_int vmd_inactive_us; /* Microseconds for above. */
+ u_int vmd_addl_shortage; /* (a) Shortage accumulator. */
+ u_int vmd_inactive_freed; /* (a) Successful inactive frees. */
+ u_int vmd_inactive_us; /* (a) Microseconds for above. */
u_int vmd_inactive_pps; /* Exponential decay frees/second. */
int vmd_oom_seq;
int vmd_last_active_scan;
diff --git a/tests/ci/tools/freebsdci b/tests/ci/tools/freebsdci
index 7b4ce9669ab2..51bd19e2967d 100755
--- a/tests/ci/tools/freebsdci
+++ b/tests/ci/tools/freebsdci
@@ -25,9 +25,6 @@
. /etc/rc.subr
-: ${freebsdci_enable:="NO"}
-: ${freebsdci_type:="full"}
-
name="freebsdci"
desc="Run FreeBSD CI"
rcvar=freebsdci_enable
@@ -39,6 +36,11 @@ tardev=/dev/vtbd1
metadir=/meta
istar=$(file -s ${tardev} | grep "POSIX tar archive" | wc -l)
+load_rc_config $name
+: ${freebsdci_enable:="NO"}
+: ${freebsdci_type:="full"}
+PATH="${PATH}:/usr/local/sbin:/usr/local/bin"
+
auto_shutdown()
{
# NOTE: Currently RISC-V kernels lack the ability to
@@ -105,5 +107,4 @@ firstboot_ci_run()
auto_shutdown
}
-load_rc_config $name
run_rc_command "$1"
diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile
index f2c24ad9dec9..336e73f29835 100644
--- a/tests/sys/kern/Makefile
+++ b/tests/sys/kern/Makefile
@@ -17,6 +17,7 @@ ATF_TESTS_C+= kern_copyin
ATF_TESTS_C+= kern_descrip_test
# One test modifies the maxfiles limit, which can cause spurious test failures.
TEST_METADATA.kern_descrip_test+= is_exclusive="true"
+ATF_TESTS_C+= exterr_test
ATF_TESTS_C+= fdgrowtable_test
ATF_TESTS_C+= getdirentries_test
ATF_TESTS_C+= jail_lookup_root
diff --git a/tests/sys/kern/exterr_test.c b/tests/sys/kern/exterr_test.c
new file mode 100644
index 000000000000..17c84c1f8ed4
--- /dev/null
+++ b/tests/sys/kern/exterr_test.c
@@ -0,0 +1,108 @@
+/*-
+ * Copyright (C) 2025 ConnectWise, LLC. 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 <sys/exterrvar.h>
+#include <sys/mman.h>
+
+#include <atf-c.h>
+#include <errno.h>
+#include <exterr.h>
+#include <stdio.h>
+
+ATF_TC(gettext_extended);
+ATF_TC_HEAD(gettext_extended, tc)
+{
+ atf_tc_set_md_var(tc, "descr", "Retrieve an extended error message");
+}
+ATF_TC_BODY(gettext_extended, tc)
+{
+ char exterr[UEXTERROR_MAXLEN];
+ int r;
+
+ /*
+ * Use an invalid call to mmap() because it supports extended error
+ * messages, requires no special resources, and does not need root.
+ */
+ ATF_CHECK_ERRNO(ENOTSUP,
+ mmap(NULL, 0, PROT_MAX(PROT_READ) | PROT_WRITE, 0, -1, 0));
+ r = uexterr_gettext(exterr, sizeof(exterr));
+ ATF_CHECK_EQ(0, r);
+ printf("Extended error: %s\n", exterr);
+ /* Note: error string may need to be updated due to kernel changes */
+ ATF_CHECK(strstr(exterr, "prot is not subset of max_prot") != 0);
+}
+
+ATF_TC(gettext_noextended);
+ATF_TC_HEAD(gettext_noextended, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Fail to retrieve an extended error message because none exists");
+}
+ATF_TC_BODY(gettext_noextended, tc)
+{
+ char exterr[UEXTERROR_MAXLEN];
+ int r;
+
+ ATF_CHECK_ERRNO(EINVAL, exterrctl(EXTERRCTL_UD, 0, NULL));
+ r = uexterr_gettext(exterr, sizeof(exterr));
+ ATF_CHECK_EQ(0, r);
+ ATF_CHECK_STREQ(exterr, "");
+}
+
+ATF_TC(gettext_noextended_after_extended);
+ATF_TC_HEAD(gettext_noextended_after_extended, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "uexterr_gettext should not return a stale extended error message");
+}
+ATF_TC_BODY(gettext_noextended_after_extended, tc)
+{
+ char exterr[UEXTERROR_MAXLEN];
+ int r;
+
+ /*
+ * First do something that will create an extended error message, but
+ * ignore it.
+ */
+ ATF_CHECK_ERRNO(ENOTSUP,
+ mmap(NULL, 0, PROT_MAX(PROT_READ) | PROT_WRITE, 0, -1, 0));
+
+ /* Then do something that won't create an extended error message */
+ ATF_CHECK_ERRNO(EINVAL, exterrctl(EXTERRCTL_UD, 0, NULL));
+
+ /* Hopefully we won't see the stale extended error message */
+ r = uexterr_gettext(exterr, sizeof(exterr));
+ ATF_CHECK_EQ(0, r);
+ ATF_CHECK_STREQ(exterr, "");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, gettext_extended);
+ ATF_TP_ADD_TC(tp, gettext_noextended);
+ ATF_TP_ADD_TC(tp, gettext_noextended_after_extended);
+
+ return (atf_no_error());
+}
diff --git a/tests/sys/netinet6/addr6.sh b/tests/sys/netinet6/addr6.sh
index 38e4bb152240..6fd66d5aa0c7 100755
--- a/tests/sys/netinet6/addr6.sh
+++ b/tests/sys/netinet6/addr6.sh
@@ -39,7 +39,32 @@ addr6_invalid_addr_cleanup()
vnet_cleanup
}
+atf_test_case "anycast_raw_addr" "cleanup"
+anycast_raw_addr_head()
+{
+ atf_set descr "a raw socket can bind to an anycast address"
+ atf_set require.user root
+}
+
+anycast_raw_addr_body()
+{
+ # lo0 needs to be up in the test jail for this test to work
+ ifconfig lo0 up
+
+ netif=$(ifconfig lo create)
+ echo $netif >netif
+ atf_check -s exit:0 ifconfig $netif inet6 2001:db8::1/128 up
+ atf_check -s exit:0 ifconfig $netif inet6 2001:db8::2/128 anycast
+ atf_check -s exit:0 -o ignore ping -c1 -S 2001:db8::2 2001:db8::1
+}
+
+anycast_raw_addr_cleanup()
+{
+ ifconfig $(cat netif) destroy
+}
+
atf_init_test_cases()
{
atf_add_test_case "addr6_invalid_addr"
+ atf_add_test_case "anycast_raw_addr"
}
diff --git a/tests/sys/netpfil/pf/mbuf.sh b/tests/sys/netpfil/pf/mbuf.sh
index d845f793a969..e3f138bb73b9 100644
--- a/tests/sys/netpfil/pf/mbuf.sh
+++ b/tests/sys/netpfil/pf/mbuf.sh
@@ -105,6 +105,12 @@ inet6_in_mbuf_len_body()
epair=$(vnet_mkepair)
ifconfig ${epair}a inet6 2001:db8::1/64 up no_dad
+ # Ensure we don't unintentionally send MLD packets to alcatraz
+ pfctl -e
+ echo "block
+ pass out inet6 proto icmp6 icmp6-type { neighbrsol, neighbradv, echoreq, echorep }
+ " | pfctl -g -f -
+
# Set up a simple jail with one interface
vnet_mkjail alcatraz ${epair}b
jexec alcatraz ifconfig ${epair}b inet6 2001:db8::2/64 up no_dad
diff --git a/tests/sys/netpfil/pf/nat64.py b/tests/sys/netpfil/pf/nat64.py
index adae2489ce5e..5cc4713a16cc 100644
--- a/tests/sys/netpfil/pf/nat64.py
+++ b/tests/sys/netpfil/pf/nat64.py
@@ -272,3 +272,18 @@ class TestNAT64(VnetTestTemplate):
reply = self.common_test_source_addr(packet)
icmp = reply.getlayer(sp.ICMPv6EchoRequest)
assert icmp
+
+ @pytest.mark.require_user("root")
+ @pytest.mark.require_progs(["scapy"])
+ def test_bad_len(self):
+ """
+ PR 288224: we can panic if the IPv6 plen is longer than the packet length.
+ """
+ ToolsHelper.print_output("/sbin/route -6 add default 2001:db8::1")
+ import scapy.all as sp
+
+ packet = sp.IPv6(dst="64:ff9b::198.51.100.2", hlim=2, plen=512) \
+ / sp.ICMPv6EchoRequest() / sp.Raw("foo")
+ reply = sp.sr1(packet, timeout=3)
+ # We don't expect a reply to a corrupted packet
+ assert not reply
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index 1e63e4616909..4c127b392138 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -1441,6 +1441,10 @@ OLD_LIBS+=${DEBUG_LIBS}
.endif
.endif
+.if ${MK_DETECT_TZ_CHANGES} == no
+OLD_FILES+=tests/lib/libc/stdtime/detect_tz_changes_test
+.endif
+
.if ${MK_DIALOG} == no
OLD_FILES+=usr/bin/dialog
OLD_FILES+=usr/bin/dpv
diff --git a/tools/test/stress2/misc/all.exclude b/tools/test/stress2/misc/all.exclude
index f8a5ea4a91f1..54524c92eac0 100644
--- a/tools/test/stress2/misc/all.exclude
+++ b/tools/test/stress2/misc/all.exclude
@@ -16,8 +16,6 @@ fsck12.sh Waiting for fix 20230319
fsync.sh panic: Journal overflow 20190208
fuse.sh https://people.freebsd.org/~pho/stress/log/log0546.txt 20240828
fuse2.sh https://people.freebsd.org/~pho/stress/log/log0547.txt 20240828
-getrandom.sh Known DoS issue 20201107
-getrandom2.sh Known DoS issue 20200302
gjournal.sh panic: Journal overflow 20190626
gjournal2.sh panic: Journal overflow 20180125
gjournal3.sh panic: Bio not on queue 20171225
@@ -34,6 +32,7 @@ maxvnodes2.sh https://people.freebsd.org/~pho/stress/log/log0083.txt 20210329
memguard.sh https://people.freebsd.org/~pho/stress/log/log0088.txt 20210402
memguard2.sh Waiting for fix commit
memguard3.sh Waiting for fix commit
+mount7.sh https://people.freebsd.org/~pho/stress/log/log0549.txt 20240912
mlockall2.sh Unrecoverable OOM killing seen 20190203
mlockall6.sh https://people.freebsd.org/~pho/stress/log/log0430.txt 20230403
mlockall7.sh Needs further investigation 20210123
@@ -46,6 +45,7 @@ nfs16.sh panic: Failed to register NFS lock locally - error=11 20160608
nullfs28.sh Hang in "mount drain" seen 20220111
oom2.sh Hang in pfault 20180324
overcommit2.sh CAM stuck in vmwait seen 20200112
+pmc4.sh https://people.freebsd.org/~pho/stress/log/log0548.txt 20240904
pmc8.sh panic: [pmc,2749] (ri21, rc1) waiting too long for pmc to ... 20210621
rename14.sh https://people.freebsd.org/~pho/stress/log/log0433.txt 20230409
sctp2.sh panic: Queues are not empty when handling SHUTDOWN-COMPLETE 20210211
@@ -71,8 +71,12 @@ syzkaller59.sh Page fault 20220625
syzkaller65.sh panic: in_pcblookup_hash_locked: invalid local address 20230318
syzkaller66.sh panic: in_pcbconnect: inp is already connected 20230621
syzkaller67.sh panic: ASan: Invalid access, 8-byte read at ... 20230621
+syzkaller80.sh panic 20250711
+syzkaller81.sh panic 20250711
quota6.sh https://people.freebsd.org/~pho/stress/log/log0456.txt 20240707
truss3.sh WiP 20200915
+zfs18.sh https://people.freebsd.org/~pho/stress/log/log0560.txt 20241118
+zfs9.sh panic: sacked_bytes < 0 20250711
# Test not to run for other reasons:
diff --git a/tools/test/stress2/misc/fullpath2.sh b/tools/test/stress2/misc/fullpath2.sh
index e4024c32f317..413f832420d4 100755
--- a/tools/test/stress2/misc/fullpath2.sh
+++ b/tools/test/stress2/misc/fullpath2.sh
@@ -123,7 +123,7 @@ static volatile u_int *share;
#define NB 1024
#define RUNTIME 300
-/* dtrace -w -n 'fbt::*vn_fullpath1:entry {@rw[execname,probefunc] = count(); }' */
+/* dtrace -n 'fbt::vn_fullpath:entry {@rw[execname,probefunc] = count(); }' */
static void
getfiles(pid_t pid)
diff --git a/tools/test/stress2/misc/syzkaller80.sh b/tools/test/stress2/misc/syzkaller80.sh
new file mode 100755
index 000000000000..31eae210d5b3
--- /dev/null
+++ b/tools/test/stress2/misc/syzkaller80.sh
@@ -0,0 +1,320 @@
+#!/bin/sh
+
+# panic: ../../../kern/uipc_usrreq.c:1256: uipc_sosend_stream_or_seqpacket: Empty stailq 0xfffffe00ffe5fc88->stqh_last is 0xfffffe00ffe5fcd0, not head's first field address
+# cpuid = 5
+# time = 1749593630
+# KDB: stack backtrace:
+# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe00ffe5fab0
+# vpanic() at vpanic+0x136/frame 0xfffffe00ffe5fbe0
+# panic() at panic+0x43/frame 0xfffffe00ffe5fc40
+# uipc_sosend_stream_or_seqpacket() at uipc_sosend_stream_or_seqpacket+0xa39/frame 0xfffffe00ffe5fd10
+# sousrsend() at sousrsend+0x79/frame 0xfffffe00ffe5fd70
+# dofilewrite() at dofilewrite+0x81/frame 0xfffffe00ffe5fdc0
+# sys_writev() at sys_writev+0x69/frame 0xfffffe00ffe5fe00
+# amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe00ffe5ff30
+# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe00ffe5ff30
+# --- syscall (0, FreeBSD ELF64, syscall), rip = 0x82330181a, rsp = 0x8238dbf68, rbp = 0x8238dbf90 ---
+# KDB: enter: panic
+# [ thread pid 4484 tid 101524 ]
+# Stopped at kdb_enter+0x33: movq $0,0x122ebc2(%rip)
+# db> x/s version
+# version: FreeBSD 15.0-CURRENT #0 main-n277833-948078b65c27-dirty: Tue Jun 10 06:01:36 CEST 2025
+# pho@mercat1.netperf.freebsd.org:/usr/src/sys/amd64/compile/PHO
+# db>
+
+[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
+
+. ../default.cfg
+set -u
+prog=$(basename "$0" .sh)
+cat > /tmp/$prog.c <<EOF
+// https://syzkaller.appspot.com/bug?id=210ae0bfcef6324abfffbfaf10120b767106a990
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+// syzbot+cfcb8520b0071b548fba@syzkaller.appspotmail.com
+
+#define _GNU_SOURCE
+
+#include <sys/types.h>
+
+#include <errno.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/endian.h>
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+static unsigned long long procid;
+
+static void kill_and_wait(int pid, int* status)
+{
+ kill(pid, SIGKILL);
+ while (waitpid(-1, status, 0) != pid) {
+ }
+}
+
+static void sleep_ms(uint64_t ms)
+{
+ usleep(ms * 1000);
+}
+
+static uint64_t current_time_ms(void)
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts))
+ exit(1);
+ return (uint64_t)ts.tv_sec * 1000 + (uint64_t)ts.tv_nsec / 1000000;
+}
+
+static void thread_start(void* (*fn)(void*), void* arg)
+{
+ pthread_t th;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setstacksize(&attr, 128 << 10);
+ int i = 0;
+ for (; i < 100; i++) {
+ if (pthread_create(&th, &attr, fn, arg) == 0) {
+ pthread_attr_destroy(&attr);
+ return;
+ }
+ if (errno == EAGAIN) {
+ usleep(50);
+ continue;
+ }
+ break;
+ }
+ exit(1);
+}
+
+typedef struct {
+ pthread_mutex_t mu;
+ pthread_cond_t cv;
+ int state;
+} event_t;
+
+static void event_init(event_t* ev)
+{
+ if (pthread_mutex_init(&ev->mu, 0))
+ exit(1);
+ if (pthread_cond_init(&ev->cv, 0))
+ exit(1);
+ ev->state = 0;
+}
+
+static void event_reset(event_t* ev)
+{
+ ev->state = 0;
+}
+
+static void event_set(event_t* ev)
+{
+ pthread_mutex_lock(&ev->mu);
+ if (ev->state)
+ exit(1);
+ ev->state = 1;
+ pthread_mutex_unlock(&ev->mu);
+ pthread_cond_broadcast(&ev->cv);
+}
+
+static void event_wait(event_t* ev)
+{
+ pthread_mutex_lock(&ev->mu);
+ while (!ev->state)
+ pthread_cond_wait(&ev->cv, &ev->mu);
+ pthread_mutex_unlock(&ev->mu);
+}
+
+static int event_isset(event_t* ev)
+{
+ pthread_mutex_lock(&ev->mu);
+ int res = ev->state;
+ pthread_mutex_unlock(&ev->mu);
+ return res;
+}
+
+static int event_timedwait(event_t* ev, uint64_t timeout)
+{
+ uint64_t start = current_time_ms();
+ uint64_t now = start;
+ pthread_mutex_lock(&ev->mu);
+ for (;;) {
+ if (ev->state)
+ break;
+ uint64_t remain = timeout - (now - start);
+ struct timespec ts;
+ ts.tv_sec = remain / 1000;
+ ts.tv_nsec = (remain % 1000) * 1000 * 1000;
+ pthread_cond_timedwait(&ev->cv, &ev->mu, &ts);
+ now = current_time_ms();
+ if (now - start > timeout)
+ break;
+ }
+ int res = ev->state;
+ pthread_mutex_unlock(&ev->mu);
+ return res;
+}
+
+struct thread_t {
+ int created, call;
+ event_t ready, done;
+};
+
+static struct thread_t threads[16];
+static void execute_call(int call);
+static int running;
+
+static void* thr(void* arg)
+{
+ struct thread_t* th = (struct thread_t*)arg;
+ for (;;) {
+ event_wait(&th->ready);
+ event_reset(&th->ready);
+ execute_call(th->call);
+ __atomic_fetch_sub(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->done);
+ }
+ return 0;
+}
+
+static void execute_one(void)
+{
+ if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
+ }
+ int i, call, thread;
+ for (call = 0; call < 5; call++) {
+ for (thread = 0; thread < (int)(sizeof(threads) / sizeof(threads[0]));
+ thread++) {
+ struct thread_t* th = &threads[thread];
+ if (!th->created) {
+ th->created = 1;
+ event_init(&th->ready);
+ event_init(&th->done);
+ event_set(&th->done);
+ thread_start(thr, th);
+ }
+ if (!event_isset(&th->done))
+ continue;
+ event_reset(&th->done);
+ th->call = call;
+ __atomic_fetch_add(&running, 1, __ATOMIC_RELAXED);
+ event_set(&th->ready);
+ if (call == 2)
+ break;
+ event_timedwait(&th->done, 50);
+ break;
+ }
+ }
+ for (i = 0; i < 100 && __atomic_load_n(&running, __ATOMIC_RELAXED); i++)
+ sleep_ms(1);
+}
+
+static void execute_one(void);
+
+#define WAIT_FLAGS 0
+
+static void loop(void)
+{
+ int iter = 0;
+ for (;; iter++) {
+ int pid = fork();
+ if (pid < 0)
+ exit(1);
+ if (pid == 0) {
+ execute_one();
+ exit(0);
+ }
+ int status = 0;
+ uint64_t start = current_time_ms();
+ for (;;) {
+ sleep_ms(10);
+ if (waitpid(-1, &status, WNOHANG | WAIT_FLAGS) == pid)
+ break;
+ if (current_time_ms() - start < 5000)
+ continue;
+ kill_and_wait(pid, &status);
+ break;
+ }
+ }
+}
+
+uint64_t r[2] = {0xffffffffffffffff, 0xffffffffffffffff};
+
+void execute_call(int call)
+{
+ intptr_t res = 0;
+ switch (call) {
+ case 0:
+ res = syscall(SYS_socketpair, /*domain=*/1ul, /*type=SOCK_STREAM*/ 1ul,
+ /*proto=*/0, /*fds=*/0x200000000040ul);
+ if (res != -1) {
+ r[0] = *(uint32_t*)0x200000000040;
+ r[1] = *(uint32_t*)0x200000000044;
+ }
+ break;
+ case 1:
+ memcpy((void*)0x200000000100, "\x09\x00\x10\x00", 4);
+ syscall(SYS_setsockopt, /*fd=*/r[1], /*level=*/0, /*optname=*/3,
+ /*optval=*/0x200000000100ul, /*optlen=*/4ul);
+ break;
+ case 2:
+ *(uint64_t*)0x2000000018c0 = 0;
+ *(uint32_t*)0x2000000018c8 = 0;
+ *(uint64_t*)0x2000000018d0 = 0;
+ *(uint64_t*)0x2000000018d8 = 0;
+ *(uint64_t*)0x2000000018e0 = 0x200000001880;
+ memcpy((void*)0x200000001880, "\x10\x00\x00\x00\xff\xff\x00\x00\x06", 9);
+ *(uint64_t*)0x2000000018e8 = 0x10;
+ *(uint32_t*)0x2000000018f0 = 0;
+ syscall(SYS_sendmsg, /*fd=*/r[0], /*msg=*/0x2000000018c0ul, /*f=*/0ul);
+ for (int i = 0; i < 64; i++) {
+ syscall(SYS_sendmsg, /*fd=*/r[0], /*msg=*/0x2000000018c0ul, /*f=*/0ul);
+ }
+ break;
+ case 3:
+ syscall(SYS_writev, /*fd=*/r[0], /*vec=*/0ul, /*vlen=*/0ul);
+ for (int i = 0; i < 64; i++) {
+ syscall(SYS_writev, /*fd=*/r[0], /*vec=*/0ul, /*vlen=*/0ul);
+ }
+ break;
+ case 4:
+ syscall(SYS_setsockopt, /*fd=*/(intptr_t)-1, /*level=*/0, /*optname=*/0xa,
+ /*optval=*/0ul, /*optlen=*/0ul);
+ break;
+ }
+}
+int main(void)
+{
+ syscall(SYS_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul,
+ /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul,
+ /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x1012ul,
+ /*fd=*/(intptr_t)-1, /*offset=*/0ul);
+ const char* reason;
+ (void)reason;
+ for (procid = 0; procid < 4; procid++) {
+ if (fork() == 0) {
+ loop();
+ }
+ }
+ sleep(1000000);
+ return 0;
+}
+EOF
+mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c -lpthread || exit 1
+
+work=/tmp/$prog.dir
+rm -rf $work
+mkdir $work
+cd /tmp/$prog.dir
+timeout 3m /tmp/$prog > /dev/null 2>&1
+
+rm -rf /tmp/$prog /tmp/$prog.c /tmp/$prog.core /tmp/$prog.?????? $work
+exit 0
diff --git a/tools/test/stress2/misc/syzkaller81.sh b/tools/test/stress2/misc/syzkaller81.sh
new file mode 100755
index 000000000000..e3e4ec50aeea
--- /dev/null
+++ b/tools/test/stress2/misc/syzkaller81.sh
@@ -0,0 +1,72 @@
+#!/bin/sh
+
+# panic: kern_clock_gettime: 22
+# cpuid = 1
+# time = 1750181240
+# KDB: stack backtrace:
+# db_trace_self_wrapper() at db_trace_self_wrapper+0x2b/frame 0xfffffe01a6084ba0
+# vpanic() at vpanic+0x136/frame 0xfffffe01a6084cd0
+# panic() at panic+0x43/frame 0xfffffe01a6084d30
+# kern_clock_nanosleep() at kern_clock_nanosleep+0x38f/frame 0xfffffe01a6084db0
+# sys_clock_nanosleep() at sys_clock_nanosleep+0x49/frame 0xfffffe01a6084e00
+# amd64_syscall() at amd64_syscall+0x169/frame 0xfffffe01a6084f30
+# fast_syscall_common() at fast_syscall_common+0xf8/frame 0xfffffe01a6084f30
+# --- syscall (0, FreeBSD ELF64, syscall), rip = 0x8233d281a, rsp = 0x820bfb2b8, rbp = 0x820bfb2e0 ---
+# KDB: enter: panic
+# [ thread pid 26119 tid 104417 ]
+# Stopped at kdb_enter+0x33: movq $0,0x122a7b2(%rip)
+# db> x/s version
+# version: FreeBSD 15.0-CURRENT #1 ufs-n278031-3296ff02387b: Tue Jun 17 16:40:44 CEST 2025
+# pho@mercat1.netperf.freebsd.org:/var/tmp/deviant3/sys/amd64/compile/PHO
+# db>
+
+[ `id -u ` -ne 0 ] && echo "Must be root!" && exit 1
+
+. ../default.cfg
+set -u
+prog=$(basename "$0" .sh)
+cat > /tmp/$prog.c <<EOF
+// https://syzkaller.appspot.com/bug?id=5eb7636bc26fcbd20412de35ec10944233b8577d
+// autogenerated by syzkaller (https://github.com/google/syzkaller)
+// syzbot+e17e46b1f0b65027b005@syzkaller.appspotmail.com
+
+#define _GNU_SOURCE
+
+#include <pwd.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/endian.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+int main(void)
+{
+ syscall(SYS_mmap, /*addr=*/0x200000000000ul, /*len=*/0x1000000ul,
+ /*prot=PROT_WRITE|PROT_READ|PROT_EXEC*/ 7ul,
+ /*flags=MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE*/ 0x1012ul,
+ /*fd=*/(intptr_t)-1, /*offset=*/0ul);
+ const char* reason;
+ (void)reason;
+ if (write(1, "executing program\n", sizeof("executing program\n") - 1)) {
+ }
+ *(uint64_t*)0x200000000040 = 0x10000000000;
+ *(uint64_t*)0x200000000048 = 0x4000000;
+ syscall(SYS_clock_nanosleep, /*id=*/0x10ul, /*flags=TIMER_ABSTIME*/ 1ul,
+ /*rqtp=*/0x200000000040ul, /*rmtp=*/0ul);
+ return 0;
+}
+EOF
+mycc -o /tmp/$prog -Wall -Wextra -O0 /tmp/$prog.c || exit 1
+
+work=/tmp/$prog.dir
+rm -rf $work
+mkdir $work
+cd /tmp/$prog.dir
+timeout 3m /tmp/$prog > /dev/null 2>&1
+
+rm -rf /tmp/$prog /tmp/$prog.c /tmp/$prog.core /tmp/$prog.?????? $work
+exit 0
diff --git a/usr.bin/bmake/Makefile.config b/usr.bin/bmake/Makefile.config
index 78babc2f1382..8ff6c81b8c78 100644
--- a/usr.bin/bmake/Makefile.config
+++ b/usr.bin/bmake/Makefile.config
@@ -6,7 +6,7 @@ SRCTOP?= ${.CURDIR:H:H}
# things set by configure
-_MAKE_VERSION?=20250618
+_MAKE_VERSION?=20250707
prefix?= /usr
srcdir= ${SRCTOP}/contrib/bmake
diff --git a/usr.bin/bmake/unit-tests/Makefile b/usr.bin/bmake/unit-tests/Makefile
index 1b9a47febe11..d4ee6f33f862 100644
--- a/usr.bin/bmake/unit-tests/Makefile
+++ b/usr.bin/bmake/unit-tests/Makefile
@@ -1,9 +1,9 @@
# This is a generated file, do NOT edit!
# See contrib/bmake/bsd.after-import.mk
#
-# $Id: Makefile,v 1.239 2025/06/15 21:32:16 sjg Exp $
+# $Id: Makefile,v 1.240 2025/06/30 18:40:54 sjg Exp $
#
-# $NetBSD: Makefile,v 1.367 2025/06/13 20:23:16 rillig Exp $
+# $NetBSD: Makefile,v 1.369 2025/06/29 09:40:13 rillig Exp $
#
# Unit tests for make(1)
#
@@ -61,6 +61,7 @@ rm-tmpdir: .NOMETA
# src/tests/usr.bin/make/t_make.sh as well.
#TESTS+= archive
#TESTS+= archive-suffix
+TESTS+= char-005c-reverse-solidus
TESTS+= cmd-errors
TESTS+= cmd-errors-jobs
TESTS+= cmd-errors-lint
@@ -416,6 +417,7 @@ TESTS+= varmod-to-upper
TESTS+= varmod-undefined
TESTS+= varmod-unique
TESTS+= varname
+TESTS+= varname-circumflex
TESTS+= varname-dollar
TESTS+= varname-dot-alltargets
TESTS+= varname-dot-curdir
@@ -544,7 +546,6 @@ TESTS:= ${TESTS:${BROKEN_TESTS:S,^,N,:ts:}}
# Ideas for more tests:
# char-0020-space.mk
-# char-005C-backslash.mk
# escape-cond-str.mk
# escape-cond-func-arg.mk
# escape-varmod.mk
diff --git a/usr.bin/calendar/calendars/calendar.freebsd b/usr.bin/calendar/calendars/calendar.freebsd
index 0b1a37f43723..1ca63b371f65 100644
--- a/usr.bin/calendar/calendars/calendar.freebsd
+++ b/usr.bin/calendar/calendars/calendar.freebsd
@@ -259,6 +259,7 @@
06/11 Alonso Cardenas Marquez <acm@FreeBSD.org> born in Arequipa, Peru, 1979
06/14 Josh Paetzel <jpaetzel@FreeBSD.org> born in Minneapolis, Minnesota, United States, 1973
06/15 Second quarterly status reports are due on 06/30
+06/15 Aymeric Wibo <obiwac@FreeBSD.org> born in Plaistow, London, United Kingdom, 2004
06/17 Tilman Linneweh <arved@FreeBSD.org> born in Weinheim, Baden-Wuerttemberg, Germany, 1978
06/18 Li-Wen Hsu <lwhsu@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1984
06/18 Roman Bogorodskiy <novel@FreeBSD.org> born in Saratov, Russian Federation, 1986
diff --git a/usr.bin/du/du.1 b/usr.bin/du/du.1
index 37f7d7837b11..1b6d800b0285 100644
--- a/usr.bin/du/du.1
+++ b/usr.bin/du/du.1
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 29, 2024
+.Dd July 16, 2025
.Dt DU 1
.Os
.Sh NAME
@@ -58,7 +58,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl A
Display the apparent size instead of the disk usage.
@@ -225,7 +225,7 @@ Also display a grand total at the end:
.Xr chflags 2 ,
.Xr fts 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr symlink 7 ,
.Xr quot 8
.Sh STANDARDS
diff --git a/usr.bin/iscsictl/iscsictl.8 b/usr.bin/iscsictl/iscsictl.8
index 74394063a007..88c79c297848 100644
--- a/usr.bin/iscsictl/iscsictl.8
+++ b/usr.bin/iscsictl/iscsictl.8
@@ -24,7 +24,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 27, 2018
+.Dd July 16, 2025
.Dt ISCSICTL 8
.Os
.Sh NAME
@@ -88,7 +88,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl A
Add session.
@@ -190,7 +190,7 @@ Disconnect all iSCSI sessions:
.Dl Nm Fl Ra
.Sh SEE ALSO
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr iscsi 4 ,
.Xr iscsi.conf 5 ,
.Xr iscsid 8
diff --git a/usr.bin/last/last.1 b/usr.bin/last/last.1
index f3ccc6e772af..b026ed6a7921 100644
--- a/usr.bin/last/last.1
+++ b/usr.bin/last/last.1
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 9, 2021
+.Dd July 16, 2025
.Dt LAST 1
.Os
.Sh NAME
@@ -75,7 +75,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl d Ar date
Specify the snapshot date and time.
@@ -223,7 +223,7 @@ alice ttyv0 Mon Dec 7 19:18 - 22:27 (03:09)
.Xr lastcomm 1 ,
.Xr getutxent 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr ac 8 ,
.Xr lastlogin 8
.Sh HISTORY
diff --git a/usr.bin/netstat/netstat.1 b/usr.bin/netstat/netstat.1
index cf6a907c6aa4..1931c38a1fad 100644
--- a/usr.bin/netstat/netstat.1
+++ b/usr.bin/netstat/netstat.1
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 30, 2025
+.Dd July 16, 2025
.Dt NETSTAT 1
.Os
.Sh NAME
@@ -166,7 +166,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl 4
Show IPv4 only.
@@ -954,7 +954,7 @@ Show IPv4 listening sockets:
.Xr ps 1 ,
.Xr sockstat 1 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr bpf 4 ,
.Xr inet 4 ,
.Xr route 4 ,
diff --git a/usr.bin/nfsstat/nfsstat.1 b/usr.bin/nfsstat/nfsstat.1
index 7d641b50f1ac..a4a00586f21b 100644
--- a/usr.bin/nfsstat/nfsstat.1
+++ b/usr.bin/nfsstat/nfsstat.1
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 28, 2023
+.Dd July 16, 2025
.Dt NFSSTAT 1
.Os
.Sh NAME
@@ -123,7 +123,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.El
.Sh SEE ALSO
diff --git a/usr.bin/procstat/procstat.1 b/usr.bin/procstat/procstat.1
index 1e05e235e619..b810abf66da7 100644
--- a/usr.bin/procstat/procstat.1
+++ b/usr.bin/procstat/procstat.1
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 7, 2022
+.Dd July 16, 2025
.Dt PROCSTAT 1
.Os
.Sh NAME
@@ -136,7 +136,7 @@ flag is specified the output is generated via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.Pp
The following commands are available for
@@ -870,7 +870,7 @@ procstat: procstat_getprocs()
.Xr libprocstat 3 ,
.Xr libxo 3 ,
.Xr signal 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr ddb 4 ,
.Xr divert 4 ,
.Xr icmp 4 ,
diff --git a/usr.bin/sed/sed.1 b/usr.bin/sed/sed.1
index 345f673310d8..5fd894eaf78b 100644
--- a/usr.bin/sed/sed.1
+++ b/usr.bin/sed/sed.1
@@ -1,3 +1,6 @@
+.\"
+.\" SPDX-License-Identifier: BSD-3-Clause
+.\"
.\" Copyright (c) 1992, 1993
.\" The Regents of the University of California. All rights reserved.
.\"
@@ -28,7 +31,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 17, 2024
+.Dd June 14, 2025
.Dt SED 1
.Os
.Sh NAME
@@ -597,17 +600,17 @@ with
.Ql baz
when piped from another command:
.Bd -literal -offset indent
-echo "An alternate word, like bar, is sometimes used in examples." | sed 's/bar/baz/'
+echo "use bar in examples" | sed 's/bar/baz/'
.Ed
.Pp
Using backlashes can sometimes be hard to read and follow:
.Bd -literal -offset indent
-echo "/home/example" | sed 's/\\/home\\/example/\\/usr\\/local\\/example/'
+echo "/bin/bash" | sed 's/\\/bin\\/bash/\\/bin\\/sh/'
.Ed
.Pp
Using a different separator can be handy when working with paths:
.Bd -literal -offset indent
-echo "/home/example" | sed 's#/home/example#/usr/local/example#'
+echo "/bin/bash" | sed 's#/bin/bash#/bin/sh#'
.Ed
.Pp
Replace all occurrences of
diff --git a/usr.bin/sockstat/sockstat.1 b/usr.bin/sockstat/sockstat.1
index da658e33e542..4832a09764fd 100644
--- a/usr.bin/sockstat/sockstat.1
+++ b/usr.bin/sockstat/sockstat.1
@@ -25,7 +25,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 June 27, 2025
+.Dd June 30, 2025
.Dt SOCKSTAT 1
.Os
.Sh NAME
@@ -33,7 +33,7 @@
.Nd list open sockets
.Sh SYNOPSIS
.Nm
-.Op Fl 46ACcfIiLlnqSsUuv
+.Op Fl 46ACcfIiLlnqSsUuvw
.Op Fl j Ar jail
.Op Fl p Ar ports
.Op Fl P Ar protocols
@@ -119,6 +119,8 @@ Show
sockets.
.It Fl v
Verbose mode.
+.It Fl w
+Automatically size the columns.
.El
.Pp
If neither
diff --git a/usr.bin/sockstat/sockstat.c b/usr.bin/sockstat/sockstat.c
index 1a24ff67c321..d0540c54a1aa 100644
--- a/usr.bin/sockstat/sockstat.c
+++ b/usr.bin/sockstat/sockstat.c
@@ -97,6 +97,7 @@ static bool opt_s; /* Show protocol state if applicable */
static bool opt_U; /* Show remote UDP encapsulation port number */
static bool opt_u; /* Show Unix domain sockets */
static u_int opt_v; /* Verbose mode */
+static bool opt_w; /* Automatically size the columns */
/*
* Default protocols to use if no -P was defined.
@@ -1101,7 +1102,7 @@ format_unix_faddr(struct addr *faddr, char *buf, size_t bufsize) {
/* Remote peer we connect(2) to, if any. */
if (faddr->conn != 0) {
struct sock *p;
- pos += strlcpy(buf, "-> ", bufsize);
+ pos += strlcpy(SAFEBUF, "-> ", SAFESIZE);
p = RB_FIND(pcbs_t, &pcbs,
&(struct sock){ .pcb = faddr->conn });
if (__predict_false(p == NULL)) {
@@ -1132,8 +1133,7 @@ format_unix_faddr(struct addr *faddr, char *buf, size_t bufsize) {
while ((p = RB_FIND(pcbs_t, &pcbs,
&(struct sock){ .pcb = ref })) != 0) {
f = RB_FIND(files_t, &ftree,
- &(struct file){ .xf_data =
- p->socket });
+ &(struct file){ .xf_data = p->socket });
if (f != NULL) {
pos += snprintf(SAFEBUF, SAFESIZE,
"%s[%lu %d]", fref ? "" : ",",
@@ -1178,13 +1178,10 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
len = strlen(s->protoname);
if (s->vflag & (INP_IPV4 | INP_IPV6))
len += 1;
- if (laddr != NULL && faddr != NULL && s->family == AF_UNIX &&
- laddr->address.ss_len == 0 && faddr->conn == 0)
- len += strlen(" (not connected)");
cw->proto = MAX(cw->proto, len);
while (laddr != NULL || faddr != NULL) {
- if (s->family == AF_UNIX) {
+ if (opt_w && s->family == AF_UNIX) {
if ((laddr == NULL) || (faddr == NULL))
errx(1, "laddr = %p or faddr = %p is NULL",
(void *)laddr, (void *)faddr);
@@ -1193,7 +1190,7 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
cw->local_addr = MAX(cw->local_addr, len);
len = format_unix_faddr(faddr, NULL, 0);
cw->foreign_addr = MAX(cw->foreign_addr, len);
- } else {
+ } else if (opt_w) {
if (laddr != NULL) {
len = formataddr(&laddr->address, NULL, 0);
cw->local_addr = MAX(cw->local_addr, len);
@@ -1296,23 +1293,6 @@ calculate_sock_column_widths(struct col_widths *cw, struct sock *s)
static void
calculate_column_widths(struct col_widths *cw)
{
- cw->user = 4;
- cw->command = 10;
- cw->pid = 3;
- cw->fd = 2;
- cw->proto = 5;
- cw->local_addr = 13;
- cw->foreign_addr = 15;
- cw->pcb_kva = 18;
- cw->fib = 3;
- cw->splice_address = 14;
- cw->inp_gencnt = 2;
- cw->encaps = 6;
- cw->path_state = 10;
- cw->conn_state = 10;
- cw->stack = 5;
- cw->cc = 2;
-
int n, len;
struct file *xf;
struct sock *s;
@@ -1366,13 +1346,10 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
faddr = s->faddr;
first = true;
- snprintf(buf, bufsize, "%s%s%s%s",
+ snprintf(buf, bufsize, "%s%s%s",
s->protoname,
s->vflag & INP_IPV4 ? "4" : "",
- s->vflag & INP_IPV6 ? "6" : "",
- (laddr != NULL && faddr != NULL &&
- s->family == AF_UNIX && laddr->address.ss_len == 0 &&
- faddr->conn == 0) ? " (not connected)" : "");
+ s->vflag & INP_IPV6 ? "6" : "");
printf(" %-*s", cw->proto, buf);
while (laddr != NULL || faddr != NULL) {
if (s->family == AF_UNIX) {
@@ -1381,23 +1358,27 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
(void *)laddr, (void *)faddr);
if (laddr->address.ss_len > 0)
formataddr(&laddr->address, buf, bufsize);
+ else if (laddr->address.ss_len == 0 && faddr->conn == 0)
+ strlcpy(buf, "(not connected)", bufsize);
else
strlcpy(buf, "??", bufsize);
- printf(" %-*s", cw->local_addr, buf);
+ printf(" %-*.*s", cw->local_addr, cw->local_addr, buf);
if (format_unix_faddr(faddr, buf, bufsize) == 0)
strlcpy(buf, "??", bufsize);
- printf(" %-*s", cw->foreign_addr, buf);
+ printf(" %-*.*s", cw->foreign_addr,
+ cw->foreign_addr, buf);
} else {
if (laddr != NULL)
formataddr(&laddr->address, buf, bufsize);
else
strlcpy(buf, "??", bufsize);
- printf(" %-*s", cw->local_addr, buf);
+ printf(" %-*.*s", cw->local_addr, cw->local_addr, buf);
if (faddr != NULL)
formataddr(&faddr->address, buf, bufsize);
else
strlcpy(buf, "??", bufsize);
- printf(" %-*s", cw->foreign_addr, buf);
+ printf(" %-*.*s", cw->foreign_addr,
+ cw->foreign_addr, buf);
}
if (opt_A)
printf(" %#*" PRIx64, cw->pcb_kva, s->pcb);
@@ -1411,6 +1392,8 @@ display_sock(struct sock *s, struct col_widths *cw, char *buf, size_t bufsize)
if (sp != NULL)
formataddr(&sp->laddr->address,
buf, bufsize);
+ else
+ strlcpy(buf, "??", bufsize);
} else
strlcpy(buf, "??", bufsize);
printf(" %-*s", cw->splice_address, buf);
@@ -1510,6 +1493,25 @@ display(void)
err(1, "malloc()");
return;
}
+
+ cw = (struct col_widths) {
+ .user = strlen("USER"),
+ .command = 10,
+ .pid = strlen("PID"),
+ .fd = strlen("FD"),
+ .proto = strlen("PROTO"),
+ .local_addr = opt_w ? strlen("LOCAL ADDRESS") : 21,
+ .foreign_addr = opt_w ? strlen("FOREIGN ADDRESS") : 21,
+ .pcb_kva = 18,
+ .fib = strlen("FIB"),
+ .splice_address = strlen("SPLICE ADDRESS"),
+ .inp_gencnt = strlen("ID"),
+ .encaps = strlen("ENCAPS"),
+ .path_state = strlen("PATH STATE"),
+ .conn_state = strlen("CONN STATE"),
+ .stack = strlen("STACK"),
+ .cc = strlen("CC"),
+ };
calculate_column_widths(&cw);
if (!opt_q) {
@@ -1642,7 +1644,7 @@ static void
usage(void)
{
errx(1,
- "usage: sockstat [-46ACcfIiLlnqSsUuv] [-j jid] [-p ports] [-P protocols]");
+ "usage: sockstat [-46ACcfIiLlnqSsUuvw] [-j jid] [-p ports] [-P protocols]");
}
int
@@ -1721,7 +1723,7 @@ main(int argc, char *argv[])
++opt_v;
break;
case 'w':
- /* left for backward compatibility. */
+ opt_w = true;
break;
default:
usage();
diff --git a/usr.bin/top/top.1 b/usr.bin/top/top.1
index d8ef763e7a34..53b078839526 100644
--- a/usr.bin/top/top.1
+++ b/usr.bin/top/top.1
@@ -1,4 +1,4 @@
-.Dd April 1, 2025
+.Dd June 9, 2025
.Dt TOP 1
.Os
.Sh NAME
@@ -398,6 +398,7 @@ ID corresponding to the process,
USERNAME is the name of the process's owner (if
.Fl u
is specified, a UID column will be substituted for USERNAME),
+THR is the thread count, showing the number of threads a process has,
PRI is the current priority of the process,
NICE is the
.Xr nice 1
diff --git a/usr.bin/vmstat/vmstat.8 b/usr.bin/vmstat/vmstat.8
index de4176c9361c..80facb05cc35 100644
--- a/usr.bin/vmstat/vmstat.8
+++ b/usr.bin/vmstat/vmstat.8
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 21, 2021
+.Dd July 16, 2025
.Dt VMSTAT 8
.Os
.Sh NAME
@@ -71,7 +71,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl a
When used with
@@ -371,7 +371,7 @@ statistics every second.
.Xr systat 1 ,
.Xr libmemstat 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr gstat 8 ,
.Xr iostat 8 ,
.Xr pstat 8 ,
diff --git a/usr.bin/w/w.1 b/usr.bin/w/w.1
index a92edc6f0059..159eb3370c8c 100644
--- a/usr.bin/w/w.1
+++ b/usr.bin/w/w.1
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd August 24, 2020
+.Dd July 16, 2025
.Dt W 1
.Os
.Sh NAME
@@ -61,7 +61,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl d
dumps out the entire process list on a per controlling
@@ -145,7 +145,7 @@ flags are no longer supported.
.Xr uptime 1 ,
.Xr who 1 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3
+.Xr xo_options 7
.Sh HISTORY
The
.Nm
diff --git a/usr.bin/wc/wc.1 b/usr.bin/wc/wc.1
index 482145c8f01f..656408794950 100644
--- a/usr.bin/wc/wc.1
+++ b/usr.bin/wc/wc.1
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 11, 2020
+.Dd July 16, 2025
.Dt WC 1
.Os
.Sh NAME
@@ -70,7 +70,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl L
Write the length of the line containing the most bytes (default) or characters
@@ -196,7 +196,7 @@ utility.
.Sh SEE ALSO
.Xr iswspace 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3
+.Xr xo_options 7
.Sh STANDARDS
The
.Nm
diff --git a/usr.sbin/arp/arp.8 b/usr.sbin/arp/arp.8
index d31b2b482ba3..0a171c9e36be 100644
--- a/usr.sbin/arp/arp.8
+++ b/usr.sbin/arp/arp.8
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 13, 2020
+.Dd July 16, 2025
.Dt ARP 8
.Os
.Sh NAME
@@ -80,7 +80,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl a
The program displays or, if it is used with the
@@ -183,7 +183,7 @@ character will mark the rest of the line as a comment.
.Sh SEE ALSO
.Xr inet 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr arp 4 ,
.Xr ifconfig 8 ,
.Xr ndp 8
diff --git a/usr.sbin/bsdinstall/scripts/wlanconfig b/usr.sbin/bsdinstall/scripts/wlanconfig
index 8ac64858eaba..33d94a933f45 100755
--- a/usr.sbin/bsdinstall/scripts/wlanconfig
+++ b/usr.sbin/bsdinstall/scripts/wlanconfig
@@ -92,7 +92,7 @@ dialog_country_select()
sub(/.*domains:/, ""), /[^[:alnum:][[:space:]]/ {
n = split($0, domains)
for (i = 1; i <= n; i++)
- printf "'\''%s'\'' '\'\''", domains[i]
+ printf "'\''%s'\'' '\'\''\n", domains[i]
}
' | sort )
countries=$( echo "$input" | awk '
@@ -200,6 +200,12 @@ fi
while :; do
SCANSSID=0
+ # While wpa_supplicant may IFF_UP the interface, we do not want to rely
+ # in this. In case the script is run manually (outside the installer,
+ # e.g., for testing) wpa_supplicant may be running and the wlanN
+ # interface may be down (especially if dialog_country_select is not
+ # run successfully either) and scanning will not work.
+ f_eval_catch -d wlanconfig ifconfig "ifconfig $WLAN_IFACE up"
f_eval_catch -d wlanconfig wpa_cli "wpa_cli scan"
f_dialog_title "Scanning"
f_dialog_pause "Waiting 5 seconds to scan for wireless networks..." 5 ||
diff --git a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
index 9d5a693c7c68..9252e63749bb 100644
--- a/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
+++ b/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
@@ -1179,8 +1179,10 @@ main(int argc, char ** argv)
/* On -h (help) exit without error. */
if (opt_num == -2)
exit(0);
- else
+ else {
+ fprintf(stderr, "Error: %s\n", snmp_client.error);
exit(1);
+ }
}
oid_cnt = argc - opt_num - 1;
@@ -1239,7 +1241,7 @@ main(int argc, char ** argv)
}
if (snmp_open(NULL, NULL, NULL, NULL)) {
- warn("Failed to open snmp session");
+ fprintf(stderr, "snmp_open(3): %s\n", snmp_client.error);
snmp_tool_freeall(&snmptoolctx);
exit(1);
}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
index fb09e1ac785e..b4613763fff5 100644
--- a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
@@ -790,15 +790,6 @@ parse_server(char *opt_arg)
if (snmp_parse_server(&snmp_client, opt_arg) < 0)
return (-1);
- if (snmp_client.trans > SNMP_TRANS_UDP && snmp_client.chost == NULL) {
- if ((snmp_client.chost = malloc(strlen(SNMP_DEFAULT_LOCAL) + 1))
- == NULL) {
- syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
- return (-1);
- }
- strcpy(snmp_client.chost, SNMP_DEFAULT_LOCAL);
- }
-
return (2);
}
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h
index 2874f311fbd0..54a087491a4f 100644
--- a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.h
@@ -43,7 +43,6 @@
#define MAX_BUFF_SIZE (ASN_MAXOCTETSTRING + 50)
#define SNMP_DEFS_DIR "/usr/share/snmp/defs/"
-#define SNMP_DEFAULT_LOCAL "/var/run/snmpd.sock"
#define SNMP_MAX_REPETITIONS 10
diff --git a/usr.sbin/certctl/certctl.8 b/usr.sbin/certctl/certctl.8
index 286072c1b4d6..7e49bb89e2ac 100644
--- a/usr.sbin/certctl/certctl.8
+++ b/usr.sbin/certctl/certctl.8
@@ -24,7 +24,7 @@
.\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd October 10, 2023
+.Dd July 17, 2025
.Dt CERTCTL 8
.Os
.Sh NAME
@@ -38,15 +38,15 @@
.Op Fl v
.Ic untrusted
.Nm
-.Op Fl nUv
+.Op Fl cnUv
.Op Fl D Ar destdir
.Op Fl M Ar metalog
.Ic rehash
.Nm
-.Op Fl nv
+.Op Fl cnv
.Ic untrust Ar file
.Nm
-.Op Fl nv
+.Op Fl cnv
.Ic trust Ar file
.Sh DESCRIPTION
The
@@ -56,6 +56,8 @@ applications that use OpenSSL.
.Pp
Flags:
.Bl -tag -width 4n
+.It Fl c
+Copy certificates instead of linking to them.
.It Fl D Ar destdir
Specify the DESTDIR (overriding values from the environment).
.It Fl d Ar distbase
diff --git a/usr.sbin/certctl/certctl.sh b/usr.sbin/certctl/certctl.sh
index 458f5c53682f..2bde651de126 100755
--- a/usr.sbin/certctl/certctl.sh
+++ b/usr.sbin/certctl/certctl.sh
@@ -36,6 +36,7 @@ set -u
############################################################ GLOBALS
SCRIPTNAME="${0##*/}"
+LINK=-lrs
ERRORS=0
NOOP=false
UNPRIV=false
@@ -110,7 +111,6 @@ create_trusted()
{
local hash certhash otherfile otherhash
local suffix
- local link=${2:+-lrs}
hash=$(do_hash "$1") || return
certhash=$(openssl x509 -sha1 -in "$1" -noout -fingerprint)
@@ -130,7 +130,7 @@ create_trusted()
done
suffix=$(get_decimal "$CERTDESTDIR" "$hash")
verbose "Adding $hash.$suffix to trust store"
- perform install ${INSTALLFLAGS} -m 0444 ${link} \
+ perform install ${INSTALLFLAGS} -m 0444 ${LINK} \
"$(realpath "$1")" "$CERTDESTDIR/$hash.$suffix"
}
@@ -159,7 +159,6 @@ resolve_certname()
create_untrusted()
{
local srcfile filename
- local link=${2:+-lrs}
set -- $(resolve_certname "$1")
srcfile=$1
@@ -170,7 +169,7 @@ create_untrusted()
fi
verbose "Adding $filename to untrusted list"
- perform install ${INSTALLFLAGS} -m 0444 ${link} \
+ perform install ${INSTALLFLAGS} -m 0444 ${LINK} \
"$srcfile" "$UNTRUSTDESTDIR/$filename"
}
@@ -190,7 +189,7 @@ do_scan()
0)
;;
1)
- "$CFUNC" "$CFILE" link
+ "$CFUNC" "$CFILE"
;;
*)
verbose "Multiple certificates found, splitting..."
@@ -303,19 +302,20 @@ usage()
echo " List trusted certificates"
echo " $SCRIPTNAME [-v] untrusted"
echo " List untrusted certificates"
- echo " $SCRIPTNAME [-nUv] [-D <destdir>] [-d <distbase>] [-M <metalog>] rehash"
- echo " Generate hash links for all certificates"
- echo " $SCRIPTNAME [-nv] untrust <file>"
+ echo " $SCRIPTNAME [-cnUv] [-D <destdir>] [-d <distbase>] [-M <metalog>] rehash"
+ echo " Rehash all trusted and untrusted certificates"
+ echo " $SCRIPTNAME [-cnv] untrust <file>"
echo " Add <file> to the list of untrusted certificates"
- echo " $SCRIPTNAME [-nv] trust <file>"
+ echo " $SCRIPTNAME [-cnv] trust <file>"
echo " Remove <file> from the list of untrusted certificates"
exit 64
}
############################################################ MAIN
-while getopts D:d:M:nUv flag; do
+while getopts cD:d:M:nUv flag; do
case "$flag" in
+ c) LINK=-c ;;
D) DESTDIR=${OPTARG} ;;
d) DISTBASE=${OPTARG} ;;
M) METALOG=${OPTARG} ;;
@@ -334,7 +334,7 @@ fi
: ${METALOG:=${DESTDIR}/METALOG}
INSTALLFLAGS=
if "$UNPRIV" ; then
- INSTALLFLAGS="-U -M ${METALOG} -D ${DESTDIR} -o root -g wheel"
+ INSTALLFLAGS="-U -M ${METALOG} -D ${DESTDIR:-/} -o root -g wheel"
fi
: ${LOCALBASE:=$(sysctl -n user.localbase)}
: ${TRUSTPATH:=${DESTDIR}${DISTBASE}/usr/share/certs/trusted:${DESTDIR}${LOCALBASE}/share/certs:${DESTDIR}${LOCALBASE}/etc/ssl/certs}
diff --git a/usr.sbin/efitable/efitable.8 b/usr.sbin/efitable/efitable.8
index d1f4cedcdea8..bb8a9cc3d0e1 100644
--- a/usr.sbin/efitable/efitable.8
+++ b/usr.sbin/efitable/efitable.8
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 10, 2021
+.Dd July 16, 2025
.Dt EFITABLE 8
.Os
.Sh NAME
@@ -45,7 +45,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl t Ar name Fl -table Ar name
Specify the name of the table to print.
diff --git a/usr.sbin/fwget/Makefile b/usr.sbin/fwget/Makefile
index 1cdf0f18230d..4c934aee3413 100644
--- a/usr.sbin/fwget/Makefile
+++ b/usr.sbin/fwget/Makefile
@@ -2,6 +2,6 @@ PACKAGE= fwget
SCRIPTS= fwget
MAN= fwget.8
-SUBDIR= pci
+SUBDIR= pci usb
.include <bsd.prog.mk>
diff --git a/usr.sbin/fwget/fwget.8 b/usr.sbin/fwget/fwget.8
index 7b8b606cc591..86e304775e2d 100644
--- a/usr.sbin/fwget/fwget.8
+++ b/usr.sbin/fwget/fwget.8
@@ -23,7 +23,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 June 27, 2024
+.Dd July 7, 2025
.Dt FWGET 8
.Os
.Sh NAME
@@ -47,7 +47,11 @@ Dry run, only show needed packages
.It Fl v
Be more verbose
.It Ar subsystem
-Hardware subsystem, default pci
+Hardware subsystem(s), default is all supported subsystems.
+Space separated hardware subsystems, accepts
+.Cm pci
+and
+.Cm usb
.El
.Sh SEE ALSO
.Xr firmware 9
@@ -64,4 +68,8 @@ utility and this manual page were written by
.An Emmanuel Vadot Aq Mt manu@FreeBSD.org
for Beckhoff Automation GmbH & Co\. KG.
.Sh CAVEATS
-This utility currently only supports the pci subsystem.
+This utility currently only supports the
+.Xr pci 4
+and
+.Xr usb 4
+subsystems.
diff --git a/usr.sbin/fwget/fwget.sh b/usr.sbin/fwget/fwget.sh
index 138a2a26bfb1..de1e6fa51f0f 100755
--- a/usr.sbin/fwget/fwget.sh
+++ b/usr.sbin/fwget/fwget.sh
@@ -35,7 +35,7 @@ usage()
Usage: $(basename "$0") [options] [subsystem]
Supported subsystems
- pci
+ pci, usb
Options:
-n -- Do not install packages, only print the results
@@ -100,9 +100,9 @@ done
shift $(($OPTIND - 1))
subsystems="$@"
-# Default searching PCI subsystem
+# Default searching PCI and USB subsystem
if [ -z "${subsystems}" ]; then
- subsystems="pci"
+ subsystems="pci usb"
fi
# Fail early on unsupported subsystem
diff --git a/usr.sbin/fwget/usb/Makefile b/usr.sbin/fwget/usb/Makefile
new file mode 100644
index 000000000000..315e9c743cc8
--- /dev/null
+++ b/usr.sbin/fwget/usb/Makefile
@@ -0,0 +1,10 @@
+PACKAGE= fwget
+
+SCRIPTS=usb \
+ usb_ralink
+
+BINDIR= ${LIBEXECDIR}/fwget
+
+MAN=
+
+.include <bsd.prog.mk>
diff --git a/usr.sbin/fwget/usb/usb b/usr.sbin/fwget/usb/usb
new file mode 100755
index 000000000000..fef6bc76ba89
--- /dev/null
+++ b/usr.sbin/fwget/usb/usb
@@ -0,0 +1,43 @@
+#
+# Copyright 2023 Beckhoff Automation GmbH & Co. KG
+# Copyright 2023 Bjoern A. Zeeb
+# Copyright 2025 Jesper Schmitz Mouridsen
+
+# SPDX-License-Identifier: BSD-2-Clause
+
+
+usb_get_vendor()
+{
+ local hexvendor=$(echo $1 | sed 's/.*idVendor=\(0x[0-9a-z]*\).*/\1/')
+ case "${hexvendor}" in
+ 0x148f) echo "ralink" ;;
+ esac
+}
+
+usb_get_device()
+{
+ local hexdevice=$(echo $1 | sed 's/.*idProduct=\(0x[0-9a-z]*\).*/\1/')
+ echo "${hexdevice}"
+
+}
+
+usb_search_packages()
+{
+ local IFS
+
+ oldifs=$IFS
+ IFS=$'\n'
+ for fulldevice in $(usbconfig -l dump_device_desc); do
+ vendor=$(usb_get_vendor "${fulldevice}")
+ if [ -z "${vendor}" ]; then
+ continue
+ fi
+ device=$(usb_get_device "${fulldevice}")
+ log_verbose "Trying to match device ${device} and vendor ${vendor} with usb_${vendor}"
+ if [ -f ${LIBEXEC_PATH}/usb_${vendor} ]; then
+ . ${LIBEXEC_PATH}/usb_${vendor}
+ usb_${vendor} ${device}
+ fi
+ done
+ IFS=${oldifs}
+}
diff --git a/usr.sbin/fwget/usb/usb_ralink b/usr.sbin/fwget/usb/usb_ralink
new file mode 100755
index 000000000000..8d3135063011
--- /dev/null
+++ b/usr.sbin/fwget/usb/usb_ralink
@@ -0,0 +1,12 @@
+#
+# Copyright (c) 2025 Jesper Schmitz Mouridsen
+#
+# SPDX-License-Identifier: BSD-2-Clause
+
+usb_ralink()
+{
+
+ case "$1" in
+ 0x7601) addpkg "wifi-firmware-mt7601u-kmod"; return 1 ;;
+ esac
+}
diff --git a/usr.sbin/inetd/inetd.conf b/usr.sbin/inetd/inetd.conf
index 40f1e1285af6..a8359ea793f5 100644
--- a/usr.sbin/inetd/inetd.conf
+++ b/usr.sbin/inetd/inetd.conf
@@ -7,8 +7,8 @@
#
#ftp stream tcp nowait root /usr/libexec/ftpd ftpd -l
#ftp stream tcp6 nowait root /usr/libexec/ftpd ftpd -l
-#ssh stream tcp nowait root /usr/sbin/sshd sshd -i -4
-#ssh stream tcp6 nowait root /usr/sbin/sshd sshd -i -6
+#ssh stream tcp nowait root /usr/sbin/sshd sshd -i
+#ssh stream tcp6 nowait root /usr/sbin/sshd sshd -i
#telnet stream tcp nowait root /usr/local/libexec/telnetd telnetd
#telnet stream tcp6 nowait root /usr/local/libexec/telnetd telnetd
#shell stream tcp nowait root /usr/local/sbin/rshd rshd
diff --git a/usr.sbin/lastlogin/lastlogin.8 b/usr.sbin/lastlogin/lastlogin.8
index 3b2d47fdaf76..9fd5c88d02cd 100644
--- a/usr.sbin/lastlogin/lastlogin.8
+++ b/usr.sbin/lastlogin/lastlogin.8
@@ -73,7 +73,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
for details on command line arguments.
.It Fl f Ar file
Open last login database
@@ -93,7 +93,7 @@ last login database
.Xr last 1 ,
.Xr getutxent 3 ,
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr ac 8
.Sh AUTHORS
.An -nosplit
diff --git a/usr.sbin/makefs/ffs.c b/usr.sbin/makefs/ffs.c
index 4efcd20ad91a..c0fcadf11fba 100644
--- a/usr.sbin/makefs/ffs.c
+++ b/usr.sbin/makefs/ffs.c
@@ -1056,7 +1056,7 @@ ffs_make_dirbuf(dirbuf_t *dbuf, const char *name, fsnode *node, int needswap)
reclen = DIRSIZ_SWAP(0, &de, needswap);
de.d_reclen = ufs_rw16(reclen, needswap);
- dp = (struct direct *)(dbuf->buf + dbuf->cur);
+ dp = dbuf->buf == NULL ? NULL : (struct direct *)(dbuf->buf + dbuf->cur);
llen = 0;
if (dp != NULL)
llen = DIRSIZ_SWAP(0, dp, needswap);
diff --git a/usr.sbin/makefs/tests/makefs_msdos_tests.sh b/usr.sbin/makefs/tests/makefs_msdos_tests.sh
index b36b43b3abf6..fb94429b477b 100644
--- a/usr.sbin/makefs/tests/makefs_msdos_tests.sh
+++ b/usr.sbin/makefs/tests/makefs_msdos_tests.sh
@@ -4,7 +4,7 @@
# Copyright (c) 2025 The FreeBSD Foundation
#
# This software was developed by Klara, Inc.
-# under sponsorship from the FreeBSD Foundation and the Sovereign Tech Agency.
+# 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
diff --git a/usr.sbin/sesutil/sesutil.8 b/usr.sbin/sesutil/sesutil.8
index 664dcab593e9..d4960b3ec6bf 100644
--- a/usr.sbin/sesutil/sesutil.8
+++ b/usr.sbin/sesutil/sesutil.8
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 5, 2022
+.Dd July 16, 2025
.Dt SESUTIL 8
.Os
.Sh NAME
@@ -129,7 +129,7 @@ Generate output via
.Xr libxo 3
in a selection of different human and machine readable formats.
See
-.Xr xo_parse_args 3
+.Xr xo_options 7
.El
.Sh EXAMPLES
Turn off all locate LEDs:
@@ -146,7 +146,7 @@ Turn on the fault LED for a drive bay not associated with a device:
.Dl Nm Cm fault -u /dev/ses2 7 on
.Sh SEE ALSO
.Xr libxo 3 ,
-.Xr xo_parse_args 3 ,
+.Xr xo_options 7 ,
.Xr ses 4
.Sh HISTORY
The
diff --git a/usr.sbin/trim/trim.8 b/usr.sbin/trim/trim.8
index 1ac10d7e3d46..a4874c54c183 100644
--- a/usr.sbin/trim/trim.8
+++ b/usr.sbin/trim/trim.8
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd January 18, 2019
+.Dd July 20, 2025
.Dt TRIM 8
.Os
.Sh NAME
@@ -36,7 +36,7 @@
.Bk -words
.Sm off
.Ar offset
-.Op Cm K | k | M | m | G | g | T | t ]
+.Op Cm K | k | M | m | G | g | T | t | P | p | E | e ]
.Sm on
.Xc
.Ek
@@ -68,13 +68,13 @@ Overrides
.It Fl l Xo
.Sm off
.Ar offset
-.Op Cm K | k | M | m | G | g | T | t
+.Op Cm K | k | M | m | G | g | T | t | P | p | E | e
.Sm on
.Xc
.It Fl o Xo
.Sm off
.Ar offset
-.Op Cm K | k | M | m | G | g | T | t
+.Op Cm K | k | M | m | G | g | T | t | P | p | E | e
.Sm on
.Xc
Specify the length
@@ -88,12 +88,14 @@ unless one or both of these options are presented.
The argument may be suffixed with one of
.Cm K ,
.Cm M ,
-.Cm G
+.Cm G ,
+.Cm T ,
+.Cm P
or
-.Cm T
+.Cm E
(either upper or lower case) to indicate a multiple of
-Kilobytes, Megabytes, Gigabytes or Terabytes
-respectively.
+Kilobytes, Megabytes, Gigabytes, Terabytes, Petabytes or
+Exabytes, respectively.
.It Fl q
Do not output anything except of possible error messages (quiet mode).
Overrides
diff --git a/usr.sbin/trim/trim.c b/usr.sbin/trim/trim.c
index 3e187faa0fb3..27f57ac2fb72 100644
--- a/usr.sbin/trim/trim.c
+++ b/usr.sbin/trim/trim.c
@@ -114,7 +114,7 @@ main(int argc, char **argv)
*
* trim -f -- /dev/da0 -r rfile
*/
-
+
if (strcmp(argv[optind-1], "--") != 0) {
for (ch = optind; ch < argc; ch++)
if (argv[ch][0] == '-')
@@ -127,6 +127,9 @@ main(int argc, char **argv)
if (argc < 1)
usage(name);
+ if (dryrun)
+ printf("dry run: add -f to actually perform the operation\n");
+
while ((fname = *argv++) != NULL)
if (trim(fname, offset, length, dryrun, verbose) < 0)
error++;
@@ -213,10 +216,8 @@ trim(const char *path, off_t offset, off_t length, bool dryrun, bool verbose)
printf("trim %s offset %ju length %ju\n",
path, (uintmax_t)offset, (uintmax_t)length);
- if (dryrun) {
- printf("dry run: add -f to actually perform the operation\n");
+ if (dryrun)
return (0);
- }
fd = opendev(path, O_RDWR | O_DIRECT);
arg[0] = offset;
@@ -237,7 +238,7 @@ static void
usage(const char *name)
{
(void)fprintf(stderr,
- "usage: %s [-[lo] offset[K|k|M|m|G|g|T|t]] [-r rfile] [-Nfqv] device ...\n",
+ "usage: %s [-[lo] offset[K|k|M|m|G|g|T|t|P|p|E|e]] [-r rfile] [-Nfqv] device ...\n",
name);
exit(EX_USAGE);
}