aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/checklist.yml2
-rw-r--r--CONTRIBUTING.md20
-rw-r--r--ObsoleteFiles.inc67
-rw-r--r--RELNOTES12
-rw-r--r--UPDATING39
-rw-r--r--bin/cpuset/Makefile2
-rw-r--r--bin/cpuset/cpuset.c153
-rw-r--r--cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ticks.d54
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c73
-rw-r--r--cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h1
-rw-r--r--cddl/usr.sbin/dtrace/tests/common/profile-n/Makefile1
-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/bsnmpclient.319
-rw-r--r--contrib/bsnmp/lib/snmpclient.c257
-rw-r--r--contrib/bsnmp/lib/snmpclient.h5
-rw-r--r--contrib/bsnmp/snmpd/main.c20
-rw-r--r--contrib/bsnmp/snmpd/snmpd.h6
-rw-r--r--contrib/bsnmp/snmpd/trans_inet.c24
-rw-r--r--contrib/bsnmp/snmpd/trans_lsock.c43
-rw-r--r--contrib/bsnmp/snmpd/trans_udp.c439
-rw-r--r--contrib/bsnmp/snmpd/tree.def9
-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/llvm-project/clang/include/clang/Sema/Sema.h9
-rw-r--r--contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp23
-rw-r--r--contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp10
-rw-r--r--contrib/tzcode/localtime.c34
-rw-r--r--etc/gss-krb5/mech16
-rw-r--r--include/rpc/des.h20
-rw-r--r--krb5/include/Makefile2
-rw-r--r--krb5/include/autoconf.h3
-rw-r--r--krb5/lib/Makefile.inc4
-rw-r--r--krb5/lib/apputils/Makefile2
-rw-r--r--krb5/lib/crypto/Makefile7
-rw-r--r--krb5/lib/crypto/version.map109
-rw-r--r--krb5/lib/gssapi/Makefile3
-rw-r--r--krb5/lib/gssapi/version.map176
-rw-r--r--krb5/lib/kadm5clnt/Makefile10
-rw-r--r--krb5/lib/kadm5clnt/version.map119
-rw-r--r--krb5/lib/kadm5srv/Makefile10
-rw-r--r--krb5/lib/kadm5srv/version.map138
-rw-r--r--krb5/lib/kdb/Makefile3
-rw-r--r--krb5/lib/kdb/version.map112
-rw-r--r--krb5/lib/krad/Makefile7
-rw-r--r--krb5/lib/krad/version.map27
-rw-r--r--krb5/lib/krb5/Makefile26
-rw-r--r--krb5/lib/krb5/error_tables/Makefile.inc2
-rw-r--r--krb5/lib/krb5/version.map633
-rw-r--r--krb5/lib/rpc/Makefile9
-rw-r--r--krb5/lib/rpc/version.map148
-rw-r--r--krb5/libexec/Makefile.inc1
-rw-r--r--krb5/libexec/kadmind/Makefile3
-rw-r--r--krb5/libexec/kdc/Makefile2
-rw-r--r--krb5/libexec/kprop/Makefile2
-rw-r--r--krb5/libexec/kpropd/Makefile2
-rw-r--r--krb5/libexec/kproplog/Makefile2
-rw-r--r--krb5/plugins/Makefile.inc3
-rw-r--r--krb5/plugins/audit/Makefile3
-rw-r--r--krb5/plugins/audit/version.map11
-rw-r--r--krb5/plugins/k5tls/Makefile3
-rw-r--r--krb5/plugins/k5tls/version.map5
-rw-r--r--krb5/plugins/kdb/db2/Makefile18
-rw-r--r--krb5/plugins/kdb/db2/version.map5
-rw-r--r--krb5/plugins/preauth/Makefile.inc1
-rw-r--r--krb5/plugins/preauth/otp/Makefile3
-rw-r--r--krb5/plugins/preauth/otp/version.map5
-rw-r--r--krb5/plugins/preauth/pkinit/Makefile3
-rw-r--r--krb5/plugins/preauth/pkinit/version.map6
-rw-r--r--krb5/plugins/preauth/spake/Makefile3
-rw-r--r--krb5/plugins/preauth/spake/version.map6
-rw-r--r--krb5/plugins/preauth/test/Makefile3
-rw-r--r--krb5/plugins/preauth/test/version.map6
-rw-r--r--krb5/usr.bin/Makefile.inc1
-rw-r--r--krb5/usr.bin/gss-client/Makefile2
-rw-r--r--krb5/usr.bin/kadmin/Makefile6
-rw-r--r--krb5/usr.bin/kdestroy/Makefile2
-rw-r--r--krb5/usr.bin/kinit/Makefile2
-rw-r--r--krb5/usr.bin/klist/Makefile2
-rw-r--r--krb5/usr.bin/kpasswd/Makefile2
-rw-r--r--krb5/usr.bin/ksu/Makefile2
-rw-r--r--krb5/usr.bin/kswitch/Makefile2
-rw-r--r--krb5/usr.bin/ktutil/Makefile2
-rw-r--r--krb5/usr.bin/kvno/Makefile2
-rw-r--r--krb5/usr.bin/sclient/Makefile2
-rw-r--r--krb5/usr.bin/sim_client/Makefile2
-rw-r--r--krb5/usr.sbin/gss-server/Makefile2
-rw-r--r--krb5/usr.sbin/kadmin.local/Makefile2
-rw-r--r--krb5/usr.sbin/kdb5_util/Makefile8
-rw-r--r--krb5/usr.sbin/sim_server/Makefile2
-rw-r--r--krb5/usr.sbin/sserver/Makefile2
-rw-r--r--krb5/util/Makefile.inc2
-rw-r--r--krb5/util/build-tools/Makefile2
-rw-r--r--krb5/util/compile_et/Makefile2
-rw-r--r--krb5/util/et/Makefile3
-rw-r--r--krb5/util/et/version.map17
-rw-r--r--krb5/util/profile/Makefile10
-rw-r--r--krb5/util/profile/version.map74
-rw-r--r--krb5/util/ss/Makefile2
-rw-r--r--krb5/util/support/Makefile3
-rw-r--r--krb5/util/support/version.map103
-rw-r--r--krb5/util/verto/Makefile3
-rw-r--r--krb5/util/verto/libverto.exports33
-rw-r--r--krb5/util/verto/version.map37
-rw-r--r--lib/libbsnmp/libbsnmp/Makefile2
-rw-r--r--lib/libc/db/hash/hash.c3
-rw-r--r--lib/libc/net/gethostbydns.c6
-rw-r--r--lib/libc/net/res_config.h4
-rw-r--r--lib/libc/resolv/res_debug.h2
-rw-r--r--lib/libc/resolv/res_init.c6
-rw-r--r--lib/libc/resolv/res_mkquery.c5
-rw-r--r--lib/libc/resolv/res_mkupdate.c4
-rw-r--r--lib/libc/resolv/res_query.c5
-rw-r--r--lib/libc/resolv/res_send.c49
-rw-r--r--lib/libc/stdtime/Makefile.inc1
-rw-r--r--lib/libc/stdtime/Symbol.map6
-rw-r--r--lib/libc/string/memchr.322
-rw-r--r--lib/libc/tests/db/Makefile2
-rw-r--r--lib/libc/tests/db/dbm_open_test.c43
-rw-r--r--lib/libc/tests/stdtime/Makefile5
-rw-r--r--lib/libc/tests/stdtime/detect_tz_changes_test.c281
-rw-r--r--lib/libcasper/services/cap_net/tests/net_test.c168
-rw-r--r--lib/libnvmf/libnvmf.h7
-rw-r--r--lib/libnvmf/nvmf_controller.c50
-rw-r--r--lib/libpam/modules/pam_krb5/Makefile2
-rw-r--r--lib/libpfctl/libpfctl.c7
-rw-r--r--lib/libsecureboot/h/libsecureboot.h1
-rw-r--r--lib/libsys/fhopen.24
-rw-r--r--lib/libsys/getsockopt.29
-rw-r--r--lib/libsys/mkdir.22
-rw-r--r--lib/libsys/statfs.26
-rw-r--r--lib/libusb/libusb.330
-rw-r--r--lib/libusb/libusb.h9
-rw-r--r--lib/libusb/libusb10.c14
-rw-r--r--lib/libusb/libusb10_hotplug.c18
-rw-r--r--lib/libusb/libusb10_io.c22
-rw-r--r--lib/libutil/Makefile1
-rw-r--r--lib/libutil/cpuset.351
-rw-r--r--lib/libutil/cpuset.c98
-rw-r--r--lib/libutil/libutil.h8
-rw-r--r--lib/libvmmapi/Makefile2
-rw-r--r--lib/libvmmapi/internal.h11
-rw-r--r--lib/libvmmapi/vmmapi.c181
-rw-r--r--lib/libvmmapi/vmmapi.h22
-rw-r--r--libexec/comsat/comsat.c40
-rw-r--r--libexec/dma/dmagent/Makefile8
-rw-r--r--libexec/rc/rc.conf2
-rw-r--r--libexec/rc/rc.d/Makefile2
-rwxr-xr-xlibexec/rc/rc.d/mountd2
-rw-r--r--libexec/rtld-elf/map_object.c2
-rw-r--r--libexec/tftpd/tftpd.c6
-rw-r--r--release/Makefile7
-rwxr-xr-xrelease/packages/generate-ucl.lua12
-rw-r--r--release/packages/ucl/bmake-all.ucl5
-rw-r--r--release/packages/ucl/gssd-all.ucl11
-rw-r--r--release/packages/ucl/kerberos-all.ucl4
-rw-r--r--release/packages/ucl/kerberos-kdc-all.ucl5
-rw-r--r--release/packages/ucl/kerberos-lib-all.ucl4
-rw-r--r--release/packages/ucl/kernel-man.ucl5
-rw-r--r--release/packages/ucl/sendmail.ucl7
-rw-r--r--release/packages/ucl/yp.ucl7
-rw-r--r--release/scripts/make-oci-image.sh4
-rw-r--r--release/tools/oci-image-static.conf7
-rw-r--r--sbin/devd/devd.cc27
-rw-r--r--sbin/devd/hyperv.conf1
-rw-r--r--sbin/devd/moused.conf2
-rw-r--r--sbin/dhclient/dhclient.c2
-rw-r--r--sbin/ifconfig/ifbridge.c47
-rw-r--r--sbin/ifconfig/ifconfig.816
-rw-r--r--sbin/ifconfig/ifgif.c3
-rw-r--r--sbin/kldstat/kldstat.c4
-rw-r--r--sbin/mount_fusefs/Makefile2
-rw-r--r--sbin/reboot/reboot.89
-rw-r--r--sbin/reboot/reboot.c7
-rw-r--r--sbin/recoverdisk/recoverdisk.1258
-rw-r--r--sbin/recoverdisk/recoverdisk.c766
-rw-r--r--sbin/zfsbootcfg/zfsbootcfg.88
-rw-r--r--share/examples/oci/Containerfile.pkg7
-rw-r--r--share/man/man1/Makefile24
-rw-r--r--share/man/man3/Makefile2
-rw-r--r--share/man/man4/Makefile8
-rw-r--r--share/man/man4/gif.4154
-rw-r--r--share/man/man4/ice.4946
-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.412
-rw-r--r--share/man/man5/Makefile90
-rw-r--r--share/man/man5/core.548
-rw-r--r--share/man/man5/pf.conf.510
-rw-r--r--share/man/man5/src.conf.57
-rw-r--r--share/man/man7/named_attribute.723
-rw-r--r--share/man/man8/Makefile39
-rw-r--r--share/man/man8/crash.832
-rw-r--r--share/man/man9/Makefile4
-rw-r--r--share/man/man9/coredumper_register.9168
-rw-r--r--share/man/man9/domainset.916
-rw-r--r--share/man/man9/mbuf.934
-rw-r--r--share/man/man9/style.9160
-rw-r--r--share/misc/committers-ports.dot3
-rw-r--r--share/misc/committers-src.dot5
-rw-r--r--share/mk/Makefile1
-rw-r--r--share/mk/bsd.man.mk158
-rw-r--r--share/mk/bsd.subdir.mk9
-rw-r--r--share/mk/src.opts.mk4
-rw-r--r--share/termcap/termcap22
-rw-r--r--stand/common/bootstrap.h2
-rw-r--r--stand/common/console.c23
-rw-r--r--stand/common/dev_net.c57
-rw-r--r--stand/common/install.c4
-rw-r--r--stand/defaults/loader.conf2
-rw-r--r--stand/defaults/loader.conf.56
-rw-r--r--stand/efi/loader/main.c3
-rw-r--r--stand/fdt/fdt_loader_cmd.c7
-rw-r--r--stand/i386/Makefile2
-rw-r--r--stand/i386/common/bootargs.h2
-rw-r--r--stand/i386/gptboot/Makefile6
-rw-r--r--stand/i386/gptzfsboot/Makefile7
-rw-r--r--stand/i386/gptzfsboot/zfsboot.c (renamed from stand/i386/zfsboot/zfsboot.c)0
-rw-r--r--stand/i386/isoboot/Makefile6
-rw-r--r--stand/i386/libi386/Makefile1
-rw-r--r--stand/i386/libi386/biosmemdisk.c140
-rw-r--r--stand/i386/libi386/libi386.h2
-rw-r--r--stand/i386/loader/main.c5
-rw-r--r--stand/i386/zfsboot/Makefile92
-rw-r--r--stand/i386/zfsboot/Makefile.depend17
-rw-r--r--stand/i386/zfsboot/zfsboot.8130
-rw-r--r--stand/i386/zfsboot/zfsldr.S281
-rw-r--r--stand/libsa/bootp.c78
-rw-r--r--stand/libsa/hexdump.c2
-rw-r--r--stand/libsa/pkgfs.c33
-rw-r--r--stand/libsa/stand.h18
-rw-r--r--sys/amd64/acpica/acpi_wakeup.c18
-rw-r--r--sys/amd64/amd64/apic_vector.S3
-rw-r--r--sys/amd64/amd64/cpu_switch.S4
-rw-r--r--sys/amd64/amd64/exec_machdep.c2
-rw-r--r--sys/amd64/amd64/machdep.c9
-rw-r--r--sys/amd64/amd64/pmap.c372
-rw-r--r--sys/amd64/amd64/support.S20
-rw-r--r--sys/amd64/amd64/trap.c19
-rw-r--r--sys/amd64/conf/MINIMALUP4
-rw-r--r--sys/amd64/include/param.h2
-rw-r--r--sys/amd64/include/pmap.h14
-rw-r--r--sys/amd64/include/smp.h3
-rw-r--r--sys/amd64/include/vmm.h2
-rw-r--r--sys/amd64/include/vmm_dev.h7
-rw-r--r--sys/amd64/include/vmm_instruction_emul.h25
-rw-r--r--sys/amd64/include/vmparam.h20
-rw-r--r--sys/amd64/vmm/amd/svm.c90
-rw-r--r--sys/amd64/vmm/intel/vmx.c2
-rw-r--r--sys/amd64/vmm/vmm_instruction_emul.c34
-rw-r--r--sys/amd64/vmm/vmm_ioport.c40
-rw-r--r--sys/arm/allwinner/aw_mmc.c33
-rw-r--r--sys/arm64/arm64/pmap.c36
-rw-r--r--sys/arm64/broadcom/genet/if_genet.c4
-rw-r--r--sys/arm64/include/vmm_dev.h5
-rw-r--r--sys/cam/cam_xpt.c9
-rw-r--r--sys/cam/mmc/mmc_da.c2
-rw-r--r--sys/cam/mmc/mmc_xpt.c1
-rw-r--r--sys/cddl/dev/sdt/sdt.c23
-rw-r--r--sys/compat/linprocfs/linprocfs.c8
-rw-r--r--sys/compat/linux/linux_file.c2
-rw-r--r--sys/conf/files2
-rw-r--r--sys/conf/files.amd648
-rw-r--r--sys/conf/files.arm644
-rw-r--r--sys/conf/files.x861
-rw-r--r--sys/dev/amdsmu/amdsmu.c466
-rw-r--r--sys/dev/amdsmu/amdsmu.h95
-rw-r--r--sys/dev/amdsmu/amdsmu_reg.h84
-rw-r--r--sys/dev/cxgbe/tom/t4_cpl_io.c6
-rw-r--r--sys/dev/cxgbe/tom/t4_tls.c4
-rw-r--r--sys/dev/drm2/drm_fb_helper.c2
-rw-r--r--sys/dev/efidev/efirt.c42
-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/iicbus/iichid.c74
-rw-r--r--sys/dev/md/md.c23
-rw-r--r--sys/dev/nvme/nvme_ctrlr.c295
-rw-r--r--sys/dev/nvme/nvme_private.h4
-rw-r--r--sys/dev/nvmf/controller/nvmft_subr.c40
-rw-r--r--sys/dev/ofw/ofw_bus_subr.c101
-rw-r--r--sys/dev/qlnx/qlnxe/qlnx_os.c5
-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/vmm/vmm_dev.c135
-rw-r--r--sys/dev/vmm/vmm_mem.c15
-rw-r--r--sys/dev/vmm/vmm_mem.h27
-rw-r--r--sys/dev/vt/hw/vga/vt_vga.c2
-rw-r--r--sys/dev/vt/vt_core.c4
-rw-r--r--sys/fs/fuse/fuse_internal.h6
-rw-r--r--sys/fs/fuse/fuse_ipc.c2
-rw-r--r--sys/fs/fuse/fuse_vnops.c2
-rw-r--r--sys/fs/msdosfs/msdosfs_conv.c11
-rw-r--r--sys/fs/nfs/nfs_commonport.c3
-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.c6
-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/pseudofs/pseudofs_vnops.c31
-rw-r--r--sys/fs/smbfs/smbfs_io.c20
-rw-r--r--sys/fs/smbfs/smbfs_node.h2
-rw-r--r--sys/fs/smbfs/smbfs_vnops.c6
-rw-r--r--sys/geom/concat/g_concat.c1
-rw-r--r--sys/geom/geom.h2
-rw-r--r--sys/geom/geom_ccd.c10
-rw-r--r--sys/geom/geom_event.c2
-rw-r--r--sys/geom/geom_io.c2
-rw-r--r--sys/geom/geom_slice.c6
-rw-r--r--sys/geom/geom_subr.c21
-rw-r--r--sys/geom/multipath/g_multipath.c10
-rw-r--r--sys/geom/virstor/g_virstor.c30
-rw-r--r--sys/kern/coredump_vnode.c562
-rw-r--r--sys/kern/imgact_elf.c15
-rw-r--r--sys/kern/kern_cpuset.c98
-rw-r--r--sys/kern/kern_exec.c21
-rw-r--r--sys/kern/kern_jail.c17
-rw-r--r--sys/kern/kern_prot.c38
-rw-r--r--sys/kern/kern_sendfile.c11
-rw-r--r--sys/kern/kern_sig.c594
-rw-r--r--sys/kern/kern_sysctl.c2
-rw-r--r--sys/kern/kern_ucoredump.c299
-rw-r--r--sys/kern/subr_compressor.c6
-rw-r--r--sys/kern/sys_generic.c2
-rw-r--r--sys/kern/uipc_ktls.c2
-rw-r--r--sys/kern/uipc_shm.c50
-rw-r--r--sys/kern/uipc_sockbuf.c43
-rw-r--r--sys/kern/uipc_socket.c12
-rw-r--r--sys/kern/vfs_inotify.c5
-rw-r--r--sys/kern/vfs_subr.c11
-rw-r--r--sys/kern/vfs_syscalls.c4
-rw-r--r--sys/kern/vnode_if.src5
-rw-r--r--sys/modules/Makefile2
-rw-r--r--sys/modules/amdsmu/Makefile14
-rw-r--r--sys/modules/efirt/Makefile2
-rw-r--r--sys/modules/ice/Makefile1
-rw-r--r--sys/net/if_bridge.c197
-rw-r--r--sys/net/if_bridgevar.h4
-rw-r--r--sys/net/if_gif.h3
-rw-r--r--sys/net/if_ovpn.c321
-rw-r--r--sys/net/if_ovpn.h1
-rw-r--r--sys/net/if_tuntap.c76
-rw-r--r--sys/net/if_vlan.c12
-rw-r--r--sys/net/pfvar.h11
-rw-r--r--sys/netinet/icmp_var.h9
-rw-r--r--sys/netinet/in_fib_dxr.c6
-rw-r--r--sys/netinet/ip_icmp.c3
-rw-r--r--sys/netinet/sctp_timer.c1
-rw-r--r--sys/netinet/tcp_hpts.c73
-rw-r--r--sys/netinet/tcp_hpts.h17
-rw-r--r--sys/netinet/tcp_input.c48
-rw-r--r--sys/netinet/tcp_log_buf.c2
-rw-r--r--sys/netinet/tcp_log_buf.h14
-rw-r--r--sys/netinet/tcp_lro.c12
-rw-r--r--sys/netinet/tcp_sack.c2
-rw-r--r--sys/netinet/tcp_stacks/bbr.c40
-rw-r--r--sys/netinet/tcp_stacks/rack.c80
-rw-r--r--sys/netinet/tcp_stacks/rack_bbr_common.c2
-rw-r--r--sys/netinet/tcp_stacks/rack_pcm.c4
-rw-r--r--sys/netinet/tcp_stacks/sack_filter.c8
-rw-r--r--sys/netinet/tcp_stacks/sack_filter.h2
-rw-r--r--sys/netinet/tcp_subr.c2
-rw-r--r--sys/netinet/tcp_timer.c4
-rw-r--r--sys/netinet/tcp_usrreq.c10
-rw-r--r--sys/netinet/tcp_var.h26
-rw-r--r--sys/netinet/udp_usrreq.c11
-rw-r--r--sys/netinet6/in6_gif.c18
-rw-r--r--sys/netinet6/mld6.c29
-rw-r--r--sys/netinet6/udp6_usrreq.c11
-rw-r--r--sys/netpfil/ipfw/ip_fw2.c2
-rw-r--r--sys/netpfil/pf/if_pfsync.c16
-rw-r--r--sys/netpfil/pf/pf.c312
-rw-r--r--sys/netpfil/pf/pf_ioctl.c264
-rw-r--r--sys/netpfil/pf/pf_lb.c31
-rw-r--r--sys/netpfil/pf/pf_norm.c109
-rw-r--r--sys/netpfil/pf/pf_osfp.c17
-rw-r--r--sys/netpfil/pf/pf_ruleset.c13
-rw-r--r--sys/netpfil/pf/pf_syncookies.c6
-rw-r--r--sys/netpfil/pf/pf_table.c4
-rw-r--r--sys/netsmb/smb_conn.c4
-rw-r--r--sys/riscv/allwinner/files.allwinner1
-rw-r--r--sys/riscv/conf/std.allwinner1
-rw-r--r--sys/riscv/include/vmm_dev.h5
-rw-r--r--sys/rpc/authunix_prot.c7
-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/rpc/svc_auth_unix.c3
-rw-r--r--sys/security/audit/audit.c2
-rw-r--r--sys/security/audit/audit_arg.c2
-rw-r--r--sys/sys/compressor.h1
-rw-r--r--sys/sys/domainset.h14
-rw-r--r--sys/sys/efi.h18
-rw-r--r--sys/sys/exec.h20
-rw-r--r--sys/sys/exterr_cat.h1
-rw-r--r--sys/sys/imgact_elf.h3
-rw-r--r--sys/sys/inotify.h14
-rw-r--r--sys/sys/jail.h2
-rw-r--r--sys/sys/mbuf.h1
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/random.h3
-rw-r--r--sys/sys/signalvar.h1
-rw-r--r--sys/sys/sockbuf.h4
-rw-r--r--sys/sys/syscallsubr.h3
-rw-r--r--sys/sys/sysent.h4
-rw-r--r--sys/sys/ucoredump.h99
-rw-r--r--sys/sys/unistd.h2
-rw-r--r--sys/sys/vnode.h34
-rw-r--r--sys/ufs/ufs/ufs_vnops.c30
-rw-r--r--sys/vm/vm_page.c2
-rw-r--r--targets/pseudo/userland/misc/Makefile.depend1
-rw-r--r--tests/ci/Makefile44
-rw-r--r--tests/ci/Makefile.aarch642
-rw-r--r--tests/ci/Makefile.armv72
-rw-r--r--tests/ci/Makefile.powerpc641
-rw-r--r--tests/ci/Makefile.powerpc64le1
-rw-r--r--tests/ci/Makefile.riscv641
-rw-r--r--tests/sys/cam/ctl/ctl.subr9
-rw-r--r--tests/sys/fs/fusefs/Makefile3
-rw-r--r--tests/sys/mac/bsdextended/Makefile1
-rw-r--r--tests/sys/mac/bsdextended/matches_test.sh3
-rw-r--r--tests/sys/mac/portacl/Makefile1
-rwxr-xr-xtests/sys/net/if_bridge_test.sh28
-rw-r--r--tests/sys/net/if_ovpn/if_ovpn.sh258
-rwxr-xr-xtests/sys/net/if_vlan.sh27
-rw-r--r--tests/sys/netpfil/common/dummynet.sh4
-rw-r--r--tests/sys/netpfil/pf/Makefile2
-rw-r--r--tests/sys/netpfil/pf/forward.sh4
-rw-r--r--tests/sys/netpfil/pf/icmp.py19
-rw-r--r--tests/sys/netpfil/pf/igmp.py95
-rw-r--r--tests/sys/netpfil/pf/killstate.sh4
-rw-r--r--tests/sys/netpfil/pf/mbuf.sh6
-rw-r--r--tests/sys/netpfil/pf/mld.py95
-rw-r--r--tests/sys/netpfil/pf/set_tos.sh4
-rw-r--r--tests/sys/netpfil/pf/table.sh29
-rwxr-xr-xtools/boot/install-boot.sh23
-rwxr-xr-xtools/boot/rootgen.sh65
-rw-r--r--tools/build/mk/OptionalObsoleteFiles.inc60
-rw-r--r--tools/build/options/WITH_LLVM_ASSERTIONS1
-rwxr-xr-xtools/test/stress2/misc/fullpath2.sh2
-rw-r--r--tools/tools/vt/mkkfont/Makefile2
-rw-r--r--usr.bin/asa/asa.12
-rw-r--r--usr.bin/bmake/Makefile2
-rw-r--r--usr.bin/bmake/Makefile.config2
-rw-r--r--usr.bin/bmake/Makefile.inc2
-rw-r--r--usr.bin/bmake/unit-tests/Makefile7
-rw-r--r--usr.bin/calendar/calendars/calendar.freebsd1
-rw-r--r--usr.bin/clang/clang-scan-deps/Makefile7
-rw-r--r--usr.bin/clang/clang.prog.mk2
-rw-r--r--usr.bin/clang/llvm-ar/Makefile1
-rw-r--r--usr.bin/clang/llvm-nm/Makefile1
-rw-r--r--usr.bin/clang/llvm-size/Makefile1
-rw-r--r--usr.bin/clang/llvm.prog.mk2
-rw-r--r--usr.bin/find/Makefile2
-rw-r--r--usr.bin/find/extern.h7
-rw-r--r--usr.bin/find/find.1178
-rw-r--r--usr.bin/find/find.h4
-rw-r--r--usr.bin/find/function.c73
-rw-r--r--usr.bin/find/option.c6
-rw-r--r--usr.bin/find/printf.c307
-rw-r--r--usr.bin/fstat/Makefile2
-rw-r--r--usr.bin/grep/Makefile2
-rwxr-xr-xusr.bin/man/man.sh13
-rw-r--r--usr.bin/pom/pom.610
-rw-r--r--usr.bin/pom/pom.c1
-rw-r--r--usr.bin/sdiff/Makefile2
-rw-r--r--usr.bin/strings/Makefile2
-rw-r--r--usr.bin/top/top.12
-rw-r--r--usr.bin/vtfontcvt/Makefile2
-rw-r--r--usr.bin/xargs/tests/Makefile5
-rw-r--r--usr.bin/xargs/tests/legacy_test.sh5
-rw-r--r--usr.bin/xargs/tests/regress.nargmax.out (renamed from usr.bin/xargs/tests/regress.n2147483647.out)0
-rw-r--r--usr.bin/xargs/tests/regress.sh32
-rwxr-xr-xusr.bin/xargs/tests/xargs_test.sh193
-rw-r--r--usr.bin/xargs/xargs.c2
-rw-r--r--usr.sbin/bhyve/acpi.c124
-rw-r--r--usr.sbin/bhyve/acpi.h3
-rw-r--r--usr.sbin/bhyve/amd64/bhyverun_machdep.c14
-rw-r--r--usr.sbin/bhyve/amd64/xmsr.c9
-rw-r--r--usr.sbin/bhyve/bhyve.880
-rw-r--r--usr.sbin/bhyve/bhyverun.c174
-rw-r--r--usr.sbin/bhyve/bhyverun.h1
-rw-r--r--usr.sbin/bhyve/bootrom.c1
-rw-r--r--usr.sbin/bhyve/pci_emul.c1
-rw-r--r--usr.sbin/bhyve/pci_fbuf.c1
-rw-r--r--usr.sbin/bhyve/pci_passthru.c1
-rw-r--r--usr.sbin/bhyve/pci_xhci.c12
-rw-r--r--usr.sbin/bhyve/tpm_ppi_qemu.c2
-rw-r--r--usr.sbin/bhyve/usb_emul.h1
-rw-r--r--usr.sbin/bluetooth/sdpd/server.c12
-rw-r--r--usr.sbin/bsdinstall/Makefile5
-rw-r--r--usr.sbin/bsdinstall/bsdinstall.82
-rwxr-xr-xusr.sbin/bsdinstall/scripts/bootconfig2
-rwxr-xr-xusr.sbin/bsdinstall/scripts/pkgbase.in13
-rwxr-xr-xusr.sbin/bsdinstall/scripts/zfsboot143
-rw-r--r--usr.sbin/bsnmpd/bsnmpd/Makefile2
-rw-r--r--usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c5
-rw-r--r--usr.sbin/chroot/chroot.814
-rw-r--r--usr.sbin/chroot/chroot.c7
-rw-r--r--usr.sbin/ctladm/tests/port.sh16
-rw-r--r--usr.sbin/devinfo/devinfo.c13
-rw-r--r--usr.sbin/efitable/efitable.813
-rw-r--r--usr.sbin/efitable/efitable.c50
-rw-r--r--usr.sbin/getfmac/getfmac.83
-rw-r--r--usr.sbin/gssd/Makefile2
-rw-r--r--usr.sbin/jail/command.c38
-rw-r--r--usr.sbin/jail/config.c13
-rw-r--r--usr.sbin/jail/jail.c7
-rw-r--r--usr.sbin/jail/tests/commands.jail.conf2
-rwxr-xr-xusr.sbin/jail/tests/jail_basic_test.sh164
-rw-r--r--usr.sbin/jls/jls.820
-rw-r--r--usr.sbin/jls/jls.c56
-rw-r--r--usr.sbin/makefs/makefs.816
-rw-r--r--usr.sbin/makefs/tests/Makefile4
-rw-r--r--usr.sbin/makefs/tests/makefs_zfs_tests.sh92
-rw-r--r--usr.sbin/makefs/zfs.c6
-rw-r--r--usr.sbin/makefs/zfs/dsl.c44
-rw-r--r--usr.sbin/mfiutil/Makefile2
-rw-r--r--usr.sbin/rpc.lockd/kern.c19
-rw-r--r--usr.sbin/rwhod/rwhod.c8
-rw-r--r--usr.sbin/spi/Makefile2
-rw-r--r--usr.sbin/trim/trim.818
-rw-r--r--usr.sbin/trim/trim.c11
-rw-r--r--usr.sbin/ypldap/ldapclient.c2
-rw-r--r--usr.sbin/ypldap/ypldap.c2
-rw-r--r--usr.sbin/ypldap/ypldap_dns.c2
687 files changed, 17143 insertions, 6209 deletions
diff --git a/.github/workflows/checklist.yml b/.github/workflows/checklist.yml
index 7f7b0d51f46e..ecc3939f34b8 100644
--- a/.github/workflows/checklist.yml
+++ b/.github/workflows/checklist.yml
@@ -89,7 +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"
+ msg += "\nPlease review [CONTRIBUTING.md](https://github.com/freebsd/freebsd-src/blob/main/CONTRIBUTING.md), then update and push your branch again.\n"
comment_func({
owner: context.repo.owner,
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8e79652a09d2..02d718ef8018 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -33,9 +33,10 @@ and need discussion, or changes that require specialized review.
A pull request will be considered if:
+* The request is substantive in nature. We generally don't accept minor or cosmetic changes unless they are part of larger work in that area. Pull requests should solve a real, actual problem.
* It is ready or nearly ready to be committed. A committer should be able to land the pull request with less than 10 minutes of additional work.
* It passes all the GitHub CI jobs.
-* You can respond to feedback quickly.
+* You can respond to feedback quickly. If feedback is requested and one month passes without a response we may close the pull request.
* It touches fewer than about 10 files and the changes are less than about 200 lines. Changes larger than this may be OK, or you may be asked to submit multiple pull requests of a more manageable size.
* Each logical change is a separate commit within the pull request. Commit messages for each change should follow the [commit log message guide](https://docs.freebsd.org/en/articles/committers-guide/#commit-log-message).
* All commits have, as the author, your name and valid email address as you would like to see them in the FreeBSD repository. Fake github.com addresses cannot be used.
@@ -43,11 +44,14 @@ A pull request will be considered if:
* Fixup commits should be squashed with the commit they are fixing. Each commit in your branch should be suitable for FreeBSD's repository.
* Commits should include one or more `Signed-off-by:` lines with full name and email address certifying [Developer Certificate of Origin](https://developercertificate.org/).
* The commits follow FreeBSD's style guide. See [Style](#Style).
-* Run tools/build/checkstyle9.pl on your Git branch and eliminate all errors.
+* Run tools/build/checkstyle9.pl on your Git branch and eliminate all errors, or provide an explanation for exceptions.
* The commits do not introduce trailing white space.
-* If the commit fixes a bug, please add 'PR: \<bugnumber\>' to the commit message.
-* If there's a code review in Phabricator, please include a link as a 'Differential Revision: ' line.
+* If the commit fixes a bug, please add 'PR: \<bugnumber\>' to the commit message to document the Bugzilla Problem Report number.
+* If there's a code review related to this change, please include its URL in the commit message. However, where possible, please do not open both a differential review and a GitHub pull request.
* If you have run FreeBSD's sources through a static analysis tool, please don't submit the raw results. Please also see the chunking up guidelines. Also, please make sure that kyua tests are the same before / after your change. Ideally, you'd also create a test case that shows an actual bug that's being fixed by these changes.
+* FreeBSD committers submitting pull requests are responsible for pushing them into the tree (possibly with approval if cross-repo commit bit policy needs it). Pull requests by FreeBSD committers will be closed after a month unless there's a very good reason not to.
+* Submissions using generative AI will be rejected.
+* Submissions from AI chatbots will result in the account being banned.
When updating your pull request, please rebase with a forced push rather than a
merge commit.
@@ -70,7 +74,8 @@ so. While the project strives to have a uniform coding style, our style offers a
range of choices making some 'cleanups' ambiguous at best. Also, some files have
their own consistent style that deviates from style(9). Style changes take
volunteer time to process, but that time can be quite limited, so please be
-respectful.
+respectful. Trivial spelling changes should generally not be made in isolation
+as they usually add little value, but do take up valuable volunteer time.
The current theory for pull requests on GitHub is to facilitate inclusion in the
project. The guidelines are streamlined for quick decisions about each pull
@@ -90,7 +95,8 @@ closing it.
We require that contributions are associated with a unique identity.
The author email address should not be `<something>@users.noreply.github.com`.
Do note that your name and email address will become a permanent and immutable
-part of the public Git history of the FreeBSD source tree.
+part of the public Git history of the FreeBSD source tree. Authors that use
+pseudonyms will be considered on a case by case basis.
## Style
@@ -128,7 +134,7 @@ not present in FreeBSD's [shell](https://man.freebsd.org/cgi/man.cgi?query=sh&se
## Signed-off-by
-Other projects use Signed-off-by to create a paper trail for contributions they
+Other projects mandate Signed-off-by to create a paper trail for contributions they
receive. The Developer Certificate of Origin is an attestation that the person
making the contribution can do it under the current license of the file. Other
projects that have 'delegated' hierarchies also use it when maintainers
diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc
index e5a3da94e127..83fb2d3f3a2c 100644
--- a/ObsoleteFiles.inc
+++ b/ObsoleteFiles.inc
@@ -51,6 +51,73 @@
# xargs -n1 | sort | uniq -d;
# done
+# 20250728: zfsboot (MBR) removed
+OLD_FILES+=boot/zfsboot
+OLD_FILES+=usr/share/man/man8/zfsboot.8.gz
+
+# 20250728: Machine versions of 'runq.h' do not exist anymore
+OLD_FILES+=usr/include/machine/runq.h
+
+# 20250726: MIT KRB5 DSO bump
+OLD_LIBS+=usr/lib/libcom_err.so.121
+OLD_LIBS+=usr/lib/libgssapi_krb5.so.121
+OLD_LIBS+=usr/lib/libgssrpc.so.121
+OLD_LIBS+=usr/lib/libk5crypto.so.121
+OLD_LIBS+=usr/lib/libkadm5clnt_mit.so.121
+OLD_LIBS+=usr/lib/libkadm5srv_mit.so.121
+OLD_LIBS+=usr/lib/libkdb5.so.121
+OLD_LIBS+=usr/lib/libkrad.so.121
+OLD_LIBS+=usr/lib/libkrb5.so.121
+OLD_LIBS+=usr/lib/libkrb5profile.so.121
+OLD_LIBS+=usr/lib/libkrb5support.so.121
+OLD_LIBS+=usr/lib/libverto.so.121
+OLD_LIBS+=usr/lib/libcom_err.so.121
+OLD_LIBS+=usr/lib/libgssapi_krb5.so.121
+OLD_LIBS+=usr/lib/libgssrpc.so.121
+OLD_LIBS+=usr/lib/libk5crypto.so.121
+OLD_LIBS+=usr/lib/libkadm5clnt_mit.so.121
+OLD_LIBS+=usr/lib/libkadm5srv_mit.so.121
+OLD_LIBS+=usr/lib/libkdb5.so.121
+OLD_LIBS+=usr/lib/libkrad.so.121
+OLD_LIBS+=usr/lib/libkrb5.so.121
+OLD_LIBS+=usr/lib/libkrb5profile.so.121
+OLD_LIBS+=usr/lib/libkrb5support.so.121
+OLD_LIBS+=usr/lib/libverto.so.121
+
+# 20250726: xargs tests rewritten
+OLD_FILES+=usr/tests/usr.bin/xargs/legacy_test
+OLD_FILES+=usr/tests/usr.bin/xargs/regress.n2147483647.out
+OLD_FILES+=usr/tests/usr.bin/xargs/regress.sh
+
+# 20250726: This file is now installed in /etc/dma
+OLD_FILES+=usr/share/examples/dma/auth.conf
+
+# 20250725: libbsnmp bumped to version 7
+OLD_LIBS+=usr/lib/libbsnmp.so.6
+
+# 20250725: Files which were briefly installed by WITH_MITKRB5 in 15.0.
+OLD_FILES+=usr/include/kadm5/admin_internal.h
+OLD_FILES+=usr/include/kadm5/admin_xdr.h
+OLD_FILES+=usr/include/kadm5/kadm_rpc.h
+OLD_FILES+=usr/include/kadm5/server_internal.h
+OLD_FILES+=usr/include/internal.h
+OLD_FILES+=usr/include/t_daemon.h
+OLD_FILES+=usr/include/t_test.h
+OLD_FILES+=usr/include/dyn.h
+OLD_FILES+=usr/include/dynP.h
+OLD_FILES+=usr/include/gssrpcint.h
+OLD_FILES+=usr/include/import_err.h
+OLD_FILES+=usr/share/man/man3/db_btree.3.gz
+OLD_FILES+=usr/share/man/man3/db_hash.3.gz
+OLD_FILES+=usr/share/man/man3/db_lock.3.gz
+OLD_FILES+=usr/share/man/man3/db_log.3.gz
+OLD_FILES+=usr/share/man/man3/db_mpool.3.gz
+OLD_FILES+=usr/share/man/man3/db_open.3.gz
+OLD_FILES+=usr/share/man/man3/db_recno.3.gz
+OLD_FILES+=usr/share/man/man3/db_txn.3.gz
+OLD_FILES+=usr/share/man/man5/profile.5.gz
+OLD_FILES+=usr/share/man/man8/kamdin.local.8.gz
+
# 20250716: Remove an old manual page, vn(4) was removed in FreeBSD 5.0
OLD_FILES+=usr/share/man/man4/vn.4.gz
diff --git a/RELNOTES b/RELNOTES
index 09696a37998b..9ab511b7a3d3 100644
--- a/RELNOTES
+++ b/RELNOTES
@@ -10,6 +10,18 @@ newline. Entries should be separated by a newline.
Changes to this file should not be MFCed.
+9ba51cce8bbd:
+ bsnmpd(1) no longer supports legacy UDP transport. Users, that have
+ not updated their /etc/snmpd.config since 12.0-RELEASE or older will
+ need to merge in the new configuration. In particular, the transport
+ definition shall be changed from begemotSnmpdPortStatus OID to
+ begemotSnmpdTransInetStatus.
+
+1349a733cf28:
+ Add a driver supporting a new storage controller interface,
+ Universal Flash Storage Host Controller Interface, supporting
+ version 4.1 and earlier, via ufshci(4).
+
f1f230439fa4:
FreeBSD now implements the inotify(2) family of system calls.
diff --git a/UPDATING b/UPDATING
index 2b8320c1204d..5fb9574dfb0f 100644
--- a/UPDATING
+++ b/UPDATING
@@ -27,6 +27,45 @@ 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".)
+20250727:
+ bmake (i.e., /usr/bin/make and /usr/share/mk) has moved to a new
+ package, FreeBSD-bmake. If you use pkgbase and you need make, you
+ should install this package.
+
+20250727:
+ LLVM's debugging assertions are now disabled in main by default.
+ The WITH_LLVM_ASSERTIONS src.conf(5) knob should be used to
+ enable it when working on LLVM or requesting help with it.
+
+20250726:
+ amd64 kernel configurations must contain "options SMP".
+
+20250725:
+ gssd(8) has been moved to a new package, FreeBSD-gssd. If you use
+ pkgbase and you need gssd, you should install this package.
+
+20250724:
+ The Kerberos packages which are built when WITH_MITKRB5 is enabled
+ have been renamed from FreeBSD-krb5* to FreeBSD-kerberos*. This
+ affects pkgbase users who manually enabled WITH_MITKRB5, *or* use
+ the default value of WITH_MITKRB5 and updated past c7da9fb90b0b
+ (20250721) which made WITH_MITKRB5 the default.
+
+ In either case, if you have FreeBSD-krb5* packages installed, you
+ should remove them and (re)install the equivalent FreeBSD-kerberos*
+ packages instead.
+
+20250721:
+ WITH_MITKRB5 is now enabled by default. MIT KRB5 has replaced
+ Heimdal in base. Ports that use USES=gssapi must be rebuilt.
+ A clean buildworld is required.
+
+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/cpuset/Makefile b/bin/cpuset/Makefile
index d6f58db62901..639dd9812171 100644
--- a/bin/cpuset/Makefile
+++ b/bin/cpuset/Makefile
@@ -1,6 +1,6 @@
PROG= cpuset
-LIBADD= jail
+LIBADD= jail util
SYMLINKS+= ../..${BINDIR}/cpuset /usr/bin/cpuset
diff --git a/bin/cpuset/cpuset.c b/bin/cpuset/cpuset.c
index 82ffcaeec252..7416e100a3c6 100644
--- a/bin/cpuset/cpuset.c
+++ b/bin/cpuset/cpuset.c
@@ -43,6 +43,7 @@
#include <err.h>
#include <errno.h>
#include <jail.h>
+#include <libutil.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -69,154 +70,6 @@ static cpuwhich_t which;
static void usage(void) __dead2;
-struct numa_policy {
- const char *name;
- int policy;
-};
-
-static struct numa_policy policies[] = {
- { "round-robin", DOMAINSET_POLICY_ROUNDROBIN },
- { "rr", DOMAINSET_POLICY_ROUNDROBIN },
- { "first-touch", DOMAINSET_POLICY_FIRSTTOUCH },
- { "ft", DOMAINSET_POLICY_FIRSTTOUCH },
- { "prefer", DOMAINSET_POLICY_PREFER },
- { "interleave", DOMAINSET_POLICY_INTERLEAVE},
- { "il", DOMAINSET_POLICY_INTERLEAVE},
- { NULL, DOMAINSET_POLICY_INVALID }
-};
-
-static void printset(struct bitset *mask, int size);
-
-static void
-parselist(char *list, struct bitset *mask, int size)
-{
- enum { NONE, NUM, DASH } state;
- int lastnum;
- int curnum;
- char *l;
-
- state = NONE;
- curnum = lastnum = 0;
- for (l = list; *l != '\0';) {
- if (isdigit(*l)) {
- curnum = atoi(l);
- if (curnum >= size)
- errx(EXIT_FAILURE,
- "List entry %d exceeds maximum of %d",
- curnum, size - 1);
- while (isdigit(*l))
- l++;
- switch (state) {
- case NONE:
- lastnum = curnum;
- state = NUM;
- break;
- case DASH:
- for (; lastnum <= curnum; lastnum++)
- BIT_SET(size, lastnum, mask);
- state = NONE;
- break;
- case NUM:
- default:
- goto parserr;
- }
- continue;
- }
- switch (*l) {
- case ',':
- switch (state) {
- case NONE:
- break;
- case NUM:
- BIT_SET(size, curnum, mask);
- state = NONE;
- break;
- case DASH:
- goto parserr;
- break;
- }
- break;
- case '-':
- if (state != NUM)
- goto parserr;
- state = DASH;
- break;
- default:
- goto parserr;
- }
- l++;
- }
- switch (state) {
- case NONE:
- break;
- case NUM:
- BIT_SET(size, curnum, mask);
- break;
- case DASH:
- goto parserr;
- }
- return;
-parserr:
- errx(EXIT_FAILURE, "Malformed list %s", list);
-}
-
-static void
-parsecpulist(char *list, cpuset_t *mask)
-{
-
- if (strcasecmp(list, "all") == 0) {
- if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
- sizeof(*mask), mask) != 0)
- err(EXIT_FAILURE, "getaffinity");
- return;
- }
- parselist(list, (struct bitset *)mask, CPU_SETSIZE);
-}
-
-/*
- * permissively parse policy:domain list
- * allow:
- * round-robin:0-4 explicit
- * round-robin:all explicit root domains
- * 0-4 implicit root policy
- * round-robin implicit root domains
- * all explicit root domains and implicit policy
- */
-static void
-parsedomainlist(char *list, domainset_t *mask, int *policyp)
-{
- domainset_t rootmask;
- struct numa_policy *policy;
- char *l;
- int p;
-
- /*
- * Use the rootset's policy as the default for unspecified policies.
- */
- if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
- sizeof(rootmask), &rootmask, &p) != 0)
- err(EXIT_FAILURE, "getdomain");
-
- l = list;
- for (policy = &policies[0]; policy->name != NULL; policy++) {
- if (strncasecmp(l, policy->name, strlen(policy->name)) == 0) {
- p = policy->policy;
- l += strlen(policy->name);
- if (*l != ':' && *l != '\0')
- errx(EXIT_FAILURE, "Malformed list %s", list);
- if (*l == ':')
- l++;
- break;
- }
- }
- *policyp = p;
- if (strcasecmp(l, "all") == 0 || *l == '\0') {
- DOMAINSET_COPY(&rootmask, mask);
- return;
- }
- parselist(l, (struct bitset *)mask, DOMAINSET_SETSIZE);
-}
-
static void
printset(struct bitset *mask, int size)
{
@@ -327,11 +180,11 @@ main(int argc, char *argv[])
break;
case 'l':
lflag = 1;
- parsecpulist(optarg, &mask);
+ cpuset_parselist(optarg, &mask);
break;
case 'n':
nflag = 1;
- parsedomainlist(optarg, &domains, &policy);
+ domainset_parselist(optarg, &domains, &policy);
break;
case 'p':
pflag = 1;
diff --git a/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ticks.d b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ticks.d
new file mode 100644
index 000000000000..4061db9858c1
--- /dev/null
+++ b/cddl/contrib/opensolaris/cmd/dtrace/test/tst/common/profile-n/tst.ticks.d
@@ -0,0 +1,54 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright 2025 Mark Johnston <markj@FreeBSD.org>
+ */
+
+/*
+ * For 10s, verify that the value of `ticks goes up by `hz each second.
+ */
+
+#pragma D option quiet
+
+BEGIN
+{
+ i = 0;
+}
+
+tick-1s
+{
+ if (i == 0) {
+ t = *(int *)&`ticks;
+ i++;
+ } else {
+ u = *(int *)&`ticks;
+ if (u - t != `hz) {
+ printf("ticks: %d, expected %d\n", u - t, `hz);
+ exit(1);
+ }
+ t = u;
+ i++;
+ if (i == 10) {
+ exit(0);
+ }
+ }
+}
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
index d1ebaa8791da..8cc504856567 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.c
@@ -1918,6 +1918,14 @@ dt_node_op1(int op, dt_node_t *cp)
return (cp);
}
+ /*
+ * When applying the addressof operator to an identifier, it's okay if
+ * we can't find type information for the identifier, so flag the node
+ * to ensure that we don't raise an error.
+ */
+ if (op == DT_TOK_ADDROF && cp->dn_kind == DT_NODE_IDENT)
+ cp->dn_flags |= DT_NF_IDENTADDR;
+
dnp = dt_node_alloc(DT_NODE_OP1);
assert(op <= USHRT_MAX);
dnp->dn_op = (ushort_t)op;
@@ -2786,10 +2794,21 @@ dt_xcook_ident(dt_node_t *dnp, dt_idhash_t *dhp, uint_t idkind, int create)
dt_module_modelname(dtp->dt_ddefs));
}
- xyerror(D_SYM_NOTYPES,
+ /*
+ * If we're taking the address of an identifier that
+ * doesn't have type info, try to make it a void *.
+ * This lets us use identifiers that are defined in
+ * assembly and don't have type information.
+ */
+ if ((dnp->dn_flags & DT_NF_IDENTADDR) == 0 ||
+ dtrace_lookup_by_type(dtp, DTRACE_OBJ_CDEFS,
+ "void", &dtt) != 0) {
+ xyerror(D_SYM_NOTYPES,
"no symbolic type information is available for "
- "%s%s%s: %s\n", dts.dts_object, mark, dts.dts_name,
- dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ "%s%s%s: %s\n", dts.dts_object, mark,
+ dts.dts_name,
+ dtrace_errmsg(dtp, dtrace_errno(dtp)));
+ }
}
idp = dt_ident_create(name, DT_IDENT_SYMBOL, 0, 0,
@@ -4506,30 +4525,30 @@ dt_cook_none(dt_node_t *dnp, uint_t idflags)
return (dnp);
}
-static dt_node_t *(*dt_cook_funcs[])(dt_node_t *, uint_t) = {
- dt_cook_none, /* DT_NODE_FREE */
- dt_cook_none, /* DT_NODE_INT */
- dt_cook_none, /* DT_NODE_STRING */
- dt_cook_ident, /* DT_NODE_IDENT */
- dt_cook_var, /* DT_NODE_VAR */
- dt_cook_none, /* DT_NODE_SYM */
- dt_cook_none, /* DT_NODE_TYPE */
- dt_cook_func, /* DT_NODE_FUNC */
- dt_cook_op1, /* DT_NODE_OP1 */
- dt_cook_op2, /* DT_NODE_OP2 */
- dt_cook_op3, /* DT_NODE_OP3 */
- dt_cook_statement, /* DT_NODE_DEXPR */
- dt_cook_statement, /* DT_NODE_DFUNC */
- dt_cook_aggregation, /* DT_NODE_AGG */
- dt_cook_none, /* DT_NODE_PDESC */
- dt_cook_clause, /* DT_NODE_CLAUSE */
- dt_cook_inline, /* DT_NODE_INLINE */
- dt_cook_member, /* DT_NODE_MEMBER */
- dt_cook_xlator, /* DT_NODE_XLATOR */
- dt_cook_none, /* DT_NODE_PROBE */
- dt_cook_provider, /* DT_NODE_PROVIDER */
- dt_cook_none, /* DT_NODE_PROG */
- dt_cook_none, /* DT_NODE_IF */
+static dt_node_t *(* const dt_cook_funcs[])(dt_node_t *, uint_t) = {
+ [DT_NODE_FREE] = dt_cook_none,
+ [DT_NODE_INT] = dt_cook_none,
+ [DT_NODE_STRING] = dt_cook_none,
+ [DT_NODE_IDENT] = dt_cook_ident,
+ [DT_NODE_VAR] = dt_cook_var,
+ [DT_NODE_SYM] = dt_cook_none,
+ [DT_NODE_TYPE] = dt_cook_none,
+ [DT_NODE_FUNC] = dt_cook_func,
+ [DT_NODE_OP1] = dt_cook_op1,
+ [DT_NODE_OP2] = dt_cook_op2,
+ [DT_NODE_OP3] = dt_cook_op3,
+ [DT_NODE_DEXPR] = dt_cook_statement,
+ [DT_NODE_DFUNC] = dt_cook_statement,
+ [DT_NODE_AGG] = dt_cook_aggregation,
+ [DT_NODE_PDESC] = dt_cook_none,
+ [DT_NODE_CLAUSE] = dt_cook_clause,
+ [DT_NODE_INLINE] = dt_cook_inline,
+ [DT_NODE_MEMBER] = dt_cook_member,
+ [DT_NODE_XLATOR] = dt_cook_xlator,
+ [DT_NODE_PROBE] = dt_cook_none,
+ [DT_NODE_PROVIDER] = dt_cook_provider,
+ [DT_NODE_PROG] = dt_cook_none,
+ [DT_NODE_IF] = dt_cook_none,
};
/*
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
index 3a146c5d2592..1d2f33beee0f 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_parser.h
@@ -182,6 +182,7 @@ typedef struct dt_node {
#define DT_NF_WRITABLE 0x10 /* node is writable (can be modified) */
#define DT_NF_BITFIELD 0x20 /* node is an integer bitfield */
#define DT_NF_USERLAND 0x40 /* data is a userland address */
+#define DT_NF_IDENTADDR 0x80 /* node is an identifier address */
#define DT_TYPE_NAMELEN 128 /* reasonable size for ctf_type_name() */
diff --git a/cddl/usr.sbin/dtrace/tests/common/profile-n/Makefile b/cddl/usr.sbin/dtrace/tests/common/profile-n/Makefile
index 84f4706b61ee..ceb52fcf5bd0 100644
--- a/cddl/usr.sbin/dtrace/tests/common/profile-n/Makefile
+++ b/cddl/usr.sbin/dtrace/tests/common/profile-n/Makefile
@@ -37,6 +37,7 @@ ${PACKAGE}FILES= \
tst.profileusec.d \
tst.profileusec.d.out \
tst.sym.ksh \
+ tst.ticks.d \
tst.ufunc.ksh \
tst.ufuncsort.ksh \
tst.ufuncsort.ksh.out \
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/bsnmpclient.3 b/contrib/bsnmp/lib/bsnmpclient.3
index 0a2286eb14c4..1a5aa2e5e3a6 100644
--- a/contrib/bsnmp/lib/bsnmpclient.3
+++ b/contrib/bsnmp/lib/bsnmpclient.3
@@ -31,7 +31,7 @@
.\"
.\" $Begemot: bsnmp/lib/bsnmpclient.3,v 1.12 2005/10/04 08:46:50 brandt_h Exp $
.\"
-.Dd March 31, 2020
+.Dd June 24, 2025
.Dt BSNMPCLIENT 3
.Os
.Sh NAME
@@ -155,7 +155,7 @@ struct snmp_client {
snmp_timeout_start_f timeout_start;
snmp_timeout_stop_f timeout_stop;
- char local_path[sizeof(SNMP_LOCAL_PATH)];
+ char local_path[SUNPATHLEN];
};
.Ed
.Pp
@@ -285,8 +285,19 @@ The function will be called with the return value of the corresponding
.Fn timeout_start
function.
.It Va local_path
-If in local socket mode, the name of the clients socket.
-Not needed by the application.
+In local socket mode, optional path name the client socket shall be bound to
+before connecting to the server.
+For
+.Dv SOCK_STREAM
+local socket the named path is optional, and library will skip
+.Xr bind 2
+if path is not provided.
+For
+.Dv SOCK_DGRAM
+local socket the named path is required, thus library will create a random
+one in
+.Pa /tmp
+if path is not provided.
.El
.Pp
In the current implementation there is a global variable
diff --git a/contrib/bsnmp/lib/snmpclient.c b/contrib/bsnmp/lib/snmpclient.c
index d5d4af998a0c..44dfbd5a06b1 100644
--- a/contrib/bsnmp/lib/snmpclient.c
+++ b/contrib/bsnmp/lib/snmpclient.c
@@ -977,7 +977,10 @@ remove_local(void)
static int
open_client_local(const char *path)
{
- struct sockaddr_un sa;
+ struct sockaddr_un sa = {
+ .sun_family = AF_LOCAL,
+ .sun_len = sizeof(sa),
+ };
char *ptr;
int stype;
@@ -1003,43 +1006,56 @@ open_client_local(const char *path)
return (-1);
}
- snprintf(snmp_client.local_path, sizeof(snmp_client.local_path),
- "%s", SNMP_LOCAL_PATH);
-
- if (mktemp(snmp_client.local_path) == NULL) {
- seterr(&snmp_client, "%s", strerror(errno));
- (void)close(snmp_client.fd);
- snmp_client.fd = -1;
- return (-1);
+ /*
+ * A datagram socket requires a name to receive replies back. Would
+ * be cool to have an extension to unix(4) sockets similar to ip(4)
+ * IP_RECVDSTADDR/IP_SENDSRCADDR, so that a one-to-many datagram
+ * UNIX socket can send replies to its anonymous peers.
+ */
+ if (snmp_client.trans == SNMP_TRANS_LOC_DGRAM &&
+ snmp_client.local_path[0] == '\0') {
+ (void)strlcpy(snmp_client.local_path, "/tmp/snmpXXXXXXXXXXXXXX",
+ sizeof(snmp_client.local_path));
+ if (mktemp(snmp_client.local_path) == NULL) {
+ seterr(&snmp_client, "mktemp(3): %s", strerror(errno));
+ goto fail;
+ }
}
- sa.sun_family = AF_LOCAL;
- sa.sun_len = sizeof(sa);
- strcpy(sa.sun_path, snmp_client.local_path);
-
- if (bind(snmp_client.fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) {
- seterr(&snmp_client, "%s", strerror(errno));
- (void)close(snmp_client.fd);
- snmp_client.fd = -1;
- (void)remove(snmp_client.local_path);
- return (-1);
+ if (snmp_client.local_path[0] != '\0') {
+ if (strlcpy(sa.sun_path, snmp_client.local_path,
+ sizeof(sa.sun_path)) >=
+ sizeof(sa.sun_path)) {
+ seterr(&snmp_client, "%s",
+ "Local socket pathname too long");
+ goto fail;
+ }
+ if (bind(snmp_client.fd, (struct sockaddr *)&sa, sizeof(sa)) ==
+ -1) {
+ seterr(&snmp_client, "%s", strerror(errno));
+ goto fail;
+ }
+ atexit(remove_local);
}
- atexit(remove_local);
- sa.sun_family = AF_LOCAL;
- sa.sun_len = offsetof(struct sockaddr_un, sun_path) +
- strlen(snmp_client.chost);
- strncpy(sa.sun_path, snmp_client.chost, sizeof(sa.sun_path) - 1);
- sa.sun_path[sizeof(sa.sun_path) - 1] = '\0';
+ if (strlcpy(sa.sun_path, snmp_client.chost, sizeof(sa.sun_path)) >=
+ sizeof(sa.sun_path)) {
+ seterr(&snmp_client, "%s", "Server socket pathname too long");
+ goto fail;
+ }
if (connect(snmp_client.fd, (struct sockaddr *)&sa, sa.sun_len) == -1) {
seterr(&snmp_client, "%s", strerror(errno));
- (void)close(snmp_client.fd);
- snmp_client.fd = -1;
- (void)remove(snmp_client.local_path);
- return (-1);
+ goto fail;
}
return (0);
+
+fail:
+ (void)close(snmp_client.fd);
+ snmp_client.fd = -1;
+ if (snmp_client.local_path[0] != '\0')
+ (void)remove(snmp_client.local_path);
+ return (-1);
}
/*
@@ -1926,70 +1942,64 @@ get_transp(struct snmp_client *sc, const char **strp)
* community strings are legal.
*
* \param sc client struct to set errors
- * \param strp possible start of community; updated to the point to
- * the next character to parse
+ * \param comm possible start of community; updated to start & end
*
- * \return end of community; equals *strp if there is none; NULL if there
- * was an error
+ * \return the next character to parse; NULL if there was an error
*/
static inline const char *
-get_comm(struct snmp_client *sc, const char **strp)
+get_comm(struct snmp_client *sc, const char *comm[2])
{
- const char *p = strrchr(*strp, '@');
+ const char *p = strrchr(comm[0], '@');
if (p == NULL)
/* no community string */
- return (*strp);
+ return (comm[1] = comm[0]);
- if (p - *strp > SNMP_COMMUNITY_MAXLEN) {
+ if (p - comm[0] > SNMP_COMMUNITY_MAXLEN) {
seterr(sc, "community string too long '%.*s'",
- p - *strp, *strp);
+ p - comm[0], comm[0]);
return (NULL);
}
- *strp = p + 1;
- return (p);
+ return ((comm[1] = p) + 1);
}
/**
* Try to get an IPv6 address. This starts with an [ and should end with an ]
* and everything between should be not longer than INET6_ADDRSTRLEN and
- * parseable by inet_pton().
+ * parseable by getaddrinfo().
*
* \param sc client struct to set errors
- * \param strp possible start of IPv6 address (the '['); updated to point to
- * the next character to parse (the one after the closing ']')
+ * \param ipv6 possible start of IPv6 address (the '['); updated to actual
+ * start (one after '[') and actual end (the '[' itself)
*
- * \return end of address (equals *strp + 1 if there is none) or NULL
- * on errors
+ * \return the next character to parse (the one after the closing ']')
+ * or NULL on errors
*/
static inline const char *
-get_ipv6(struct snmp_client *sc, const char **strp)
+get_ipv6(struct snmp_client *sc, const char *ipv6[2])
{
- char str[INET6_ADDRSTRLEN + IF_NAMESIZE];
+ char str[INET6_ADDRSTRLEN];
+ const char *p;
struct addrinfo hints, *res;
int error;
- if (**strp != '[')
- return (*strp + 1);
+ if (ipv6[0][0] != '[')
+ return (ipv6[1] = ipv6[0]);
- const char *p = *strp + 1;
- while (*p != ']' ) {
- if (*p == '\0') {
- seterr(sc, "unterminated IPv6 address '%.*s'",
- p - *strp, *strp);
- return (NULL);
- }
- p++;
+ if ((p = strchr(++(ipv6[0]), ']')) == NULL) {
+ seterr(sc, "unterminated IPv6 address '%s'", ipv6[0]);
+ return (NULL);
}
- if (p - *strp > INET6_ADDRSTRLEN + IF_NAMESIZE) {
- seterr(sc, "IPv6 address too long '%.*s'", p - *strp, *strp);
+ if ((size_t)(p - ipv6[0]) >= sizeof(str)) {
+ seterr(sc, "IPv6 address too long '%.*s'",
+ p - ipv6[0], ipv6[0]);
return (NULL);
}
- strncpy(str, *strp + 1, p - (*strp + 1));
- str[p - (*strp + 1)] = '\0';
+ strncpy(str, ipv6[0], p - ipv6[0]);
+ str[p - ipv6[0]] = '\0';
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME | AI_NUMERICHOST;
@@ -2002,8 +2012,7 @@ get_ipv6(struct snmp_client *sc, const char **strp)
return (NULL);
}
freeaddrinfo(res);
- *strp = p + 1;
- return (p);
+ return ((ipv6[1] = p) + 1);
}
/**
@@ -2012,30 +2021,29 @@ get_ipv6(struct snmp_client *sc, const char **strp)
* inet_aton().
*
* \param sc client struct to set errors
- * \param strp possible start of IPv4 address; updated to point to the
- * next character to parse
+ * \param ipv4 possible start of IPv4 address; updated to start & end
*
- * \return end of address (equals *strp if there is none) or NULL
- * on errors
+ * \return the next character to parse; or NULL on errors
*/
static inline const char *
-get_ipv4(struct snmp_client *sc, const char **strp)
+get_ipv4(struct snmp_client *sc, const char *ipv4[2])
{
- const char *p = *strp;
+ char str[INET_ADDRSTRLEN];
+ const char *p = ipv4[0];
while (isascii(*p) && (isdigit(*p) || *p == '.'))
p++;
- if (p - *strp > INET_ADDRSTRLEN) {
- seterr(sc, "IPv4 address too long '%.*s'", p - *strp, *strp);
+ if ((size_t)(p - ipv4[0]) >= sizeof(str)) {
+ seterr(sc, "IPv4 address too long '%.*s'",
+ p - ipv4[0], ipv4[0]);
return (NULL);
}
- if (*strp == p)
- return *strp;
+ if (p == ipv4[0])
+ return (ipv4[1] = ipv4[0]);
- char str[INET_ADDRSTRLEN + 1];
- strncpy(str, *strp, p - *strp);
- str[p - *strp] = '\0';
+ strncpy(str, ipv4[0], p - ipv4[0]);
+ str[p - ipv4[0]] = '\0';
struct in_addr addr;
if (inet_aton(str, &addr) != 1) {
@@ -2043,8 +2051,7 @@ get_ipv4(struct snmp_client *sc, const char **strp)
return (NULL);
}
- *strp = p;
- return (p);
+ return (ipv4[1] = p);
}
/**
@@ -2052,24 +2059,19 @@ get_ipv4(struct snmp_client *sc, const char **strp)
* the last colon (if any). There is no length restriction.
*
* \param sc client struct to set errors
- * \param strp possible start of hostname; updated to point to the next
- * character to parse (the trailing NUL character or the last
- * colon)
+ * \param host possible start of hostname; start & end updated
*
- * \return end of address (equals *strp if there is none)
+ * \return next character to parse (semicolon or NUL)
*/
static inline const char *
-get_host(struct snmp_client *sc __unused, const char **strp)
+get_host(struct snmp_client *sc __unused, const char *host[2])
{
- const char *p = strrchr(*strp, ':');
+ const char *p = strrchr(host[0], ':');
- if (p == NULL) {
- *strp += strlen(*strp);
- return (*strp);
- }
+ if (p == NULL)
+ return (host[1] = host[0] + strlen(host[0]));
- *strp = p;
- return (p);
+ return (host[1] = p);
}
/**
@@ -2077,25 +2079,24 @@ get_host(struct snmp_client *sc __unused, const char **strp)
* of string. The port number must not be empty.
*
* \param sc client struct to set errors
- * \param strp possible start of port specification; if this points to a
+ * \param port possible start of port specification; if this points to a
* colon there is a port specification
*
* \return end of port number (equals *strp if there is none); NULL
* if there is no port number
*/
static inline const char *
-get_port(struct snmp_client *sc, const char **strp)
+get_port(struct snmp_client *sc, const char *port[2])
{
- if (**strp != ':')
- return (*strp + 1);
+ if (*port[0] != ':')
+ return (port[1] = port[0]);
- if ((*strp)[1] == '\0') {
+ if (port[0][1] == '\0') {
seterr(sc, "empty port name");
return (NULL);
}
- *strp += strlen(*strp);
- return (*strp);
+ return (port[1] = ++(port[0]) + strlen(port[0]));
}
/**
@@ -2156,6 +2157,7 @@ int
snmp_parse_server(struct snmp_client *sc, const char *str)
{
const char *const orig = str;
+ const char *comm[2], *ipv6[2], *ipv4[2], *host[2], *port[2];
/* parse input */
int def_trans = 0, trans = get_transp(sc, &str);
@@ -2165,42 +2167,32 @@ snmp_parse_server(struct snmp_client *sc, const char *str)
if (orig == str)
def_trans = 1;
- const char *const comm[2] = {
- str,
- get_comm(sc, &str),
- };
- if (comm[1] == NULL)
+ comm[0] = str;
+ if ((str = get_comm(sc, comm)) == NULL)
return (-1);
- const char *const ipv6[2] = {
- str + 1,
- get_ipv6(sc, &str),
- };
- if (ipv6[1] == NULL)
+ ipv6[0] = str;
+ if ((str = get_ipv6(sc, ipv6)) == NULL)
return (-1);
- const char *ipv4[2] = {
- str,
- str,
- };
-
- const char *host[2] = {
- str,
- str,
- };
-
if (ipv6[0] == ipv6[1]) {
- ipv4[1] = get_ipv4(sc, &str);
+ ipv4[0] = str;
+ if ((str = get_ipv4(sc, ipv4)) == NULL) {
+ /* This failure isn't fatal: restore str. */
+ str = ipv4[0];
+ ipv4[0] = ipv4[1] = NULL;
+ }
- if (ipv4[0] == ipv4[1])
- host[1] = get_host(sc, &str);
- }
+ if (ipv4[0] == ipv4[1]) {
+ host[0] = str;
+ str = get_host(sc, host);
+ } else
+ host[0] = host[1] = NULL;
+ } else
+ ipv4[0] = ipv4[1] = host[0] = host[1] = NULL;
- const char *port[2] = {
- str + 1,
- get_port(sc, &str),
- };
- if (port[1] == NULL)
+ port[0] = str;
+ if ((str = get_port(sc, port)) == NULL)
return (-1);
if (*str != '\0') {
@@ -2231,7 +2223,7 @@ snmp_parse_server(struct snmp_client *sc, const char *str)
return (-1);
if (def_trans)
trans = SNMP_TRANS_UDP;
- } else {
+ } else if (host[0] != host[1]) {
if ((chost = save_str(sc, host)) == NULL)
return (-1);
@@ -2246,6 +2238,17 @@ snmp_parse_server(struct snmp_client *sc, const char *str)
break;
}
}
+ } else switch (trans) {
+ case SNMP_TRANS_UDP:
+ case SNMP_TRANS_UDP6:
+ if ((chost = strdup(DEFAULT_HOST)) == NULL)
+ return (-1);
+ break;
+ case SNMP_TRANS_LOC_DGRAM:
+ case SNMP_TRANS_LOC_STREAM:
+ if ((chost = strdup(SNMP_DEFAULT_LOCAL)) == NULL)
+ return (-1);
+ break;
}
char *cport;
diff --git a/contrib/bsnmp/lib/snmpclient.h b/contrib/bsnmp/lib/snmpclient.h
index 662dc7c4a204..a8a79ff824bc 100644
--- a/contrib/bsnmp/lib/snmpclient.h
+++ b/contrib/bsnmp/lib/snmpclient.h
@@ -35,6 +35,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <stddef.h>
@@ -42,8 +43,6 @@
#define SNMP_STRERROR_LEN 200
#define SNMP_DEFAULT_LOCAL "/var/run/snmpd.sock"
-#define SNMP_LOCAL_PATH "/tmp/snmpXXXXXXXXXXXXXX"
-
/*
* transport methods
*/
@@ -111,7 +110,7 @@ struct snmp_client {
snmp_timeout_start_f timeout_start;
snmp_timeout_stop_f timeout_stop;
- char local_path[sizeof(SNMP_LOCAL_PATH)];
+ char local_path[SUNPATHLEN];
};
/* the global context */
diff --git a/contrib/bsnmp/snmpd/main.c b/contrib/bsnmp/snmpd/main.c
index c77572934d24..933ab7aa655a 100644
--- a/contrib/bsnmp/snmpd/main.c
+++ b/contrib/bsnmp/snmpd/main.c
@@ -237,7 +237,6 @@ static struct request_info req;
#endif
/* transports */
-extern const struct transport_def udp_trans;
extern const struct transport_def lsock_trans;
struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list);
@@ -1187,12 +1186,7 @@ snmpd_input(struct port_input *pi, struct tport *tport)
sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
if (ferr == SNMPD_INPUT_OK) {
- if (tport->transport->vtab->send != NULL)
- slen = tport->transport->vtab->send(tport, sndbuf,
- sndlen, pi->peer, pi->peerlen);
- else
- slen = tport->transport->vtab->send2(tport, sndbuf,
- sndlen, pi);
+ slen = tport->transport->vtab->send(tport, sndbuf, sndlen, pi);
if (slen == -1)
syslog(LOG_ERR, "send*: %m");
else if ((size_t)slen != sndlen)
@@ -1215,6 +1209,11 @@ void
snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
const struct sockaddr *addr, socklen_t addrlen)
{
+ struct port_input pi = {
+ .fd = -1,
+ .peer = __DECONST(struct sockaddr *, addr),
+ .peerlen = addrlen,
+ };
struct transport *trans = targ;
struct tport *tp;
u_char *sndbuf;
@@ -1232,10 +1231,7 @@ snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY");
- if (trans->vtab->send != NULL)
- len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen);
- else
- len = trans->vtab->send2(tp, sndbuf, sndlen, NULL);
+ len = trans->vtab->send(tp, sndbuf, sndlen, &pi);
if (len == -1)
syslog(LOG_ERR, "sendto: %m");
@@ -1661,8 +1657,6 @@ main(int argc, char *argv[])
syslog(LOG_ERR, "atexit failed: %m");
exit(1);
}
- if (udp_trans.start() != SNMP_ERR_NOERROR)
- syslog(LOG_WARNING, "cannot start UDP transport");
if (lsock_trans.start() != SNMP_ERR_NOERROR)
syslog(LOG_WARNING, "cannot start LSOCK transport");
if (inet_trans.start() != SNMP_ERR_NOERROR)
diff --git a/contrib/bsnmp/snmpd/snmpd.h b/contrib/bsnmp/snmpd/snmpd.h
index 394a4f4736d6..b0e60040d025 100644
--- a/contrib/bsnmp/snmpd/snmpd.h
+++ b/contrib/bsnmp/snmpd/snmpd.h
@@ -192,12 +192,8 @@ struct transport_def {
int (*init_port)(struct tport *);
ssize_t (*send)(struct tport *, const u_char *, size_t,
- const struct sockaddr *, size_t);
- ssize_t (*recv)(struct tport *, struct port_input *);
-
- /** send via a multi-socket port */
- ssize_t (*send2)(struct tport *, const u_char *, size_t,
struct port_input *);
+ ssize_t (*recv)(struct tport *, struct port_input *);
};
struct transport {
struct asn_oid index; /* transport table index */
diff --git a/contrib/bsnmp/snmpd/trans_inet.c b/contrib/bsnmp/snmpd/trans_inet.c
index dccfb6234222..d06b85ac11f6 100644
--- a/contrib/bsnmp/snmpd/trans_inet.c
+++ b/contrib/bsnmp/snmpd/trans_inet.c
@@ -375,17 +375,16 @@ inet_recv(struct tport *tp, struct port_input *pi)
* \param tp port
* \param buf data to send
* \param len number of bytes to send
- * \param addr destination address
- * \param addlen destination address length
+ * \param pi destination
*
* \return number of bytes sent
*/
static ssize_t
-inet_send2(struct tport *tp, const u_char *buf, size_t len,
+inet_send(struct tport *tp, const u_char *buf, size_t len,
struct port_input *pi)
{
struct inet_port *p = __containerof(tp, struct inet_port, tport);
- struct port_sock *s = (pi == NULL) ? TAILQ_FIRST(&p->socks) :
+ struct port_sock *s = (pi->fd == -1) ? TAILQ_FIRST(&p->socks) :
__containerof(pi, struct port_sock, input);
struct iovec iov;
@@ -414,15 +413,14 @@ inet_send2(struct tport *tp, const u_char *buf, size_t len,
/** exported to daemon */
const struct transport_def inet_trans = {
- "inet",
- OIDX_begemotSnmpdTransInet,
- inet_start,
- inet_stop,
- inet_destroy_port,
- inet_activate,
- NULL,
- inet_recv,
- inet_send2,
+ .name = "inet",
+ .id = OIDX_begemotSnmpdTransInet,
+ .start = inet_start,
+ .stop = inet_stop,
+ .close_port = inet_destroy_port,
+ .init_port = inet_activate,
+ .recv = inet_recv,
+ .send = inet_send,
};
struct inet_port_params {
diff --git a/contrib/bsnmp/snmpd/trans_lsock.c b/contrib/bsnmp/snmpd/trans_lsock.c
index ca2311be7cc3..01beb01927ec 100644
--- a/contrib/bsnmp/snmpd/trans_lsock.c
+++ b/contrib/bsnmp/snmpd/trans_lsock.c
@@ -58,20 +58,19 @@ static int lsock_stop(int);
static void lsock_close_port(struct tport *);
static int lsock_init_port(struct tport *);
static ssize_t lsock_send(struct tport *, const u_char *, size_t,
- const struct sockaddr *, size_t);
+ struct port_input *);
static ssize_t lsock_recv(struct tport *, struct port_input *);
/* exported */
const struct transport_def lsock_trans = {
- "lsock",
- OIDX_begemotSnmpdTransLsock,
- lsock_start,
- lsock_stop,
- lsock_close_port,
- lsock_init_port,
- lsock_send,
- lsock_recv,
- NULL
+ .name = "lsock",
+ .id = OIDX_begemotSnmpdTransLsock,
+ .start = lsock_start,
+ .stop = lsock_stop,
+ .close_port = lsock_close_port,
+ .init_port = lsock_init_port,
+ .send = lsock_send,
+ .recv = lsock_recv,
};
static struct transport *my_trans;
@@ -396,28 +395,10 @@ lsock_init_port(struct tport *tp)
* Send something
*/
static ssize_t
-lsock_send(struct tport *tp, const u_char *buf, size_t len,
- const struct sockaddr *addr, size_t addrlen)
+lsock_send(struct tport *tp __unused, const u_char *buf, size_t len,
+ struct port_input *pi)
{
- struct lsock_port *p = (struct lsock_port *)tp;
- struct lsock_peer *peer;
-
- if (p->type == LOCP_DGRAM_PRIV || p->type == LOCP_DGRAM_UNPRIV) {
- peer = LIST_FIRST(&p->peers);
-
- } else {
- /* search for the peer */
- LIST_FOREACH(peer, &p->peers, link)
- if (peer->input.peerlen == addrlen &&
- memcmp(peer->input.peer, addr, addrlen) == 0)
- break;
- if (peer == NULL) {
- errno = ENOTCONN;
- return (-1);
- }
- }
-
- return (sendto(peer->input.fd, buf, len, MSG_NOSIGNAL, addr, addrlen));
+ return (sendto(pi->fd, buf, len, MSG_NOSIGNAL, pi->peer, pi->peerlen));
}
static void
diff --git a/contrib/bsnmp/snmpd/trans_udp.c b/contrib/bsnmp/snmpd/trans_udp.c
deleted file mode 100644
index 8e9d1510d1d7..000000000000
--- a/contrib/bsnmp/snmpd/trans_udp.c
+++ /dev/null
@@ -1,439 +0,0 @@
-/*
- * Copyright (c) 2003
- * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
- * All rights reserved.
- *
- * Author: Harti Brandt <harti@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 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 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.
- *
- * $Begemot: bsnmp/snmpd/trans_udp.c,v 1.5 2005/10/04 08:46:56 brandt_h Exp $
- *
- * UDP transport
- */
-#include <sys/types.h>
-#include <sys/queue.h>
-#include <sys/ucred.h>
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <syslog.h>
-#include <string.h>
-#include <errno.h>
-#include <unistd.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include "snmpmod.h"
-#include "snmpd.h"
-#include "trans_udp.h"
-#include "tree.h"
-#include "oid.h"
-
-static int udp_start(void);
-static int udp_stop(int);
-static void udp_close_port(struct tport *);
-static int udp_init_port(struct tport *);
-static ssize_t udp_send(struct tport *, const u_char *, size_t,
- const struct sockaddr *, size_t);
-static ssize_t udp_recv(struct tport *, struct port_input *);
-
-/* exported */
-const struct transport_def udp_trans = {
- "udp",
- OIDX_begemotSnmpdTransUdp,
- udp_start,
- udp_stop,
- udp_close_port,
- udp_init_port,
- udp_send,
- udp_recv,
- NULL
-};
-static struct transport *my_trans;
-
-static int
-udp_start(void)
-{
- return (trans_register(&udp_trans, &my_trans));
-}
-
-static int
-udp_stop(int force __unused)
-{
- if (my_trans != NULL)
- if (trans_unregister(my_trans) != 0)
- return (SNMP_ERR_GENERR);
- return (SNMP_ERR_NOERROR);
-}
-
-/*
- * A UDP port is ready
- */
-static void
-udp_input(int fd __unused, void *udata)
-{
- struct udp_port *p = udata;
-
- p->input.peerlen = sizeof(p->ret);
- snmpd_input(&p->input, &p->tport);
-}
-
-/*
- * Create a UDP socket and bind it to the given port
- */
-static int
-udp_init_port(struct tport *tp)
-{
- struct udp_port *p = (struct udp_port *)tp;
- struct sockaddr_in addr;
- u_int32_t ip;
- const int on = 1;
-
- if ((p->input.fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
- syslog(LOG_ERR, "creating UDP socket: %m");
- return (SNMP_ERR_RES_UNAVAIL);
- }
- ip = (p->addr[0] << 24) | (p->addr[1] << 16) | (p->addr[2] << 8) |
- p->addr[3];
- memset(&addr, 0, sizeof(addr));
- addr.sin_addr.s_addr = htonl(ip);
- addr.sin_port = htons(p->port);
- addr.sin_family = AF_INET;
- addr.sin_len = sizeof(addr);
- if (addr.sin_addr.s_addr == INADDR_ANY) {
- if (setsockopt(p->input.fd, IPPROTO_IP, IP_RECVDSTADDR, &on,
- sizeof(on)) == -1) {
- syslog(LOG_ERR, "setsockopt(IP_RECVDSTADDR): %m");
- close(p->input.fd);
- p->input.fd = -1;
- return (SNMP_ERR_GENERR);
- }
- p->recvdstaddr = true;
- }
- if (bind(p->input.fd, (struct sockaddr *)&addr, sizeof(addr))) {
- if (errno == EADDRNOTAVAIL) {
- close(p->input.fd);
- p->input.fd = -1;
- return (SNMP_ERR_INCONS_NAME);
- }
- syslog(LOG_ERR, "bind: %s:%u %m", inet_ntoa(addr.sin_addr),
- p->port);
- close(p->input.fd);
- p->input.fd = -1;
- return (SNMP_ERR_GENERR);
- }
- if ((p->input.id = fd_select(p->input.fd, udp_input,
- p, NULL)) == NULL) {
- close(p->input.fd);
- p->input.fd = -1;
- return (SNMP_ERR_GENERR);
- }
- return (SNMP_ERR_NOERROR);
-}
-
-/*
- * Create a new SNMP Port object and start it, if we are not
- * in initialization mode. The arguments are in host byte order.
- */
-static int
-udp_open_port(u_int8_t *addr, u_int32_t udp_port, struct udp_port **pp)
-{
- struct udp_port *port;
- int err;
-
- if (udp_port > 0xffff)
- return (SNMP_ERR_NO_CREATION);
- if ((port = malloc(sizeof(*port))) == NULL)
- return (SNMP_ERR_GENERR);
- memset(port, 0, sizeof(*port));
-
- /* initialize common part */
- port->tport.index.len = 5;
- port->tport.index.subs[0] = addr[0];
- port->tport.index.subs[1] = addr[1];
- port->tport.index.subs[2] = addr[2];
- port->tport.index.subs[3] = addr[3];
- port->tport.index.subs[4] = udp_port;
-
- port->addr[0] = addr[0];
- port->addr[1] = addr[1];
- port->addr[2] = addr[2];
- port->addr[3] = addr[3];
- port->port = udp_port;
-
- port->input.fd = -1;
- port->input.id = NULL;
- port->input.stream = 0;
- port->input.cred = 0;
- port->input.peer = (struct sockaddr *)&port->ret;
- port->input.peerlen = sizeof(port->ret);
-
- trans_insert_port(my_trans, &port->tport);
-
- if (community != COMM_INITIALIZE &&
- (err = udp_init_port(&port->tport)) != SNMP_ERR_NOERROR) {
- udp_close_port(&port->tport);
- return (err);
- }
- *pp = port;
- return (SNMP_ERR_NOERROR);
-}
-
-/*
- * Close an SNMP port
- */
-static void
-udp_close_port(struct tport *tp)
-{
- struct udp_port *port = (struct udp_port *)tp;
-
- snmpd_input_close(&port->input);
- trans_remove_port(tp);
- free(port);
-}
-
-/*
- * Send something
- */
-static ssize_t
-udp_send(struct tport *tp, const u_char *buf, size_t len,
- const struct sockaddr *addr, size_t addrlen)
-{
- struct udp_port *p = (struct udp_port *)tp;
- struct cmsghdr *cmsg;
- struct msghdr msg;
- char cbuf[CMSG_SPACE(sizeof(struct in_addr))];
- struct iovec iov;
-
- iov.iov_base = __DECONST(void*, buf);
- iov.iov_len = len;
-
- msg.msg_flags = 0;
- msg.msg_iov = &iov;
- msg.msg_iovlen = 1;
- msg.msg_name = __DECONST(void *, addr);
- msg.msg_namelen = addrlen;
-
- if (p->recvdstaddr) {
- msg.msg_control = cbuf;
- msg.msg_controllen = sizeof(cbuf);
-
- cmsg = CMSG_FIRSTHDR(&msg);
- cmsg->cmsg_level = IPPROTO_IP;
- cmsg->cmsg_type = IP_SENDSRCADDR;
- cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
- memcpy(CMSG_DATA(cmsg), &p->dstaddr, sizeof(struct in_addr));
- } else {
- msg.msg_control = NULL;
- msg.msg_controllen = 0;
- }
-
- return (sendmsg(p->input.fd, &msg, 0));
-}
-
-static void
-check_priv_dgram(struct port_input *pi, struct sockcred *cred)
-{
-
- /* process explicitly sends credentials */
- if (cred)
- pi->priv = (cred->sc_euid == 0);
- else
- pi->priv = 0;
-}
-
-/*
- * Input from a datagram socket.
- * Each receive should return one datagram.
- */
-static ssize_t
-udp_recv(struct tport *tp, struct port_input *pi)
-{
- u_char embuf[1000];
- char cbuf[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) +
- CMSG_SPACE(sizeof(struct in_addr))];
- struct udp_port *p = (struct udp_port *)tp;
- struct msghdr msg;
- struct iovec iov[1];
- ssize_t len;
- struct cmsghdr *cmsg;
- struct sockcred *cred = NULL;
-
- if (pi->buf == NULL) {
- /* no buffer yet - allocate one */
- if ((pi->buf = buf_alloc(0)) == NULL) {
- /* ups - could not get buffer. Read away input
- * and drop it */
- (void)recvfrom(pi->fd, embuf, sizeof(embuf),
- 0, NULL, NULL);
- /* return error */
- return (-1);
- }
- pi->buflen = buf_size(0);
- }
-
- /* try to get a message */
- msg.msg_name = pi->peer;
- msg.msg_namelen = pi->peerlen;
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
- memset(cbuf, 0, sizeof(cbuf));
- msg.msg_control = cbuf;
- msg.msg_controllen = sizeof(cbuf);
- msg.msg_flags = 0;
-
- iov[0].iov_base = pi->buf;
- iov[0].iov_len = pi->buflen;
-
- len = recvmsg(pi->fd, &msg, 0);
-
- if (len == -1 || len == 0)
- /* receive error */
- return (-1);
-
- if (msg.msg_flags & MSG_TRUNC) {
- /* truncated - drop */
- snmpd_stats.silentDrops++;
- snmpd_stats.inTooLong++;
- return (-1);
- }
-
- pi->length = (size_t)len;
-
- for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
- cmsg = CMSG_NXTHDR(&msg, cmsg)) {
- if (cmsg->cmsg_level == IPPROTO_IP &&
- cmsg->cmsg_type == IP_RECVDSTADDR)
- memcpy(&p->dstaddr, CMSG_DATA(cmsg),
- sizeof(struct in_addr));
- if (cmsg->cmsg_level == SOL_SOCKET &&
- cmsg->cmsg_type == SCM_CREDS)
- cred = (struct sockcred *)(void *)CMSG_DATA(cmsg);
- }
-
- if (pi->cred)
- check_priv_dgram(pi, cred);
-
- return (0);
-}
-
-/*
- * Port table
- */
-int
-op_snmp_port(struct snmp_context *ctx, struct snmp_value *value,
- u_int sub, u_int iidx, enum snmp_op op)
-{
- asn_subid_t which = value->var.subs[sub-1];
- struct udp_port *p;
- u_int8_t addr[4];
- u_int32_t port;
-
- switch (op) {
-
- case SNMP_OP_GETNEXT:
- if ((p = (struct udp_port *)trans_next_port(my_trans,
- &value->var, sub)) == NULL)
- return (SNMP_ERR_NOSUCHNAME);
- index_append(&value->var, sub, &p->tport.index);
- break;
-
- case SNMP_OP_GET:
- if ((p = (struct udp_port *)trans_find_port(my_trans,
- &value->var, sub)) == NULL)
- return (SNMP_ERR_NOSUCHNAME);
- break;
-
- case SNMP_OP_SET:
- p = (struct udp_port *)trans_find_port(my_trans,
- &value->var, sub);
- ctx->scratch->int1 = (p != NULL);
-
- if (which != LEAF_begemotSnmpdPortStatus)
- abort();
- if (!TRUTH_OK(value->v.integer))
- return (SNMP_ERR_WRONG_VALUE);
-
- ctx->scratch->int2 = TRUTH_GET(value->v.integer);
-
- if (ctx->scratch->int2) {
- /* open an SNMP port */
- if (p != NULL)
- /* already open - do nothing */
- return (SNMP_ERR_NOERROR);
-
- if (index_decode(&value->var, sub, iidx, addr, &port))
- return (SNMP_ERR_NO_CREATION);
- return (udp_open_port(addr, port, &p));
-
- } else {
- /* close SNMP port - do in commit */
- }
- return (SNMP_ERR_NOERROR);
-
- case SNMP_OP_ROLLBACK:
- p = (struct udp_port *)trans_find_port(my_trans,
- &value->var, sub);
- if (ctx->scratch->int1 == 0) {
- /* did not exist */
- if (ctx->scratch->int2 == 1) {
- /* created */
- if (p != NULL)
- udp_close_port(&p->tport);
- }
- }
- return (SNMP_ERR_NOERROR);
-
- case SNMP_OP_COMMIT:
- p = (struct udp_port *)trans_find_port(my_trans,
- &value->var, sub);
- if (ctx->scratch->int1 == 1) {
- /* did exist */
- if (ctx->scratch->int2 == 0) {
- /* delete */
- if (p != NULL)
- udp_close_port(&p->tport);
- }
- }
- return (SNMP_ERR_NOERROR);
-
- default:
- abort();
- }
-
- /*
- * Come here to fetch the value
- */
- switch (which) {
-
- case LEAF_begemotSnmpdPortStatus:
- value->v.integer = 1;
- break;
-
- default:
- abort();
- }
-
- return (SNMP_ERR_NOERROR);
-}
diff --git a/contrib/bsnmp/snmpd/tree.def b/contrib/bsnmp/snmpd/tree.def
index 61b581120528..074a6e7e5390 100644
--- a/contrib/bsnmp/snmpd/tree.def
+++ b/contrib/bsnmp/snmpd/tree.def
@@ -117,15 +117,6 @@ typedef BegemotSnmpdTransportProto ENUM (
)
)
#
-# Port table
-#
- (4 begemotSnmpdPortTable
- (1 begemotSnmpdPortEntry : IPADDRESS INTEGER op_snmp_port
- (1 begemotSnmpdPortAddress IPADDRESS)
- (2 begemotSnmpdPortPort UNSIGNED32)
- (3 begemotSnmpdPortStatus INTEGER GET SET)
- ))
-#
# Community table
#
(5 begemotSnmpdCommunityTable
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/llvm-project/clang/include/clang/Sema/Sema.h b/contrib/llvm-project/clang/include/clang/Sema/Sema.h
index 7bfdaaae45a9..a59a9342341d 100644
--- a/contrib/llvm-project/clang/include/clang/Sema/Sema.h
+++ b/contrib/llvm-project/clang/include/clang/Sema/Sema.h
@@ -13052,12 +13052,19 @@ public:
/// ForConstraintInstantiation indicates we should continue looking when
/// encountering a lambda generic call operator, and continue looking for
/// arguments on an enclosing class template.
+ ///
+ /// \param SkipForSpecialization when specified, any template specializations
+ /// in a traversal would be ignored.
+ /// \param ForDefaultArgumentSubstitution indicates we should continue looking
+ /// when encountering a specialized member function template, rather than
+ /// returning immediately.
MultiLevelTemplateArgumentList getTemplateInstantiationArgs(
const NamedDecl *D, const DeclContext *DC = nullptr, bool Final = false,
std::optional<ArrayRef<TemplateArgument>> Innermost = std::nullopt,
bool RelativeToPrimary = false, const FunctionDecl *Pattern = nullptr,
bool ForConstraintInstantiation = false,
- bool SkipForSpecialization = false);
+ bool SkipForSpecialization = false,
+ bool ForDefaultArgumentSubstitution = false);
/// RAII object to handle the state changes required to synthesize
/// a function body.
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp
index a09e3be83c45..c2e8ed0c602e 100644
--- a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -269,7 +269,8 @@ HandleClassTemplateSpec(const ClassTemplateSpecializationDecl *ClassTemplSpec,
Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
MultiLevelTemplateArgumentList &Result,
const FunctionDecl *Pattern, bool RelativeToPrimary,
- bool ForConstraintInstantiation) {
+ bool ForConstraintInstantiation,
+ bool ForDefaultArgumentSubstitution) {
// Add template arguments from a function template specialization.
if (!RelativeToPrimary &&
Function->getTemplateSpecializationKindForInstantiation() ==
@@ -299,7 +300,8 @@ Response HandleFunction(Sema &SemaRef, const FunctionDecl *Function,
// If this function was instantiated from a specialized member that is
// a function template, we're done.
assert(Function->getPrimaryTemplate() && "No function template?");
- if (Function->getPrimaryTemplate()->isMemberSpecialization())
+ if (!ForDefaultArgumentSubstitution &&
+ Function->getPrimaryTemplate()->isMemberSpecialization())
return Response::Done();
// If this function is a generic lambda specialization, we are done.
@@ -465,7 +467,7 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
const NamedDecl *ND, const DeclContext *DC, bool Final,
std::optional<ArrayRef<TemplateArgument>> Innermost, bool RelativeToPrimary,
const FunctionDecl *Pattern, bool ForConstraintInstantiation,
- bool SkipForSpecialization) {
+ bool SkipForSpecialization, bool ForDefaultArgumentSubstitution) {
assert((ND || DC) && "Can't find arguments for a decl if one isn't provided");
// Accumulate the set of template argument lists in this structure.
MultiLevelTemplateArgumentList Result;
@@ -507,7 +509,8 @@ MultiLevelTemplateArgumentList Sema::getTemplateInstantiationArgs(
SkipForSpecialization);
} else if (const auto *Function = dyn_cast<FunctionDecl>(CurDecl)) {
R = HandleFunction(*this, Function, Result, Pattern, RelativeToPrimary,
- ForConstraintInstantiation);
+ ForConstraintInstantiation,
+ ForDefaultArgumentSubstitution);
} else if (const auto *Rec = dyn_cast<CXXRecordDecl>(CurDecl)) {
R = HandleRecordDecl(*this, Rec, Result, Context,
ForConstraintInstantiation);
@@ -3231,7 +3234,6 @@ bool Sema::SubstDefaultArgument(
// default argument expression appears.
ContextRAII SavedContext(*this, FD);
std::unique_ptr<LocalInstantiationScope> LIS;
- MultiLevelTemplateArgumentList NewTemplateArgs = TemplateArgs;
if (ForCallExpr) {
// When instantiating a default argument due to use in a call expression,
@@ -3244,19 +3246,10 @@ bool Sema::SubstDefaultArgument(
/*ForDefinition*/ false);
if (addInstantiatedParametersToScope(FD, PatternFD, *LIS, TemplateArgs))
return true;
- const FunctionTemplateDecl *PrimaryTemplate = FD->getPrimaryTemplate();
- if (PrimaryTemplate && PrimaryTemplate->isOutOfLine()) {
- TemplateArgumentList *CurrentTemplateArgumentList =
- TemplateArgumentList::CreateCopy(getASTContext(),
- TemplateArgs.getInnermost());
- NewTemplateArgs = getTemplateInstantiationArgs(
- FD, FD->getDeclContext(), /*Final=*/false,
- CurrentTemplateArgumentList->asArray(), /*RelativeToPrimary=*/true);
- }
}
runWithSufficientStackSpace(Loc, [&] {
- Result = SubstInitializer(PatternExpr, NewTemplateArgs,
+ Result = SubstInitializer(PatternExpr, TemplateArgs,
/*DirectInit*/ false);
});
}
diff --git a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index a12d2eff1d2c..614e6ea12541 100644
--- a/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/contrib/llvm-project/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -4659,10 +4659,12 @@ bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD,
//
// template<typename T>
// A<T> Foo(int a = A<T>::FooImpl());
- MultiLevelTemplateArgumentList TemplateArgs =
- getTemplateInstantiationArgs(FD, FD->getLexicalDeclContext(),
- /*Final=*/false, /*Innermost=*/std::nullopt,
- /*RelativeToPrimary=*/true);
+ MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(
+ FD, FD->getLexicalDeclContext(),
+ /*Final=*/false, /*Innermost=*/std::nullopt,
+ /*RelativeToPrimary=*/true, /*Pattern=*/nullptr,
+ /*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/false,
+ /*ForDefaultArgumentSubstitution=*/true);
if (SubstDefaultArgument(CallLoc, Param, TemplateArgs, /*ForCallExpr*/ true))
return true;
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/etc/gss-krb5/mech b/etc/gss-krb5/mech
index 94fed68a24eb..b13f665705c5 100644
--- a/etc/gss-krb5/mech
+++ b/etc/gss-krb5/mech
@@ -1,10 +1,10 @@
#
# Name OID Library name Kernel module
-kerberosv5 1.2.840.113554.1.2.2 /usr/lib/libgssapi_krb5.so.121 kgssapi_krb5
-kerberosv5 1.2.840.113554.1.2.3 /usr/lib/libgssapi_krb5.so.121 kgssapi_krb5
-kerberosv5 1.3.6.1.5.5.2 /usr/lib/libgssapi_krb5.so.121 kgssapi_krb5
-kerberosv5 1.2.840.48018.1.2.2.1 /usr/lib/libgssapi_krb5.so.121 kgssapi_krb5
-kerberosv5 1.2.840.48018.1.2.2.2 /usr/lib/libgssapi_krb5.so.121 kgssapi_krb5
-kerberosv5 1.2.840.48018.1.2.2.4 /usr/lib/libgssapi_krb5.so.121 kgssapi_krb5
-kerberosv5 1.2.840.48018.1.2.2.5 /usr/lib/libgssapi_krb5.so.121 kgssapi_krb5
-kerberosv5 1.3.5.1.5.2 /usr/lib/libgssapi_krb5.so.121 kgssapi_krb5
+kerberosv5 1.2.840.113554.1.2.2 /usr/lib/libgssapi_krb5.so.122 kgssapi_krb5
+kerberosv5 1.2.840.113554.1.2.3 /usr/lib/libgssapi_krb5.so.122 kgssapi_krb5
+kerberosv5 1.3.6.1.5.5.2 /usr/lib/libgssapi_krb5.so.122 kgssapi_krb5
+kerberosv5 1.2.840.48018.1.2.2.1 /usr/lib/libgssapi_krb5.so.122 kgssapi_krb5
+kerberosv5 1.2.840.48018.1.2.2.2 /usr/lib/libgssapi_krb5.so.122 kgssapi_krb5
+kerberosv5 1.2.840.48018.1.2.2.4 /usr/lib/libgssapi_krb5.so.122 kgssapi_krb5
+kerberosv5 1.2.840.48018.1.2.2.5 /usr/lib/libgssapi_krb5.so.122 kgssapi_krb5
+kerberosv5 1.3.5.1.5.2 /usr/lib/libgssapi_krb5.so.122 kgssapi_krb5
diff --git a/include/rpc/des.h b/include/rpc/des.h
index 5056e4b1545c..df4ab75d9bf0 100644
--- a/include/rpc/des.h
+++ b/include/rpc/des.h
@@ -56,26 +56,6 @@ struct desparams {
# define des_buf UDES.UDES_buf /* otherwise, pointer to data */
};
-#ifdef notdef
-
-/*
- * These ioctls are only implemented in SunOS. Maybe someday
- * if somebody writes a driver for DES hardware that works
- * with FreeBSD, we can being that back.
- */
-
-/*
- * Encrypt an arbitrary sized buffer
- */
-#define DESIOCBLOCK _IOWR('d', 6, struct desparams)
-
-/*
- * Encrypt of small amount of data, quickly
- */
-#define DESIOCQUICK _IOWR('d', 7, struct desparams)
-
-#endif
-
/*
* Software DES.
*/
diff --git a/krb5/include/Makefile b/krb5/include/Makefile
index 0a2ceaebb689..c7b3f0f10a99 100644
--- a/krb5/include/Makefile
+++ b/krb5/include/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
+PACKAGE= kerberos-lib
.include <src.opts.mk>
diff --git a/krb5/include/autoconf.h b/krb5/include/autoconf.h
index 24039611c7e7..a5e2ea5838b0 100644
--- a/krb5/include/autoconf.h
+++ b/krb5/include/autoconf.h
@@ -5,9 +5,6 @@
#ifndef KRB5_AUTOCONF_H
#define KRB5_AUTOCONF_H
-#include <sys/types.h>
-#include <machine/param.h>
-
/* Define if AES-NI support is enabled */
/* #undef AESNI */
diff --git a/krb5/lib/Makefile.inc b/krb5/lib/Makefile.inc
index 8df7b76410a2..b6e5f6275039 100644
--- a/krb5/lib/Makefile.inc
+++ b/krb5/lib/Makefile.inc
@@ -9,8 +9,10 @@
.include "../Makefile.inc"
+PACKAGE?= kerberos-lib
+
KRB5_KRB5LIBDIR= ${KRB5_SRCLIBDIR}/krb5
KRB5_K5CRYPTODIR= ${KRB5_SRCLIBDIR}/crypto
SHLIBDIR?= /usr/lib
-SHLIB_MAJOR?= 121
+SHLIB_MAJOR?= 122
diff --git a/krb5/lib/apputils/Makefile b/krb5/lib/apputils/Makefile
index 62ef36f0615e..cf430eb3cd27 100644
--- a/krb5/lib/apputils/Makefile
+++ b/krb5/lib/apputils/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5-lib
-
.include <src.opts.mk>
.include "../Makefile.inc"
diff --git a/krb5/lib/crypto/Makefile b/krb5/lib/crypto/Makefile
index 5087a2fb559b..4dda0d85da54 100644
--- a/krb5/lib/crypto/Makefile
+++ b/krb5/lib/crypto/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= k5crypto
# SHLIB_MAJOR= 3
LDFLAGS=-Wl,--no-undefined
LIBADD= com_err krb5support crypto
+VERSION_MAP= ${.CURDIR}/version.map
# XXX The following doesn't work. Even though the pathnames are the same
# XXX we need to use the alternative .include statements.
@@ -24,10 +23,6 @@ LIBADD= com_err krb5support crypto
# .include "${KRB5_CRYPTOLIBDIR}/builtin/Makefile.inc"
# .include "${KRB5_CRYPTOLIBDIR}/openssl/Makefile.inc"
-.include "${KRB5_SRCTOP}/lib/krb5/error_tables/Makefile.inc"
-
-SRCS+= ${GEN_ET}
-
.include "${KRB5_SRCTOP}/lib/crypto/krb/Makefile.inc"
.include "${KRB5_SRCTOP}/lib/crypto/builtin/Makefile.inc"
.include "${KRB5_SRCTOP}/lib/crypto/openssl/Makefile.inc"
diff --git a/krb5/lib/crypto/version.map b/krb5/lib/crypto/version.map
new file mode 100644
index 000000000000..57448f6d85fa
--- /dev/null
+++ b/krb5/lib/crypto/version.map
@@ -0,0 +1,109 @@
+k5crypto_3_MIT {
+ global:
+ krb5_c_make_random_key;
+ krb5_c_encrypt_length;
+ krb5_process_key;
+ krb5_string_to_cksumtype;
+ krb5_c_valid_enctype;
+ krb5_c_valid_cksumtype;
+ krb5_string_to_key;
+ krb5_c_encrypt_iov;
+ krb5_c_checksum_length;
+ is_keyed_cksum;
+ krb5_c_padding_length;
+ is_coll_proof_cksum;
+ krb5_init_random_key;
+ krb5_c_string_to_key_with_params;
+ krb5_c_random_make_octets;
+ krb5_c_random_os_entropy;
+ krb5_c_decrypt;
+ krb5_c_crypto_length;
+ krb5_c_block_size;
+ krb5_cksumtype_to_string;
+ krb5_c_keyed_checksum_types;
+ krb5_c_is_keyed_cksum;
+ krb5_c_crypto_length_iov;
+ valid_cksumtype;
+ krb5_c_random_seed;
+ krb5_c_random_to_key;
+ krb5_verify_checksum;
+ krb5_c_free_state;
+ krb5_c_verify_checksum;
+ krb5_c_random_add_entropy;
+ krb5_c_decrypt_iov;
+ krb5_c_make_checksum;
+ krb5_checksum_size;
+ krb5_free_cksumtypes;
+ krb5_finish_key;
+ krb5_encrypt_size;
+ krb5_c_keylengths;
+ krb5_c_prf;
+ krb5_encrypt;
+ krb5_string_to_enctype;
+ krb5_c_is_coll_proof_cksum;
+ krb5_c_init_state;
+ krb5_eblock_enctype;
+ krb5_decrypt;
+ krb5_c_encrypt;
+ krb5_c_enctype_compare;
+ krb5_c_verify_checksum_iov;
+ valid_enctype;
+ krb5_enctype_to_string;
+ krb5_enctype_to_name;
+ krb5_c_make_checksum_iov;
+ krb5_calculate_checksum;
+ krb5_c_string_to_key;
+ krb5_use_enctype;
+ krb5_random_key;
+ krb5_finish_random_key;
+ krb5_c_prf_length;
+ krb5int_c_mandatory_cksumtype;
+ krb5_c_fx_cf2_simple;
+ krb5int_c_weak_enctype;
+ krb5_encrypt_data;
+ krb5int_c_copy_keyblock;
+ krb5int_c_copy_keyblock_contents;
+ krb5int_c_free_keyblock_contents;
+ krb5int_c_free_keyblock;
+ krb5int_c_init_keyblock;
+ krb5int_hash_md4;
+ krb5int_hash_md5;
+ krb5int_hash_sha256;
+ krb5int_hash_sha384;
+ krb5int_enc_arcfour;
+ krb5int_hmac;
+ krb5_k_create_key;
+ krb5_k_decrypt;
+ krb5_k_decrypt_iov;
+ krb5_k_encrypt;
+ krb5_k_encrypt_iov;
+ krb5_k_free_key;
+ krb5_k_key_enctype;
+ krb5_k_key_keyblock;
+ krb5_k_make_checksum;
+ krb5_k_make_checksum_iov;
+ krb5_k_prf;
+ krb5_k_reference_key;
+ krb5_k_verify_checksum;
+ krb5_k_verify_checksum_iov;
+ krb5int_aes_encrypt;
+ krb5int_aes_decrypt;
+ krb5int_enc_des3;
+ krb5int_arcfour_gsscrypt;
+ krb5int_camellia_encrypt;
+ krb5int_cmac_checksum;
+ krb5int_enc_aes128;
+ krb5int_enc_aes256;
+ krb5int_enc_camellia128;
+ krb5int_enc_camellia256;
+ krb5int_derive_key;
+ krb5int_derive_random;
+ k5_sha256;
+ krb5int_nfold;
+ k5_allow_weak_pbkdf2iter;
+ krb5_c_prfplus;
+ krb5_c_derive_prfplus;
+ k5_enctype_to_ssf;
+ krb5int_c_deprecated_enctype;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/lib/gssapi/Makefile b/krb5/lib/gssapi/Makefile
index 51ed6f162d65..63e4d7df4bed 100644
--- a/krb5/lib/gssapi/Makefile
+++ b/krb5/lib/gssapi/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= gssapi_krb5
# SHLIB_MAJOR= 2
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5 k5crypto com_err krb5profile krb5support
+VERSION_MAP= ${.CURDIR}/version.map
# This is a contcatonation of:
# crypto/krb5/src/lib/gssapi/libgssapi_krb5.exports
diff --git a/krb5/lib/gssapi/version.map b/krb5/lib/gssapi/version.map
new file mode 100644
index 000000000000..d52c0d3d1e36
--- /dev/null
+++ b/krb5/lib/gssapi/version.map
@@ -0,0 +1,176 @@
+HEIMDAL_GSS_2.0 {
+ global:
+ gss_accept_sec_context;
+ gss_acquire_cred;
+ gss_acquire_cred_with_password;
+ gss_add_buffer_set_member;
+ gss_add_cred;
+ gss_add_cred_with_password;
+ gss_add_oid_set_member;
+ gss_authorize_localname;
+ gss_canonicalize_name;
+ gss_compare_name;
+ gss_context_time;
+ gss_create_empty_buffer_set;
+ gss_create_empty_oid_set;
+ gss_decapsulate_token;
+ gss_delete_name_attribute;
+ gss_delete_sec_context;
+ gss_display_mech_attr;
+ gss_display_name;
+ gss_display_name_ext;
+ gss_display_status;
+ gss_duplicate_name;
+ gss_encapsulate_token;
+ gss_export_cred;
+ gss_export_name;
+ gss_export_name_composite;
+ gss_export_sec_context;
+ gss_get_mic;
+ gss_get_name_attribute;
+ gss_import_cred;
+ gss_import_name;
+ gss_import_sec_context;
+ gss_indicate_mechs;
+ gss_indicate_mechs_by_attrs;
+ gss_init_sec_context;
+ gss_inquire_attrs_for_mech;
+ gss_inquire_context;
+ gss_inquire_cred;
+ gss_inquire_cred_by_mech;
+ gss_inquire_cred_by_oid;
+ gss_inquire_mech_for_saslname;
+ gss_inquire_mechs_for_name;
+ gss_inquire_name;
+ gss_inquire_names_for_mech;
+ gss_inquire_saslname_for_mech;
+ gss_krb5_ccache_name;
+ gss_krb5_copy_ccache;
+ gss_krb5_export_lucid_sec_context;
+ gss_krb5_free_lucid_sec_context;
+ gss_krb5_get_tkt_flags;
+ gss_krb5_import_cred;
+ gss_krb5_set_allowable_enctypes;
+ gss_oid_equal;
+ gss_oid_to_str;
+ gss_pname_to_uid;
+ gss_process_context_token;
+ gss_pseudo_random;
+ gss_release_buffer;
+ gss_release_buffer_set;
+ gss_release_cred;
+ gss_release_iov_buffer;
+ gss_release_name;
+ gss_release_oid;
+ gss_release_oid_set;
+ gss_seal;
+ gss_set_cred_option;
+ gss_set_name_attribute;
+ gss_set_sec_context_option;
+ gss_sign;
+ gss_store_cred;
+ gss_test_oid_set_member;
+ gss_unseal;
+ gss_unwrap;
+ gss_unwrap_iov;
+ gss_userok;
+ gss_verify;
+ gss_verify_mic;
+ gss_wrap;
+ gss_wrap_iov;
+ gss_wrap_iov_length;
+ gss_wrap_size_limit;
+ gsskrb5_extract_authtime_from_sec_context;
+ gsskrb5_extract_authz_data_from_sec_context;
+ krb5_gss_register_acceptor_identity;
+};
+
+gssapi_krb5_2_MIT {
+ global:
+ GSS_C_ATTR_LOCAL_LOGIN_USER;
+ GSS_C_INQ_SSPI_SESSION_KEY;
+ GSS_C_INQ_NEGOEX_KEY;
+ GSS_C_INQ_NEGOEX_VERIFY_KEY;
+ GSS_C_NT_ANONYMOUS;
+ GSS_C_NT_COMPOSITE_EXPORT;
+ GSS_C_NT_EXPORT_NAME;
+ GSS_C_NT_HOSTBASED_SERVICE;
+ GSS_C_NT_HOSTBASED_SERVICE_X;
+ GSS_C_NT_MACHINE_UID_NAME;
+ GSS_C_NT_STRING_UID_NAME;
+ GSS_C_NT_USER_NAME;
+ GSS_KRB5_NT_PRINCIPAL_NAME;
+ GSS_KRB5_NT_ENTERPRISE_NAME;
+ GSS_KRB5_NT_X509_CERT;
+ GSS_KRB5_CRED_NO_CI_FLAGS_X;
+ GSS_KRB5_GET_CRED_IMPERSONATOR;
+ GSS_C_MA_MECH_CONCRETE;
+ GSS_C_MA_MECH_PSEUDO;
+ GSS_C_MA_MECH_COMPOSITE;
+ GSS_C_MA_MECH_NEGO;
+ GSS_C_MA_MECH_GLUE;
+ GSS_C_MA_NOT_MECH;
+ GSS_C_MA_DEPRECATED;
+ GSS_C_MA_NOT_DFLT_MECH;
+ GSS_C_MA_ITOK_FRAMED;
+ GSS_C_MA_AUTH_INIT;
+ GSS_C_MA_AUTH_TARG;
+ GSS_C_MA_AUTH_INIT_INIT;
+ GSS_C_MA_AUTH_TARG_INIT;
+ GSS_C_MA_AUTH_INIT_ANON;
+ GSS_C_MA_AUTH_TARG_ANON;
+ GSS_C_MA_DELEG_CRED;
+ GSS_C_MA_INTEG_PROT;
+ GSS_C_MA_CONF_PROT;
+ GSS_C_MA_MIC;
+ GSS_C_MA_WRAP;
+ GSS_C_MA_PROT_READY;
+ GSS_C_MA_REPLAY_DET;
+ GSS_C_MA_OOS_DET;
+ GSS_C_MA_CBINDINGS;
+ GSS_C_MA_PFS;
+ GSS_C_MA_COMPRESS;
+ GSS_C_MA_CTX_TRANS;
+ GSS_C_MA_NEGOEX_AND_SPNEGO;
+ GSS_C_SEC_CONTEXT_SASL_SSF;
+ gss_acquire_cred_impersonate_name;
+ gss_add_cred_impersonate_name;
+ gss_complete_auth_token;
+ gss_get_mic_iov;
+ gss_get_mic_iov_length;
+ gss_krb5_set_cred_rcache;
+ gss_krb5int_make_seal_token_v3;
+ gss_krb5int_unseal_token_v3;
+ gss_localname;
+ gss_map_name_to_any;
+ gss_mech_iakerb;
+ gss_mech_krb5;
+ gss_mech_krb5_old;
+ gss_mech_krb5_wrong;
+ gss_mech_set_krb5;
+ gss_mech_set_krb5_both;
+ gss_mech_set_krb5_old;
+ gss_nt_exported_name;
+ gss_nt_krb5_name;
+ gss_nt_krb5_principal;
+ gss_nt_machine_uid_name;
+ gss_nt_service_name;
+ gss_nt_service_name_v2;
+ gss_nt_string_uid_name;
+ gss_nt_user_name;
+ gss_release_any_name_mapping;
+ gss_set_neg_mechs;
+ gss_str_to_oid;
+ gss_unwrap_aead;
+ gss_verify_mic_iov;
+ gss_wrap_aead;
+ gssspi_set_cred_option;
+ gssspi_mech_invoke;
+ krb5_gss_dbg_client_expcreds;
+ krb5_gss_use_kdc_context;
+ gss_acquire_cred_from;
+ gss_add_cred_from;
+ gss_store_cred_into;
+ gssint_g_seqstate_init;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/lib/kadm5clnt/Makefile b/krb5/lib/kadm5clnt/Makefile
index ddb9b0e9fec5..898276e77d04 100644
--- a/krb5/lib/kadm5clnt/Makefile
+++ b/krb5/lib/kadm5clnt/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= kadm5clnt_mit
# SHLIB_MAJOR= 12
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile gssrpc gssapi_krb5 krb5 k5crypto krb5support com_err
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= alt_prof.c \
chpass_util.c \
@@ -29,7 +28,8 @@ SRCS= alt_prof.c \
.include "${KRB5_SRCTOP}/lib/kadm5clnt/clnt/Makefile.inc"
-CFLAGS+=-I${KRB5_DIR}/lib/kadm5 \
+CFLAGS+=-I${KRB5_DIR}/lib \
+ -I${KRB5_DIR}/lib/kadm5 \
-I${KRB5_DIR}/include \
-I${KRB5_OBJTOP}/include/krb5_private \
-I${KRB5_SRCTOP}/include \
@@ -37,10 +37,6 @@ CFLAGS+=-I${KRB5_DIR}/lib/kadm5 \
INCSDIR=${INCLUDEDIR}/kadm5
INCS= admin.h \
- admin_internal.h \
- admin_xdr.h \
- kadm_rpc.h \
- server_internal.h \
${GENI}
KADM_ERR= kadm_err.et
diff --git a/krb5/lib/kadm5clnt/version.map b/krb5/lib/kadm5clnt/version.map
new file mode 100644
index 000000000000..1b624130144d
--- /dev/null
+++ b/krb5/lib/kadm5clnt/version.map
@@ -0,0 +1,119 @@
+kadm5clnt_mit_12_MIT {
+ global:
+ _kadm5_check_handle;
+ _kadm5_chpass_principal_util;
+ kadm5_chpass_principal;
+ kadm5_chpass_principal_3;
+ kadm5_chpass_principal_util;
+ kadm5_create_policy;
+ kadm5_create_principal;
+ kadm5_create_principal_3;
+ kadm5_decrypt_key;
+ kadm5_delete_policy;
+ kadm5_delete_principal;
+ kadm5_destroy;
+ kadm5_flush;
+ kadm5_free_config_params;
+ kadm5_free_kadm5_key_data;
+ kadm5_free_key_data;
+ kadm5_free_name_list;
+ kadm5_free_policy_ent;
+ kadm5_free_principal_ent;
+ kadm5_free_strings;
+ kadm5_get_admin_service_name;
+ kadm5_get_config_params;
+ kadm5_get_policies;
+ kadm5_get_policy;
+ kadm5_get_principal;
+ kadm5_get_principal_keys;
+ kadm5_get_principals;
+ kadm5_get_privs;
+ kadm5_get_strings;
+ kadm5_init;
+ kadm5_init_anonymous;
+ kadm5_init_krb5_context;
+ kadm5_init_with_creds;
+ kadm5_init_with_password;
+ kadm5_init_with_skey;
+ kadm5_lock;
+ kadm5_modify_policy;
+ kadm5_modify_principal;
+ kadm5_purgekeys;
+ kadm5_randkey_principal;
+ kadm5_randkey_principal_3;
+ kadm5_rename_principal;
+ kadm5_set_string;
+ kadm5_setkey_principal;
+ kadm5_setkey_principal_3;
+ kadm5_setkey_principal_4;
+ kadm5_unlock;
+ krb5_aprof_get_boolean;
+ krb5_aprof_get_deltat;
+ krb5_aprof_get_int32;
+ krb5_aprof_get_string;
+ krb5_aprof_getvals;
+ krb5_flagnum_to_string;
+ krb5_flagspec_to_mask;
+ krb5_flags_to_strings;
+ krb5_free_key_data_contents;
+ krb5_keysalt_is_present;
+ krb5_keysalt_iterate;
+ krb5_klog_close;
+ krb5_klog_init;
+ krb5_klog_reopen;
+ krb5_klog_set_context;
+ krb5_klog_syslog;
+ krb5_string_to_keysalts;
+ xdr_chpass3_arg;
+ xdr_chpass_arg;
+ xdr_chrand3_arg;
+ xdr_chrand_arg;
+ xdr_chrand_ret;
+ xdr_cpol_arg;
+ xdr_cprinc3_arg;
+ xdr_cprinc_arg;
+ xdr_dpol_arg;
+ xdr_dprinc_arg;
+ xdr_generic_ret;
+ xdr_getpkeys_arg;
+ xdr_getpkeys_ret;
+ xdr_getprivs_ret;
+ xdr_gpol_arg;
+ xdr_gpol_ret;
+ xdr_gpols_arg;
+ xdr_gpols_ret;
+ xdr_gprinc_arg;
+ xdr_gprinc_ret;
+ xdr_gprincs_arg;
+ xdr_gprincs_ret;
+ xdr_kadm5_key_data;
+ xdr_kadm5_policy_ent_rec;
+ xdr_kadm5_principal_ent_rec;
+ xdr_kadm5_ret_t;
+ xdr_krb5_deltat;
+ xdr_krb5_enctype;
+ xdr_krb5_flags;
+ xdr_krb5_int16;
+ xdr_krb5_key_data_nocontents;
+ xdr_krb5_key_salt_tuple;
+ xdr_krb5_keyblock;
+ xdr_krb5_kvno;
+ xdr_krb5_octet;
+ xdr_krb5_principal;
+ xdr_krb5_salttype;
+ xdr_krb5_timestamp;
+ xdr_krb5_tl_data;
+ xdr_krb5_ui_2;
+ xdr_krb5_ui_4;
+ xdr_mpol_arg;
+ xdr_mprinc_arg;
+ xdr_nullstring;
+ xdr_nulltype;
+ xdr_rprinc_arg;
+ xdr_setkey3_arg;
+ xdr_setkey4_arg;
+ xdr_setkey_arg;
+ xdr_ui_4;
+ kadm5_init_iprop;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/lib/kadm5srv/Makefile b/krb5/lib/kadm5srv/Makefile
index f716dfcdaedc..e0ec557a3f5b 100644
--- a/krb5/lib/kadm5srv/Makefile
+++ b/krb5/lib/kadm5srv/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= kadm5srv_mit
# SHLIB_MAJOR= 12
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile gssrpc gssapi_krb5 kdb5 krb5 k5crypto krb5support com_err
+VERSION_MAP= ${.CURDIR}/version.map
INCSDIR= ${INCLUDEDIR}/kadm5
@@ -38,7 +37,8 @@ INCS= admin.h \
GEN= kadm_err.c kadm_err.h chpass_util_strings.c chpass_util_strings.h
CLEANFILES= ${GEN} ${GENI}
-CFLAGS+=-I${KRB5_DIR}/lib/kadm5 \
+CFLAGS+=-I${KRB5_DIR}/lib \
+ -I${KRB5_DIR}/lib/kadm5 \
-I${KRB5_DIR}/include \
-I${KRB5_OBJTOP}/include/krb5_private \
-I${KRB5_SRCTOP}/include \
@@ -49,10 +49,6 @@ CFLAGS+=-I${KRB5_DIR}/lib/kadm5 \
HDRDIR= ${KRB5_OBJHDR}/kadm5
HDRS= ${HDRDIR}/admin.h \
- ${HDRDIR}/admin_internal.h \
- ${HDRDIR}/admin_xdr.h \
- ${HDRDIR}/kadm_rpc.h \
- ${HDRDIR}/server_internal.h \
${HDRDIR}/chpass_util_strings.h \
${HDRDIR}/kadm_err.h
diff --git a/krb5/lib/kadm5srv/version.map b/krb5/lib/kadm5srv/version.map
new file mode 100644
index 000000000000..d18753acad3f
--- /dev/null
+++ b/krb5/lib/kadm5srv/version.map
@@ -0,0 +1,138 @@
+kadm5srv_mit_12_MIT {
+ global:
+ _kadm5_check_handle;
+ _kadm5_chpass_principal_util;
+ hist_princ;
+ kadm5_chpass_principal;
+ kadm5_chpass_principal_3;
+ kadm5_chpass_principal_util;
+ kadm5_create_policy;
+ kadm5_create_principal;
+ kadm5_create_principal_3;
+ kadm5_decrypt_key;
+ kadm5_delete_policy;
+ kadm5_delete_principal;
+ kadm5_destroy;
+ kadm5_flush;
+ kadm5_free_config_params;
+ kadm5_free_kadm5_key_data;
+ kadm5_free_key_data;
+ kadm5_free_name_list;
+ kadm5_free_policy_ent;
+ kadm5_free_principal_ent;
+ kadm5_free_strings;
+ kadm5_get_config_params;
+ kadm5_get_policies;
+ kadm5_get_policy;
+ kadm5_get_principal;
+ kadm5_get_principal_keys;
+ kadm5_get_principals;
+ kadm5_get_privs;
+ kadm5_get_strings;
+ kadm5_init;
+ kadm5_init_anonymous;
+ kadm5_init_krb5_context;
+ kadm5_init_with_creds;
+ kadm5_init_with_password;
+ kadm5_init_with_skey;
+ kadm5_lock;
+ kadm5_modify_policy;
+ kadm5_modify_principal;
+ kadm5_purgekeys;
+ kadm5_randkey_principal;
+ kadm5_randkey_principal_3;
+ kadm5_rename_principal;
+ kadm5_set_string;
+ kadm5_setkey_principal;
+ kadm5_setkey_principal_3;
+ kadm5_setkey_principal_4;
+ kadm5_unlock;
+ kdb_delete_entry;
+ kdb_free_entry;
+ kdb_init_hist;
+ kdb_init_master;
+ kdb_iter_entry;
+ kdb_put_entry;
+ krb5_aprof_get_boolean;
+ krb5_aprof_get_deltat;
+ krb5_aprof_get_int32;
+ krb5_aprof_get_string;
+ krb5_aprof_get_string_all;
+ krb5_aprof_getvals;
+ krb5_copy_key_data_contents;
+ krb5_flagnum_to_string;
+ krb5_flagspec_to_mask;
+ krb5_flags_to_strings;
+ krb5_free_key_data_contents;
+ krb5_keysalt_is_present;
+ krb5_keysalt_iterate;
+ krb5_klog_close;
+ krb5_klog_init;
+ krb5_klog_reopen;
+ krb5_klog_set_context;
+ krb5_klog_syslog;
+ krb5_string_to_keysalts;
+ master_db;
+ master_princ;
+ osa_free_princ_ent;
+ passwd_check;
+ xdr_chpass3_arg;
+ xdr_chpass_arg;
+ xdr_chrand3_arg;
+ xdr_chrand_arg;
+ xdr_chrand_ret;
+ xdr_cpol_arg;
+ xdr_cprinc3_arg;
+ xdr_cprinc_arg;
+ xdr_dpol_arg;
+ xdr_dprinc_arg;
+ xdr_generic_ret;
+ xdr_getpkeys_arg;
+ xdr_getpkeys_ret;
+ xdr_getprivs_ret;
+ xdr_gpol_arg;
+ xdr_gpol_ret;
+ xdr_gpols_arg;
+ xdr_gpols_ret;
+ xdr_gprinc_arg;
+ xdr_gprinc_ret;
+ xdr_gprincs_arg;
+ xdr_gprincs_ret;
+ xdr_gstrings_arg;
+ xdr_gstrings_ret;
+ xdr_kadm5_policy_ent_rec;
+ xdr_kadm5_principal_ent_rec;
+ xdr_kadm5_ret_t;
+ xdr_krb5_deltat;
+ xdr_krb5_enctype;
+ xdr_krb5_flags;
+ xdr_krb5_int16;
+ xdr_krb5_key_data;
+ xdr_krb5_key_data_nocontents;
+ xdr_krb5_key_salt_tuple;
+ xdr_krb5_keyblock;
+ xdr_krb5_kvno;
+ xdr_krb5_octet;
+ xdr_krb5_principal;
+ xdr_krb5_salttype;
+ xdr_krb5_string_attr;
+ xdr_krb5_timestamp;
+ xdr_krb5_tl_data;
+ xdr_krb5_ui_2;
+ xdr_krb5_ui_4;
+ xdr_mpol_arg;
+ xdr_mprinc_arg;
+ xdr_nullstring;
+ xdr_nulltype;
+ xdr_osa_princ_ent_rec;
+ xdr_osa_pw_hist_ent;
+ xdr_purgekeys_arg;
+ xdr_rprinc_arg;
+ xdr_setkey3_arg;
+ xdr_setkey4_arg;
+ xdr_setkey_arg;
+ xdr_sstring_arg;
+ xdr_ui_4;
+ kadm5_init_iprop;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/lib/kdb/Makefile b/krb5/lib/kdb/Makefile
index ac7f058a7f11..ff17900fb7ec 100644
--- a/krb5/lib/kdb/Makefile
+++ b/krb5/lib/kdb/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= kdb5
# SHLIB_MAJOR= 10
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile gssrpc krb5 k5crypto com_err krb5support gssapi_krb5
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= decrypt_key.c \
encrypt_key.c \
diff --git a/krb5/lib/kdb/version.map b/krb5/lib/kdb/version.map
new file mode 100644
index 000000000000..63096fe7190a
--- /dev/null
+++ b/krb5/lib/kdb/version.map
@@ -0,0 +1,112 @@
+kdb5_10_MIT {
+ global:
+ krb5_db_setup_lib_handle;
+ krb5_db_open;
+ krb5_db_inited;
+ krb5_db_alloc;
+ krb5_db_free;
+ krb5_db_allowed_to_delegate_from;
+ krb5_db_audit_as_req;
+ krb5_db_check_allowed_to_delegate;
+ krb5_db_get_s4u_x509_principal;
+ krb5_db_check_policy_as;
+ krb5_db_check_policy_tgs;
+ krb5_db_check_transited_realms;
+ krb5_db_create;
+ krb5_db_delete_principal;
+ krb5_db_destroy;
+ krb5_db_fetch_mkey;
+ krb5_db_fetch_mkey_list;
+ krb5_db_fini;
+ krb5_db_free_principal;
+ krb5_db_get_age;
+ krb5_db_get_key_data_kvno;
+ krb5_db_get_context;
+ krb5_db_get_principal;
+ krb5_db_issue_pac;
+ krb5_db_iterate;
+ krb5_db_lock;
+ krb5_db_mkey_list_alias;
+ krb5_db_put_principal;
+ krb5_db_refresh_config;
+ krb5_db_rename_principal;
+ krb5_db_set_context;
+ krb5_db_setup_mkey_name;
+ krb5_db_unlock;
+ krb5_db_store_master_key;
+ krb5_db_store_master_key_list;
+ krb5_dbe_apw;
+ krb5_dbe_ark;
+ krb5_dbe_cpw;
+ krb5_dbe_create_key_data;
+ krb5_dbe_crk;
+ krb5_dbe_find_act_mkey;
+ krb5_dbe_fetch_act_key_list;
+ krb5_dbe_find_enctype;
+ krb5_dbe_find_mkey;
+ krb5_dbe_free_actkvno_list;
+ krb5_dbe_free_key_data_contents;
+ krb5_dbe_free_mkey_aux_list;
+ krb5_dbe_free_key_list;
+ krb5_dbe_free_string;
+ krb5_dbe_free_strings;
+ krb5_dbe_get_mkvno;
+ krb5_dbe_get_string;
+ krb5_dbe_get_strings;
+ krb5_dbe_compute_salt;
+ krb5_dbe_lookup_last_admin_unlock;
+ krb5_dbe_lookup_last_pwd_change;
+ krb5_dbe_lookup_actkvno;
+ krb5_dbe_lookup_mkey_aux;
+ krb5_dbe_lookup_mkvno;
+ krb5_dbe_lookup_mod_princ_data;
+ krb5_dbe_lookup_tl_data;
+ krb5_dbe_search_enctype;
+ krb5_dbe_set_string;
+ krb5_dbe_specialize_salt;
+ krb5_dbe_update_actkvno;
+ krb5_dbe_update_last_admin_unlock;
+ krb5_dbe_update_last_pwd_change;
+ krb5_dbe_update_mkey_aux;
+ krb5_dbe_update_mkvno;
+ krb5_dbe_update_mod_princ_data;
+ krb5_dbe_update_tl_data;
+ krb5_db_update_tl_data;
+ krb5_dbe_def_encrypt_key_data;
+ krb5_dbe_def_decrypt_key_data;
+ krb5_dbe_decrypt_key_data;
+ krb5_dbe_encrypt_key_data;
+ krb5_kt_kdb_ops;
+ krb5_ktkdb_close;
+ krb5_ktkdb_get_entry;
+ krb5_ktkdb_resolve;
+ krb5_ktkdb_set_context;
+ krb5_mkey_pwd_prompt1;
+ krb5_mkey_pwd_prompt2;
+ krb5_db_create_policy;
+ krb5_db_get_policy;
+ krb5_db_put_policy;
+ krb5_db_iter_policy;
+ krb5_db_delete_policy;
+ krb5_db_free_policy;
+ krb5_def_store_mkey_list;
+ krb5_db_promote;
+ krb5_db_register_keytab;
+ ulog_add_update;
+ ulog_init_header;
+ ulog_map;
+ ulog_set_role;
+ ulog_free_entries;
+ xdr_kdb_last_t;
+ xdr_kdb_incr_result_t;
+ xdr_kdb_fullresync_result_t;
+ ulog_fini;
+ ulog_get_entries;
+ ulog_get_last;
+ ulog_get_sno_status;
+ ulog_replay;
+ ulog_set_last;
+ xdr_kdb_incr_update_t;
+ krb5_dbe_sort_key_data;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/lib/krad/Makefile b/krb5/lib/krad/Makefile
index 4b18af482207..a990354c1877 100644
--- a/krb5/lib/krad/Makefile
+++ b/krb5/lib/krad/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5-lib
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= krad
# SHLIB_MAJOR= 0
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5 k5crypto com_err krb5profile krb5support verto
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= attr.c \
attrset.c \
@@ -25,10 +24,6 @@ SRCS= attr.c \
packet.c \
remote.c
-INCS= internal.h \
- t_daemon.h \
- t_test.h
-
CFLAGS+=-I${KRB5_DIR}/lib/krad \
-I${KRB5_DIR}/include \
-I${KRB5_SRCTOP}/include \
diff --git a/krb5/lib/krad/version.map b/krb5/lib/krad/version.map
new file mode 100644
index 000000000000..a18fa4665e50
--- /dev/null
+++ b/krb5/lib/krad/version.map
@@ -0,0 +1,27 @@
+krad_0_MIT {
+ global:
+ krad_code_name2num;
+ krad_code_num2name;
+ krad_attr_name2num;
+ krad_attr_num2name;
+ krad_attrset_new;
+ krad_attrset_copy;
+ krad_attrset_free;
+ krad_attrset_add;
+ krad_attrset_add_number;
+ krad_attrset_del;
+ krad_attrset_get;
+ krad_packet_bytes_needed;
+ krad_packet_free;
+ krad_packet_new_request;
+ krad_packet_new_response;
+ krad_packet_decode_request;
+ krad_packet_decode_response;
+ krad_packet_encode;
+ krad_packet_get_code;
+ krad_packet_get_attr;
+ krad_client_new;
+ krad_client_free;
+ krad_client_send;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/lib/krb5/Makefile b/krb5/lib/krb5/Makefile
index bf90c7fc80f7..dc6c53ec6ce2 100644
--- a/krb5/lib/krb5/Makefile
+++ b/krb5/lib/krb5/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= krb5
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile k5crypto com_err krb5support
# SHLIB_MAJOR= 3
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= krb5_libinit.c
@@ -51,19 +50,24 @@ CFLAGS+=${DEFINES} \
-I${KRB5_SRCTOP}/include \
-I${KRB5_DIR}
-MAN= k5identity.5 \
- k5login.5 \
- kadm5.acl.5 \
- kdc.conf.5 \
- krb5.conf.5 \
- kerberos.7
+MANGROUPS= KRB5
+KRB5= k5identity.5 \
+ k5login.5 \
+ krb5.conf.5 \
+ kerberos.7
+KRB5PACKAGE= kerberos
+KRB5LINKS=k5identity.5 .k5identity.5
+KRB5LINKS+=k5login.5 .k5login.5
+
+MANGROUPS+= KDC
+KDC= kadm5.acl.5 \
+ kdc.conf.5
+KDCPACKAGE= kerberos-kdc
-MLINKS= k5identity.5 .k5identity.5
-MLINKS+=k5login.5 .k5login.5
.include <bsd.lib.mk>
-.SUFFIXES: .h .c .et .man .5 .7
+.SUFFIXES: .et .man
.man.5:
@cp ${.ALLSRC} ${.TARGET}
diff --git a/krb5/lib/krb5/error_tables/Makefile.inc b/krb5/lib/krb5/error_tables/Makefile.inc
index dee259798dae..5d2ec3b9e920 100644
--- a/krb5/lib/krb5/error_tables/Makefile.inc
+++ b/krb5/lib/krb5/error_tables/Makefile.inc
@@ -144,3 +144,5 @@ ${GEN_ASN1_ERR_C}: ${GEN_ASN1_ERR}
${COMPILE_ET} et-c-${.PREFIX}.et
mv et-c-${.PREFIX}.c ${.PREFIX}.c
rm -f et-c-${.PREFIX}.et et-c-${.PREFIX}.c
+
+SRCS+= ${GEN_ET}
diff --git a/krb5/lib/krb5/version.map b/krb5/lib/krb5/version.map
new file mode 100644
index 000000000000..ce399a93e03e
--- /dev/null
+++ b/krb5/lib/krb5/version.map
@@ -0,0 +1,633 @@
+HEIMDAL_KRB5_2.0 {
+ global:
+ initialize_k524_error_table;
+ initialize_krb5_error_table;
+ krb524_convert_creds_kdc;
+ krb5_address_compare;
+ krb5_address_order;
+ krb5_address_search;
+ krb5_allow_weak_crypto;
+ krb5_aname_to_localname;
+ krb5_appdefault_boolean;
+ krb5_appdefault_string;
+ krb5_auth_con_free;
+ krb5_auth_con_genaddrs;
+ krb5_auth_con_getaddrs;
+ krb5_auth_con_getauthenticator;
+ krb5_auth_con_getflags;
+ krb5_auth_con_getkey;
+ krb5_auth_con_getlocalseqnumber;
+ krb5_auth_con_getlocalsubkey;
+ krb5_auth_con_getrcache;
+ krb5_auth_con_getrecvsubkey;
+ krb5_auth_con_getremoteseqnumber;
+ krb5_auth_con_getremotesubkey;
+ krb5_auth_con_getsendsubkey;
+ krb5_auth_con_init;
+ krb5_auth_con_setaddrs;
+ krb5_auth_con_setflags;
+ krb5_auth_con_setrcache;
+ krb5_auth_con_setrecvsubkey;
+ krb5_auth_con_setsendsubkey;
+ krb5_build_principal;
+ krb5_build_principal_ext;
+ krb5_build_principal_va;
+ krb5_cc_cache_match;
+ krb5_cc_close;
+ krb5_cc_copy_creds;
+ krb5_cc_default;
+ krb5_cc_default_name;
+ krb5_cc_destroy;
+ krb5_cc_end_seq_get;
+ krb5_cc_gen_new;
+ krb5_cc_get_config;
+ krb5_cc_get_full_name;
+ krb5_cc_get_name;
+ krb5_cc_get_principal;
+ krb5_cc_get_type;
+ krb5_cc_initialize;
+ krb5_cc_move;
+ krb5_cc_new_unique;
+ krb5_cc_next_cred;
+ krb5_cc_register;
+ krb5_cc_remove_cred;
+ krb5_cc_resolve;
+ krb5_cc_retrieve_cred;
+ krb5_cc_set_config;
+ krb5_cc_set_default_name;
+ krb5_cc_set_flags;
+ krb5_cc_start_seq_get;
+ krb5_cc_store_cred;
+ krb5_cc_support_switch;
+ krb5_cc_switch;
+ krb5_cccol_cursor_free;
+ krb5_cccol_cursor_new;
+ krb5_cccol_cursor_next;
+ krb5_change_password;
+ krb5_clear_error_message;
+ krb5_copy_addresses;
+ krb5_copy_checksum;
+ krb5_copy_context;
+ krb5_copy_creds;
+ krb5_copy_data;
+ krb5_copy_keyblock;
+ krb5_copy_keyblock_contents;
+ krb5_copy_principal;
+ krb5_copy_ticket;
+ krb5_expand_hostname;
+ krb5_fcc_ops;
+ krb5_free_address;
+ krb5_free_addresses;
+ krb5_free_ap_rep_enc_part;
+ krb5_free_authenticator;
+ krb5_free_checksum;
+ krb5_free_checksum_contents;
+ krb5_free_config_files;
+ krb5_free_context;
+ krb5_free_cred_contents;
+ krb5_free_creds;
+ krb5_free_data;
+ krb5_free_data_contents;
+ krb5_free_default_realm;
+ krb5_free_error_message;
+ krb5_free_host_realm;
+ krb5_free_kdc_rep;
+ krb5_free_keyblock;
+ krb5_free_keyblock_contents;
+ krb5_free_principal;
+ krb5_free_ticket;
+ krb5_free_unparsed_name;
+ krb5_fwd_tgt_creds;
+ krb5_generate_seq_number;
+ krb5_generate_subkey;
+ krb5_get_credentials;
+ krb5_get_default_config_files;
+ krb5_get_default_realm;
+ krb5_get_error_message;
+ krb5_get_host_realm;
+ krb5_get_in_tkt_with_keytab;
+ krb5_get_in_tkt_with_password;
+ krb5_get_in_tkt_with_skey;
+ krb5_get_init_creds_keytab;
+ krb5_get_init_creds_opt_alloc;
+ krb5_get_init_creds_opt_free;
+ krb5_get_init_creds_opt_init;
+ krb5_get_init_creds_opt_set_address_list;
+ krb5_get_init_creds_opt_set_anonymous;
+ krb5_get_init_creds_opt_set_canonicalize;
+ krb5_get_init_creds_opt_set_etype_list;
+ krb5_get_init_creds_opt_set_forwardable;
+ krb5_get_init_creds_opt_set_pac_request;
+ krb5_get_init_creds_opt_set_preauth_list;
+ krb5_get_init_creds_opt_set_proxiable;
+ krb5_get_init_creds_opt_set_renew_life;
+ krb5_get_init_creds_opt_set_salt;
+ krb5_get_init_creds_opt_set_tkt_life;
+ krb5_get_init_creds_password;
+ krb5_get_permitted_enctypes;
+ krb5_get_renewed_creds;
+ krb5_get_server_rcache;
+ krb5_get_validated_creds;
+ krb5_init_context;
+ krb5_init_creds_free;
+ krb5_init_creds_get;
+ krb5_init_creds_get_creds;
+ krb5_init_creds_get_error;
+ krb5_init_creds_init;
+ krb5_init_creds_set_keytab;
+ krb5_init_creds_set_password;
+ krb5_init_creds_set_service;
+ krb5_is_config_principal;
+ krb5_is_thread_safe;
+ krb5_kt_add_entry;
+ krb5_kt_close;
+ krb5_kt_default;
+ krb5_kt_default_name;
+ krb5_kt_end_seq_get;
+ krb5_kt_free_entry;
+ krb5_kt_get_entry;
+ krb5_kt_get_name;
+ krb5_kt_get_type;
+ krb5_kt_have_content;
+ krb5_kt_next_entry;
+ krb5_kt_read_service_key;
+ krb5_kt_register;
+ krb5_kt_remove_entry;
+ krb5_kt_resolve;
+ krb5_kt_start_seq_get;
+ krb5_kuserok;
+ krb5_mcc_ops;
+ krb5_mk_error;
+ krb5_mk_priv;
+ krb5_mk_rep;
+ krb5_mk_req;
+ krb5_mk_req_extended;
+ krb5_mk_safe;
+ krb5_net_read;
+ krb5_net_write;
+ krb5_pac_add_buffer;
+ krb5_pac_free;
+ krb5_pac_get_buffer;
+ krb5_pac_get_types;
+ krb5_pac_init;
+ krb5_pac_parse;
+ krb5_pac_verify;
+ krb5_parse_name;
+ krb5_parse_name_flags;
+ krb5_prepend_error_message;
+ krb5_principal_compare;
+ krb5_principal_compare_any_realm;
+ krb5_prompter_posix;
+ krb5_rc_default;
+ krb5_rc_destroy;
+ krb5_rc_get_lifespan;
+ krb5_rc_initialize;
+ krb5_rd_cred;
+ krb5_rd_error;
+ krb5_rd_priv;
+ krb5_rd_rep;
+ krb5_rd_req;
+ krb5_rd_safe;
+ krb5_read_message;
+ krb5_realm_compare;
+ krb5_recvauth;
+ krb5_salttype_to_string;
+ krb5_sendauth;
+ krb5_sendto_kdc;
+ krb5_set_config_files;
+ krb5_set_default_realm;
+ krb5_set_error_message;
+ krb5_set_password;
+ krb5_set_password_using_ccache;
+ krb5_set_real_time;
+ krb5_sname_to_principal;
+ krb5_string_to_deltat;
+ krb5_string_to_salttype;
+ krb5_timeofday;
+ krb5_unparse_name;
+ krb5_unparse_name_flags;
+ krb5_us_timeofday;
+ krb5_verify_init_creds;
+ krb5_verify_init_creds_opt_init;
+ krb5_verify_init_creds_opt_set_ap_req_nofail;
+ krb5_vprepend_error_message;
+ krb5_vset_error_message;
+ krb5_write_message;
+};
+
+krb5_3_MIT {
+ global:
+ _krb5_conf_boolean;
+ decode_krb5_ad_kdcissued;
+ decode_krb5_ap_rep;
+ decode_krb5_ap_rep_enc_part;
+ decode_krb5_ap_req;
+ decode_krb5_as_rep;
+ decode_krb5_as_req;
+ decode_krb5_authdata;
+ decode_krb5_authenticator;
+ decode_krb5_cammac;
+ decode_krb5_cred;
+ decode_krb5_enc_cred_part;
+ decode_krb5_enc_data;
+ decode_krb5_enc_kdc_rep_part;
+ decode_krb5_enc_priv_part;
+ decode_krb5_enc_sam_response_enc_2;
+ decode_krb5_enc_tkt_part;
+ decode_krb5_encryption_key;
+ decode_krb5_error;
+ decode_krb5_etype_info;
+ decode_krb5_etype_info2;
+ decode_krb5_fast_req;
+ decode_krb5_fast_response;
+ decode_krb5_iakerb_finished;
+ decode_krb5_iakerb_header;
+ decode_krb5_kdc_req_body;
+ decode_krb5_otp_tokeninfo;
+ decode_krb5_kkdcp_message;
+ decode_krb5_pa_enc_ts;
+ decode_krb5_pa_for_user;
+ decode_krb5_pa_fx_fast_reply;
+ decode_krb5_pa_fx_fast_request;
+ decode_krb5_pa_otp_challenge;
+ decode_krb5_pa_otp_req;
+ decode_krb5_pa_otp_enc_req;
+ decode_krb5_pa_pac_options;
+ decode_krb5_pa_pac_req;
+ decode_krb5_pa_s4u_x509_user;
+ decode_krb5_pa_spake;
+ decode_krb5_padata_sequence;
+ decode_krb5_priv;
+ decode_krb5_safe;
+ decode_krb5_sam_challenge_2;
+ decode_krb5_sam_challenge_2_body;
+ decode_krb5_sam_response_2;
+ decode_krb5_secure_cookie;
+ decode_krb5_setpw_req;
+ decode_krb5_spake_factor;
+ decode_krb5_tgs_rep;
+ decode_krb5_tgs_req;
+ decode_krb5_ticket;
+ decode_krb5_typed_data;
+ decode_utf8_strings;
+ encode_krb5_ad_kdcissued;
+ encode_krb5_ap_rep;
+ encode_krb5_ap_rep_enc_part;
+ encode_krb5_ap_req;
+ encode_krb5_as_rep;
+ encode_krb5_as_req;
+ encode_krb5_authdata;
+ encode_krb5_authenticator;
+ encode_krb5_cammac;
+ encode_krb5_checksum;
+ encode_krb5_cred;
+ encode_krb5_enc_cred_part;
+ encode_krb5_enc_data;
+ encode_krb5_enc_kdc_rep_part;
+ encode_krb5_enc_priv_part;
+ encode_krb5_enc_sam_response_enc_2;
+ encode_krb5_enc_tkt_part;
+ encode_krb5_encryption_key;
+ encode_krb5_error;
+ encode_krb5_etype_info;
+ encode_krb5_etype_info2;
+ encode_krb5_fast_response;
+ encode_krb5_iakerb_finished;
+ encode_krb5_iakerb_header;
+ encode_krb5_kdc_req_body;
+ encode_krb5_otp_tokeninfo;
+ encode_krb5_kkdcp_message;
+ encode_krb5_pa_enc_ts;
+ encode_krb5_pa_for_user;
+ encode_krb5_pa_fx_fast_reply;
+ encode_krb5_pa_otp_challenge;
+ encode_krb5_pa_otp_req;
+ encode_krb5_pa_otp_enc_req;
+ encode_krb5_pa_pac_options;
+ encode_krb5_pa_s4u_x509_user;
+ encode_krb5_pa_spake;
+ encode_krb5_padata_sequence;
+ encode_krb5_pkinit_supp_pub_info;
+ encode_krb5_priv;
+ encode_krb5_s4u_userid;
+ encode_krb5_safe;
+ encode_krb5_sam_challenge_2;
+ encode_krb5_sam_challenge_2_body;
+ encode_krb5_sam_response_2;
+ encode_krb5_secure_cookie;
+ encode_krb5_sp80056a_other_info;
+ encode_krb5_spake_factor;
+ encode_krb5_tgs_rep;
+ encode_krb5_tgs_req;
+ encode_krb5_ticket;
+ encode_krb5_typed_data;
+ encode_utf8_strings;
+ et_asn1_error_table;
+ et_k524_error_table;
+ et_kdb5_error_table;
+ et_krb5_error_table;
+ et_kv5m_error_table;
+ initialize_asn1_error_table;
+ initialize_kdb5_error_table;
+ initialize_k5e1_error_table;
+ initialize_kv5m_error_table;
+ k5_add_empty_pa_data;
+ k5_add_pa_data_element;
+ k5_add_pa_data_from_data;
+ k5_alloc_pa_data;
+ k5_authind_decode;
+ k5_build_conf_principals;
+ k5_cc_store_primary_cred;
+ k5_ccselect_free_context;
+ k5_change_error_message_code;
+ k5_etypes_contains;
+ k5_expand_path_tokens;
+ k5_expand_path_tokens_extra;
+ k5_externalize_auth_context;
+ k5_externalize_authdata;
+ k5_externalize_authdata_context;
+ k5_externalize_context;
+ k5_externalize_keyblock;
+ k5_externalize_principal;
+ k5_free_algorithm_identifier;
+ k5_free_cammac;
+ k5_free_data_ptr_list;
+ k5_free_otp_tokeninfo;
+ k5_free_kkdcp_message;
+ k5_free_pa_data_element;
+ k5_free_pa_otp_challenge;
+ k5_free_pa_otp_req;
+ k5_free_secure_cookie;
+ k5_free_pa_spake;
+ k5_free_serverlist;
+ k5_free_spake_factor;
+ k5_hostrealm_free_context;
+ k5_init_trace;
+ k5_internalize_auth_context;
+ k5_internalize_authdata;
+ k5_internalize_authdata_context;
+ k5_internalize_context;
+ k5_internalize_keyblock;
+ k5_internalize_principal;
+ k5_is_string_numeric;
+ k5_kt_get_principal;
+ k5_kt_have_match;
+ k5_localauth_free_context;
+ k5_locate_kdc;
+ k5_marshal_cred;
+ k5_marshal_princ;
+ k5_os_free_context;
+ k5_os_init_context;
+ k5_parse_host_string;
+ k5_plugin_free_modules;
+ k5_plugin_load;
+ k5_plugin_load_all;
+ k5_plugin_register;
+ k5_plugin_register_dyn;
+ k5_rc_close;
+ k5_rc_get_name;
+ k5_rc_resolve;
+ k5_rc_store;
+ k5_size_auth_context;
+ k5_size_authdata;
+ k5_size_authdata_context;
+ k5_size_context;
+ k5_size_keyblock;
+ k5_size_principal;
+ k5_sname_compare;
+ k5_unmarshal_cred;
+ k5_unmarshal_princ;
+ k5_unwrap_cammac_svc;
+ k5_zapfree_pa_data;
+ krb524_init_ets;
+ krb5_425_conv_principal;
+ krb5_524_conv_principal;
+ krb5_524_convert_creds;
+ krb5_anonymous_principal;
+ krb5_anonymous_realm;
+ krb5_auth_con_get_checksum_func;
+ krb5_auth_con_get_authdata_context;
+ krb5_auth_con_getivector;
+ krb5_auth_con_getkey_k;
+ krb5_auth_con_getpermetypes;
+ krb5_auth_con_getrecvsubkey_k;
+ krb5_auth_con_getsendsubkey_k;
+ krb5_auth_con_initivector;
+ krb5_auth_con_set_authdata_context;
+ krb5_auth_con_set_checksum_func;
+ krb5_auth_con_set_req_cksumtype;
+ krb5_auth_con_set_safe_cksumtype;
+ krb5_auth_con_setivector;
+ krb5_auth_con_setpermetypes;
+ krb5_auth_con_setports;
+ krb5_auth_con_setrecvsubkey_k;
+ krb5_auth_con_setsendsubkey_k;
+ krb5_auth_con_setuseruserkey;
+ krb5_authdata_context_copy;
+ krb5_authdata_context_free;
+ krb5_authdata_context_init;
+ krb5_authdata_delete_attribute;
+ krb5_authdata_get_attribute_types;
+ krb5_authdata_get_attribute;
+ krb5_authdata_set_attribute;
+ krb5_authdata_export_attributes;
+ krb5_authdata_export_authdata;
+ krb5_authdata_export_internal;
+ krb5_authdata_free_internal;
+ krb5_authdata_import_attributes;
+ krb5_build_principal_alloc_va;
+ krb5_cc_dfl_ops;
+ krb5_cc_dup;
+ krb5_cc_file_ops;
+ krb5_cc_select;
+ krb5_cccol_have_content;
+ krb5_change_cache;
+ krb5_check_clockskew;
+ krb5_check_transited_list;
+ krb5_chpw_message;
+ krb5_chpw_result_code_string;
+ krb5_copy_addr;
+ krb5_copy_authdata;
+ krb5_copy_authenticator;
+ krb5_copy_error_message;
+ krb5_crypto_us_timeofday;
+ krb5_decode_authdata_container;
+ krb5_decode_ticket;
+ krb5_decrypt_tkt_part;
+ krb5_deltat_to_string;
+ krb5_encode_authdata_container;
+ krb5_encode_kdc_rep;
+ krb5_encrypt_helper;
+ krb5_encrypt_tkt_part;
+ krb5_find_authdata;
+ krb5_free_ad_kdcissued;
+ krb5_free_ap_rep;
+ krb5_free_ap_req;
+ krb5_free_authdata;
+ krb5_free_authenticator_contents;
+ krb5_free_cred;
+ krb5_free_cred_enc_part;
+ krb5_free_enc_data;
+ krb5_free_enc_kdc_rep_part;
+ krb5_free_enc_sam_response_enc_2;
+ krb5_free_enc_sam_response_enc_2_contents;
+ krb5_free_enc_tkt_part;
+ krb5_free_enctypes;
+ krb5_free_error;
+ krb5_free_etype_info;
+ krb5_free_fast_armored_req;
+ krb5_free_fast_req;
+ krb5_free_fast_response;
+ krb5_free_iakerb_finished;
+ krb5_free_iakerb_header;
+ krb5_free_kdc_req;
+ krb5_free_keytab_entry_contents;
+ krb5_free_last_req;
+ krb5_free_octet_data;
+ krb5_free_pa_data;
+ krb5_free_pa_enc_ts;
+ krb5_free_pa_for_user;
+ krb5_free_pa_pac_req;
+ krb5_free_pa_s4u_x509_user;
+ krb5_free_priv;
+ krb5_free_priv_enc_part;
+ krb5_free_realm_tree;
+ krb5_free_safe;
+ krb5_free_sam_challenge_2;
+ krb5_free_sam_challenge_2_body;
+ krb5_free_sam_challenge_2_body_contents;
+ krb5_free_sam_challenge_2_contents;
+ krb5_free_sam_response_2;
+ krb5_free_sam_response_2_contents;
+ krb5_free_string;
+ krb5_free_tgt_creds;
+ krb5_free_tickets;
+ krb5_free_tkt_authent;
+ krb5_gen_portaddr;
+ krb5_gen_replay_name;
+ krb5_get_cred_via_tkt;
+ krb5_get_credentials_for_proxy;
+ krb5_get_credentials_for_user;
+ krb5_get_credentials_renew;
+ krb5_get_credentials_validate;
+ krb5_get_default_in_tkt_ktypes;
+ krb5_get_etype_info;
+ krb5_get_fallback_host_realm;
+ krb5_get_init_creds_opt_free_pa;
+ krb5_get_init_creds_opt_get_fast_flags;
+ krb5_get_init_creds_opt_get_pa;
+ krb5_get_init_creds_opt_set_change_password_prompt;
+ krb5_get_init_creds_opt_set_expire_callback;
+ krb5_get_init_creds_opt_set_fast_ccache;
+ krb5_get_init_creds_opt_set_fast_ccache_name;
+ krb5_get_init_creds_opt_set_fast_flags;
+ krb5_get_init_creds_opt_set_in_ccache;
+ krb5_get_init_creds_opt_set_out_ccache;
+ krb5_get_init_creds_opt_set_pa;
+ krb5_get_init_creds_opt_set_responder;
+ krb5_get_notification_message;
+ krb5_get_profile;
+ krb5_get_prompt_types;
+ krb5_get_realm_domain;
+ krb5_get_tgs_ktypes;
+ krb5_get_time_offsets;
+ krb5_init_context_profile;
+ krb5_init_creds_get_times;
+ krb5_init_creds_step;
+ krb5_init_keyblock;
+ krb5_init_secure_context;
+ krb5_is_permitted_enctype;
+ krb5_is_referral_realm;
+ krb5_kdc_rep_decrypt_proc;
+ krb5_kdc_sign_ticket;
+ krb5_kdc_verify_ticket;
+ krb5_kt_client_default;
+ krb5_kt_dfl_ops;
+ krb5_kt_dup;
+ krb5_ktf_ops;
+ krb5_ktf_writable_ops;
+ krb5_lock_file;
+ krb5_make_authdata_kdc_issued;
+ krb5_make_full_ipaddr;
+ krb5_make_fulladdr;
+ krb5_marshal_credentials;
+ krb5_merge_authdata;
+ krb5_mk_1cred;
+ krb5_mk_ncred;
+ krb5_mk_rep_dce;
+ krb5_os_localaddr;
+ krb5_overridekeyname;
+ krb5_pac_sign;
+ krb5_pac_sign_ext;
+ krb5_pac_verify_ext;
+ krb5_pac_get_client_info;
+ krb5_principal2salt;
+ krb5_principal2salt_norealm;
+ krb5_principal_compare_flags;
+ krb5_rd_rep_dce;
+ krb5_rd_req_decoded;
+ krb5_rd_req_decoded_anyflag;
+ krb5_read_password;
+ krb5_recvauth_version;
+ krb5_responder_get_challenge;
+ krb5_responder_list_questions;
+ krb5_responder_set_answer;
+ krb5_responder_otp_get_challenge;
+ krb5_responder_otp_set_answer;
+ krb5_responder_otp_challenge_free;
+ krb5_responder_pkinit_get_challenge;
+ krb5_responder_pkinit_set_answer;
+ krb5_responder_pkinit_challenge_free;
+ krb5_ser_pack_bytes;
+ krb5_ser_pack_int32;
+ krb5_ser_pack_int64;
+ krb5_ser_unpack_bytes;
+ krb5_ser_unpack_int32;
+ krb5_ser_unpack_int64;
+ krb5_server_decrypt_ticket_keytab;
+ krb5_set_debugging_time;
+ krb5_set_default_tgs_enctypes;
+ krb5_set_default_tgs_ktypes;
+ krb5_set_principal_realm;
+ krb5_set_kdc_send_hook;
+ krb5_set_kdc_recv_hook;
+ krb5_set_time_offsets;
+ krb5_set_trace_callback;
+ krb5_set_trace_filename;
+ krb5_sname_match;
+ krb5_string_to_timestamp;
+ krb5int_tgtname;
+ krb5_tkt_creds_free;
+ krb5_tkt_creds_get;
+ krb5_tkt_creds_get_creds;
+ krb5_tkt_creds_get_times;
+ krb5_tkt_creds_init;
+ krb5_tkt_creds_step;
+ krb5_timestamp_to_sfstring;
+ krb5_timestamp_to_string;
+ krb5_unlock_file;
+ krb5_unmarshal_credentials;
+ krb5_unpack_full_ipaddr;
+ krb5_unparse_name_ext;
+ krb5_unparse_name_flags_ext;
+ krb5_use_natural_time;
+ krb5_verify_authdata_kdc_issued;
+ krb5_vwrap_error_message;
+ krb5_walk_realm_tree;
+ krb5_wrap_error_message;
+ krb5int_accessor;
+ krb5int_cc_default;
+ krb5int_cleanup_library;
+ krb5int_copy_data_contents;
+ krb5int_copy_data_contents_add0;
+ krb5int_find_pa_data;
+ krb5int_foreach_localaddr;
+ krb5int_free_data_list;
+ krb5int_get_authdata_containee_types;
+ krb5int_init_context_kdc;
+ krb5int_initialize_library;
+ krb5int_parse_enctype_list;
+ krb5int_random_string;
+ krb5int_trace;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/lib/rpc/Makefile b/krb5/lib/rpc/Makefile
index 13499b184d30..a539803cc57c 100644
--- a/krb5/lib/rpc/Makefile
+++ b/krb5/lib/rpc/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= gssrpc
# SHLIB_MAJOR= 4
LDFLAGS=-Wl,--no-undefined
LIBADD= gssapi_krb5 krb5 k5crypto com_err krb5support
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= auth_gss.c \
auth_gssapi.c \
@@ -66,10 +65,6 @@ SRCS= auth_gss.c \
xdr_sizeof.c \
xdr_stdio.c
-INCS= dyn.h \
- dynP.h \
- gssrpcint.h
-
CFLAGS+=-I${KRB5_DIR}/lib/rpc \
-I${KRB5_DIR}/include \
-I${KRB5_SRCTOP}/include \
@@ -80,6 +75,4 @@ CFLAGS+=-I${KRB5_DIR}/lib/rpc \
.include <bsd.lib.mk>
-.SUFFIXES: .h .c
-
.PATH: ${KRB5_DIR}/lib/rpc
diff --git a/krb5/lib/rpc/version.map b/krb5/lib/rpc/version.map
new file mode 100644
index 000000000000..95ef4715572c
--- /dev/null
+++ b/krb5/lib/rpc/version.map
@@ -0,0 +1,148 @@
+gssrpc_4_MIT {
+ global:
+ gssrpc_auth_debug_gss;
+ gssrpc_auth_debug_gssapi;
+ gssrpc_auth_gssapi_create;
+ gssrpc_auth_gssapi_create_default;
+ gssrpc_auth_gssapi_display_status;
+ gssrpc_auth_gssapi_seal_seq;
+ gssrpc_auth_gssapi_unseal_seq;
+ gssrpc_auth_gssapi_unwrap_data;
+ gssrpc_auth_gssapi_wrap_data;
+ gssrpc_authgss_create;
+ gssrpc_authgss_create_default;
+ gssrpc_authgss_get_private_data;
+ gssrpc_authgss_service;
+ gssrpc_authnone_create;
+ gssrpc_authunix_create;
+ gssrpc_authunix_create_default;
+ gssrpc_bindresvport;
+ gssrpc_bindresvport_sa;
+ gssrpc_callrpc;
+ gssrpc_clnt_broadcast;
+ gssrpc_clnt_create;
+ gssrpc_clnt_pcreateerror;
+ gssrpc_clnt_perrno;
+ gssrpc_clnt_perror;
+ gssrpc_clnt_spcreateerror;
+ gssrpc_clnt_sperrno;
+ gssrpc_clnt_sperror;
+ gssrpc_clntraw_create;
+ gssrpc_clnttcp_create;
+ gssrpc_clntudp_bufcreate;
+ gssrpc_clntudp_create;
+ gssrpc_get_myaddress;
+ gssrpc_getrpcport;
+ gssrpc_log_debug;
+ gssrpc_log_hexdump;
+ gssrpc_log_status;
+ gssrpc_misc_debug_gss;
+ gssrpc_misc_debug_gssapi;
+ gssrpc_pmap_getmaps;
+ gssrpc_pmap_getport;
+ gssrpc_pmap_rmtcall;
+ gssrpc_pmap_set;
+ gssrpc_pmap_unset;
+ gssrpc_registerrpc;
+ gssrpc_rpc_createrr;
+ gssrpc_svc_auth_gss_ops;
+ gssrpc_svc_auth_gssapi_ops;
+ gssrpc_svc_auth_none;
+ gssrpc_svc_auth_none_ops;
+ gssrpc_svc_debug_gss;
+ gssrpc_svc_debug_gssapi;
+ gssrpc_svc_fdset;
+ gssrpc_svc_fdset_init;
+ gssrpc_svc_getreq;
+ gssrpc_svc_getreqset;
+ gssrpc_svc_maxfd;
+ gssrpc_svc_register;
+ gssrpc_svc_run;
+ gssrpc_svc_sendreply;
+ gssrpc_svc_unregister;
+ gssrpc_svcauth_gss_get_principal;
+ gssrpc_svcauth_gss_set_log_badauth_func;
+ gssrpc_svcauth_gss_set_log_badauth2_func;
+ gssrpc_svcauth_gss_set_log_badverf_func;
+ gssrpc_svcauth_gss_set_log_miscerr_func;
+ gssrpc_svcauth_gss_set_svc_name;
+ gssrpc_svcauth_gssapi_set_log_badauth_func;
+ gssrpc_svcauth_gssapi_set_log_badauth2_func;
+ gssrpc_svcauth_gssapi_set_log_badverf_func;
+ gssrpc_svcauth_gssapi_set_log_miscerr_func;
+ gssrpc_svcauth_gssapi_set_names;
+ gssrpc_svcauth_gssapi_unset_names;
+ gssrpc_svcerr_auth;
+ gssrpc_svcerr_decode;
+ gssrpc_svcerr_noproc;
+ gssrpc_svcerr_noprog;
+ gssrpc_svcerr_progvers;
+ gssrpc_svcerr_systemerr;
+ gssrpc_svcerr_weakauth;
+ gssrpc_svcfd_create;
+ gssrpc_svcraw_create;
+ gssrpc_svctcp_create;
+ gssrpc_svcudp_bufcreate;
+ gssrpc_svcudp_create;
+ gssrpc_svcudp_enablecache;
+ gssrpc_xdr_accepted_reply;
+ gssrpc_xdr_array;
+ gssrpc_xdr_authgssapi_creds;
+ gssrpc_xdr_authgssapi_init_arg;
+ gssrpc_xdr_authgssapi_init_res;
+ gssrpc_xdr_authunix_parms;
+ gssrpc_xdr_bool;
+ gssrpc_xdr_bytes;
+ gssrpc_xdr_callhdr;
+ gssrpc_xdr_callmsg;
+ gssrpc_xdr_char;
+ gssrpc_xdr_des_block;
+ gssrpc_xdr_enum;
+ gssrpc_xdr_free;
+ gssrpc_xdr_gss_buf;
+ gssrpc_xdr_int;
+ gssrpc_xdr_int32;
+ gssrpc_xdr_long;
+ gssrpc_xdr_netobj;
+ gssrpc_xdr_opaque;
+ gssrpc_xdr_opaque_auth;
+ gssrpc_xdr_pmap;
+ gssrpc_xdr_pmaplist;
+ gssrpc_xdr_pointer;
+ gssrpc_xdr_reference;
+ gssrpc_xdr_rejected_reply;
+ gssrpc_xdr_replymsg;
+ gssrpc_xdr_rmtcall_args;
+ gssrpc_xdr_rmtcallres;
+ gssrpc_xdr_rpc_gss_buf;
+ gssrpc_xdr_rpc_gss_cred;
+ gssrpc_xdr_rpc_gss_data;
+ gssrpc_xdr_rpc_gss_init_args;
+ gssrpc_xdr_rpc_gss_init_res;
+ gssrpc_xdr_rpc_gss_unwrap_data;
+ gssrpc_xdr_rpc_gss_wrap_data;
+ gssrpc_xdr_short;
+ gssrpc_xdr_sizeof;
+ gssrpc_xdr_string;
+ gssrpc_xdr_u_char;
+ gssrpc_xdr_u_int;
+ gssrpc_xdr_u_int32;
+ gssrpc_xdr_u_long;
+ gssrpc_xdr_u_short;
+ gssrpc_xdr_union;
+ gssrpc_xdr_vector;
+ gssrpc_xdr_void;
+ gssrpc_xdr_wrapstring;
+ gssrpc_xdralloc_create;
+ gssrpc_xdralloc_getdata;
+ gssrpc_xdralloc_release;
+ gssrpc_xdrmem_create;
+ gssrpc_xdrrec_create;
+ gssrpc_xdrrec_endofrecord;
+ gssrpc_xdrrec_eof;
+ gssrpc_xdrrec_skiprecord;
+ gssrpc_xdrstdio_create;
+ gssrpc_xprt_register;
+ gssrpc_xprt_unregister;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/libexec/Makefile.inc b/krb5/libexec/Makefile.inc
index bcc6d4b1c21e..6ce709d08304 100644
--- a/krb5/libexec/Makefile.inc
+++ b/krb5/libexec/Makefile.inc
@@ -9,4 +9,5 @@
.include "../Makefile.inc"
+PACKAGE?= kerberos-kdc
BINDIR?= /usr/libexec
diff --git a/krb5/libexec/kadmind/Makefile b/krb5/libexec/kadmind/Makefile
index bb572a32445f..62046214af7b 100644
--- a/krb5/libexec/kadmind/Makefile
+++ b/krb5/libexec/kadmind/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include "../Makefile.inc"
PROG= kadmind
@@ -31,6 +29,7 @@ CFLAGS+=-I${KRB5_DIR}/include \
-I${KRB5_SRCTOP}/include \
-I${KRB5_OBJTOP}/lib/gssapi \
-I${KRB5_OBJTOP}/lib \
+ -I${KRB5_DIR}/lib \
-I${KRB5_DIR}/lib/gssapi/krb5 \
-I${KRB5_DIR}/lib/gssapi/generic
diff --git a/krb5/libexec/kdc/Makefile b/krb5/libexec/kdc/Makefile
index a990666d9338..ac5ada19eb37 100644
--- a/krb5/libexec/kdc/Makefile
+++ b/krb5/libexec/kdc/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include "../Makefile.inc"
PROG= krb5kdc
diff --git a/krb5/libexec/kprop/Makefile b/krb5/libexec/kprop/Makefile
index 74a56232f6bb..1294d9014ee4 100644
--- a/krb5/libexec/kprop/Makefile
+++ b/krb5/libexec/kprop/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include "../Makefile.inc"
PROG= kprop
diff --git a/krb5/libexec/kpropd/Makefile b/krb5/libexec/kpropd/Makefile
index 2fb2bfdff228..e7ffe5a26016 100644
--- a/krb5/libexec/kpropd/Makefile
+++ b/krb5/libexec/kpropd/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= kpropd
LIBADD= kprop_util kdb5 kadm5clnt_mit gssrpc gssapi_krb5 krb5 k5crypto \
diff --git a/krb5/libexec/kproplog/Makefile b/krb5/libexec/kproplog/Makefile
index 533b6fdaa5c2..81405260a06e 100644
--- a/krb5/libexec/kproplog/Makefile
+++ b/krb5/libexec/kproplog/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= kproplog
LIBADD= kadm5srv_mit kdb5 gssrpc gssapi_krb5 krb5 k5crypto com_err \
krb5support sys
diff --git a/krb5/plugins/Makefile.inc b/krb5/plugins/Makefile.inc
index 846770a801e0..d98ed1d3887b 100644
--- a/krb5/plugins/Makefile.inc
+++ b/krb5/plugins/Makefile.inc
@@ -7,10 +7,11 @@
# under sponsorship from the FreeBSD Foundation.
#
+PACKAGE?= kerberos-kdc
MK_INSTALLLIB= no
SHLIB_NAME?= ${LIB}.so.${SHLIB_MAJOR}
PLUGINSDIR= ${LIBDIR_BASE}/krb5/plugins
SHLIBDIR= ${LIBDIR}
-SHLIB_MAJOR= 121
+SHLIB_MAJOR= 122
.include "../Makefile.inc"
diff --git a/krb5/plugins/audit/Makefile b/krb5/plugins/audit/Makefile
index 507cde261300..f85e5d1a81a5 100644
--- a/krb5/plugins/audit/Makefile
+++ b/krb5/plugins/audit/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -16,6 +14,7 @@ PACKAGE= krb5
LIB= kdc_j_encode
LIBDIR= ${PLUGINSDIR}/audit
LDFLAGS=-Wl,--no-undefined
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/plugins/audit
diff --git a/krb5/plugins/audit/version.map b/krb5/plugins/audit/version.map
new file mode 100644
index 000000000000..599442dcd8ab
--- /dev/null
+++ b/krb5/plugins/audit/version.map
@@ -0,0 +1,11 @@
+audit_121_MIT {
+ global:
+ kau_j_kdc_stop;
+ kau_j_kdc_start;
+ kau_j_as_req;
+ kau_j_tgs_req;
+ kau_j_tgs_s4u2self;
+ kau_j_tgs_s4u2proxy;
+ kau_j_tgs_u2u;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/plugins/k5tls/Makefile b/krb5/plugins/k5tls/Makefile
index 8af5efb06b80..30738a70e71d 100644
--- a/krb5/plugins/k5tls/Makefile
+++ b/krb5/plugins/k5tls/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -18,6 +16,7 @@ SHLIBDIR= ${LIBDIR}
LIB= k5tls
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5 krb5profile krb5support ssl crypto k5crypto com_err sys
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= notls.c \
openssl.c
diff --git a/krb5/plugins/k5tls/version.map b/krb5/plugins/k5tls/version.map
new file mode 100644
index 000000000000..d8602cb1559a
--- /dev/null
+++ b/krb5/plugins/k5tls/version.map
@@ -0,0 +1,5 @@
+HIDDEN { local: __*; _rest*; _save*; *; };
+k5tls_0_MIT {
+ global:
+ tls_k5tls_initvt;
+};
diff --git a/krb5/plugins/kdb/db2/Makefile b/krb5/plugins/kdb/db2/Makefile
index 7526283f37be..3230a77171f4 100644
--- a/krb5/plugins/kdb/db2/Makefile
+++ b/krb5/plugins/kdb/db2/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -18,6 +16,7 @@ SHLIBDIR= ${LIBDIR}
LIB= db2
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile krb5 com_err k5crypto kadm5srv_mit kdb5 gssrpc gssapi_krb5 krb5support
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= \
adb_openclose.c \
@@ -30,15 +29,6 @@ SRCS= \
.include "${KRB5_SRCTOP}/plugins/kdb/db2/libdb2/Makefile.inc"
-MAN= db_btree.3 \
- db_hash.3 \
- db_lock.3 \
- db_log.3 \
- db_mpool.3 \
- db_open.3 \
- db_recno.3 \
- db_txn.3
-
CFLAGS+=-I${KRB5_DIR}/plugins/kdb/db2 \
-I${KRB5_DIR}/plugins/kdb/db2/libdb2 \
-I${KRB5_DIR}/plugins/kdb/db2/libdb2/include \
@@ -50,16 +40,12 @@ CFLAGS+=-I${KRB5_DIR}/plugins/kdb/db2 \
-I${KRB5_DIR}/include \
-I${KRB5_SRCTOP}/include \
-I${KRB5_DIR}/lib/kdb \
+ -I${KRB5_DIR}/lib \
-I${KRB5_OBJTOP}/plugins/kdb/db2 \
-I${KRB5_OBJTOP}/lib/kdb
.include <bsd.lib.mk>
-.SUFFIXES: .h .c .man .3
-
-.man.3:
- @cp ${.ALLSRC} ${.TARGET}
-
.PATH: ${KRB5_DIR}/plugins/kdb/db2 \
${KRB5_DIR}/plugins/kdb/db2/libdb2 \
${KRB5_DIR}/plugins/kdb/db2/libdb2/man
diff --git a/krb5/plugins/kdb/db2/version.map b/krb5/plugins/kdb/db2/version.map
new file mode 100644
index 000000000000..6c7362e3e06b
--- /dev/null
+++ b/krb5/plugins/kdb/db2/version.map
@@ -0,0 +1,5 @@
+HIDDEN { local: __*; _rest*; _save*; *; };
+db2_0_MIT {
+ global:
+ kdb_function_table;
+};
diff --git a/krb5/plugins/preauth/Makefile.inc b/krb5/plugins/preauth/Makefile.inc
index aecd360f50e7..8a713e4d0856 100644
--- a/krb5/plugins/preauth/Makefile.inc
+++ b/krb5/plugins/preauth/Makefile.inc
@@ -7,6 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
+PACKAGE?= kerberos-kdc
LIBDIR= ${PLUGINSDIR}/preauth
SHLIBDIR= ${LIBDIR}
diff --git a/krb5/plugins/preauth/otp/Makefile b/krb5/plugins/preauth/otp/Makefile
index 9222f9785a80..48fc35db0727 100644
--- a/krb5/plugins/preauth/otp/Makefile
+++ b/krb5/plugins/preauth/otp/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= otp
LIBDIR= ${PLUGINSDIR}/preauth
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile krad verto krb5 k5crypto com_err krb5support m
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/plugins/preauth/otp
diff --git a/krb5/plugins/preauth/otp/version.map b/krb5/plugins/preauth/otp/version.map
new file mode 100644
index 000000000000..f2d914551789
--- /dev/null
+++ b/krb5/plugins/preauth/otp/version.map
@@ -0,0 +1,5 @@
+HIDDEN { local: __*; _rest*; _save*; *; };
+otp_0_MIT {
+ global:
+ kdcpreauth_otp_initvt;
+};
diff --git a/krb5/plugins/preauth/pkinit/Makefile b/krb5/plugins/preauth/pkinit/Makefile
index f2a76d1e33da..7d227aca5420 100644
--- a/krb5/plugins/preauth/pkinit/Makefile
+++ b/krb5/plugins/preauth/pkinit/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= pkinit
LIBDIR= ${PLUGINSDIR}/preauth
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile krb5 com_err k5crypto crypto krb5support
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/plugins/preauth/pkinit
diff --git a/krb5/plugins/preauth/pkinit/version.map b/krb5/plugins/preauth/pkinit/version.map
new file mode 100644
index 000000000000..c4498e8f473a
--- /dev/null
+++ b/krb5/plugins/preauth/pkinit/version.map
@@ -0,0 +1,6 @@
+HIDDEN { local: __*; _rest*; _save*; *; };
+pkinit_0_MIT {
+ global:
+ clpreauth_pkinit_initvt;
+ kdcpreauth_pkinit_initvt;
+};
diff --git a/krb5/plugins/preauth/spake/Makefile b/krb5/plugins/preauth/spake/Makefile
index a5d9179f8adc..3aa375cb5100 100644
--- a/krb5/plugins/preauth/spake/Makefile
+++ b/krb5/plugins/preauth/spake/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= spake
LIBDIR= ${PLUGINSDIR}/preauth
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5profile krb5 k5crypto com_err krb5support crypto sys
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/plugins/preauth/spake
diff --git a/krb5/plugins/preauth/spake/version.map b/krb5/plugins/preauth/spake/version.map
new file mode 100644
index 000000000000..d29c0e05083d
--- /dev/null
+++ b/krb5/plugins/preauth/spake/version.map
@@ -0,0 +1,6 @@
+HIDDEN { local: __*; _rest*; _save*; *; };
+spake_0_MIT {
+ global:
+ clpreauth_spake_initvt;
+ kdcpreauth_spake_initvt;
+};
diff --git a/krb5/plugins/preauth/test/Makefile b/krb5/plugins/preauth/test/Makefile
index 71b7200b2039..99f632c0cb17 100644
--- a/krb5/plugins/preauth/test/Makefile
+++ b/krb5/plugins/preauth/test/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
.include <src.opts.mk>
.include "../Makefile.inc"
@@ -17,6 +15,7 @@ LIB= test
LIBDIR= ${PLUGINSDIR}/preauth
LDFLAGS=-Wl,--no-undefined
LIBADD= krb5 k5crypto com_err krb5support
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/plugins/preauth/test
diff --git a/krb5/plugins/preauth/test/version.map b/krb5/plugins/preauth/test/version.map
new file mode 100644
index 000000000000..d6d445ad5bf8
--- /dev/null
+++ b/krb5/plugins/preauth/test/version.map
@@ -0,0 +1,6 @@
+HIDDEN { local: __*; _rest*; _save*; *; };
+test_0_MIT {
+ global:
+ clpreauth_test_initvt;
+ kdcpreauth_test_initvt;
+};
diff --git a/krb5/usr.bin/Makefile.inc b/krb5/usr.bin/Makefile.inc
index ea8e5ee805bb..f27bd78cd54c 100644
--- a/krb5/usr.bin/Makefile.inc
+++ b/krb5/usr.bin/Makefile.inc
@@ -9,4 +9,5 @@
.include "../Makefile.inc"
+PACKAGE?= kerberos
BINDIR?= /usr/bin
diff --git a/krb5/usr.bin/gss-client/Makefile b/krb5/usr.bin/gss-client/Makefile
index f2b5285ac3bb..acd67f9c17c6 100644
--- a/krb5/usr.bin/gss-client/Makefile
+++ b/krb5/usr.bin/gss-client/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= gss-client
LIBADD= gssapi_krb5 krb5 k5crypto com_err krb5profile krb5support sys
diff --git a/krb5/usr.bin/kadmin/Makefile b/krb5/usr.bin/kadmin/Makefile
index 95fcea307827..b2a094795d48 100644
--- a/krb5/usr.bin/kadmin/Makefile
+++ b/krb5/usr.bin/kadmin/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= kadmin
LIBADD= kadmin_common edit kadm5clnt_mit gssrpc gssapi_krb5 krb5 k5crypto \
@@ -21,7 +19,7 @@ SCRIPTS= k5srvutil.sh
MAN= kadmin.1 \
k5srvutil.1
-MLINKS= kadmin.1 kamdin.local.8
+MLINKS= kadmin.1 kadmin.local.8
CLEANFILES= kadmin.1 k5srvutil.1
@@ -34,7 +32,7 @@ k5srvutil.1: k5srvutil.man
.include <bsd.prog.mk>
-.SUFFIXES: .h .c. .man .1
+.SUFFIXES: .man
.man.1:
@cp ${.ALLSRC} ${.TARGET}
diff --git a/krb5/usr.bin/kdestroy/Makefile b/krb5/usr.bin/kdestroy/Makefile
index 4ec2ef4a1392..e3f493ffdc60 100644
--- a/krb5/usr.bin/kdestroy/Makefile
+++ b/krb5/usr.bin/kdestroy/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= kdestroy
LIBADD= krb5 k5crypto com_err krb5profile krb5support sys
diff --git a/krb5/usr.bin/kinit/Makefile b/krb5/usr.bin/kinit/Makefile
index 8aff9af3687b..3d1285137f85 100644
--- a/krb5/usr.bin/kinit/Makefile
+++ b/krb5/usr.bin/kinit/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= kinit
LIBADD= kadm5srv_mit kdb5 gssrpc gssapi_krb5 krb5 k5crypto com_err \
diff --git a/krb5/usr.bin/klist/Makefile b/krb5/usr.bin/klist/Makefile
index a5d6cecbaddb..3094a3b69d4b 100644
--- a/krb5/usr.bin/klist/Makefile
+++ b/krb5/usr.bin/klist/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= klist
LIBADD= krb5 k5crypto com_err krb5profile krb5support sys
diff --git a/krb5/usr.bin/kpasswd/Makefile b/krb5/usr.bin/kpasswd/Makefile
index 431cf239928e..e4d7d1e8ab84 100644
--- a/krb5/usr.bin/kpasswd/Makefile
+++ b/krb5/usr.bin/kpasswd/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= kpasswd
LIBADD= krb5 k5crypto com_err krb5profile krb5support sys
diff --git a/krb5/usr.bin/ksu/Makefile b/krb5/usr.bin/ksu/Makefile
index 4ddfa8096773..37a4c166aec6 100644
--- a/krb5/usr.bin/ksu/Makefile
+++ b/krb5/usr.bin/ksu/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= ksu
.if defined(ENABLE_SUID_K5SU)
BINMODE=4555
diff --git a/krb5/usr.bin/kswitch/Makefile b/krb5/usr.bin/kswitch/Makefile
index 1e9853012ae5..10298f34a9d4 100644
--- a/krb5/usr.bin/kswitch/Makefile
+++ b/krb5/usr.bin/kswitch/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= kswitch
LIBADD= krb5 k5crypto com_err krb5profile krb5support sys
diff --git a/krb5/usr.bin/ktutil/Makefile b/krb5/usr.bin/ktutil/Makefile
index abe02965de4d..6bcb4877ed6f 100644
--- a/krb5/usr.bin/ktutil/Makefile
+++ b/krb5/usr.bin/ktutil/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= ktutil
LIBADD= edit krb5 k5crypto com_err krb5profile krb5support krb5ss tinfow sys
diff --git a/krb5/usr.bin/kvno/Makefile b/krb5/usr.bin/kvno/Makefile
index 203839624414..0a43765e53f4 100644
--- a/krb5/usr.bin/kvno/Makefile
+++ b/krb5/usr.bin/kvno/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= kvno
LIBADD= krb5 k5crypto com_err krb5profile krb5support sys
diff --git a/krb5/usr.bin/sclient/Makefile b/krb5/usr.bin/sclient/Makefile
index f27dad42fa08..8a3cc38fe3b6 100644
--- a/krb5/usr.bin/sclient/Makefile
+++ b/krb5/usr.bin/sclient/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= sclient
LIBADD= krb5 k5crypto com_err krb5profile krb5support sys
diff --git a/krb5/usr.bin/sim_client/Makefile b/krb5/usr.bin/sim_client/Makefile
index ecdf9ac8885e..3e5ea72407bc 100644
--- a/krb5/usr.bin/sim_client/Makefile
+++ b/krb5/usr.bin/sim_client/Makefile
@@ -7,8 +7,6 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
-
PROG= sim_client
LIBADD= krb5 k5crypto com_err krb5profile krb5support sys
diff --git a/krb5/usr.sbin/gss-server/Makefile b/krb5/usr.sbin/gss-server/Makefile
index 9e80b466d427..c42740045ac4 100644
--- a/krb5/usr.sbin/gss-server/Makefile
+++ b/krb5/usr.sbin/gss-server/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
+PACKAGE= kerberos
PROG= gss-server
diff --git a/krb5/usr.sbin/kadmin.local/Makefile b/krb5/usr.sbin/kadmin.local/Makefile
index 7e89d0953683..4b99f490bd7b 100644
--- a/krb5/usr.sbin/kadmin.local/Makefile
+++ b/krb5/usr.sbin/kadmin.local/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
+PACKAGE= kerberos-kdc
PROG= kadmin.local
diff --git a/krb5/usr.sbin/kdb5_util/Makefile b/krb5/usr.sbin/kdb5_util/Makefile
index 6a7b66dc205c..ef821d6867f5 100644
--- a/krb5/usr.sbin/kdb5_util/Makefile
+++ b/krb5/usr.sbin/kdb5_util/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
+PACKAGE= kerberos-kdc
PROG= kdb5_util
@@ -27,11 +27,13 @@ SRCS= dump.c \
tdumputil.c \
${GEN}
-INCS= ${GENI}
+DPSRCS= ${GENI}
MAN= kdb5_util.8
-CFLAGS+=-I${KRB5_DIR}/include \
+CFLAGS+=-I. \
+ -I${KRB5_DIR}/include \
+ -I${KRB5_DIR}/lib \
-I${KRB5_SRCTOP}/include
MAN= kdb5_util.8
diff --git a/krb5/usr.sbin/sim_server/Makefile b/krb5/usr.sbin/sim_server/Makefile
index 793a6ad421b1..adaf8d1f087f 100644
--- a/krb5/usr.sbin/sim_server/Makefile
+++ b/krb5/usr.sbin/sim_server/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
+PACKAGE= kerberos
PROG= sim_server
diff --git a/krb5/usr.sbin/sserver/Makefile b/krb5/usr.sbin/sserver/Makefile
index 3b205b490a5f..e4e85b28157e 100644
--- a/krb5/usr.sbin/sserver/Makefile
+++ b/krb5/usr.sbin/sserver/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
+PACKAGE= kerberos
PROG= sserver
diff --git a/krb5/util/Makefile.inc b/krb5/util/Makefile.inc
index 858c1eb48dd9..95b93a793d77 100644
--- a/krb5/util/Makefile.inc
+++ b/krb5/util/Makefile.inc
@@ -10,4 +10,4 @@
.include "../Makefile.inc"
SHLIBDIR?= /usr/lib
-SHLIB_MAJOR?= 121
+SHLIB_MAJOR?= 122
diff --git a/krb5/util/build-tools/Makefile b/krb5/util/build-tools/Makefile
index c33d47f70c8f..1a6a373f0e7f 100644
--- a/krb5/util/build-tools/Makefile
+++ b/krb5/util/build-tools/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
+PACKAGE= kerberos-lib
.include "../Makefile.inc"
diff --git a/krb5/util/compile_et/Makefile b/krb5/util/compile_et/Makefile
index 57eb2f614802..03446f2d7d1c 100644
--- a/krb5/util/compile_et/Makefile
+++ b/krb5/util/compile_et/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
+PACKAGE= kerberos
.include "../Makefile.inc"
diff --git a/krb5/util/et/Makefile b/krb5/util/et/Makefile
index 4457cd199801..5d0c2a3e3ca5 100644
--- a/krb5/util/et/Makefile
+++ b/krb5/util/et/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5-lib
+PACKAGE= kerberos-lib
.include <src.opts.mk>
@@ -18,6 +18,7 @@ LIB= com_err
LDFLAGS=-Wl,--no-undefined
INCSDIR=${INCLUDEDIR}
LIBADD= krb5support
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= com_err.c \
diff --git a/krb5/util/et/version.map b/krb5/util/et/version.map
new file mode 100644
index 000000000000..3bd290009f22
--- /dev/null
+++ b/krb5/util/et/version.map
@@ -0,0 +1,17 @@
+HEIMDAL_COM_ERR_1.0 {
+ global:
+ com_err;
+ com_err_va;
+ error_message;
+ error_table_name;
+ reset_com_err_hook;
+ set_com_err_hook;
+};
+
+com_err_3_MIT {
+ global:
+ add_error_table;
+ error_table_name_r;
+ remove_error_table;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/util/profile/Makefile b/krb5/util/profile/Makefile
index 24e06e8c5024..7d1b806bfb5d 100644
--- a/krb5/util/profile/Makefile
+++ b/krb5/util/profile/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
+PACKAGE= kerberos-lib
.include <src.opts.mk>
@@ -15,6 +15,7 @@ PACKAGE= krb5
LIB= krb5profile
LIBADD= com_err krb5support
+VERSION_MAP= ${.CURDIR}/version.map
SRCS= prof_file.c \
prof_get.c \
@@ -66,13 +67,8 @@ profile.h: profile.hin prof_err.h
prof_file.c: profile.h
-MAN= profile.5
-
.include <bsd.lib.mk>
-.SUFFIXES: .h .c .man .1 .et
-
-.man.5:
- cp ${.ALLSRC} ${.TARGET}
+.SUFFIXES: .et
.PATH: ${KRB5_DIR}/util/profile
diff --git a/krb5/util/profile/version.map b/krb5/util/profile/version.map
new file mode 100644
index 000000000000..31960193977b
--- /dev/null
+++ b/krb5/util/profile/version.map
@@ -0,0 +1,74 @@
+profile_1_MIT {
+ global:
+ et_prof_error_table;
+ initialize_prof_error_table;
+ profile_abandon;
+ profile_add_node;
+ profile_add_relation;
+ profile_clear_relation;
+ profile_close_file;
+ profile_copy;
+ profile_create_node;
+ profile_dereference_data;
+ profile_dereference_data_locked;
+ profile_file_is_writable;
+ profile_find_node;
+ profile_find_node_relation;
+ profile_find_node_subsection;
+ profile_flush;
+ profile_flush_file_data;
+ profile_flush_file_data_to_buffer;
+ profile_flush_file_data_to_file;
+ profile_flush_to_buffer;
+ profile_flush_to_file;
+ profile_free_buffer;
+ profile_free_file;
+ profile_free_list;
+ profile_free_node;
+ profile_get_boolean;
+ profile_get_integer;
+ profile_get_node_name;
+ profile_get_node_parent;
+ profile_get_node_value;
+ profile_get_relation_names;
+ profile_get_string;
+ profile_get_subsection_names;
+ profile_get_value;
+ profile_get_values;
+ profile_init;
+ profile_init_flags;
+ profile_init_path;
+ profile_init_vtable;
+ profile_is_modified;
+ profile_is_node_final;
+ profile_is_writable;
+ profile_iterator;
+ profile_iterator_create;
+ profile_iterator_free;
+ profile_lock_global;
+ profile_make_node_final;
+ profile_make_prf_data;
+ profile_node_iterator;
+ profile_node_iterator_create;
+ profile_node_iterator_free;
+ profile_open_file;
+ profile_parse_file;
+ profile_process_directory;
+ profile_release;
+ profile_release_string;
+ profile_remove_node;
+ profile_rename_node;
+ profile_rename_section;
+ profile_ser_externalize;
+ profile_ser_internalize;
+ profile_ser_size;
+ profile_set_relation_value;
+ profile_unlock_global;
+ profile_update_file_data;
+ profile_update_file_data_locked;
+ profile_update_relation;
+ profile_verify_node;
+ profile_write_tree_file;
+ profile_write_tree_to_buffer;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/util/ss/Makefile b/krb5/util/ss/Makefile
index 600d125a7853..e7e025184284 100644
--- a/krb5/util/ss/Makefile
+++ b/krb5/util/ss/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
+PACKAGE= kerberos-lib
.include <src.opts.mk>
diff --git a/krb5/util/support/Makefile b/krb5/util/support/Makefile
index 9ba1b8169d8e..bba65bcd89c1 100644
--- a/krb5/util/support/Makefile
+++ b/krb5/util/support/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5-lib
+PACKAGE= kerberos-lib
.include <src.opts.mk>
@@ -16,6 +16,7 @@ PACKAGE= krb5-lib
LIB= krb5support
# SHLIB_MAJOR= 0
LDFLAGS=-Wl,--no-undefined
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/util/support
diff --git a/krb5/util/support/version.map b/krb5/util/support/version.map
new file mode 100644
index 000000000000..cc48ec6a4c8e
--- /dev/null
+++ b/krb5/util/support/version.map
@@ -0,0 +1,103 @@
+krb5support_0_MIT {
+ global:
+ k5_base64_decode;
+ k5_base64_encode;
+ k5_bcmp;
+ k5_buf_init_fixed;
+ k5_buf_init_dynamic;
+ k5_buf_init_dynamic_zap;
+ k5_buf_add;
+ k5_buf_add_len;
+ k5_buf_add_fmt;
+ k5_buf_add_vfmt;
+ k5_buf_cstring;
+ k5_buf_get_space;
+ k5_buf_truncate;
+ k5_buf_status;
+ k5_buf_free;
+ k5_set_error;
+ k5_vset_error;
+ k5_get_error;
+ k5_free_error;
+ k5_clear_error;
+ k5_set_error_info_callout_fn;
+ k5_hashtab_add;
+ k5_hashtab_create;
+ k5_hashtab_free;
+ k5_hashtab_get;
+ k5_hashtab_remove;
+ k5_hex_decode;
+ k5_hex_encode;
+ k5_json_array_add;
+ k5_json_array_create;
+ k5_json_array_fmt;
+ k5_json_array_get;
+ k5_json_array_length;
+ k5_json_array_set;
+ k5_json_bool_create;
+ k5_json_bool_value;
+ k5_json_decode;
+ k5_json_encode;
+ k5_json_get_tid;
+ k5_json_null_create;
+ k5_json_null_create_val;
+ k5_json_number_create;
+ k5_json_number_value;
+ k5_json_object_count;
+ k5_json_object_create;
+ k5_json_object_get;
+ k5_json_object_iterate;
+ k5_json_object_set;
+ k5_json_release;
+ k5_json_retain;
+ k5_json_string_create;
+ k5_json_string_create_base64;
+ k5_json_string_create_len;
+ k5_json_string_unbase64;
+ k5_json_string_utf8;
+ k5_os_mutex_init;
+ k5_os_mutex_destroy;
+ k5_os_mutex_lock;
+ k5_os_mutex_unlock;
+ k5_once;
+ k5_path_isabs;
+ k5_path_join;
+ k5_path_split;
+ k5_siphash24;
+ k5_strerror_r;
+ k5_utf8_to_utf16le;
+ k5_utf16le_to_utf8;
+ k5_dir_filenames;
+ k5_free_filenames;
+ krb5int_key_register;
+ krb5int_key_delete;
+ krb5int_getspecific;
+ krb5int_setspecific;
+ krb5int_getaddrinfo;
+ krb5int_freeaddrinfo;
+ krb5int_gai_strerror;
+ krb5int_getnameinfo;
+ krb5int_in6addr_any;
+ krb5int_pthread_loaded;
+ krb5int_open_plugin;
+ krb5int_close_plugin;
+ krb5int_get_plugin_data;
+ krb5int_get_plugin_func;
+ krb5int_open_plugin_dirs;
+ krb5int_close_plugin_dirs;
+ krb5int_get_plugin_dir_data;
+ krb5int_get_plugin_dir_func;
+ krb5int_free_plugin_dir_data;
+ krb5int_free_plugin_dir_func;
+ krb5int_mutex_alloc;
+ krb5int_mutex_free;
+ krb5int_mutex_lock;
+ krb5int_mutex_unlock;
+ krb5int_gmt_mktime;
+ krb5int_ucs4_to_utf8;
+ krb5int_utf8_to_ucs4;
+ krb5int_utf8_lentab;
+ krb5int_utf8_mintab;
+ krb5int_zap;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/krb5/util/verto/Makefile b/krb5/util/verto/Makefile
index 57367e5284e0..8f02d5f897f4 100644
--- a/krb5/util/verto/Makefile
+++ b/krb5/util/verto/Makefile
@@ -7,7 +7,7 @@
# under sponsorship from the FreeBSD Foundation.
#
-PACKAGE= krb5
+PACKAGE= kerberos-lib
.include <src.opts.mk>
@@ -15,6 +15,7 @@ PACKAGE= krb5
LIB= verto
# SHLIB_MAJOR= 0
+VERSION_MAP= ${.CURDIR}/version.map
.PATH: ${KRB5_DIR}/util/verto
diff --git a/krb5/util/verto/libverto.exports b/krb5/util/verto/libverto.exports
new file mode 100644
index 000000000000..3745d5014653
--- /dev/null
+++ b/krb5/util/verto/libverto.exports
@@ -0,0 +1,33 @@
+verto_add_child
+verto_add_idle
+verto_add_io
+verto_add_signal
+verto_add_timeout
+verto_break
+verto_cleanup
+verto_convert_module
+verto_default
+verto_del
+verto_fire
+verto_free
+verto_get_ctx
+verto_get_fd
+verto_get_fd_state
+verto_get_flags
+verto_get_interval
+verto_get_private
+verto_get_proc
+verto_get_proc_status
+verto_get_signal
+verto_get_supported_types
+verto_get_type
+verto_new
+verto_reinitialize
+verto_run
+verto_run_once
+verto_set_allocator
+verto_set_default
+verto_set_fd_state
+verto_set_flags
+verto_set_private
+verto_set_proc_status
diff --git a/krb5/util/verto/version.map b/krb5/util/verto/version.map
new file mode 100644
index 000000000000..ea3b7dcc13b2
--- /dev/null
+++ b/krb5/util/verto/version.map
@@ -0,0 +1,37 @@
+verto_0_MIT {
+ global:
+ verto_add_child;
+ verto_add_idle;
+ verto_add_io;
+ verto_add_signal;
+ verto_add_timeout;
+ verto_break;
+ verto_cleanup;
+ verto_convert_module;
+ verto_default;
+ verto_del;
+ verto_fire;
+ verto_free;
+ verto_get_ctx;
+ verto_get_fd;
+ verto_get_fd_state;
+ verto_get_flags;
+ verto_get_interval;
+ verto_get_private;
+ verto_get_proc;
+ verto_get_proc_status;
+ verto_get_signal;
+ verto_get_supported_types;
+ verto_get_type;
+ verto_new;
+ verto_reinitialize;
+ verto_run;
+ verto_run_once;
+ verto_set_allocator;
+ verto_set_default;
+ verto_set_fd_state;
+ verto_set_flags;
+ verto_set_private;
+ verto_set_proc_status;
+};
+HIDDEN { local: __*; _rest*; _save*; *; };
diff --git a/lib/libbsnmp/libbsnmp/Makefile b/lib/libbsnmp/libbsnmp/Makefile
index 6bdb4003fdf4..2e2770b56c4a 100644
--- a/lib/libbsnmp/libbsnmp/Makefile
+++ b/lib/libbsnmp/libbsnmp/Makefile
@@ -7,7 +7,7 @@ CONTRIB= ${SRCTOP}/contrib/bsnmp/lib
.PATH: ${CONTRIB}
LIB= bsnmp
-SHLIB_MAJOR= 6
+SHLIB_MAJOR= 7
LD_FATAL_WARNINGS= no
CFLAGS+= -I${CONTRIB} -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY
diff --git a/lib/libc/db/hash/hash.c b/lib/libc/db/hash/hash.c
index 7a66f5443d94..cc96fb5ce326 100644
--- a/lib/libc/db/hash/hash.c
+++ b/lib/libc/db/hash/hash.c
@@ -120,7 +120,8 @@ __hash_open(const char *file, int flags, int mode,
if ((hashp->fp = _open(file, flags | O_CLOEXEC, mode)) == -1)
RETURN_ERROR(errno, error0);
new_table = _fstat(hashp->fp, &statbuf) == 0 &&
- statbuf.st_size == 0 && (flags & O_ACCMODE) != O_RDONLY;
+ statbuf.st_size == 0 &&
+ ((flags & O_ACCMODE) != O_RDONLY || (flags & O_CREAT) != 0);
} else
new_table = 1;
diff --git a/lib/libc/net/gethostbydns.c b/lib/libc/net/gethostbydns.c
index b29fa1cdd845..216fc9bcf9a4 100644
--- a/lib/libc/net/gethostbydns.c
+++ b/lib/libc/net/gethostbydns.c
@@ -74,8 +74,10 @@
#define SPRINTF(x) ((size_t)sprintf x)
+#ifdef DEBUG
static const char AskedForGot[] =
"gethostby*.gethostanswer: asked for \"%s\", got \"%s\"";
+#endif
#ifdef RESOLVSORT
static void addrsort(char **, int, res_state);
@@ -299,8 +301,10 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
switch (type) {
case T_PTR:
if (strcasecmp(tname, bp) != 0) {
+#ifdef DEBUG
syslog(LOG_NOTICE|LOG_AUTH,
AskedForGot, qname, bp);
+#endif
cp += n;
continue; /* XXX - had_error++ ? */
}
@@ -347,8 +351,10 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
case T_A:
case T_AAAA:
if (strcasecmp(he->h_name, bp) != 0) {
+#ifdef DEBUG
syslog(LOG_NOTICE|LOG_AUTH,
AskedForGot, he->h_name, bp);
+#endif
cp += n;
continue; /* XXX - had_error++ ? */
}
diff --git a/lib/libc/net/res_config.h b/lib/libc/net/res_config.h
index f049d6817b7a..39a1b5f1486f 100644
--- a/lib/libc/net/res_config.h
+++ b/lib/libc/net/res_config.h
@@ -1,5 +1,5 @@
-#define DEBUG 1 /* enable debugging code (needed for dig) */
+//#define DEBUG /* enable debugging code */
#define RESOLVSORT /* allow sorting of addresses in gethostbyname */
-#undef SUNSECURITY /* verify gethostbyaddr() calls - WE DON'T NEED IT */
+//#define SUNSECURITY /* verify gethostbyaddr() calls */
#define MULTI_PTRS_ARE_ALIASES 1 /* fold multiple PTR records into aliases */
diff --git a/lib/libc/resolv/res_debug.h b/lib/libc/resolv/res_debug.h
index dd048116fb49..ccae03e625aa 100644
--- a/lib/libc/resolv/res_debug.h
+++ b/lib/libc/resolv/res_debug.h
@@ -23,7 +23,7 @@
#ifndef DEBUG
# define Dprint(cond, args) /*empty*/
# define DprintQ(cond, args, query, size) /*empty*/
-# define Aerror(statp, file, string, error, address) /*empty*/
+# define Aerror(statp, file, string, error, address, alen) /*empty*/
# define Perror(statp, file, string, error) /*empty*/
#else
# define Dprint(cond, args) if (cond) {fprintf args;} else {}
diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c
index 70d6bc6d3bf2..71ab2dcb7038 100644
--- a/lib/libc/resolv/res_init.c
+++ b/lib/libc/resolv/res_init.c
@@ -108,12 +108,6 @@
#include "res_private.h"
-/*% Options. Should all be left alone. */
-#define RESOLVSORT
-#ifndef DEBUG
-#define DEBUG
-#endif
-
#ifdef SOLARIS2
#include <sys/systeminfo.h>
#endif
diff --git a/lib/libc/resolv/res_mkquery.c b/lib/libc/resolv/res_mkquery.c
index 0c15def5d117..f6767a92375c 100644
--- a/lib/libc/resolv/res_mkquery.c
+++ b/lib/libc/resolv/res_mkquery.c
@@ -76,11 +76,6 @@
#include <string.h>
#include "port_after.h"
-/* Options. Leave them on. */
-#ifndef DEBUG
-#define DEBUG
-#endif
-
extern const char *_res_opcodes[];
/*%
diff --git a/lib/libc/resolv/res_mkupdate.c b/lib/libc/resolv/res_mkupdate.c
index e5a3cb702cda..3f595dc4ec08 100644
--- a/lib/libc/resolv/res_mkupdate.c
+++ b/lib/libc/resolv/res_mkupdate.c
@@ -48,10 +48,6 @@
#include "port_after.h"
-/* Options. Leave them on. */
-#ifndef DEBUG
-#define DEBUG
-#endif
#define MAXPORT 1024
static int getnum_str(u_char **, u_char *);
diff --git a/lib/libc/resolv/res_query.c b/lib/libc/resolv/res_query.c
index e9c628ad8d47..f26d59e522b4 100644
--- a/lib/libc/resolv/res_query.c
+++ b/lib/libc/resolv/res_query.c
@@ -81,11 +81,6 @@
#include <unistd.h>
#include "port_after.h"
-/* Options. Leave them on. */
-#ifndef DEBUG
-#define DEBUG
-#endif
-
#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
diff --git a/lib/libc/resolv/res_send.c b/lib/libc/resolv/res_send.c
index 3fb627b83d55..08c3aed7f934 100644
--- a/lib/libc/resolv/res_send.c
+++ b/lib/libc/resolv/res_send.c
@@ -112,10 +112,6 @@
#include "un-namespace.h"
-/* Options. Leave them on. */
-#ifndef DEBUG
-#define DEBUG
-#endif
#include "res_debug.h"
#include "res_private.h"
@@ -138,15 +134,12 @@ static int send_dg(res_state,
const u_char *, int,
u_char *, int, int *, int, int,
int *, int *);
+#ifdef DEBUG
static void Aerror(const res_state, FILE *, const char *, int,
const struct sockaddr *, int);
static void Perror(const res_state, FILE *, const char *, int);
-static int sock_eq(struct sockaddr *, struct sockaddr *);
-#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
-static int pselect(int, void *, void *, void *,
- struct timespec *,
- const sigset_t *);
#endif
+static int sock_eq(struct sockaddr *, struct sockaddr *);
void res_pquery(const res_state, const u_char *, int, FILE *);
static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
@@ -302,7 +295,9 @@ res_nsend(res_state statp,
#ifdef USE_KQUEUE
int kq;
#endif
+#ifdef DEBUG
char abuf[NI_MAXHOST];
+#endif
/* No name servers or res_init() failure */
if (statp->nscount == 0 || EXT(statp).ext == NULL) {
@@ -418,10 +413,10 @@ res_nsend(res_state statp,
*/
for (tries = 0; tries < statp->retry; tries++) {
for (ns = 0; ns < statp->nscount; ns++) {
- struct sockaddr *nsap;
- int nsaplen;
- nsap = get_nsaddr(statp, ns);
- nsaplen = get_salen(nsap);
+ struct sockaddr *nsap = get_nsaddr(statp, ns);
+#ifdef DEBUG
+ int nsaplen = get_salen(nsap);
+#endif
statp->_flags &= ~RES_F_LASTMASK;
statp->_flags |= (ns << RES_F_LASTSHIFT);
same_ns:
@@ -1088,6 +1083,7 @@ send_dg(res_state statp,
return (resplen);
}
+#ifdef DEBUG
static void
Aerror(const res_state statp, FILE *file, const char *string, int error,
const struct sockaddr *address, int alen)
@@ -1119,6 +1115,7 @@ Perror(const res_state statp, FILE *file, const char *string, int error) {
string, strerror(error));
errno = save;
}
+#endif
static int
sock_eq(struct sockaddr *a, struct sockaddr *b) {
@@ -1145,29 +1142,3 @@ sock_eq(struct sockaddr *a, struct sockaddr *b) {
return 0;
}
}
-
-#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
-/* XXX needs to move to the porting library. */
-static int
-pselect(int nfds, void *rfds, void *wfds, void *efds,
- struct timespec *tsp, const sigset_t *sigmask)
-{
- struct timeval tv, *tvp;
- sigset_t sigs;
- int n;
-
- if (tsp) {
- tvp = &tv;
- tv = evTimeVal(*tsp);
- } else
- tvp = NULL;
- if (sigmask)
- sigprocmask(SIG_SETMASK, sigmask, &sigs);
- n = select(nfds, rfds, wfds, efds, tvp);
- if (sigmask)
- sigprocmask(SIG_SETMASK, &sigs, NULL);
- if (tsp)
- *tsp = evTimeSpec(tv);
- return (n);
-}
-#endif
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/string/memchr.3 b/lib/libc/string/memchr.3
index f5d1fe5d5c7f..c50e932d3382 100644
--- a/lib/libc/string/memchr.3
+++ b/lib/libc/string/memchr.3
@@ -34,7 +34,7 @@
.Os
.Sh NAME
.Nm memchr
-.Nd locate byte in byte string
+.Nd locate byte in memory object
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
@@ -51,8 +51,11 @@ locates the first occurrence of
.Fa c
(converted to an
.Vt "unsigned char" )
-in string
-.Fa b .
+in object
+.Fa b ,
+limited to at most
+.Fa len
+characters.
.Pp
The
.Fn memrchr
@@ -60,16 +63,19 @@ function behaves like
.Fn memchr ,
except that it locates the last occurrence of
.Fa c
-in string
-.Fa b .
+in object
+.Fa b ,
+limited to the first
+.Fa len
+characters.
.Sh RETURN VALUES
The
.Fn memchr
and
.Fn memrchr
-functions
-return a pointer to the byte located,
-or NULL if no such byte exists within
+functions return a pointer to the byte located, or
+.Dv NULL
+if no such byte exists within
.Fa len
bytes.
.Sh SEE ALSO
diff --git a/lib/libc/tests/db/Makefile b/lib/libc/tests/db/Makefile
index f1f33bd2bafc..54b38b94a581 100644
--- a/lib/libc/tests/db/Makefile
+++ b/lib/libc/tests/db/Makefile
@@ -7,6 +7,8 @@ PROGS+= h_lfsr
${PACKAGE}FILES+= README
+ATF_TESTS_C+= dbm_open_test
+
NETBSD_ATF_TESTS_C+= db_hash_seq_test
NETBSD_ATF_TESTS_SH+= db_test
ATF_TESTS_SH_SED_db_test= -e 's,/bin/csh,/bin/cat,g'
diff --git a/lib/libc/tests/db/dbm_open_test.c b/lib/libc/tests/db/dbm_open_test.c
new file mode 100644
index 000000000000..18d398e16b2a
--- /dev/null
+++ b/lib/libc/tests/db/dbm_open_test.c
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2025 Klara, Inc.
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/mman.h>
+
+#include <fcntl.h>
+#include <ndbm.h>
+#include <stdio.h>
+
+#include <atf-c.h>
+
+ATF_TC(dbm_open_missing_test);
+ATF_TC_HEAD(dbm_open_missing_test, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Test dbm_open when creating a new database");
+}
+
+ATF_TC_BODY(dbm_open_missing_test, tc)
+{
+ const char *path = "tmp";
+ const char *dbname = "tmp.db";
+
+ /*
+ * POSIX.1 specifies that a missing database file should
+ * always get created if O_CREAT is present, except when
+ * O_EXCL is specified as well.
+ */
+ ATF_CHECK(dbm_open(path, O_RDONLY, _PROT_ALL) == NULL);
+ ATF_REQUIRE(!atf_utils_file_exists(dbname));
+ ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT, _PROT_ALL) != NULL);
+ ATF_REQUIRE(atf_utils_file_exists(dbname));
+ ATF_CHECK(dbm_open(path, O_RDONLY | O_CREAT | O_EXCL, _PROT_ALL) == NULL);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, dbm_open_missing_test);
+ return (atf_no_error());
+}
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/libcasper/services/cap_net/tests/net_test.c b/lib/libcasper/services/cap_net/tests/net_test.c
index e1045341fe47..adf5773233c8 100644
--- a/lib/libcasper/services/cap_net/tests/net_test.c
+++ b/lib/libcasper/services/cap_net/tests/net_test.c
@@ -331,7 +331,11 @@ test_extend_mode(cap_channel_t *capnet, int current)
}
}
-ATF_TC_WITHOUT_HEAD(capnet__getnameinfo);
+ATF_TC(capnet__getnameinfo);
+ATF_TC_HEAD(capnet__getnameinfo, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__getnameinfo, tc)
{
cap_channel_t *capnet;
@@ -344,7 +348,11 @@ ATF_TC_BODY(capnet__getnameinfo, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__connect);
+ATF_TC(capnet__connect);
+ATF_TC_HEAD(capnet__connect, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__connect, tc)
{
cap_channel_t *capnet;
@@ -356,7 +364,11 @@ ATF_TC_BODY(capnet__connect, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__bind);
+ATF_TC(capnet__bind);
+ATF_TC_HEAD(capnet__bind, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__bind, tc)
{
cap_channel_t *capnet;
@@ -368,7 +380,11 @@ ATF_TC_BODY(capnet__bind, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__getaddrinfo);
+ATF_TC(capnet__getaddrinfo);
+ATF_TC_HEAD(capnet__getaddrinfo, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__getaddrinfo, tc)
{
cap_channel_t *capnet;
@@ -386,7 +402,11 @@ ATF_TC_BODY(capnet__getaddrinfo, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__gethostbyname);
+ATF_TC(capnet__gethostbyname);
+ATF_TC_HEAD(capnet__gethostbyname, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__gethostbyname, tc)
{
cap_channel_t *capnet;
@@ -398,7 +418,11 @@ ATF_TC_BODY(capnet__gethostbyname, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__gethostbyaddr);
+ATF_TC(capnet__gethostbyaddr);
+ATF_TC_HEAD(capnet__gethostbyaddr, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__gethostbyaddr, tc)
{
cap_channel_t *capnet;
@@ -411,7 +435,11 @@ ATF_TC_BODY(capnet__gethostbyaddr, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__getnameinfo_buffer);
+ATF_TC(capnet__getnameinfo_buffer);
+ATF_TC_HEAD(capnet__getnameinfo_buffer, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__getnameinfo_buffer, tc)
{
cap_channel_t *chan;
@@ -450,7 +478,11 @@ ATF_TC_BODY(capnet__getnameinfo_buffer, tc)
cap_close(chan);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_addr2name_mode);
+ATF_TC(capnet__limits_addr2name_mode);
+ATF_TC_HEAD(capnet__limits_addr2name_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_addr2name_mode, tc)
{
cap_channel_t *capnet;
@@ -481,7 +513,11 @@ ATF_TC_BODY(capnet__limits_addr2name_mode, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_addr2name_family);
+ATF_TC(capnet__limits_addr2name_family);
+ATF_TC_HEAD(capnet__limits_addr2name_family, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_addr2name_family, tc)
{
cap_channel_t *capnet;
@@ -526,7 +562,11 @@ ATF_TC_BODY(capnet__limits_addr2name_family, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_addr2name);
+ATF_TC(capnet__limits_addr2name);
+ATF_TC_HEAD(capnet__limits_addr2name, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_addr2name, tc)
{
cap_channel_t *capnet;
@@ -580,7 +620,11 @@ ATF_TC_BODY(capnet__limits_addr2name, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_addr2name_mode);
+ATF_TC(capnet__limits_deprecated_addr2name_mode);
+ATF_TC_HEAD(capnet__limits_deprecated_addr2name_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_deprecated_addr2name_mode, tc)
{
cap_channel_t *capnet;
@@ -609,7 +653,11 @@ ATF_TC_BODY(capnet__limits_deprecated_addr2name_mode, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_addr2name_family);
+ATF_TC(capnet__limits_deprecated_addr2name_family);
+ATF_TC_HEAD(capnet__limits_deprecated_addr2name_family, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_deprecated_addr2name_family, tc)
{
cap_channel_t *capnet;
@@ -660,7 +708,11 @@ ATF_TC_BODY(capnet__limits_deprecated_addr2name_family, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_addr2name);
+ATF_TC(capnet__limits_deprecated_addr2name);
+ATF_TC_HEAD(capnet__limits_deprecated_addr2name, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_deprecated_addr2name, tc)
{
cap_channel_t *capnet;
@@ -712,7 +764,11 @@ ATF_TC_BODY(capnet__limits_deprecated_addr2name, tc)
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_mode);
+ATF_TC(capnet__limits_name2addr_mode);
+ATF_TC_HEAD(capnet__limits_name2addr_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_name2addr_mode, tc)
{
cap_channel_t *capnet;
@@ -744,7 +800,11 @@ ATF_TC_BODY(capnet__limits_name2addr_mode, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_hosts);
+ATF_TC(capnet__limits_name2addr_hosts);
+ATF_TC_HEAD(capnet__limits_name2addr_hosts, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_name2addr_hosts, tc)
{
cap_channel_t *capnet;
@@ -797,7 +857,11 @@ ATF_TC_BODY(capnet__limits_name2addr_hosts, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_hosts_servnames_strict);
+ATF_TC(capnet__limits_name2addr_hosts_servnames_strict);
+ATF_TC_HEAD(capnet__limits_name2addr_hosts_servnames_strict, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_strict, tc)
{
cap_channel_t *capnet;
@@ -829,7 +893,11 @@ ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_strict, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_hosts_servnames_mix);
+ATF_TC(capnet__limits_name2addr_hosts_servnames_mix);
+ATF_TC_HEAD(capnet__limits_name2addr_hosts_servnames_mix, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_mix, tc)
{
cap_channel_t *capnet;
@@ -882,7 +950,11 @@ ATF_TC_BODY(capnet__limits_name2addr_hosts_servnames_mix, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_name2addr_family);
+ATF_TC(capnet__limits_name2addr_family);
+ATF_TC_HEAD(capnet__limits_name2addr_family, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_name2addr_family, tc)
{
cap_channel_t *capnet;
@@ -941,7 +1013,11 @@ ATF_TC_BODY(capnet__limits_name2addr_family, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_name2addr_mode);
+ATF_TC(capnet__limits_deprecated_name2addr_mode);
+ATF_TC_HEAD(capnet__limits_deprecated_name2addr_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_deprecated_name2addr_mode, tc)
{
cap_channel_t *capnet;
@@ -972,7 +1048,11 @@ ATF_TC_BODY(capnet__limits_deprecated_name2addr_mode, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_name2addr_hosts);
+ATF_TC(capnet__limits_deprecated_name2addr_hosts);
+ATF_TC_HEAD(capnet__limits_deprecated_name2addr_hosts, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_deprecated_name2addr_hosts, tc)
{
cap_channel_t *capnet;
@@ -1011,7 +1091,11 @@ ATF_TC_BODY(capnet__limits_deprecated_name2addr_hosts, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_name2addr_family);
+ATF_TC(capnet__limits_deprecated_name2addr_family);
+ATF_TC_HEAD(capnet__limits_deprecated_name2addr_family, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_deprecated_name2addr_family, tc)
{
cap_channel_t *capnet;
@@ -1065,7 +1149,11 @@ ATF_TC_BODY(capnet__limits_deprecated_name2addr_family, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_bind_mode);
+ATF_TC(capnet__limits_bind_mode);
+ATF_TC_HEAD(capnet__limits_bind_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_bind_mode, tc)
{
cap_channel_t *capnet;
@@ -1097,7 +1185,11 @@ ATF_TC_BODY(capnet__limits_bind_mode, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_bind);
+ATF_TC(capnet__limits_bind);
+ATF_TC_HEAD(capnet__limits_bind, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_bind, tc)
{
cap_channel_t *capnet;
@@ -1122,7 +1214,11 @@ ATF_TC_BODY(capnet__limits_bind, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_connect_mode);
+ATF_TC(capnet__limits_connect_mode);
+ATF_TC_HEAD(capnet__limits_connect_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_connect_mode, tc)
{
cap_channel_t *capnet;
@@ -1154,7 +1250,11 @@ ATF_TC_BODY(capnet__limits_connect_mode, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_connect_dns_mode);
+ATF_TC(capnet__limits_connect_dns_mode);
+ATF_TC_HEAD(capnet__limits_connect_dns_mode, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_connect_dns_mode, tc)
{
cap_channel_t *capnet;
@@ -1186,7 +1286,11 @@ ATF_TC_BODY(capnet__limits_connect_dns_mode, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_connect);
+ATF_TC(capnet__limits_connect);
+ATF_TC_HEAD(capnet__limits_connect, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_connect, tc)
{
cap_channel_t *capnet;
@@ -1230,7 +1334,11 @@ ATF_TC_BODY(capnet__limits_connect, tc)
cap_close(capnet);
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_connecttodns);
+ATF_TC(capnet__limits_connecttodns);
+ATF_TC_HEAD(capnet__limits_connecttodns, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_connecttodns, tc)
{
cap_channel_t *capnet;
@@ -1279,7 +1387,11 @@ ATF_TC_BODY(capnet__limits_connecttodns, tc)
}
-ATF_TC_WITHOUT_HEAD(capnet__limits_deprecated_connecttodns);
+ATF_TC(capnet__limits_deprecated_connecttodns);
+ATF_TC_HEAD(capnet__limits_deprecated_connecttodns, tc)
+{
+ atf_tc_set_md_var(tc, "require.config", "allow_network_access");
+}
ATF_TC_BODY(capnet__limits_deprecated_connecttodns, tc)
{
cap_channel_t *capnet;
diff --git a/lib/libnvmf/libnvmf.h b/lib/libnvmf/libnvmf.h
index 7cdd7e433455..6b38fd286596 100644
--- a/lib/libnvmf/libnvmf.h
+++ b/lib/libnvmf/libnvmf.h
@@ -111,8 +111,13 @@ const void *nvmf_capsule_cqe(const struct nvmf_capsule *nc);
/* Return a string name for a transport type. */
const char *nvmf_transport_type(uint8_t trtype);
-/* Validate a NVMe Qualified Name. */
+/*
+ * Validate a NVMe Qualified Name. The second version enforces
+ * stricter checks inline with the specification. The first version
+ * enforces more minimal checks.
+ */
bool nvmf_nqn_valid(const char *nqn);
+bool nvmf_nqn_valid_strict(const char *nqn);
/* Controller-specific APIs. */
diff --git a/lib/libnvmf/nvmf_controller.c b/lib/libnvmf/nvmf_controller.c
index 971dccbe039e..f26f11633e03 100644
--- a/lib/libnvmf/nvmf_controller.c
+++ b/lib/libnvmf/nvmf_controller.c
@@ -7,6 +7,7 @@
#include <sys/utsname.h>
#include <assert.h>
+#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
@@ -15,6 +16,55 @@
#include "internal.h"
#include "nvmft_subr.h"
+bool
+nvmf_nqn_valid_strict(const char *nqn)
+{
+ size_t len;
+
+ if (!nvmf_nqn_valid(nqn))
+ return (false);
+
+ /*
+ * Stricter checks from the spec. Linux does not seem to
+ * require these.
+ */
+ len = strlen(nqn);
+
+ /*
+ * NVMF_NQN_MIN_LEN does not include '.' and require at least
+ * one character of a domain name.
+ */
+ if (len < NVMF_NQN_MIN_LEN + 2)
+ return (false);
+ if (memcmp("nqn.", nqn, strlen("nqn.")) != 0)
+ return (false);
+ nqn += strlen("nqn.");
+
+ /* Next 4 digits must be a year. */
+ for (u_int i = 0; i < 4; i++) {
+ if (!isdigit(nqn[i]))
+ return (false);
+ }
+ nqn += 4;
+
+ /* '-' between year and month. */
+ if (nqn[0] != '-')
+ return (false);
+ nqn++;
+
+ /* 2 digit month. */
+ for (u_int i = 0; i < 2; i++) {
+ if (!isdigit(nqn[i]))
+ return (false);
+ }
+ nqn += 2;
+
+ /* '.' between month and reverse domain name. */
+ if (nqn[0] != '.')
+ return (false);
+ return (true);
+}
+
void
nvmf_init_cqe(void *cqe, const struct nvmf_capsule *nc, uint16_t status)
{
diff --git a/lib/libpam/modules/pam_krb5/Makefile b/lib/libpam/modules/pam_krb5/Makefile
index b537bf37b7f3..c1792b5fb61d 100644
--- a/lib/libpam/modules/pam_krb5/Makefile
+++ b/lib/libpam/modules/pam_krb5/Makefile
@@ -32,7 +32,7 @@ SRCDIR= ${SRCTOP}/contrib/pam-krb5
${SRCDIR}/pam-util \
${SRCDIR}
-PACKAGE= krb5
+PACKAGE= kerberos
LIB= pam_krb5
LIBADD= com_err krb5
diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index e4123fe02211..d8e60075e103 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -3348,6 +3348,11 @@ pfctl_clear_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
return (e.error);
}
+static struct snl_attr_parser ap_clr_addrs[] = {
+ { .type = PF_T_NBR_DELETED, .off = 0, .cb = snl_attr_get_uint64 },
+};
+SNL_DECLARE_PARSER(clr_addrs_parser, struct genlmsghdr, snl_f_p_empty, ap_clr_addrs);
+
int
pfctl_clear_addrs(struct pfctl_handle *h, const struct pfr_table *filter,
int *ndel, int flags)
@@ -3380,7 +3385,7 @@ pfctl_clear_addrs(struct pfctl_handle *h, const struct pfr_table *filter,
return (ENXIO);
while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
- if (!snl_parse_nlmsg(&h->ss, hdr, &tstats_clr_parser, &del))
+ if (!snl_parse_nlmsg(&h->ss, hdr, &clr_addrs_parser, &del))
continue;
if (ndel)
*ndel = (uint32_t)del;
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/getsockopt.2 b/lib/libsys/getsockopt.2
index 8839b61597a2..3867824681d7 100644
--- a/lib/libsys/getsockopt.2
+++ b/lib/libsys/getsockopt.2
@@ -593,6 +593,15 @@ specified amount of time has elapsed since the initial call to
If
.Fa sp_fd
is -1, the socket will be unspliced immediately.
+A successful
+.Xr select 2 ,
+.Xr poll 2 ,
+or
+.Xr kqueue 2
+operation testing the ability to read from the source socket indicates
+that the splicing has terminated and at least one byte is available for
+reading.
+When one of the sockets gets closed, splicing ends.
.Pp
When passed to
.Fn getsockopt ,
diff --git a/lib/libsys/mkdir.2 b/lib/libsys/mkdir.2
index e1f1624cebc4..100f44d1dcf9 100644
--- a/lib/libsys/mkdir.2
+++ b/lib/libsys/mkdir.2
@@ -176,4 +176,4 @@ system call appeared in
The
.Fn mkdir
system call appeared in
-.At v1 .
+.Bx 4.2 .
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/lib/libusb/libusb.3 b/lib/libusb/libusb.3
index 74b85d4aa17e..9dc752f0fd7b 100644
--- a/lib/libusb/libusb.3
+++ b/lib/libusb/libusb.3
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 13, 2025
+.Dd July 9, 2025
.Dt LIBUSB 3
.Os
.Sh NAME
@@ -366,6 +366,23 @@ argument is non-zero the feature is enabled.
Else disabled.
Returns 0 on success and a LIBUSB_ERROR code on
failure.
+.Pp
+.Ft unsigned char *
+.Fn libusb_dev_mem_alloc "libusb_device_handle *devh"
+This function attempts to allocate a DMA memory block from the given
+.Fa devh
+so that we can enjoy the zero-copy transfer from kernel.
+This function is provided for compatibility and is currently unimplemented and always returns NULL.
+.Pp
+.Ft int
+.Fn libusb_dev_mem_free "libusb_device_handle *devh" "unsigned char *buffer" "size_t size"
+This function frees the DMA memory in
+.Fa devh
+from the given
+.Fa buffer
+with
+.Fa size .
+This function is unimplemented and always returns LIBUSB_ERROR_NOT_SUPPORTED.
.Sh USB DESCRIPTORS
.Ft int
.Fn libusb_get_device_descriptor "libusb_device *dev" "libusb_device_descriptor *desc"
@@ -775,6 +792,17 @@ argument can be either of LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED or LIBUSB_HOTPLUG_
.Ft void
.Fn libusb_hotplug_deregister_callback "libusb_context *ctx" "libusb_hotplug_callback_handle handle"
This function unregisters a hotplug filter.
+.Pp
+.Ft void
+.Fn libusb_free_pollfds "const struct libusb_pollfd **pollfds"
+This function releases the memory storage in
+.Fa pollfds ,
+and is safe to call when the argument is NULL.
+.Pp void *
+.Fn libusb_hotplug_get_user_data "struct libusb_context *ctx" "libusb_hotplug_callback_handle callback_handle"
+This function returns the user data from the opaque
+.Fa callback_handle ,
+or returns NULL if no matching handle is found.
.Sh LIBUSB VERSION 0.1 COMPATIBILITY
The library is also compliant with LibUSB version 0.1.12.
.Pp
diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h
index 6fb1c19fad13..1803ff637738 100644
--- a/lib/libusb/libusb.h
+++ b/lib/libusb/libusb.h
@@ -122,6 +122,7 @@ enum libusb_transfer_type {
LIBUSB_TRANSFER_TYPE_ISOCHRONOUS = 1,
LIBUSB_TRANSFER_TYPE_BULK = 2,
LIBUSB_TRANSFER_TYPE_INTERRUPT = 3,
+ LIBUSB_TRANSFER_TYPE_BULK_STREAM = 4,
};
enum libusb_standard_request {
@@ -513,6 +514,9 @@ int libusb_detach_kernel_driver(libusb_device_handle * devh, int interface);
int libusb_attach_kernel_driver(libusb_device_handle * devh, int interface);
int libusb_set_auto_detach_kernel_driver(libusb_device_handle *dev, int enable);
int libusb_set_interface_alt_setting(libusb_device_handle * devh, int interface_number, int alternate_setting);
+unsigned char *libusb_dev_mem_alloc(libusb_device_handle *devh);
+int libusb_dev_mem_free(libusb_device_handle *devh, unsigned char *buffer,
+ size_t size);
/* USB Descriptors */
@@ -573,7 +577,8 @@ int libusb_handle_events(libusb_context * ctx);
int libusb_handle_events_locked(libusb_context * ctx, struct timeval *tv);
int libusb_get_next_timeout(libusb_context * ctx, struct timeval *tv);
void libusb_set_pollfd_notifiers(libusb_context * ctx, libusb_pollfd_added_cb added_cb, libusb_pollfd_removed_cb removed_cb, void *user_data);
-const struct libusb_pollfd **libusb_get_pollfds(libusb_context * ctx);
+const struct libusb_pollfd **libusb_get_pollfds(libusb_context *ctx);
+void libusb_free_pollfds(const struct libusb_pollfd **pollfds);
/* Synchronous device I/O */
@@ -593,6 +598,8 @@ typedef int (*libusb_hotplug_callback_fn)(libusb_context *ctx,
int libusb_hotplug_register_callback(libusb_context *ctx, libusb_hotplug_event events, libusb_hotplug_flag flags, int vendor_id, int product_id, int dev_class, libusb_hotplug_callback_fn cb_fn, void *user_data, libusb_hotplug_callback_handle *handle);
void libusb_hotplug_deregister_callback(libusb_context *ctx, libusb_hotplug_callback_handle handle);
+void *libusb_hotplug_get_user_data(struct libusb_context *ctx,
+ libusb_hotplug_callback_handle callback_handle);
/* Streams support */
diff --git a/lib/libusb/libusb10.c b/lib/libusb/libusb10.c
index 6f1ca877fc28..5c116b39ea17 100644
--- a/lib/libusb/libusb10.c
+++ b/lib/libusb/libusb10.c
@@ -1530,6 +1530,7 @@ found:
libusb20_tr_set_callback(pxfer0, libusb10_isoc_proxy);
break;
case LIBUSB_TRANSFER_TYPE_BULK:
+ case LIBUSB_TRANSFER_TYPE_BULK_STREAM:
case LIBUSB_TRANSFER_TYPE_INTERRUPT:
libusb20_tr_set_callback(pxfer0, libusb10_bulk_intr_proxy);
break;
@@ -1904,3 +1905,16 @@ libusb_setlocale(const char *locale)
return (LIBUSB_ERROR_INVALID_PARAM);
}
+
+unsigned char *
+libusb_dev_mem_alloc(libusb_device_handle *devh)
+{
+ return (NULL);
+}
+
+int
+libusb_dev_mem_free(libusb_device_handle *devh, unsigned char *buffer,
+ size_t size)
+{
+ return (LIBUSB_ERROR_NOT_SUPPORTED);
+}
diff --git a/lib/libusb/libusb10_hotplug.c b/lib/libusb/libusb10_hotplug.c
index 369539d4512e..9c46d4926bfa 100644
--- a/lib/libusb/libusb10_hotplug.c
+++ b/lib/libusb/libusb10_hotplug.c
@@ -414,3 +414,21 @@ void libusb_hotplug_deregister_callback(libusb_context *ctx,
free(handle);
}
+
+void *
+libusb_hotplug_get_user_data(struct libusb_context *ctx,
+ libusb_hotplug_callback_handle callback_handle)
+{
+ libusb_hotplug_callback_handle handle;
+
+ ctx = GET_CONTEXT(ctx);
+
+ HOTPLUG_LOCK(ctx);
+ TAILQ_FOREACH(handle, &ctx->hotplug_cbh, entry) {
+ if (handle == callback_handle)
+ break;
+ }
+ HOTPLUG_UNLOCK(ctx);
+
+ return (handle);
+}
diff --git a/lib/libusb/libusb10_io.c b/lib/libusb/libusb10_io.c
index dd541b09caa6..c99586ff650d 100644
--- a/lib/libusb/libusb10_io.c
+++ b/lib/libusb/libusb10_io.c
@@ -781,6 +781,19 @@ libusb_fill_interrupt_transfer(struct libusb_transfer *transfer,
}
void
+libusb_fill_bulk_stream_transfer(struct libusb_transfer *transfer,
+ libusb_device_handle *dev_handle, unsigned char endpoint,
+ uint32_t stream_id, unsigned char *buffer, int length,
+ libusb_transfer_cb_fn callback, void *user_data, unsigned int timeout)
+{
+ libusb_fill_bulk_transfer(transfer, dev_handle, endpoint, buffer,
+ length, callback, user_data, timeout);
+ transfer->type = LIBUSB_TRANSFER_TYPE_BULK_STREAM;
+
+ libusb_transfer_set_stream_id(transfer, stream_id);
+}
+
+void
libusb_fill_iso_transfer(struct libusb_transfer *transfer,
libusb_device_handle *devh, uint8_t endpoint, uint8_t *buf,
int length, int npacket, libusb_transfer_cb_fn callback,
@@ -842,3 +855,12 @@ libusb_transfer_get_stream_id(struct libusb_transfer *transfer)
/* get stream ID */
return (sxfer->stream_id);
}
+
+void
+libusb_free_pollfds(const struct libusb_pollfd **pollfds)
+{
+ if (pollfds == NULL)
+ return;
+
+ free(pollfds);
+}
diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile
index 0639745d08fc..2d92c5ba1916 100644
--- a/lib/libutil/Makefile
+++ b/lib/libutil/Makefile
@@ -38,6 +38,7 @@ MAN+= cpuset.3 expand_number.3 flopen.3 fparseln.3 ftime.3 getlocalbase.3 \
property.3 pty.3 quotafile.3 realhostname.3 realhostname_sa.3 \
_secure_path.3 trimdomain.3 uucplock.3 pw_util.3
MAN+= login.conf.5
+MLINKS+=cpuset.3 domainset_parselist.3
MLINKS+=flopen.3 flopenat.3
MLINKS+=kld.3 kld_isloaded.3 kld.3 kld_load.3
MLINKS+=login_auth.3 auth_cat.3 login_auth.3 auth_checknologin.3
diff --git a/lib/libutil/cpuset.3 b/lib/libutil/cpuset.3
index be29d5309ef0..47dffd209ee6 100644
--- a/lib/libutil/cpuset.3
+++ b/lib/libutil/cpuset.3
@@ -22,21 +22,22 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd October 31, 2017
+.Dd June 24, 2025
.Dt CPUSET 3
.Os
.Sh NAME
-.Nm cpuset_parselist
-.Nd utility functions for
-.Xr cpuset 2
-handling
+.Nm cpuset_parselist ,
+.Nm domainset_parselist
+.Nd utility functions for cpuset(2) handling
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In sys/cpuset.h
.In libutil.h
.Ft int
-.Fn cpuset_parselist "const char *cpu-list" "cpuset_t *mask"
+.Fn cpuset_parselist "const char *cpu_list" "cpuset_t *mask"
+.Ft int
+.Fn domainset_parselist "const char *domain_policy" "domainset_t *domain_mask" "int *policyp"
.Sh DESCRIPTION
The
.Fn cpuset_parselist
@@ -52,6 +53,27 @@ numbers.
A special list of
.Dq all
may be specified in which case the list includes all CPUs from the root set.
+.Pp
+The
+.Fn domainset_parselist
+function parses a
+.Xr domainset 9
+memory domain allocation policy
+specified by
+.Va domain_policy
+filling the
+.Va domain_mask
+and the
+.Va policyp .
+A valid
+.Va domain_policy
+is formatted as
+.Ar policy:domain-list .
+See the
+.Ar -n
+flag in
+.Xr cpuset 1
+for a list of valid domain policies.
.Sh RETURN VALUES
Return values can be the following
.Bl -tag -width Er
@@ -60,19 +82,30 @@ The parsing was successful
.It Dv CPUSET_PARSE_ERROR
The
.Va cpu-list
+or
+.Va domain-policy
format is invalid
.It Dv CPUSET_PARSE_GETAFFINITY
The
.Xr cpuset_getaffinity 2
call has failed
.It Dv CPUSET_PARSE_INVALID_CPU
-The number of supported CPUs has been exceeded.
+The number of supported CPUs or NUMA domains has been exceeded.
The maximum number being
-.Va CPU_SETSIZE .
+.Va CPU_SETSIZE
+and
+.Va DOMAINSET_SETSIZE
+respectively.
+.It Dv CPUSET_PARSE_GETDOMAIN
+The
+.Xr cpuset_getdomain 2
+call has failed
.El
.Sh SEE ALSO
.Xr cpuset 1 ,
.Xr cpuset 2 ,
-.Xr cpuset 9
+.Xr numa 4 ,
+.Xr cpuset 9 ,
+.Xr domainset 9
.Sh AUTHORS
.An Jeffrey Roberson Aq Mt jeff@FreeBSD.org
diff --git a/lib/libutil/cpuset.c b/lib/libutil/cpuset.c
index 3c374bfa6cac..d4840af7e175 100644
--- a/lib/libutil/cpuset.c
+++ b/lib/libutil/cpuset.c
@@ -27,34 +27,48 @@
* SUCH DAMAGE.
*/
+#include <sys/cdefs.h>
+#define _WANT_FREEBSD_BITSET
+
#include <sys/types.h>
#include <sys/cpuset.h>
+#include <sys/domainset.h>
#include <stdlib.h>
#include <string.h>
#include <libutil.h>
#include <ctype.h>
-int
-cpuset_parselist(const char *list, cpuset_t *mask)
+struct numa_policy {
+ const char *name;
+ int policy;
+};
+
+static const struct numa_policy policies[] = {
+ { "round-robin", DOMAINSET_POLICY_ROUNDROBIN },
+ { "rr", DOMAINSET_POLICY_ROUNDROBIN },
+ { "first-touch", DOMAINSET_POLICY_FIRSTTOUCH },
+ { "ft", DOMAINSET_POLICY_FIRSTTOUCH },
+ { "prefer", DOMAINSET_POLICY_PREFER },
+ { "interleave", DOMAINSET_POLICY_INTERLEAVE},
+ { "il", DOMAINSET_POLICY_INTERLEAVE},
+ { NULL, DOMAINSET_POLICY_INVALID }
+};
+
+static int
+parselist(const char *list, struct bitset *mask, int size)
{
enum { NONE, NUM, DASH } state;
int lastnum;
int curnum;
const char *l;
- if (strcasecmp(list, "all") == 0) {
- if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
- sizeof(*mask), mask) != 0)
- return (CPUSET_PARSE_GETAFFINITY);
- return (CPUSET_PARSE_OK);
- }
state = NONE;
curnum = lastnum = 0;
for (l = list; *l != '\0';) {
if (isdigit(*l)) {
curnum = atoi(l);
- if (curnum > CPU_SETSIZE)
+ if (curnum >= size)
return (CPUSET_PARSE_INVALID_CPU);
while (isdigit(*l))
l++;
@@ -65,7 +79,7 @@ cpuset_parselist(const char *list, cpuset_t *mask)
break;
case DASH:
for (; lastnum <= curnum; lastnum++)
- CPU_SET(lastnum, mask);
+ BIT_SET(size, lastnum, mask);
state = NONE;
break;
case NUM:
@@ -80,7 +94,7 @@ cpuset_parselist(const char *list, cpuset_t *mask)
case NONE:
break;
case NUM:
- CPU_SET(curnum, mask);
+ BIT_SET(size, curnum, mask);
state = NONE;
break;
case DASH:
@@ -102,7 +116,7 @@ cpuset_parselist(const char *list, cpuset_t *mask)
case NONE:
break;
case NUM:
- CPU_SET(curnum, mask);
+ BIT_SET(size, curnum, mask);
break;
case DASH:
goto parserr;
@@ -111,3 +125,63 @@ cpuset_parselist(const char *list, cpuset_t *mask)
parserr:
return (CPUSET_PARSE_ERROR);
}
+
+/*
+ * permissively parse policy:domain list
+ * allow:
+ * round-robin:0-4 explicit
+ * round-robin:all explicit root domains
+ * 0-4 implicit root policy
+ * round-robin implicit root domains
+ * all explicit root domains and implicit policy
+ */
+int
+domainset_parselist(const char *list, domainset_t *mask, int *policyp)
+{
+ domainset_t rootmask;
+ const struct numa_policy *policy;
+ const char *l;
+ int p;
+
+ /*
+ * Use the rootset's policy as the default for unspecified policies.
+ */
+ if (cpuset_getdomain(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
+ sizeof(rootmask), &rootmask, &p) != 0)
+ return (CPUSET_PARSE_GETDOMAIN);
+
+ if (list == NULL || strcasecmp(list, "all") == 0 || *list == '\0') {
+ *policyp = p;
+ DOMAINSET_COPY(&rootmask, mask);
+ return (CPUSET_PARSE_OK);
+ }
+
+ l = list;
+ for (policy = &policies[0]; policy->name != NULL; policy++) {
+ if (strncasecmp(l, policy->name, strlen(policy->name)) == 0) {
+ p = policy->policy;
+ l += strlen(policy->name);
+ if (*l != ':' && *l != '\0')
+ return (CPUSET_PARSE_ERROR);
+ if (*l == ':')
+ l++;
+ break;
+ }
+ }
+ *policyp = p;
+
+ return (parselist(l, (struct bitset *)mask, DOMAINSET_SETSIZE));
+}
+
+int
+cpuset_parselist(const char *list, cpuset_t *mask)
+{
+ if (strcasecmp(list, "all") == 0) {
+ if (cpuset_getaffinity(CPU_LEVEL_ROOT, CPU_WHICH_PID, -1,
+ sizeof(*mask), mask) != 0)
+ return (CPUSET_PARSE_GETAFFINITY);
+ return (CPUSET_PARSE_OK);
+ }
+
+ return (parselist(list, (struct bitset *)mask, CPU_SETSIZE));
+}
diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h
index 919855184caf..7d8bfdf67fac 100644
--- a/lib/libutil/libutil.h
+++ b/lib/libutil/libutil.h
@@ -213,7 +213,13 @@ int cpuset_parselist(const char *list, cpuset_t *mask);
#define CPUSET_PARSE_OK 0
#define CPUSET_PARSE_GETAFFINITY -1
#define CPUSET_PARSE_ERROR -2
-#define CPUSET_PARSE_INVALID_CPU -3
+#define CPUSET_PARSE_OUT_OF_RANGE -3
+#define CPUSET_PARSE_GETDOMAIN -4
+#define CPUSET_PARSE_INVALID_CPU CPUSET_PARSE_OUT_OF_RANGE /* backwards compat */
+#endif
+
+#ifdef _SYS_DOMAINSET_H_
+int domainset_parselist(const char *list, domainset_t *mask, int *policyp);
#endif
__END_DECLS
diff --git a/lib/libvmmapi/Makefile b/lib/libvmmapi/Makefile
index 1866c8fa5e7c..6dd0deeaa9c0 100644
--- a/lib/libvmmapi/Makefile
+++ b/lib/libvmmapi/Makefile
@@ -1,6 +1,6 @@
PACKAGE=lib${LIB}
LIB= vmmapi
-SHLIB_MAJOR= 6
+SHLIB_MAJOR= 7
SRCS= vmmapi.c
INCS= vmmapi.h
diff --git a/lib/libvmmapi/internal.h b/lib/libvmmapi/internal.h
index aa7b1d8e6a93..4afe1cab3460 100644
--- a/lib/libvmmapi/internal.h
+++ b/lib/libvmmapi/internal.h
@@ -8,12 +8,7 @@
#define __VMMAPI_INTERNAL_H__
#include <sys/types.h>
-
-enum {
- VM_MEMSEG_LOW,
- VM_MEMSEG_HIGH,
- VM_MEMSEG_COUNT,
-};
+#include <dev/vmm/vmm_mem.h>
struct vmctx {
int fd; /* device file descriptor */
@@ -21,7 +16,9 @@ struct vmctx {
struct {
vm_paddr_t base;
vm_size_t size;
- } memsegs[VM_MEMSEG_COUNT];
+ } memsegs[VM_MAX_MEMSEGS];
+ size_t lowmem_size;
+ size_t highmem_size;
int memflags;
char *baseaddr;
char *name;
diff --git a/lib/libvmmapi/vmmapi.c b/lib/libvmmapi/vmmapi.c
index a1a5d56ff8a2..77f0f8f5c581 100644
--- a/lib/libvmmapi/vmmapi.c
+++ b/lib/libvmmapi/vmmapi.c
@@ -28,13 +28,14 @@
#include <sys/param.h>
#include <sys/capsicum.h>
+#include <sys/cpuset.h>
+#include <sys/domainset.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/linker.h>
#include <sys/module.h>
#include <sys/_iovec.h>
-#include <sys/cpuset.h>
#include <capsicum_helpers.h>
#include <err.h>
@@ -322,8 +323,8 @@ vm_get_guestmem_from_ctx(struct vmctx *ctx, char **guest_baseaddr,
{
*guest_baseaddr = ctx->baseaddr;
- *lowmem_size = ctx->memsegs[VM_MEMSEG_LOW].size;
- *highmem_size = ctx->memsegs[VM_MEMSEG_HIGH].size;
+ *lowmem_size = ctx->lowmem_size;
+ *highmem_size = ctx->highmem_size;
return (0);
}
@@ -379,7 +380,8 @@ cmpseg(size_t len, const char *str, size_t len2, const char *str2)
}
static int
-vm_alloc_memseg(struct vmctx *ctx, int segid, size_t len, const char *name)
+vm_alloc_memseg(struct vmctx *ctx, int segid, size_t len, const char *name,
+ int ds_policy, domainset_t *ds_mask, size_t ds_size)
{
struct vm_memseg memseg;
size_t n;
@@ -407,6 +409,13 @@ vm_alloc_memseg(struct vmctx *ctx, int segid, size_t len, const char *name)
bzero(&memseg, sizeof(struct vm_memseg));
memseg.segid = segid;
memseg.len = len;
+ if (ds_mask == NULL) {
+ memseg.ds_policy = DOMAINSET_POLICY_INVALID;
+ } else {
+ memseg.ds_policy = ds_policy;
+ memseg.ds_mask = ds_mask;
+ memseg.ds_mask_size = ds_size;
+ }
if (name != NULL) {
n = strlcpy(memseg.name, name, sizeof(memseg.name));
if (n >= sizeof(memseg.name)) {
@@ -442,13 +451,14 @@ vm_get_memseg(struct vmctx *ctx, int segid, size_t *lenp, char *namebuf,
}
static int
-setup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char *base)
+map_memory_segment(struct vmctx *ctx, int segid, vm_paddr_t gpa, size_t len,
+ size_t segoff, char *base)
{
char *ptr;
int error, flags;
/* Map 'len' bytes starting at 'gpa' in the guest address space */
- error = vm_mmap_memseg(ctx, gpa, VM_SYSMEM, gpa, len, PROT_ALL);
+ error = vm_mmap_memseg(ctx, gpa, segid, segoff, len, PROT_ALL);
if (error)
return (error);
@@ -464,65 +474,136 @@ setup_memory_segment(struct vmctx *ctx, vm_paddr_t gpa, size_t len, char *base)
return (0);
}
+/*
+ * Allocates and maps virtual machine memory segments according
+ * to the NUMA topology specified by the 'doms' array.
+ *
+ * The domains are laid out sequentially in the guest's physical address space.
+ * The [VM_LOWMEM_LIMIT, VM_HIGHMEM_BASE) address range is skipped and
+ * left unmapped.
+ */
int
-vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms)
+vm_setup_memory_domains(struct vmctx *ctx, enum vm_mmap_style vms,
+ struct vm_mem_domain *doms, int ndoms)
{
- size_t objsize, len;
- vm_paddr_t gpa;
+ size_t low_len, len, totalsize;
+ struct vm_mem_domain *dom;
+ struct vm_memseg memseg;
char *baseaddr, *ptr;
- int error;
+ int error, i, segid;
+ vm_paddr_t gpa;
+ /* Sanity checks. */
assert(vms == VM_MMAP_ALL);
-
- /*
- * If 'memsize' cannot fit entirely in the 'lowmem' segment then create
- * another 'highmem' segment above VM_HIGHMEM_BASE for the remainder.
- */
- if (memsize > VM_LOWMEM_LIMIT) {
- ctx->memsegs[VM_MEMSEG_LOW].size = VM_LOWMEM_LIMIT;
- ctx->memsegs[VM_MEMSEG_HIGH].size = memsize - VM_LOWMEM_LIMIT;
- objsize = VM_HIGHMEM_BASE + ctx->memsegs[VM_MEMSEG_HIGH].size;
- } else {
- ctx->memsegs[VM_MEMSEG_LOW].size = memsize;
- ctx->memsegs[VM_MEMSEG_HIGH].size = 0;
- objsize = memsize;
+ if (doms == NULL || ndoms <= 0 || ndoms > VM_MAXMEMDOM) {
+ errno = EINVAL;
+ return (-1);
}
- error = vm_alloc_memseg(ctx, VM_SYSMEM, objsize, NULL);
- if (error)
- return (error);
+ /* Calculate total memory size. */
+ totalsize = 0;
+ for (i = 0; i < ndoms; i++)
+ totalsize += doms[i].size;
+
+ if (totalsize > VM_LOWMEM_LIMIT)
+ totalsize = VM_HIGHMEM_BASE + (totalsize - VM_LOWMEM_LIMIT);
/*
* Stake out a contiguous region covering the guest physical memory
* and the adjoining guard regions.
*/
- len = VM_MMAP_GUARD_SIZE + objsize + VM_MMAP_GUARD_SIZE;
+ len = VM_MMAP_GUARD_SIZE + totalsize + VM_MMAP_GUARD_SIZE;
ptr = mmap(NULL, len, PROT_NONE, MAP_GUARD | MAP_ALIGNED_SUPER, -1, 0);
if (ptr == MAP_FAILED)
return (-1);
-
baseaddr = ptr + VM_MMAP_GUARD_SIZE;
- if (ctx->memsegs[VM_MEMSEG_HIGH].size > 0) {
- gpa = VM_HIGHMEM_BASE;
- len = ctx->memsegs[VM_MEMSEG_HIGH].size;
- error = setup_memory_segment(ctx, gpa, len, baseaddr);
- if (error)
- return (error);
- }
- if (ctx->memsegs[VM_MEMSEG_LOW].size > 0) {
- gpa = 0;
- len = ctx->memsegs[VM_MEMSEG_LOW].size;
- error = setup_memory_segment(ctx, gpa, len, baseaddr);
- if (error)
- return (error);
- }
+ /*
+ * Allocate and map memory segments for the virtual machine.
+ */
+ gpa = VM_LOWMEM_LIMIT > 0 ? 0 : VM_HIGHMEM_BASE;
+ ctx->lowmem_size = 0;
+ ctx->highmem_size = 0;
+ for (i = 0; i < ndoms; i++) {
+ segid = VM_SYSMEM + i;
+ dom = &doms[i];
+
+ /*
+ * Check if the memory segment already exists.
+ * If 'ndoms' is greater than one, refuse to proceed if the
+ * memseg already exists. If only one domain was requested, use
+ * the existing segment to preserve the behaviour of the previous
+ * implementation.
+ *
+ * Splitting existing memory segments is tedious and
+ * error-prone, which is why we don't support NUMA
+ * domains for bhyveload(8)-loaded VMs.
+ */
+ error = vm_get_memseg(ctx, segid, &len, memseg.name,
+ sizeof(memseg.name));
+ if (error == 0 && len != 0) {
+ if (ndoms != 1) {
+ errno = EEXIST;
+ return (-1);
+ } else
+ doms[0].size = len;
+ } else {
+ error = vm_alloc_memseg(ctx, segid, dom->size, NULL,
+ dom->ds_policy, dom->ds_mask, dom->ds_size);
+ if (error)
+ return (error);
+ }
+ /*
+ * If a domain is split by VM_LOWMEM_LIMIT then break
+ * its segment mapping into two parts, one below VM_LOWMEM_LIMIT
+ * and one above VM_HIGHMEM_BASE.
+ */
+ if (gpa <= VM_LOWMEM_LIMIT &&
+ gpa + dom->size > VM_LOWMEM_LIMIT) {
+ low_len = VM_LOWMEM_LIMIT - gpa;
+ error = map_memory_segment(ctx, segid, gpa, low_len, 0,
+ baseaddr);
+ if (error)
+ return (error);
+ ctx->lowmem_size = VM_LOWMEM_LIMIT;
+ /* Map the remainder. */
+ gpa = VM_HIGHMEM_BASE;
+ len = dom->size - low_len;
+ error = map_memory_segment(ctx, segid, gpa, len,
+ low_len, baseaddr);
+ if (error)
+ return (error);
+ } else {
+ len = dom->size;
+ error = map_memory_segment(ctx, segid, gpa, len, 0,
+ baseaddr);
+ if (error)
+ return (error);
+ }
+ if (gpa <= VM_LOWMEM_LIMIT)
+ ctx->lowmem_size += len;
+ else
+ ctx->highmem_size += len;
+ gpa += len;
+ }
ctx->baseaddr = baseaddr;
return (0);
}
+int
+vm_setup_memory(struct vmctx *ctx, size_t memsize, enum vm_mmap_style vms)
+{
+ struct vm_mem_domain dom0;
+
+ memset(&dom0, 0, sizeof(dom0));
+ dom0.ds_policy = DOMAINSET_POLICY_INVALID;
+ dom0.size = memsize;
+
+ return (vm_setup_memory_domains(ctx, vms, &dom0, 1));
+}
+
/*
* Returns a non-NULL pointer if [gaddr, gaddr+len) is entirely contained in
* the lowmem or highmem regions.
@@ -535,13 +616,13 @@ vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len)
{
vm_size_t lowsize, highsize;
- lowsize = ctx->memsegs[VM_MEMSEG_LOW].size;
+ lowsize = ctx->lowmem_size;
if (lowsize > 0) {
if (gaddr < lowsize && len <= lowsize && gaddr + len <= lowsize)
return (ctx->baseaddr + gaddr);
}
- highsize = ctx->memsegs[VM_MEMSEG_HIGH].size;
+ highsize = ctx->highmem_size;
if (highsize > 0 && gaddr >= VM_HIGHMEM_BASE) {
if (gaddr < VM_HIGHMEM_BASE + highsize && len <= highsize &&
gaddr + len <= VM_HIGHMEM_BASE + highsize)
@@ -559,12 +640,12 @@ vm_rev_map_gpa(struct vmctx *ctx, void *addr)
offaddr = (char *)addr - ctx->baseaddr;
- lowsize = ctx->memsegs[VM_MEMSEG_LOW].size;
+ lowsize = ctx->lowmem_size;
if (lowsize > 0)
if (offaddr <= lowsize)
return (offaddr);
- highsize = ctx->memsegs[VM_MEMSEG_HIGH].size;
+ highsize = ctx->highmem_size;
if (highsize > 0)
if (offaddr >= VM_HIGHMEM_BASE &&
offaddr < VM_HIGHMEM_BASE + highsize)
@@ -583,8 +664,7 @@ vm_get_name(struct vmctx *ctx)
size_t
vm_get_lowmem_size(struct vmctx *ctx)
{
-
- return (ctx->memsegs[VM_MEMSEG_LOW].size);
+ return (ctx->lowmem_size);
}
vm_paddr_t
@@ -597,8 +677,7 @@ vm_get_highmem_base(struct vmctx *ctx __unused)
size_t
vm_get_highmem_size(struct vmctx *ctx)
{
-
- return (ctx->memsegs[VM_MEMSEG_HIGH].size);
+ return (ctx->highmem_size);
}
void *
@@ -616,7 +695,7 @@ vm_create_devmem(struct vmctx *ctx, int segid, const char *name, size_t len)
goto done;
}
- error = vm_alloc_memseg(ctx, segid, len, name);
+ error = vm_alloc_memseg(ctx, segid, len, name, 0, NULL, 0);
if (error)
goto done;
diff --git a/lib/libvmmapi/vmmapi.h b/lib/libvmmapi/vmmapi.h
index 440064ad13cb..b637c45d1eff 100644
--- a/lib/libvmmapi/vmmapi.h
+++ b/lib/libvmmapi/vmmapi.h
@@ -40,7 +40,7 @@
* API version for out-of-tree consumers like grub-bhyve for making compile
* time decisions.
*/
-#define VMMAPI_VERSION 0200 /* 2 digit major followed by 2 digit minor */
+#define VMMAPI_VERSION 0300 /* 2 digit major followed by 2 digit minor */
struct iovec;
struct vcpu;
@@ -64,16 +64,12 @@ enum vm_mmap_style {
#define VM_MEM_F_INCORE 0x01 /* include guest memory in core file */
#define VM_MEM_F_WIRED 0x02 /* guest memory is wired */
-/*
- * Identifiers for memory segments:
- * - vm_setup_memory() uses VM_SYSMEM for the system memory segment.
- * - the remaining identifiers can be used to create devmem segments.
- */
-enum {
- VM_SYSMEM,
- VM_BOOTROM,
- VM_FRAMEBUFFER,
- VM_PCIROM,
+/* Memory size and allocation policy for a single NUMA domain. */
+struct vm_mem_domain {
+ size_t size;
+ int ds_policy;
+ domainset_t *ds_mask;
+ size_t ds_size;
};
__BEGIN_DECLS
@@ -127,7 +123,9 @@ struct vcpu *vm_vcpu_open(struct vmctx *ctx, int vcpuid);
void vm_vcpu_close(struct vcpu *vcpu);
int vcpu_id(struct vcpu *vcpu);
int vm_parse_memsize(const char *optarg, size_t *memsize);
-int vm_setup_memory(struct vmctx *ctx, size_t len, enum vm_mmap_style s);
+int vm_setup_memory(struct vmctx *ctx, size_t len, enum vm_mmap_style s);
+int vm_setup_memory_domains(struct vmctx *ctx, enum vm_mmap_style s,
+ struct vm_mem_domain *doms, int ndoms);
void *vm_map_gpa(struct vmctx *ctx, vm_paddr_t gaddr, size_t len);
/* inverse operation to vm_map_gpa - extract guest address from host pointer */
vm_paddr_t vm_rev_map_gpa(struct vmctx *ctx, void *addr);
diff --git a/libexec/comsat/comsat.c b/libexec/comsat/comsat.c
index d5d1eedeb5f3..cb00ee4a9392 100644
--- a/libexec/comsat/comsat.c
+++ b/libexec/comsat/comsat.c
@@ -113,29 +113,24 @@ mailfor(char *name)
char *file;
off_t offset;
int folder;
- char buf[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1];
- char buf2[sizeof(_PATH_MAILDIR) + sizeof(utp->ut_user) + 1];
+ char buf[MAXPATHLEN];
- if (!(cp = strchr(name, '@')))
+ if ((cp = strchr(name, '@')) == NULL)
return;
*cp = '\0';
offset = strtoll(cp + 1, NULL, 10);
- if (!(cp = strchr(cp + 1, ':')))
- file = name;
- else
- file = cp + 1;
- sprintf(buf, "%s/%.*s", _PATH_MAILDIR, (int)sizeof(utp->ut_user),
- name);
- if (*file != '/') {
- sprintf(buf2, "%s/%.*s", _PATH_MAILDIR,
- (int)sizeof(utp->ut_user), file);
- file = buf2;
+ if ((cp = strchr(cp + 1, ':')) != NULL &&
+ strchr((file = cp + 1), '/') == NULL) {
+ snprintf(buf, sizeof(buf), "%s/%s", _PATH_MAILDIR, file);
+ folder = 1;
+ } else {
+ snprintf(buf, sizeof(buf), "%s/%s", _PATH_MAILDIR, name);
+ folder = 0;
}
- folder = strcmp(buf, file);
setutxent();
while ((utp = getutxent()) != NULL)
if (utp->ut_type == USER_PROCESS && !strcmp(utp->ut_user, name))
- notify(utp, file, offset, folder);
+ notify(utp, buf, offset, folder);
endutxent();
}
@@ -159,8 +154,7 @@ notify(struct utmpx *utp, char file[], off_t offset, int folder)
utp->ut_line);
return;
}
- (void)snprintf(tty, sizeof(tty), "%s%.*s",
- _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line);
+ (void)snprintf(tty, sizeof(tty), "%s%s", _PATH_DEV, utp->ut_line);
if (stat(tty, &stb) == -1 || !(stb.st_mode & (S_IXUSR | S_IXGRP))) {
dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_user, tty);
return;
@@ -187,26 +181,20 @@ notify(struct utmpx *utp, char file[], off_t offset, int folder)
initgroups(p->pw_name, p->pw_gid) == -1 ||
setgid(p->pw_gid) == -1 ||
setuid(p->pw_uid) == -1)
- return;
+ _exit(1);
- switch (stb.st_mode & (S_IXUSR | S_IXGRP)) {
- case S_IXUSR:
- case (S_IXUSR | S_IXGRP):
+ if (stb.st_mode & S_IXUSR) {
(void)fprintf(tp,
"%s\007New mail for %s@%.*s\007 has arrived%s%s%s:%s----%s",
cr, utp->ut_user, (int)sizeof(hostname), hostname,
folder ? cr : "", folder ? "to " : "", folder ? file : "",
cr, cr);
jkfprintf(tp, file, offset);
- break;
- case S_IXGRP:
+ } else if (stb.st_mode & S_IXGRP) {
(void)fprintf(tp, "\007");
(void)fflush(tp);
(void)sleep(1);
(void)fprintf(tp, "\007");
- break;
- default:
- break;
}
(void)fclose(tp);
_exit(0);
diff --git a/libexec/dma/dmagent/Makefile b/libexec/dma/dmagent/Makefile
index 5f7deeea0b05..f707cfa3264f 100644
--- a/libexec/dma/dmagent/Makefile
+++ b/libexec/dma/dmagent/Makefile
@@ -15,14 +15,16 @@ SRCS= aliases_parse.y \
net.c \
spool.c \
util.c
-MAN8= dma.8
+MAN= dma.8
MLINKS= dma.8 dma.conf.5
-CONFS= dma.conf
+CONFSMODE= 0640
+CONFSGRP= mail
+CONFS= auth.conf dma.conf
CONFSDIR= ${CONFDIR}/dma
CFLAGS+= -DOPENSSL_API_COMPAT=0x10100000L
YFLAGS+= -i
CLEANFILES= aliases_parse.i
-FILES= auth.conf mailer.conf
+FILES= mailer.conf
FILESDIR= ${SHAREDIR}/examples/dma
BINMODE= 2555
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/Makefile b/libexec/rc/rc.d/Makefile
index 8199779e5772..27d8a7526691 100644
--- a/libexec/rc/rc.d/Makefile
+++ b/libexec/rc/rc.d/Makefile
@@ -223,7 +223,7 @@ FTPDPACKAGE= ftpd
.if ${MK_GSSAPI} != "no"
CONFGROUPS+= GSSD
GSSD= gssd
-GSSDPACKAGE= kerberos
+GSSDPACKAGE= gssd
.endif
.if ${MK_HAST} != "no"
diff --git a/libexec/rc/rc.d/mountd b/libexec/rc/rc.d/mountd
index 8c0aa87e1d13..dfd2431f9c35 100755
--- a/libexec/rc/rc.d/mountd
+++ b/libexec/rc/rc.d/mountd
@@ -70,6 +70,8 @@ mountd_precmd()
}
load_rc_config $name
+load_rc_config nfsd
+load_rc_config zfs
# precmd is not compatible with svcj
mountd_svcj="NO"
diff --git a/libexec/rtld-elf/map_object.c b/libexec/rtld-elf/map_object.c
index 04d17072af77..c6a98b50a165 100644
--- a/libexec/rtld-elf/map_object.c
+++ b/libexec/rtld-elf/map_object.c
@@ -337,7 +337,7 @@ map_object(int fd, const char *path, const struct stat *sb, bool ismain)
obj->tlsalign = phtls->p_align;
obj->tlspoffset = phtls->p_offset;
obj->tlsinitsize = phtls->p_filesz;
- obj->tlsinit = mapbase + phtls->p_vaddr;
+ obj->tlsinit = obj->relocbase + phtls->p_vaddr;
}
obj->stack_flags = stack_flags;
if (note_start < note_end)
diff --git a/libexec/tftpd/tftpd.c b/libexec/tftpd/tftpd.c
index f8f9bd549a2e..a3faee86e7d0 100644
--- a/libexec/tftpd/tftpd.c
+++ b/libexec/tftpd/tftpd.c
@@ -351,10 +351,14 @@ main(int argc, char *argv[])
tftp_log(LOG_ERR, "chdir: %s", strerror(errno));
exit(1);
}
- if (setgroups(1, &nobody->pw_gid) != 0) {
+ if (setgroups(0, NULL) != 0) {
tftp_log(LOG_ERR, "setgroups failed");
exit(1);
}
+ if (setgid(nobody->pw_gid) != 0) {
+ tftp_log(LOG_ERR, "setgid failed");
+ exit(1);
+ }
if (setuid(nobody->pw_uid) != 0) {
tftp_log(LOG_ERR, "setuid failed");
exit(1);
diff --git a/release/Makefile b/release/Makefile
index 7cafd7ddb787..b6a9aa42c2e2 100644
--- a/release/Makefile
+++ b/release/Makefile
@@ -162,7 +162,8 @@ kernel.txz: # Also (if enabled) kernel-dbg.txz.
src.txz:
mkdir -p ${DISTDIR}/usr
- ln -fs ${WORLDDIR} ${DISTDIR}/usr/src
+ rm -f ${DISTDIR}/usr/src
+ ln -s ${WORLDDIR} ${DISTDIR}/usr/src
( cd ${DISTDIR} && ${TAR_XZ_CMD} -cLvf ${.OBJDIR}/src.txz \
--exclude .svn --exclude .zfs \
--exclude .git --exclude @ --exclude usr/src/release/dist \
@@ -170,7 +171,8 @@ src.txz:
ports.txz:
mkdir -p ${DISTDIR}/usr
- ln -fs ${PORTSDIR} ${DISTDIR}/usr/ports
+ rm -f ${DISTDIR}/usr/ports
+ ln -s ${PORTSDIR} ${DISTDIR}/usr/ports
( cd ${DISTDIR} && ${TAR_XZ_CMD} -cLvf ${.OBJDIR}/ports.txz \
--exclude .git --exclude .svn \
--exclude usr/ports/distfiles --exclude usr/ports/packages \
@@ -276,6 +278,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
diff --git a/release/packages/generate-ucl.lua b/release/packages/generate-ucl.lua
index 3d91d11bc42f..a243c6ea7ad0 100755
--- a/release/packages/generate-ucl.lua
+++ b/release/packages/generate-ucl.lua
@@ -54,8 +54,15 @@ pkg_suffixes = {
},
}
+-- A list of packages which don't get the automatic suffix handling,
+-- e.g. -man packages with no corresponding base package.
+local no_suffix_pkgs = {
+ ["kernel-man"] = true,
+}
+
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]
@@ -76,6 +83,7 @@ local no_gen_deps = {
["libcompiler_rt-dev-lib32"] = true,
["liby-dev"] = true,
["liby-dev-lib32"] = true,
+ ["kernel-man"] = true,
}
-- Return true if the package 'pkgname' should have a dependency on the package
@@ -163,7 +171,9 @@ if pkgprefix ~= nil and obj["deps"] ~= nil then
end
-- Add comment and desc suffix.
-add_suffixes(obj)
+if no_suffix_pkgs[pkgname] == nil then
+ add_suffixes(obj)
+end
-- Write the output file.
local f,err = io.open(arg[#arg], "w")
diff --git a/release/packages/ucl/bmake-all.ucl b/release/packages/ucl/bmake-all.ucl
new file mode 100644
index 000000000000..ee8175d1dd8a
--- /dev/null
+++ b/release/packages/ucl/bmake-all.ucl
@@ -0,0 +1,5 @@
+comment = "Program maintenance utility"
+desc = <<EOD
+make(1) allows programs to be built from source files based on a specification
+of the program's dependencies called a Makefile.
+EOD
diff --git a/release/packages/ucl/gssd-all.ucl b/release/packages/ucl/gssd-all.ucl
new file mode 100644
index 000000000000..5a01b0559854
--- /dev/null
+++ b/release/packages/ucl/gssd-all.ucl
@@ -0,0 +1,11 @@
+comment = "gssd(8) daemon for kernel GSS-API"
+desc = <<EOD
+The Generic Security Services (GSS) API is used to perform authentication over
+a network connection, most commonly when using Kerberos authentication.
+
+The kernel contains an implementation of GSS-API primarily for use by the NFS
+client and server. When kernel GSS-API is in use, gssd(8) allows the kernel
+to fetch authentication data such as Kerberos tickets from userland.
+
+This daemon is required when using Kerberos authentication with NFS.
+EOD
diff --git a/release/packages/ucl/kerberos-all.ucl b/release/packages/ucl/kerberos-all.ucl
index 6fb7f059296b..bf82040da3d0 100644
--- a/release/packages/ucl/kerberos-all.ucl
+++ b/release/packages/ucl/kerberos-all.ucl
@@ -1,4 +1,4 @@
-comment = "Kerberos Utilities"
+comment = "Kerberos utilities"
desc = <<EOD
-Kerberos Utilities
+The Kerberos command-line utilities, including kinit and kadmin.
EOD
diff --git a/release/packages/ucl/kerberos-kdc-all.ucl b/release/packages/ucl/kerberos-kdc-all.ucl
new file mode 100644
index 000000000000..068d2f26bc8d
--- /dev/null
+++ b/release/packages/ucl/kerberos-kdc-all.ucl
@@ -0,0 +1,5 @@
+comment = "Kerberos key distribution center"
+desc = <<EOD
+The Kerberos KDC, which manages the Kerberos database and issues tickets
+to clients.
+EOD
diff --git a/release/packages/ucl/kerberos-lib-all.ucl b/release/packages/ucl/kerberos-lib-all.ucl
index ab769ee16f96..b524563a976d 100644
--- a/release/packages/ucl/kerberos-lib-all.ucl
+++ b/release/packages/ucl/kerberos-lib-all.ucl
@@ -1,4 +1,4 @@
-comment = "Kerberos Libraries"
+comment = "Kerberos libraries"
desc = <<EOD
-Kerberos Libraries
+Libraries requires to run programs that use Kerberos.
EOD
diff --git a/release/packages/ucl/kernel-man.ucl b/release/packages/ucl/kernel-man.ucl
new file mode 100644
index 000000000000..9d70baf2c3af
--- /dev/null
+++ b/release/packages/ucl/kernel-man.ucl
@@ -0,0 +1,5 @@
+comment = "Kernel manual pages"
+desc = <<EOD
+Manual pages for kernel interfaces and drivers (section 4) and the kernel
+developer manual pages (section 9).
+EOD
diff --git a/release/packages/ucl/sendmail.ucl b/release/packages/ucl/sendmail.ucl
new file mode 100644
index 000000000000..c79775eb8af4
--- /dev/null
+++ b/release/packages/ucl/sendmail.ucl
@@ -0,0 +1,7 @@
+deps {
+ # sendmail requires make to build its configuration file.
+ "bmake": {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
diff --git a/release/packages/ucl/yp.ucl b/release/packages/ucl/yp.ucl
new file mode 100644
index 000000000000..14b2327e56d1
--- /dev/null
+++ b/release/packages/ucl/yp.ucl
@@ -0,0 +1,7 @@
+deps {
+ # YP requires bmake to rebuild the database.
+ "bmake": {
+ version = "${VERSION}"
+ origin = "base"
+ }
+}
diff --git a/release/scripts/make-oci-image.sh b/release/scripts/make-oci-image.sh
index cc599c76bd51..8a620e9d8973 100644
--- a/release/scripts/make-oci-image.sh
+++ b/release/scripts/make-oci-image.sh
@@ -22,16 +22,16 @@ echo "Building OCI freebsd${major}-${image} image for ${abi}"
init_repo() {
local workdir=$1; shift
local abi=$1; shift
+ local srcdir=$(realpath ${curdir}/..)
mkdir -p ${workdir}/repos
cat > ${workdir}/repos/base.conf <<EOF
FreeBSD-base: {
- url: "file:///usr/obj/usr/src/repo/${abi}/latest"
+ url: "file:///usr/obj${srcdir}/repo/${abi}/latest"
signature_type: "none"
fingerprints: "none"
}
EOF
- cp /etc/pkg/FreeBSD.conf ${workdir}/repos
}
# Install packages using pkg(8) into a container with rootfs at $3
diff --git a/release/tools/oci-image-static.conf b/release/tools/oci-image-static.conf
index 753a03af653b..8e642d9defce 100644
--- a/release/tools/oci-image-static.conf
+++ b/release/tools/oci-image-static.conf
@@ -14,7 +14,7 @@ oci_image_build() {
mtree -deU -p $m/usr -f ${srcdir}/etc/mtree/BSD.usr.dist > /dev/null
mtree -deU -p $m/usr/include -f ${srcdir}/etc/mtree/BSD.include.dist > /dev/null
mtree -deU -p $m/usr/lib -f ${srcdir}/etc/mtree/BSD.debug.dist > /dev/null
- install_packages ${abi} ${workdir} FreeBSD-caroot FreeBSD-zoneinfo
+ install_packages ${abi} ${workdir} FreeBSD-zoneinfo
cp ${srcdir}/etc/master.passwd $m/etc
pwd_mkdb -p -d $m/etc $m/etc/master.passwd || return $?
cp ${srcdir}/etc/group $m/etc || return $?
@@ -22,7 +22,10 @@ oci_image_build() {
# working directory to OBJDIR/release
cp ../etc/termcap/termcap.small $m/etc/termcap.small || return $?
cp ../etc/termcap/termcap.small $m/usr/share/misc/termcap || return $?
- env DESTDIR=$m /usr/sbin/certctl rehash
+ env DESTDIR=$m \
+ TRUSTPATH=${srcdir}/secure/caroot/trusted \
+ UNTRUSTPATH=${srcdir}/secure/caroot/untrusted \
+ certctl -c rehash
# Generate a suitable repo config for pkgbase
case ${branch} in
CURRENT|STABLE|BETA*)
diff --git a/sbin/devd/devd.cc b/sbin/devd/devd.cc
index d7a3fee57870..1ff405244cde 100644
--- a/sbin/devd/devd.cc
+++ b/sbin/devd/devd.cc
@@ -153,6 +153,8 @@ static volatile sig_atomic_t romeo_must_die = 0;
static const char *configfile = CF;
+static char vm_guest[80];
+
static void devdlog(int priority, const char* message, ...)
__printflike(2, 3);
static void event_loop(void);
@@ -867,6 +869,8 @@ process_event(char *buffer)
cfg.set_variable("timestamp", timestr);
free(timestr);
+ cfg.set_variable("vm_guest", vm_guest);
+
// Match doesn't have a device, and the format is a little
// different, so handle it separately.
switch (type) {
@@ -1107,6 +1111,14 @@ event_loop(void)
err(1, "select");
} else if (rv == 0)
check_clients();
+ /*
+ * Aside from the socket type, both sockets use the same
+ * protocol, so we can process clients the same way.
+ */
+ if (FD_ISSET(stream_fd, &fds))
+ new_client(stream_fd, SOCK_STREAM);
+ if (FD_ISSET(seqpacket_fd, &fds))
+ new_client(seqpacket_fd, SOCK_SEQPACKET);
if (FD_ISSET(fd, &fds)) {
rv = read(fd, buffer, sizeof(buffer) - 1);
if (rv > 0) {
@@ -1135,14 +1147,6 @@ event_loop(void)
break;
}
}
- if (FD_ISSET(stream_fd, &fds))
- new_client(stream_fd, SOCK_STREAM);
- /*
- * Aside from the socket type, both sockets use the same
- * protocol, so we can process clients the same way.
- */
- if (FD_ISSET(seqpacket_fd, &fds))
- new_client(seqpacket_fd, SOCK_SEQPACKET);
}
cfg.remove_pidfile();
close(seqpacket_fd);
@@ -1322,6 +1326,7 @@ int
main(int argc, char **argv)
{
int ch;
+ size_t len;
check_devd_enabled();
while ((ch = getopt(argc, argv, "df:l:nq")) != -1) {
@@ -1346,6 +1351,12 @@ main(int argc, char **argv)
}
}
+ len = sizeof(vm_guest);
+ if (sysctlbyname("kern.vm_guest", vm_guest, &len, NULL, 0) < 0) {
+ devdlog(LOG_ERR,
+ "sysctlbyname(kern.vm_guest) failed: %d\n", errno);
+ }
+
cfg.parse();
if (!no_daemon && daemonize_quick) {
cfg.open_pidfile();
diff --git a/sbin/devd/hyperv.conf b/sbin/devd/hyperv.conf
index 13695a0c75b6..70108ac36e54 100644
--- a/sbin/devd/hyperv.conf
+++ b/sbin/devd/hyperv.conf
@@ -103,5 +103,6 @@ notify 10 {
notify 10 {
match "system" "ETHERNET";
match "type" "IFATTACH";
+ match "vm_guest" "hv";
action "/usr/libexec/hyperv/hyperv_vfattach $subsystem 0";
};
diff --git a/sbin/devd/moused.conf b/sbin/devd/moused.conf
index 002edad9a8a9..ed1060ffdf2e 100644
--- a/sbin/devd/moused.conf
+++ b/sbin/devd/moused.conf
@@ -31,5 +31,5 @@ notify 100 {
match "type" "DESTROY";
match "cdev" "ums[0-9]+";
- action "service moused stop $cdev";
+ action "service moused quietstop $cdev";
};
diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c
index cbab3fa2973c..5d2a7453578b 100644
--- a/sbin/dhclient/dhclient.c
+++ b/sbin/dhclient/dhclient.c
@@ -539,7 +539,7 @@ main(int argc, char *argv[])
setproctitle("%s", ifi->name);
/* setgroups(2) is not permitted in capability mode. */
- if (setgroups(1, &pw->pw_gid) != 0)
+ if (setgroups(0, NULL) != 0)
error("can't restrict groups: %m");
if (caph_enter_casper() < 0)
diff --git a/sbin/ifconfig/ifbridge.c b/sbin/ifconfig/ifbridge.c
index ce5d2f4894fa..a75c37e640a2 100644
--- a/sbin/ifconfig/ifbridge.c
+++ b/sbin/ifconfig/ifbridge.c
@@ -80,6 +80,20 @@ get_val(const char *cp, u_long *valp)
}
static int
+get_vlan_id(const char *cp, ether_vlanid_t *valp)
+{
+ u_long val;
+
+ if (get_val(cp, &val) == -1)
+ return (-1);
+ if (val < DOT1Q_VID_MIN || val > DOT1Q_VID_MAX)
+ return (-1);
+
+ *valp = (ether_vlanid_t)val;
+ return (0);
+}
+
+static int
do_cmd(if_ctx *ctx, u_long op, void *arg, size_t argsize, int set)
{
struct ifdrv ifd = {};
@@ -217,8 +231,9 @@ bridge_status(if_ctx *ctx)
printf("%s%s ", prefix, member->ifbr_ifsname);
printb("flags", member->ifbr_ifsflags, IFBIFBITS);
printf("\n%s", pad);
- printf("ifmaxaddr %u port %u priority %u path cost %u",
- member->ifbr_addrmax,
+ if (member->ifbr_addrmax != 0)
+ printf("ifmaxaddr %u ", member->ifbr_addrmax);
+ printf("port %u priority %u path cost %u",
member->ifbr_portno,
member->ifbr_priority,
member->ifbr_path_cost);
@@ -241,8 +256,8 @@ bridge_status(if_ctx *ctx)
else
printf(" <unknown state %d>", state);
}
- if (member->ifbr_untagged != 0)
- printf(" untagged %u", (unsigned)member->ifbr_untagged);
+ if (member->ifbr_pvid != 0)
+ printf(" untagged %u", (unsigned)member->ifbr_pvid);
print_vlans(&bridge->member_vlans[i]);
printf("\n");
}
@@ -613,25 +628,15 @@ static void
setbridge_untagged(if_ctx *ctx, const char *ifn, const char *vlanid)
{
struct ifbreq req;
- u_long val;
memset(&req, 0, sizeof(req));
+ strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
- if (get_val(vlanid, &val) < 0)
+ if (get_vlan_id(vlanid, &req.ifbr_pvid) < 0)
errx(1, "invalid VLAN identifier: %s", vlanid);
- /*
- * Reject vlan 0, since it's not a valid vlan identifier and has a
- * special meaning in the kernel interface.
- */
- if (val == 0)
- errx(1, "invalid VLAN identifier: %lu", val);
-
- strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
- req.ifbr_untagged = val;
-
- if (do_cmd(ctx, BRDGSIFUNTAGGED, &req, sizeof(req), 1) < 0)
- err(1, "BRDGSIFUNTAGGED %s", vlanid);
+ if (do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSIFPVID %s", vlanid);
}
static void
@@ -642,10 +647,10 @@ unsetbridge_untagged(if_ctx *ctx, const char *ifn, int dummy __unused)
memset(&req, 0, sizeof(req));
strlcpy(req.ifbr_ifsname, ifn, sizeof(req.ifbr_ifsname));
- req.ifbr_untagged = 0;
+ req.ifbr_pvid = 0;
- if (do_cmd(ctx, BRDGSIFUNTAGGED, &req, sizeof(req), 1) < 0)
- err(1, "BRDGSIFUNTAGGED");
+ if (do_cmd(ctx, BRDGSIFPVID, &req, sizeof(req), 1) < 0)
+ err(1, "BRDGSIFPVID");
}
static void
diff --git a/sbin/ifconfig/ifconfig.8 b/sbin/ifconfig/ifconfig.8
index 6c61af48abec..b6e7d3ff2c63 100644
--- a/sbin/ifconfig/ifconfig.8
+++ b/sbin/ifconfig/ifconfig.8
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 11, 2025
+.Dd July 14, 2025
.Dt IFCONFIG 8
.Os
.Sh NAME
@@ -2878,13 +2878,25 @@ interfaces previously configured with
Another name for the
.Fl tunnel
parameter.
+.It Cm noclamp
+This flag prevents the MTU from being clamped to 1280 bytes, the
+minimum MTU for IPv6, when the outer protocol is IPv6. When the
+flag is set, the MTU value configured on the interface will be
+used instead of the fixed length of 1280 bytes. For more details,
+please refer to the
+.Ar MTU Configuration and Path MTU Discovery
+section in
+.Xr gif 4 .
+.It Cm -noclamp
+Clear the flag
+.Cm noclamp .
.It Cm ignore_source
Set a flag to accept encapsulated packets destined to this host
independently from source address.
This may be useful for hosts, that receive encapsulated packets
from the load balancers.
.It Cm -ignore_source
-Clear a flag
+Clear the flag
.Cm ignore_source .
.El
.Ss GRE Tunnel Parameters
diff --git a/sbin/ifconfig/ifgif.c b/sbin/ifconfig/ifgif.c
index 991cf110678f..9b8be210a59e 100644
--- a/sbin/ifconfig/ifgif.c
+++ b/sbin/ifconfig/ifgif.c
@@ -49,6 +49,7 @@
#include "ifconfig.h"
static const char *GIFBITS[] = {
+ [0] = "NOCLAMP",
[1] = "IGNORE_SOURCE",
};
@@ -90,6 +91,8 @@ setgifopts(if_ctx *ctx, const char *val __unused, int d)
}
static struct cmd gif_cmds[] = {
+ DEF_CMD("noclamp", GIF_NOCLAMP, setgifopts),
+ DEF_CMD("-noclamp", -GIF_NOCLAMP, setgifopts),
DEF_CMD("ignore_source", GIF_IGNORE_SOURCE, setgifopts),
DEF_CMD("-ignore_source", -GIF_IGNORE_SOURCE, setgifopts),
};
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_fusefs/Makefile b/sbin/mount_fusefs/Makefile
index e683b35f0c8a..a237ba99eb6b 100644
--- a/sbin/mount_fusefs/Makefile
+++ b/sbin/mount_fusefs/Makefile
@@ -20,7 +20,7 @@ DEBUG_FLAGS+= -DFUSE4BSD_VERSION="\"${F4BVERS}\""
PACKAGE=runtime
PROG= mount_fusefs
-MAN8= mount_fusefs.8
+MAN= mount_fusefs.8
LIBADD= util
.include <bsd.prog.mk>
diff --git a/sbin/reboot/reboot.8 b/sbin/reboot/reboot.8
index 0ddcee643244..1bbc39d52be4 100644
--- a/sbin/reboot/reboot.8
+++ b/sbin/reboot/reboot.8
@@ -110,6 +110,15 @@ Care should be taken if
.Va value
contains any characters that are special to the shell or loader's configuration
parsing code.
+.It Fl f
+Force reboot.
+Normally,
+.Nm
+checks for the presence of the next kernel,
+and absence of the
+.Pa /var/run/noshutdown
+file.
+Without this flag, reboot is denied if one of the conditions failed.
.It Fl k Ar kname
Boot the specified kernel
.Ar kname
diff --git a/sbin/reboot/reboot.c b/sbin/reboot/reboot.c
index 9825d4f96319..f6065e80fb66 100644
--- a/sbin/reboot/reboot.c
+++ b/sbin/reboot/reboot.c
@@ -40,6 +40,7 @@
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <paths.h>
#include <pwd.h>
#include <signal.h>
#include <spawn.h>
@@ -222,6 +223,7 @@ main(int argc, char *argv[])
{
struct utmpx utx;
const struct passwd *pw;
+ struct stat st;
int ch, howto = 0, i, sverrno;
bool Dflag, fflag, lflag, Nflag, nflag, qflag;
uint64_t pageins;
@@ -294,6 +296,11 @@ main(int argc, char *argv[])
if (argc != 0)
usage();
+ if (!donextboot && !fflag && stat(_PATH_NOSHUTDOWN, &st) == 0) {
+ errx(1, "Reboot cannot be done, " _PATH_NOSHUTDOWN
+ " is present");
+ }
+
if (Dflag && ((howto & ~RB_HALT) != 0 || kernel != NULL))
errx(1, "cannot delete existing nextboot config and do anything else");
if ((howto & (RB_DUMP | RB_HALT)) == (RB_DUMP | RB_HALT))
diff --git a/sbin/recoverdisk/recoverdisk.1 b/sbin/recoverdisk/recoverdisk.1
index 2999ac6ec409..9f1deb4c0c23 100644
--- a/sbin/recoverdisk/recoverdisk.1
+++ b/sbin/recoverdisk/recoverdisk.1
@@ -27,7 +27,7 @@
.Os
.Sh NAME
.Nm recoverdisk
-.Nd recover data from hard disk or optical media
+.Nd recover data from disk-like devices.
.Sh SYNOPSIS
.Nm
.Op Fl b Ar bigsize
@@ -41,79 +41,101 @@
.Sh DESCRIPTION
The
.Nm
-utility reads data from the
+utility reads all data from the
.Ar source
-file until all blocks could be successfully read.
+and retries read operations until they succeed.
If
.Ar destination
-was specified all data is being written to that file.
-It starts reading in multiples of the sector size.
-Whenever a block fails, it is put to the end of the working queue and will be
-read again, possibly with a smaller read size.
+is specified all data read be written there.
.Pp
-By default it uses block sizes of roughly 1 MB, 32kB, and the native
-sector size (usually 512 bytes).
-These figures are adjusted slightly, for devices whose sectorsize is not a
-power of 2, e.g., audio CDs with a sector size of 2352 bytes.
+The internal work-list can be saved and loaded so that
+.Nm
+sessions can be resumed, for instance when a marginal
+source hard-disk shuts down.
+.Pp
+The work-list is initialized with a single item which covers the entire
+.Ar source
+and
+.Nm
+always chips away at the first item on the work-list.
+
+When a read succeeds, that part of the current chunk is eliminated
+from the work-list.
+
+When a read fails, that part of the item is appended to the worklist
+as a separate item, and will be retried in due order.
+If
+.Ar destination
+is specified, the corresponding range is filled with '_UNREAD_'.
+.Pp
+The first pass attempts to read everything in "big-size" chunks,
+the second pass reads in "medium-size" chunks and third and subsequent
+passes read in "small-size" chunks. This three stage process is
+an attempt to optimize the case where only a few bad blocks exist
+on
+.Ar source .
+If too many read-errors are encountered,
+.Nm
+will fall back to smaller sizes sooner.
+.Pp
+The three sizes default to 128kB (or less if the sector size does
+not divide 128kB cleanly, for instance audio CD media), and the
+reported
+.Dv DIOCGSTRIPESIZE
+and
+.Dv DIOCGSECTORSIZE
+respectively.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl b Ar bigsize
-The size of reads attempted first.
-The middle pass is roughly the logarithmic average of the bigsize and
-the sectorsize.
-.It Fl r Ar readlist
-Read the list of blocks and block sizes to read from the specified file.
-.It Fl s Ar interval
-How often we should update the writelist file while things go OK.
-The default is 60 and the unit is "progress messages" so if things
-go well, this is the same as once per minute.
+The size of reads attempted in first pass.
+.It Fl m Ar mediumsize
+The size of reads attempted in second pass.
+.It Fl s Ar smallsize
+The size of reads attempted in third and subsequent passes.
+.It Fl r Ar work-list-file
+Read the work-list from a file.
+.It Fl w Ar work-list-file
+Write the work-list to a file when a read succeed, but at most once
+every minute.
+.It Fl l Ar log-file
+Each successful read is logged with timestamp, offset and length.
+.It Fl t Ar totalsize
+How many bytes should be recovered. The default is what
+.Dv DIOCGMEDIASIZE
+reports for character and block devices or
+.Dv st_size
+if
+.Ar source
+is a regular file.
+.It Fl p Ar pause
+.Xr sleep 3
+this long whenever a read fails. This makes the
+.Ar source
+device look less sick to the operating system.
.It Fl u Ar pattern
-By default blocks which encounter read errors will be filled with
-the pattern
+By default blocks which cannot be read are filled with the pattern
.Ql _UNREAD_
-in the output file.
-This option can be
-used to specify another pattern.
-Nothing gets written if the string is empty.
+in the output file. This option can be used to specify a different
+pattern. If the pattern is the empty string, nothing is written.
.It Fl v
-Enables nicer status report using ANSI escapes and UTF-8.
-.It Fl w Ar writelist
-Write the list of remaining blocks to read to the specified file if
-.Nm
-is aborted via
-.Dv SIGINT .
+Produce a detailed progress report with ANSI escapes and UTF-8.
.El
.Pp
-The
-.Fl r
-and
-.Fl w
-options can be specified together.
-Especially, they can point to the same file, which will be updated on abort.
-.Sh OUTPUT
-The
.Nm
-utility
-prints several columns, detailing the progress
-.Bl -tag -width remaining
-.It Va start
-Starting offset of the current block.
-.It Va size
-Read size of the current block.
-.It Va len
-Length of the current block.
-.It Va state
-Is increased for every failed read.
-.It Va done
-Number of bytes already read.
-.It Va remaining
-Number of bytes remaining.
-.It Va "% done"
-Percent complete.
-.El
+can be aborted with
+.Dv SIGINT ,
+but with a sick
+.Ar source
+it may take up to several minutes before the current read operation
+returns from the kernel.
+.Pp
.Sh EXAMPLES
.Bd -literal
+# check if all sectors can be read on a USB stick:
+recoverdisk /dev/da0
+
# recover data from failing hard drive ada3
recoverdisk /dev/ada3 /data/disk.img
@@ -129,10 +151,72 @@ recoverdisk -r worklist -w worklist /dev/cd0 /data/cd.iso
# recover a single file from the unreadable media
recoverdisk /cdrom/file.avi file.avi
-# If the disk hangs the system on read-errors try:
-recoverdisk -b 0 /dev/ada3 /somewhere
-
.Ed
+.Sh PRACTICAL ADVICE
+In Datamuseum.dk
+.Nm
+has been used to recover all sorts of data-media for two decades,
+here are some things we have learned:
+.Bl -bullet
+.It
+Interacting with failing hardware has a tendency to crash machines,
+so it is always a good idea to use the
+.Fl -w work-list-file
+so that it is possible to continue.
+.It
+When attempting to recover hard to read data from failing hard disks,
+it pays to pamper the drive as much as possible:
+.It
+It is generally best to keep the drive in it's usual physical orientation,
+but it can also help to try other orientations.
+.It
+Insulate the drive from external vibrations.
+.It
+Keep the drive cool with a fan.
+.It
+If possible, power the drive from a laboratory power supply.
+.It
+Do not loose patience: Let
+.Nm
+run as long as possible.
+.It
+(S)ATA controllers do not handle failing disks well, if this
+is a problem, use a USB-(S)ATA adapter instead.
+.It
+The
+.Nm
+source code is deliberately written to be easily portable to
+older versions of
+.Fx
+and to other operating systems.
+.It
+If you need to read ST-506, RLL or ESDI drives
+.Fx 3.5.1
+is a good compromise.
+.It
+Sometimes forcing the disk to step between reads helps.
+Since
+.Nm
+process the work-list in the order it is read, this
+can be accomplished by sorting the work-list with
+something like:
+.Dl % sort +0.5
+.It
+By default the
+.Xr CAM
+layer will retry failing read operations, but that
+will get stuck on the bad sectors for long time
+and delay recovering what actually can be read from
+a rapidly failing drive.
+In that situation, set the appropriate
+.Dl kern.cam.*.retry_count
+sysctl to zero.
+.It
+For floppies and un-zoned hard disks (ST-506 to
+early IDE) set
+.Fl b Ar bigsize
+to the size of a track.
+.El
.Sh SEE ALSO
.Xr dd 1 ,
.Xr ada 4 ,
@@ -143,7 +227,8 @@ recoverdisk -b 0 /dev/ada3 /somewhere
The
.Nm
utility first appeared in
-.Fx 7.0 .
+.Fx 7.0
+because Somebodyâ„¢ forgot to make a backup copy.
.Sh AUTHORS
.An -nosplit
The original implementation was done by
@@ -151,34 +236,29 @@ The original implementation was done by
with minor improvements from
.An Ulrich Sp\(:orlein Aq Mt uqs@FreeBSD.org .
.Pp
-This manual page was written by
+This manual page was originally written by
.An Ulrich Sp\(:orlein .
.Sh BUGS
-Reading from media where the sectorsize is not a power of 2 will make all
-1 MB reads fail.
-This is due to the DMA reads being split up into blocks of at most 128kB.
-These reads then fail if the sectorsize is not a divisor of 128kB.
-When reading a full raw audio CD, this leads to roughly 700 error messages
-flying by.
-This is harmless and can be avoided by setting
-.Fl b
-to no more than 128kB.
+If a failing device causes the machine to crash, there is
+a risk that a chunk might have been successfully read
+and removed from the work-list, but not yet flushed to
+the
+.Ar destination .
.Pp
.Nm
-needs to know about read errors as fast as possible, i.e., retries by lower
-layers will usually slow down the operation.
-When using
-.Xr cam 4
-attached drives, you may want to set kern.cam.XX.retry_count to zero, e.g.:
-.Bd -literal
-# sysctl kern.cam.ada.retry_count=0
-# sysctl kern.cam.cd.retry_count=0
-# sysctl kern.cam.da.retry_count=0
-.Ed
-.\".Pp
-.\"When reading from optical media, a bug in the GEOM framework will
-.\"prevent it from seeing that the media has been removed.
-.\"The device can still be opened, but all reads will fail.
-.\"This is usually harmless, but will send
-.\".Nm
-.\"into an infinite loop.
+calls
+.Xr fdatasync 3
+on the destination before writing the work-list to a
+temporary file, and calls it again on the temporary
+file before renaming it to the specified
+.Fl w Ar work-file-list
+filename.
+But even then things dont always work out.
+.Pp
+.Nm
+should have an option for reconstructing the work-list
+from the
+.Ar destination
+by enumerating the
+.Fl u Ar pattern
+filled ranges.
diff --git a/sbin/recoverdisk/recoverdisk.c b/sbin/recoverdisk/recoverdisk.c
index 446266c36d50..e1b283e54a93 100644
--- a/sbin/recoverdisk/recoverdisk.c
+++ b/sbin/recoverdisk/recoverdisk.c
@@ -8,6 +8,7 @@
* this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp
* ----------------------------------------------------------------------------
*/
+
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/disk.h>
@@ -27,18 +28,10 @@
#include <time.h>
#include <unistd.h>
-/* Safe printf into a fixed-size buffer */
-#define bprintf(buf, fmt, ...) \
- do { \
- int ibprintf; \
- ibprintf = snprintf(buf, sizeof buf, fmt, __VA_ARGS__); \
- assert(ibprintf >= 0 && ibprintf < (int)sizeof buf); \
- } while (0)
-
struct lump {
- off_t start;
- off_t len;
- int state;
+ uint64_t start;
+ uint64_t len;
+ unsigned pass;
TAILQ_ENTRY(lump) list;
};
@@ -46,25 +39,32 @@ struct period {
time_t t0;
time_t t1;
char str[20];
- off_t bytes_read;
+ uint64_t bytes_read;
TAILQ_ENTRY(period) list;
};
TAILQ_HEAD(period_head, period);
static volatile sig_atomic_t aborting = 0;
static int verbose = 0;
-static size_t bigsize = 1024 * 1024;
-static size_t medsize;
-static size_t minsize = 512;
-static off_t tot_size;
-static off_t done_size;
+static uint64_t big_read;
+static uint64_t medium_read;
+static uint64_t small_read;
+static uint64_t total_size;
+static uint64_t done_size;
static char *input;
-static char *wworklist = NULL;
-static char *rworklist = NULL;
+static char *write_worklist_file = NULL;
+static char *read_worklist_file = NULL;
static const char *unreadable_pattern = "_UNREAD_";
-static const int write_errors_are_fatal = 1;
-static int fdr, fdw;
-
+static int write_errors_are_fatal = 1;
+static int read_fd, write_fd;
+static FILE *log_file = NULL;
+static char *work_buf;
+static char *pattern_buf;
+static double error_pause;
+
+static unsigned nlumps;
+static double n_reads, n_good_reads;
+static time_t t_first;
static TAILQ_HEAD(, lump) lumps = TAILQ_HEAD_INITIALIZER(lumps);
static struct period_head minute = TAILQ_HEAD_INITIALIZER(minute);
static struct period_head quarter = TAILQ_HEAD_INITIALIZER(quarter);
@@ -74,7 +74,8 @@ static struct period_head day = TAILQ_HEAD_INITIALIZER(quarter);
/**********************************************************************/
static void
-report_good_read2(time_t now, size_t bytes, struct period_head *ph, time_t dt)
+account_good_read_period(time_t now, uint64_t bytes,
+ struct period_head *ph, time_t dt)
{
struct period *pp;
const char *fmt;
@@ -82,7 +83,7 @@ report_good_read2(time_t now, size_t bytes, struct period_head *ph, time_t dt)
pp = TAILQ_FIRST(ph);
if (pp == NULL || pp->t1 < now) {
- pp = calloc(1, sizeof(*pp));
+ pp = calloc(1UL, sizeof(*pp));
assert(pp != NULL);
pp->t0 = (now / dt) * dt;
pp->t1 = (now / dt + 1) * dt;
@@ -98,13 +99,13 @@ report_good_read2(time_t now, size_t bytes, struct period_head *ph, time_t dt)
}
static void
-report_good_read(time_t now, size_t bytes)
+account_good_read(time_t now, uint64_t bytes)
{
- report_good_read2(now, bytes, &minute, 60L);
- report_good_read2(now, bytes, &quarter, 900L);
- report_good_read2(now, bytes, &hour, 3600L);
- report_good_read2(now, bytes, &day, 86400L);
+ account_good_read_period(now, bytes, &minute, 60L);
+ account_good_read_period(now, bytes, &quarter, 900L);
+ account_good_read_period(now, bytes, &hour, 3600L);
+ account_good_read_period(now, bytes, &day, 86400L);
}
static void
@@ -114,20 +115,18 @@ report_one_period(const char *period, struct period_head *ph)
int n;
n = 0;
- printf("%s \xe2\x94\x82", period);
+ printf("%s ", period);
TAILQ_FOREACH(pp, ph, list) {
- if (n == 3) {
+ if (++n == 4) {
TAILQ_REMOVE(ph, pp, list);
free(pp);
break;
}
- if (n++)
- printf(" \xe2\x94\x82");
- printf(" %s %14jd", pp->str, pp->bytes_read);
+ printf("\xe2\x94\x82 %s %14ju ",
+ pp->str, (uintmax_t)pp->bytes_read);
}
for (; n < 3; n++) {
- printf(" \xe2\x94\x82");
- printf(" %5s %14s", "", "");
+ printf("\xe2\x94\x82 %5s %14s ", "", "");
}
printf("\x1b[K\n");
}
@@ -146,27 +145,23 @@ report_periods(void)
static void
set_verbose(void)
{
- struct winsize wsz;
- if (!isatty(STDIN_FILENO) || ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz))
- return;
verbose = 1;
}
static void
-report_header(int eol)
+report_header(const char *term)
{
- printf("%13s %7s %13s %5s %13s %13s %9s",
+ printf("%13s %7s %13s %5s %13s %13s %9s%s",
"start",
"size",
"block-len",
"pass",
"done",
"remaining",
- "% done");
- if (eol)
- printf("\x1b[K");
- putchar('\n');
+ "% done",
+ term
+ );
}
#define REPORTWID 79
@@ -186,20 +181,20 @@ report_hline(const char *how)
printf("\x1b[K\n");
}
-static off_t hist[REPORTWID];
-static off_t last_done = -1;
+static uint64_t hist[REPORTWID];
+static uint64_t prev_done = ~0UL;
static void
-report_histogram(const struct lump *lp)
+report_histogram(uint64_t start)
{
- off_t j, bucket, fp, fe, k, now;
+ uint64_t j, bucket, fp, fe, k, now;
double a;
struct lump *lp2;
- bucket = tot_size / REPORTWID;
- if (tot_size > bucket * REPORTWID)
+ bucket = total_size / REPORTWID;
+ if (total_size > bucket * REPORTWID)
bucket += 1;
- if (done_size != last_done) {
+ if (done_size != prev_done) {
memset(hist, 0, sizeof hist);
TAILQ_FOREACH(lp2, &lumps, list) {
fp = lp2->start;
@@ -213,9 +208,9 @@ report_histogram(const struct lump *lp)
fp += k;
}
}
- last_done = done_size;
+ prev_done = done_size;
}
- now = lp->start / bucket;
+ now = start / bucket;
for (j = 0; j < REPORTWID; j++) {
a = round(8 * (double)hist[j] / bucket);
assert (a >= 0 && a < 9);
@@ -228,7 +223,7 @@ report_histogram(const struct lump *lp)
} else {
putchar(0xe2);
putchar(0x96);
- putchar(0x80 + (int)a);
+ putchar(0x80 + (char)a);
}
if (j == now)
printf("\x1b[0m");
@@ -237,34 +232,40 @@ report_histogram(const struct lump *lp)
}
static void
-report(const struct lump *lp, size_t sz)
+report(uint64_t sz)
{
struct winsize wsz;
+ const struct lump *lp = TAILQ_FIRST(&lumps);
int j;
-
- assert(lp != NULL);
+ unsigned pass = 0;
+ uintmax_t start = 0, length = 0;
+ time_t t_now = time(NULL);
+
+ if (lp != NULL) {
+ pass = lp->pass;
+ start = lp->start;
+ length = lp->len;
+ }
if (verbose) {
printf("\x1b[H%s\x1b[K\n", input);
- report_header(1);
- } else {
- putchar('\r');
+ report_header("\x1b[K\n");
}
- printf("%13jd %7zu %13jd %5d %13jd %13jd %9.4f",
- (intmax_t)lp->start,
- sz,
- (intmax_t)lp->len,
- lp->state,
- (intmax_t)done_size,
- (intmax_t)(tot_size - done_size),
- 100*(double)done_size/(double)tot_size
+ printf("%13ju %7ju %13ju %5u %13ju %13ju %9.4f",
+ start,
+ (uintmax_t)sz,
+ length,
+ pass,
+ (uintmax_t)done_size,
+ (uintmax_t)(total_size - done_size),
+ 100*(double)done_size/(double)total_size
);
if (verbose) {
printf("\x1b[K\n");
report_hline(NULL);
- report_histogram(lp);
+ report_histogram(start);
if (TAILQ_EMPTY(&minute)) {
report_hline(NULL);
} else {
@@ -272,27 +273,36 @@ report(const struct lump *lp, size_t sz)
report_periods();
report_hline("\xe2\x94\xb4");
}
+ printf("Missing: %u", nlumps);
+ printf(" Success: %.0f/%.0f =", n_good_reads, n_reads);
+ printf(" %.4f%%", 100 * n_good_reads / n_reads);
+ printf(" Duration: %.3fs", (t_now - t_first) / n_reads);
+ printf("\x1b[K\n");
+ report_hline(NULL);
j = ioctl(STDIN_FILENO, TIOCGWINSZ, &wsz);
if (!j)
printf("\x1b[%d;1H", wsz.ws_row);
+ } else {
+ printf("\n");
}
- fflush(stdout);
}
/**********************************************************************/
static void
-new_lump(off_t start, off_t len, int state)
+new_lump(uint64_t start, uint64_t len, unsigned pass)
{
struct lump *lp;
+ assert(len > 0);
lp = malloc(sizeof *lp);
if (lp == NULL)
err(1, "Malloc failed");
lp->start = start;
lp->len = len;
- lp->state = state;
+ lp->pass = pass;
TAILQ_INSERT_TAIL(&lumps, lp, list);
+ nlumps += 1;
}
/**********************************************************************
@@ -306,98 +316,100 @@ save_worklist(void)
struct lump *llp;
char buf[PATH_MAX];
- if (fdw >= 0 && fdatasync(fdw))
+ if (write_fd >= 0 && fdatasync(write_fd))
err(1, "Write error, probably disk full");
- if (wworklist != NULL) {
- bprintf(buf, "%s.tmp", wworklist);
- (void)fprintf(stderr, "\nSaving worklist ...");
- (void)fflush(stderr);
+ if (write_worklist_file != NULL) {
+ snprintf(buf, sizeof(buf), "%s.tmp", write_worklist_file);
+ fprintf(stderr, "\nSaving worklist ...");
file = fopen(buf, "w");
if (file == NULL)
err(1, "Error opening file %s", buf);
- TAILQ_FOREACH(llp, &lumps, list)
- fprintf(file, "%jd %jd %d\n",
- (intmax_t)llp->start, (intmax_t)llp->len,
- llp->state);
- (void)fflush(file);
+ TAILQ_FOREACH(llp, &lumps, list) {
+ assert (llp->len > 0);
+ fprintf(file, "%ju %ju %u\n",
+ (uintmax_t)llp->start,
+ (uintmax_t)llp->len,
+ llp->pass);
+ }
+ fflush(file);
if (ferror(file) || fdatasync(fileno(file)) || fclose(file))
err(1, "Error writing file %s", buf);
- if (rename(buf, wworklist))
- err(1, "Error renaming %s to %s", buf, wworklist);
- (void)fprintf(stderr, " done.\n");
+ if (rename(buf, write_worklist_file))
+ err(1, "Error renaming %s to %s",
+ buf, write_worklist_file);
+ fprintf(stderr, " done.\n");
}
}
/* Read the worklist if -r was given */
-static off_t
-read_worklist(off_t t)
+static uint64_t
+read_worklist(void)
{
- off_t s, l, d;
- int state, lines;
+ uintmax_t start, length;
+ uint64_t missing = 0;
+ unsigned pass, lines;
FILE *file;
- (void)fprintf(stderr, "Reading worklist ...");
- (void)fflush(stderr);
- file = fopen(rworklist, "r");
+ fprintf(stderr, "Reading worklist ...");
+ file = fopen(read_worklist_file, "r");
if (file == NULL)
- err(1, "Error opening file %s", rworklist);
+ err(1, "Error opening file %s", read_worklist_file);
lines = 0;
- d = t;
for (;;) {
++lines;
- if (3 != fscanf(file, "%jd %jd %d\n", &s, &l, &state)) {
+ if (3 != fscanf(file, "%ju %ju %u\n", &start, &length, &pass)) {
if (!feof(file))
- err(1, "Error parsing file %s at line %d",
- rworklist, lines);
+ err(1, "Error parsing file %s at line %u",
+ read_worklist_file, lines);
else
break;
}
- new_lump(s, l, state);
- d -= l;
+ if (length > 0) {
+ new_lump(start, length, pass);
+ missing += length;
+ }
}
if (fclose(file))
- err(1, "Error closing file %s", rworklist);
- (void)fprintf(stderr, " done.\n");
+ err(1, "Error closing file %s", read_worklist_file);
+ fprintf(stderr, " done.\n");
/*
- * Return the number of bytes already read
- * (at least not in worklist).
+ * Return the number of bytes outstanding
*/
- return (d);
+ return (missing);
}
/**********************************************************************/
static void
-write_buf(int fd, const void *buf, ssize_t len, off_t where)
+write_buf(int fd, const void *buf, uint64_t length, uint64_t where)
{
- ssize_t i;
+ int64_t i;
- i = pwrite(fd, buf, len, where);
- if (i == len)
+ i = pwrite(fd, buf, length, (off_t)where);
+ if (i > 0 && (uint64_t)i == length)
return;
- printf("\nWrite error at %jd/%zu\n\t%s\n",
- where, i, strerror(errno));
+ printf("\nWrite error at %ju/%ju: %jd (%s)\n",
+ (uintmax_t)where,
+ (uintmax_t)length,
+ (intmax_t)i, strerror(errno));
save_worklist();
if (write_errors_are_fatal)
exit(3);
}
static void
-fill_buf(char *buf, ssize_t len, const char *pattern)
+fill_buf(char *buf, int64_t len, const char *pattern)
{
- ssize_t sz = strlen(pattern);
- ssize_t i, j;
+ int64_t sz = strlen(pattern);
+ int64_t i;
for (i = 0; i < len; i += sz) {
- j = len - i;
- if (j > sz)
- j = sz;
- memcpy(buf + i, pattern, j);
+ memcpy(buf + i, pattern, MIN(len - i, sz));
}
}
@@ -406,45 +418,334 @@ fill_buf(char *buf, ssize_t len, const char *pattern)
static void
usage(void)
{
- (void)fprintf(stderr, "usage: recoverdisk [-b bigsize] [-r readlist] "
+ fprintf(stderr, "usage: recoverdisk [-b big_read] [-r readlist] "
"[-s interval] [-w writelist] source [destination]\n");
/* XXX update */
exit(1);
}
static void
-sighandler(__unused int sig)
+sighandler(int sig)
{
+ (void)sig;
aborting = 1;
}
+/**********************************************************************/
+
+static int64_t
+attempt_one_lump(time_t t_now)
+{
+ struct lump *lp;
+ uint64_t sz;
+ int64_t retval;
+ int error;
+
+ lp = TAILQ_FIRST(&lumps);
+ if (lp == NULL)
+ return(0);
+
+ if (lp->pass == 0) {
+ sz = MIN(lp->len, big_read);
+ } else if (lp->pass == 1) {
+ sz = MIN(lp->len, medium_read);
+ } else {
+ sz = MIN(lp->len, small_read);
+ }
+
+ assert(sz != 0);
+
+ n_reads += 1;
+ retval = pread(read_fd, work_buf, sz, lp->start);
+
+#if 0 /* enable this when testing */
+ if (!(random() & 0xf)) {
+ retval = -1;
+ errno = EIO;
+ usleep(20000);
+ } else {
+ usleep(2000);
+ }
+#endif
+
+ error = errno;
+ if (retval > 0) {
+ n_good_reads += 1;
+ sz = retval;
+ done_size += sz;
+ if (write_fd >= 0) {
+ write_buf(write_fd, work_buf, sz, lp->start);
+ }
+ if (log_file != NULL) {
+ fprintf(log_file, "%jd %ju %ju\n",
+ (intmax_t)t_now,
+ (uintmax_t)lp->start,
+ (uintmax_t)sz
+ );
+ fflush(log_file);
+ }
+ } else {
+ printf("%14ju %7ju read error %d: (%s)",
+ (uintmax_t)lp->start,
+ (uintmax_t)sz, error, strerror(error));
+ if (error_pause > 1) {
+ printf(" (Pausing %g s)", error_pause);
+ }
+ printf("\n");
+
+ if (write_fd >= 0 && pattern_buf != NULL) {
+ write_buf(write_fd, pattern_buf, sz, lp->start);
+ }
+ new_lump(lp->start, sz, lp->pass + 1);
+ retval = -sz;
+ }
+ lp->start += sz;
+ lp->len -= sz;
+ if (lp->len == 0) {
+ TAILQ_REMOVE(&lumps, lp, list);
+ nlumps -= 1;
+ free(lp);
+ }
+ errno = error;
+ return (retval);
+}
+
+
+/**********************************************************************/
+
+static void
+determine_total_size(void)
+{
+ struct stat sb;
+ int error;
+
+ if (total_size != 0)
+ return;
+
+ error = fstat(read_fd, &sb);
+ if (error < 0)
+ err(1, "fstat failed");
+
+ if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
+#ifdef DIOCGMEDIASIZE
+ off_t mediasize;
+ error = ioctl(read_fd, DIOCGMEDIASIZE, &mediasize);
+ if (error == 0 && mediasize > 0) {
+ total_size = mediasize;
+ printf("# Got total_size from DIOCGMEDIASIZE: %ju\n",
+ (uintmax_t)total_size);
+ return;
+ }
+#endif
+ } else if (S_ISREG(sb.st_mode) && sb.st_size > 0) {
+ total_size = sb.st_size;
+ printf("# Got total_size from stat(2): %ju\n",
+ (uintmax_t)total_size);
+ return;
+ } else {
+ errx(1, "Input must be device or regular file");
+ }
+ fprintf(stderr, "Specify total size with -t option\n");
+ exit(1);
+}
+
+static void
+determine_read_sizes(void)
+{
+ int error;
+ u_int sectorsize;
+ off_t stripesize;
+
+ determine_total_size();
+
+#ifdef DIOCGSECTORSIZE
+ if (small_read == 0) {
+ error = ioctl(read_fd, DIOCGSECTORSIZE, &sectorsize);
+ if (error >= 0 && sectorsize > 0) {
+ small_read = sectorsize;
+ printf("# Got small_read from DIOCGSECTORSIZE: %ju\n",
+ (uintmax_t)small_read
+ );
+ }
+ }
+#endif
+
+ if (small_read == 0) {
+ printf("Assuming 512 for small_read\n");
+ small_read = 512;
+ }
+
+ if (medium_read && (medium_read % small_read)) {
+ errx(1,
+ "medium_read (%ju) is not a multiple of small_read (%ju)\n",
+ (uintmax_t)medium_read, (uintmax_t)small_read
+ );
+ }
+
+ if (big_read != 0 && (big_read % small_read)) {
+ errx(1,
+ "big_read (%ju) is not a multiple of small_read (%ju)\n",
+ (uintmax_t)big_read, (uintmax_t)small_read
+ );
+ }
+
+#ifdef DIOCGSTRIPESIZE
+ if (medium_read == 0) {
+ error = ioctl(read_fd, DIOCGSTRIPESIZE, &stripesize);
+ if (error < 0 || stripesize < 0) {
+ // nope
+ } else if ((uint64_t)stripesize < small_read) {
+ // nope
+ } else if (stripesize % small_read) {
+ // nope
+ } else if (0 < stripesize && stripesize < (128<<10)) {
+ medium_read = stripesize;
+ printf("# Got medium_read from DIOCGSTRIPESIZE: %ju\n",
+ (uintmax_t)medium_read
+ );
+ }
+ }
+#endif
+#if defined(DIOCGFWSECTORS) && defined(DIOCGFWHEADS)
+ if (medium_read == 0) {
+ u_int fwsectors = 0, fwheads = 0;
+ error = ioctl(read_fd, DIOCGFWSECTORS, &fwsectors);
+ if (error)
+ fwsectors = 0;
+ error = ioctl(read_fd, DIOCGFWHEADS, &fwheads);
+ if (error)
+ fwheads = 0;
+ if (fwsectors && fwheads) {
+ medium_read = fwsectors * fwheads * small_read;
+ printf(
+ "# Got medium_read from DIOCGFW{SECTORS,HEADS}: %ju\n",
+ (uintmax_t)medium_read
+ );
+ }
+ }
+#endif
+
+ if (big_read == 0 && medium_read != 0) {
+ if (medium_read > (64<<10)) {
+ big_read = medium_read;
+ } else {
+ big_read = 128 << 10;
+ big_read -= big_read % medium_read;
+ }
+ printf("# Got big_read from medium_read: %ju\n",
+ (uintmax_t)big_read
+ );
+ }
+
+ if (big_read == 0) {
+ big_read = 128 << 10;
+ printf("# Defaulting big_read to %ju\n",
+ (uintmax_t)big_read
+ );
+ }
+
+ if (medium_read == 0) {
+ /*
+ * We do not want to go directly to single sectors, but
+ * we also dont want to waste time doing multi-sector
+ * reads with high failure probability.
+ */
+ uint64_t h = big_read;
+ uint64_t l = small_read;
+ while (h > l) {
+ h >>= 2;
+ l <<= 1;
+ }
+ medium_read = h;
+ printf("# Got medium_read from small_read & big_read: %ju\n",
+ (uintmax_t)medium_read
+ );
+ }
+ fprintf(stderr,
+ "# Bigsize = %ju, medium_read = %ju, small_read = %ju\n",
+ (uintmax_t)big_read, (uintmax_t)medium_read, (uintmax_t)small_read);
+
+}
+
+
+/**********************************************************************/
+
+static void
+monitor_read_sizes(uint64_t failed_size)
+{
+
+ if (failed_size == big_read && medium_read != small_read) {
+ if (n_reads < n_good_reads + 3)
+ return;
+ fprintf(
+ stderr,
+ "Too many failures for big reads."
+ " (%.0f bad of %.0f)"
+ " Shifting to medium_reads.\n",
+ n_reads - n_good_reads, n_reads
+ );
+ big_read = medium_read;
+ medium_read = small_read;
+ return;
+ }
+
+ if (failed_size > small_read) {
+ if (n_reads < n_good_reads + 100)
+ return;
+ fprintf(
+ stderr,
+ "Too many failures."
+ " (%.0f bad of %.0f)"
+ " Shifting to small_reads.\n",
+ n_reads - n_good_reads, n_reads
+ );
+ big_read = small_read;
+ medium_read = small_read;
+ return;
+ }
+}
+
+/**********************************************************************/
+
int
main(int argc, char * const argv[])
{
int ch;
- size_t sz, j;
+ int64_t sz;
int error;
- char *buf;
- u_int sectorsize;
- off_t stripesize;
- time_t t1, t2;
- struct stat sb;
- u_int n, snapshot = 60;
- static struct lump *lp;
+ time_t t_now, t_report, t_save;
+ unsigned snapshot = 60, unsaved;
+ setbuf(stdout, NULL);
+ setbuf(stderr, NULL);
- while ((ch = getopt(argc, argv, "b:r:w:s:u:v")) != -1) {
+ while ((ch = getopt(argc, argv, "b:l:p:m:r:w:s:t:u:v")) != -1) {
switch (ch) {
case 'b':
- bigsize = strtoul(optarg, NULL, 0);
+ big_read = strtoul(optarg, NULL, 0);
+ break;
+ case 'l':
+ log_file = fopen(optarg, "a");
+ if (log_file == NULL) {
+ err(1, "Could not open logfile for append");
+ }
+ break;
+ case 'p':
+ error_pause = strtod(optarg, NULL);
+ break;
+ case 'm':
+ medium_read = strtoul(optarg, NULL, 0);
break;
case 'r':
- rworklist = strdup(optarg);
- if (rworklist == NULL)
+ read_worklist_file = strdup(optarg);
+ if (read_worklist_file == NULL)
err(1, "Cannot allocate enough memory");
break;
case 's':
- snapshot = strtoul(optarg, NULL, 0);
+ small_read = strtoul(optarg, NULL, 0);
+ break;
+ case 't':
+ total_size = strtoul(optarg, NULL, 0);
break;
case 'u':
unreadable_pattern = optarg;
@@ -453,8 +754,8 @@ main(int argc, char * const argv[])
set_verbose();
break;
case 'w':
- wworklist = strdup(optarg);
- if (wworklist == NULL)
+ write_worklist_file = strdup(optarg);
+ if (write_worklist_file == NULL)
err(1, "Cannot allocate enough memory");
break;
default:
@@ -469,149 +770,106 @@ main(int argc, char * const argv[])
usage();
input = argv[0];
- fdr = open(argv[0], O_RDONLY);
- if (fdr < 0)
+ read_fd = open(argv[0], O_RDONLY);
+ if (read_fd < 0)
err(1, "Cannot open read descriptor %s", argv[0]);
- error = fstat(fdr, &sb);
- if (error < 0)
- err(1, "fstat failed");
- if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
- error = ioctl(fdr, DIOCGSECTORSIZE, &sectorsize);
- if (error < 0)
- err(1, "DIOCGSECTORSIZE failed");
-
- error = ioctl(fdr, DIOCGSTRIPESIZE, &stripesize);
- if (error == 0 && stripesize < sectorsize)
- sectorsize = stripesize;
+ determine_read_sizes();
- minsize = sectorsize;
- bigsize = rounddown(bigsize, sectorsize);
+ work_buf = malloc(big_read);
+ assert (work_buf != NULL);
- error = ioctl(fdr, DIOCGMEDIASIZE, &tot_size);
- if (error < 0)
- err(1, "DIOCGMEDIASIZE failed");
+ if (argc > 1) {
+ write_fd = open(argv[1], O_WRONLY | O_CREAT, DEFFILEMODE);
+ if (write_fd < 0)
+ err(1, "Cannot open write descriptor %s", argv[1]);
+ if (ftruncate(write_fd, (off_t)total_size) < 0)
+ err(1, "Cannot truncate output %s to %ju bytes",
+ argv[1], (uintmax_t)total_size);
} else {
- tot_size = sb.st_size;
+ write_fd = -1;
}
- if (bigsize < minsize)
- bigsize = minsize;
-
- for (ch = 0; (bigsize >> ch) > minsize; ch++)
- continue;
- medsize = bigsize >> (ch / 2);
- medsize = rounddown(medsize, minsize);
-
- fprintf(stderr, "Bigsize = %zu, medsize = %zu, minsize = %zu\n",
- bigsize, medsize, minsize);
-
- buf = malloc(bigsize);
- if (buf == NULL)
- err(1, "Cannot allocate %zu bytes buffer", bigsize);
+ if (strlen(unreadable_pattern)) {
+ pattern_buf = malloc(big_read);
+ assert(pattern_buf != NULL);
+ fill_buf(pattern_buf, big_read, unreadable_pattern);
+ }
- if (argc > 1) {
- fdw = open(argv[1], O_WRONLY | O_CREAT, DEFFILEMODE);
- if (fdw < 0)
- err(1, "Cannot open write descriptor %s", argv[1]);
- if (ftruncate(fdw, tot_size) < 0)
- err(1, "Cannot truncate output %s to %jd bytes",
- argv[1], (intmax_t)tot_size);
- } else
- fdw = -1;
-
- if (rworklist != NULL) {
- done_size = read_worklist(tot_size);
+ if (read_worklist_file != NULL) {
+ done_size = total_size - read_worklist();
} else {
- new_lump(0, tot_size, 0);
+ new_lump(0UL, total_size, 0UL);
done_size = 0;
}
- if (wworklist != NULL)
+ if (write_worklist_file != NULL)
signal(SIGINT, sighandler);
- t1 = time(NULL);
sz = 0;
if (!verbose)
- report_header(0);
+ report_header("\n");
else
printf("\x1b[2J");
- n = 0;
- for (;;) {
- lp = TAILQ_FIRST(&lumps);
- if (lp == NULL)
- break;
- while (lp->len > 0) {
- if (lp->state == 0)
- sz = MIN(lp->len, (off_t)bigsize);
- else if (lp->state == 1)
- sz = MIN(lp->len, (off_t)medsize);
- else
- sz = MIN(lp->len, (off_t)minsize);
- assert(sz != 0);
-
- t2 = time(NULL);
- if (t1 != t2 || lp->len < (off_t)bigsize) {
- t1 = t2;
- if (++n == snapshot) {
- save_worklist();
- n = 0;
- }
- report(lp, sz);
- }
+ t_first = time(NULL);
+ t_report = t_first;
+ t_save = t_first;
+ unsaved = 0;
+ while (!aborting) {
+ t_now = time(NULL);
+ sz = attempt_one_lump(t_now);
+ error = errno;
- j = pread(fdr, buf, sz, lp->start);
-#if 0
-if (!(random() & 0xf)) {
- j = -1;
- errno = EIO;
-}
-#endif
- if (j == sz) {
- done_size += sz;
- if (fdw >= 0)
- write_buf(fdw, buf, sz, lp->start);
- lp->start += sz;
- lp->len -= sz;
- if (verbose && lp->state > 2)
- report_good_read(t2, sz);
- continue;
- }
- error = errno;
-
- printf("%jd %zu %d read error (%s)\n",
- lp->start, sz, lp->state, strerror(error));
- if (verbose)
- report(lp, sz);
- if (fdw >= 0 && strlen(unreadable_pattern)) {
- fill_buf(buf, sz, unreadable_pattern);
- write_buf(fdw, buf, sz, lp->start);
+ if (sz == 0) {
+ break;
+ }
+
+ if (sz > 0) {
+ unsaved += 1;
+ }
+ if (unsaved && (t_save + snapshot) < t_now) {
+ save_worklist();
+ unsaved = 0;
+ t_save = t_now;
+ if (!verbose) {
+ report_header("\n");
+ t_report = t_now;
}
- new_lump(lp->start, sz, lp->state + 1);
- lp->start += sz;
- lp->len -= sz;
- if (error == EINVAL) {
- printf("Try with -b 131072 or lower ?\n");
- aborting = 1;
- break;
+ }
+ if (sz > 0) {
+ if (verbose) {
+ account_good_read(t_now, sz);
}
- if (error == ENXIO) {
- printf("Input device probably detached...\n");
- aborting = 1;
- break;
+ if (t_report != t_now) {
+ report(sz);
+ t_report = t_now;
}
+ continue;
}
- if (aborting)
- save_worklist();
- if (aborting || !TAILQ_NEXT(lp, list))
- report(lp, sz);
- if (aborting)
+
+ monitor_read_sizes(-sz);
+
+ if (error == EINVAL) {
+ printf("Try with -b 131072 or lower ?\n");
+ aborting = 1;
break;
- assert(lp->len == 0);
- TAILQ_REMOVE(&lumps, lp, list);
- free(lp);
+ }
+ if (error == ENXIO) {
+ printf("Input device probably detached...\n");
+ aborting = 1;
+ break;
+ }
+ report(-sz);
+ t_report = t_now;
+ if (error_pause > 0) {
+ usleep((unsigned long)(1e6 * error_pause));
+ }
}
+ save_worklist();
+ free(work_buf);
+ if (pattern_buf != NULL)
+ free(pattern_buf);
printf("%s", aborting ? "Aborted\n" : "Completed\n");
- free(buf);
- return (0);
+ report(0UL);
+ return (0); // XXX
}
diff --git a/sbin/zfsbootcfg/zfsbootcfg.8 b/sbin/zfsbootcfg/zfsbootcfg.8
index 5e7f02b2578c..3831adfc81bd 100644
--- a/sbin/zfsbootcfg/zfsbootcfg.8
+++ b/sbin/zfsbootcfg/zfsbootcfg.8
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 22, 2020
+.Dd July 28, 2025
.Dt ZFSBOOTCFG 8
.Os
.Sh NAME
@@ -44,14 +44,11 @@
is used to set
.Xr boot.config 5 Ns -style
options to be used by
-.Xr zfsboot 8 ,
.Xr gptzfsboot 8
or
.Xr loader 8
the next time the machine is booted.
Once
-.Xr zfsboot 8
-or
.Xr gptzfsboot 8
or
.Xr loader 8
@@ -130,8 +127,7 @@ To clear the boot options:
.Xr boot.config 5 ,
.Xr bectl 8 ,
.Xr gptzfsboot 8 ,
-.Xr loader 8 ,
-.Xr zfsboot 8
+.Xr loader 8
.Sh HISTORY
.Nm
appeared in
diff --git a/share/examples/oci/Containerfile.pkg b/share/examples/oci/Containerfile.pkg
index 074c470affc9..f6699c79af71 100644
--- a/share/examples/oci/Containerfile.pkg
+++ b/share/examples/oci/Containerfile.pkg
@@ -6,7 +6,7 @@
ARG version=14.snap
# Select freebsd-runtime as our starting point.
-FROM localhost/freebsd-runtime:${version}
+FROM ghcr.io/freebsd/freebsd-runtime:${version}
# A list of package(s) to install
ARG packages
@@ -15,7 +15,10 @@ ARG packages
# use for downloading pkg since the freebsd-runtime image has both FreeBSD and
# FreeBSD-base pkg repo configs installed and FreeBSD-base does not contain the
# pkg package.
-RUN env ASSUME_ALWAYS_YES=yes pkg bootstrap -r FreeBSD && pkg update
+#
+# Set IGNORE_OSVERSION to allow building e.g. FreeBSD-14 images on
+# FreeBSD-15 hosts.
+RUN pkg bootstrap -y -r FreeBSD && pkg -o IGNORE_OSVERSION=yes update -f
# Install some package(s).
RUN pkg install -y ${packages}
diff --git a/share/man/man1/Makefile b/share/man/man1/Makefile
index 5b1d3ac1091d..d3975c8e8084 100644
--- a/share/man/man1/Makefile
+++ b/share/man/man1/Makefile
@@ -1,16 +1,17 @@
.include <src.opts.mk>
-MAN= builtin.1 intro.1
+MANGROUPS= MAN
-.if ${MK_TESTS} != "no"
-ATF= ${SRCTOP}/contrib/atf
-.PATH: ${ATF}/doc
-MAN+= atf-test-program.1
-.endif
+MANLINKS= intro.1 introduction.1
+
+MANGROUPS+= RUNTIME
+RUNTIME= builtin.1 intro.1
+RUNTIMEPACKAGE= runtime
# Create MLINKS for Shell built in commands for which there are no userland
# utilities of the same name:
-MLINKS= builtin.1 alias.1 \
+RUNTIMELINKS=\
+ builtin.1 alias.1 \
builtin.1 alloc.1 \
builtin.1 bg.1 \
builtin.1 bind.1 \
@@ -96,6 +97,13 @@ MLINKS= builtin.1 alias.1 \
builtin.1 wait.1 \
builtin.1 where.1 \
builtin.1 while.1
-MLINKS+=intro.1 introduction.1
+
+.if ${MK_TESTS} != "no"
+MANGROUPS+= TESTS
+ATF= ${SRCTOP}/contrib/atf
+.PATH: ${ATF}/doc
+TESTS= atf-test-program.1
+TESTSPACKAGE= tests
+.endif
.include <bsd.prog.mk>
diff --git a/share/man/man3/Makefile b/share/man/man3/Makefile
index 6cdd443ec067..3511acb254e1 100644
--- a/share/man/man3/Makefile
+++ b/share/man/man3/Makefile
@@ -1,5 +1,7 @@
.include <src.opts.mk>
+PACKAGE= clibs
+
MAN= alloca.3 \
arb.3 \
assert.3 \
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index 505e83a67369..1ba1fe46523e 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -1,5 +1,8 @@
.include <src.opts.mk>
+MANGROUPS= MAN
+MANPACKAGE= kernel
+
# If you add a new file here, please consider adding an entry to the
# hardware notes template (website/archetypes/release/hardware.adoc in
# the doc repository); otherwise the automatically generated hardware
@@ -58,7 +61,6 @@ MAN= aac.4 \
atkbdc.4 \
${_atopcase.4} \
atp.4 \
- ${_atf_test_case.4} \
${_atrtc.4} \
${_attimer.4} \
audit.4 \
@@ -1023,9 +1025,11 @@ MAN+= mlx5io.4
.endif
.if ${MK_TESTS} != "no"
+MANGROUPS+= TESTS
ATF= ${SRCTOP}/contrib/atf
.PATH: ${ATF}/doc
-_atf_test_case.4= atf-test-case.4
+TESTS= atf-test-case.4
+TESTSPACKAGE= tests
.endif
.if ${MK_PF} != "no"
diff --git a/share/man/man4/gif.4 b/share/man/man4/gif.4
index 959510451011..ad33d5d21e81 100644
--- a/share/man/man4/gif.4
+++ b/share/man/man4/gif.4
@@ -1,6 +1,7 @@
.\" $KAME: gif.4,v 1.28 2001/05/18 13:15:56 itojun Exp $
.\"
.\" Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
+.\" Copyright (C) 2024 Hiroki Sato <hrs@FreeBSD.org>
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -27,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd October 21, 2018
+.Dd July 14, 2025
.Dt GIF 4
.Os
.Sh NAME
@@ -67,8 +68,8 @@ variable in
.Pp
To use
.Nm ,
-the administrator needs to configure the protocol and addresses used for the outer
-header.
+the administrator needs to configure the protocol and addresses used for
+the outer header.
This can be done by using
.Xr ifconfig 8
.Cm tunnel ,
@@ -79,8 +80,7 @@ The administrator also needs to configure the protocol and addresses for the
inner header, with
.Xr ifconfig 8 .
Note that IPv6 link-local addresses
-(those that start with
-.Li fe80:: )
+.Pq those that start with Li fe80\&:\&:
will be automatically configured whenever possible.
You may need to remove IPv6 link-local addresses manually using
.Xr ifconfig 8 ,
@@ -89,12 +89,139 @@ if you want to disable the use of IPv6 as the inner header
Finally, you must modify the routing table to route the packets through the
.Nm
interface.
+.Ss MTU Configuration and Path MTU Discovery
+The
+.Nm
+interface uses the fixed length,
+.Li 1280 ,
+to determine whether the outgoing IPv6 packets are split.
+This means the MTU value configured on the interface will be ignored
+when the outer protocol is IPv6.
+When the
+.Dv NOCLAMP
+interface flag is set,
+.Nm
+uses the same configured value as IPv4 communications.
+This behavior prevents potential issues when the path MTU is
+smaller than the interface MTU.
+This section describes the reason why the default behavior is different.
+The
+.Dv NOCLAMP
+interface flag can be set using the following command:
+.Pp
+.Dl ifconfig Ar gif0 Cm noclamp
+.Pp
+and clear the flag using the following:
+.Pp
+.Dl ifconfig Ar gif0 Cm -noclamp
+.Pp
+where
+.Ar gif0
+is the actual interface name.
+.Pp
+A tunnel interface always has an implicit smaller MTU for the inner protocol
+than the outer protocol because of the additional header.
+Note that the interface MTU on a
+.Nm
+interface,
+the default value is
+.Li 1280 ,
+is used as MTU for the outer protocol.
+This means that the MTU for the inner protocol varies depending on the
+outer protocol header length.
+If an outgoing packet bigger than the inner protocol MTU arrives at a
+.Nm
+interface for encapsulation,
+it will be split into fragments.
+Specifically,
+if IPv4 is used as the outer protocol,
+the inner is 20 octets smaller than the interface MTU.
+In the case of the default interface MTU,
+.Li 1280 ,
+inner packets bigger than
+.Li 1260
+will be fragmented.
+In the case of IPv6,
+the inner is 40 octets smaller than the outer.
+.Pp
+This fragmentation is not harmful though it can degrade the
+performance.
+Note that while an increased MTU on
+.Nm
+interface helps to mitigate this reduced performance issue,
+it can also cause packet losses on the intermediate narrowest path
+between the two communication endpoints in IPv6.
+IPv6 allows fragmentation only on the sender,
+not on the routers in the communication path.
+A big outgoing packet will be dropped on a router with a smaller MTU.
.Pp
+In normal IPv6 communication,
+an ICMPv6 Packet Too Big error will be sent back to the sender,
+who can adjust the packet length and re-send it.
+This process is performed in the upper protocols than L3,
+such as TCP,
+and makes the packet length shorter so that packets go through
+the path without fragmentation.
+This behavior is known as path MTU discovery.
+.Pp
+When using a
+.Nm
+interface,
+the Packet Too Big message is generated for the outer protocol.
+Since the
+.Nm
+interface does not translate this error to the inner protocol,
+the inner protocol sees it just as a packet loss with no useful
+information to adjust the length of the next packets.
+In this situation,
+path MTU discovery does not work,
+and communications of the inner protocol
+become stalled.
+.Pp
+In order to avoid this,
+a
+.Nm
+interface silently splits a packet of over 1240 octets into fragments to make
+the outer protocol packets equal or shorter than 1280 octets,
+even when the interface MTU is configured as larger than 1280.
+Note that this occurs only when the outer protocol is IPv6.
+.Li 1280
+is the smallest MTU in IPv6 and guarantees no packet loss occurs
+on intermediate routers.
+.Pp
+As mentioned earlier,
+the performance is sub-optimal if the actual path MTU is larger than
+.Li 1280 .
+A typical confusing scenario is as follows.
The
.Nm
-device can be configured to be ECN friendly.
-This can be configured by
-.Dv IFF_LINK1 .
+interface can have Ethernet,
+whose MTU is usually 1500,
+as the inner protocol.
+It is called an EtherIP tunnel,
+and can be configured by adding the
+.Nm
+interface as a member of
+.Xr if_bridge 4
+interface.
+The
+.Xr if_bridge 4
+interface forcibly changes the MTU of the
+.Nm
+interface with those for the other member interfaces,
+which are likely 1500.
+In this case,
+a situation in which the MTU of the
+.Nm
+interface is 1500 but fragmentation in 1280 octets always occurs.
+.Pp
+The default behavior is most conservative to prevent confusing packet loss.
+Depending on the network configuration,
+enabling the
+.Dv NOCLAMP
+interface flag might be helpful for better performance.
+It is crucial to ensure that the path MTU is equal to or larger than
+the interface MTU when enabling this flag.
.Ss ECN friendly behavior
The
.Nm
@@ -169,6 +296,7 @@ variable
to the desired level of nesting.
.Sh SEE ALSO
.Xr gre 4 ,
+.Xr if_bridge 4 ,
.Xr inet 4 ,
.Xr inet6 4 ,
.Xr ifconfig 8
@@ -199,7 +327,8 @@ There are many tunnelling protocol specifications, all
defined differently from each other.
The
.Nm
-device may not interoperate with peers which are based on different specifications,
+device may not interoperate with peers which are based on different
+specifications,
and are picky about outer header fields.
For example, you cannot usually use
.Nm
@@ -219,11 +348,14 @@ to 1240 or smaller, when the outer header is IPv6 and the inner header is IPv4.
.Pp
The
.Nm
-device does not translate ICMP messages for the outer header into the inner header.
+device does not translate ICMP messages for the outer header into the inner
+header.
.Pp
In the past,
.Nm
had a multi-destination behavior, configurable via
-.Dv IFF_LINK0
+.Dv NOCLAMP
flag.
The behavior is obsolete and is no longer supported.
+This flag is now used to determine whether performing fragmentation when
+the outer protocol is IPv6.
diff --git a/share/man/man4/ice.4 b/share/man/man4/ice.4
index 63fdb244f3ed..3f7a9017756d 100644
--- a/share/man/man4/ice.4
+++ b/share/man/man4/ice.4
@@ -32,18 +32,18 @@
.\"
.\" * Other names and brands may be claimed as the property of others.
.\"
-.Dd May 20, 2024
+.Dd March 28, 2025
.Dt ICE 4
.Os
.Sh NAME
.Nm ice
-.Nd "Intel Ethernet 800 Series Driver"
+.Nd "Intel\(rg Ethernet 800 Series 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 iflib"
-.Cd "device ice"
+.Bd -literal -offset indent
+.Cd device iflib
+.Cd device ice
.Ed
.Pp
To load the driver as a module at boot time, place the following lines in
@@ -57,7 +57,7 @@ The
.Nm
driver provides support for any PCI Express adapter or LOM
(LAN On Motherboard)
-in the Intel Ethernet 800 Series.
+in the Intel\(rg Ethernet 800 Series.
As of this writing, the series includes devices with these model numbers:
.Pp
.Bl -bullet -compact
@@ -73,6 +73,16 @@ Intel\(rg Ethernet Connection E822\-L
Intel\(rg Ethernet Connection E823\-C
.It
Intel\(rg Ethernet Connection E823\-L
+.It
+Intel\(rg Ethernet Connection E825\-C
+.It
+Intel\(rg Ethernet Connection E830\-C
+.It
+Intel\(rg Ethernet Connection E830\-CC
+.It
+Intel\(rg Ethernet Connection E830\-L
+.It
+Intel\(rg Ethernet Connection E830\-XXV
.El
.Pp
For questions related to hardware requirements, refer to the documentation
@@ -83,11 +93,17 @@ Selecting an MTU larger than 1500 bytes with the
.Xr ifconfig 8
utility configures the adapter to receive and transmit Jumbo Frames.
The maximum MTU size for Jumbo Frames is 9706.
-This value coincides with the maximum Jumbo Frame size of 9728.
+For more information, see the
+.Sx Jumbo Frames
+section.
.Pp
This driver version supports VLANs.
-For information on enabling VLANs, see the
-.Pa README .
+For information on enabling VLANs, see
+.Xr vlan 4 .
+For additional information on configuring VLANs, see
+.Xr ifconfig 8 Ap s
+.Dq VLAN Parameters
+section.
.Pp
Offloads are also controlled via the interface, for instance, checksumming for
both IPv4 and IPv6 can be set and unset, TSO4 and/or TSO6, and finally LRO can
@@ -95,29 +111,739 @@ be set and unset.
.Pp
For more information on configuring this device, see
.Xr ifconfig 8 .
+.Pp
+The associated Virtual Function (VF) driver for this driver is
+.Xr iavf 4 .
+.Pp
+The associated RDMA driver for this driver is
+.Xr irdma 4 .
+.Ss Dynamic Device Personalization
+The DDP package loads during device initialization.
+The driver looks for the
+.Sy ice_ddp
+module and checks that it contains a valid DDP package file.
+.Pp
+If the driver is unable to load the DDP package, the device will enter Safe
+Mode.
+Safe Mode disables advanced and performance features and supports only
+basic traffic and minimal functionality, such as updating the NVM or
+downloading a new driver or DDP package.
+Safe Mode only applies to the affected physical function and does not impact
+any other PFs.
+See the
+.Dq Intel\(rg Ethernet Adapters and Devices User Guide
+for more details on DDP and Safe Mode.
+.Pp
+If you encounter issues with the DDP package file, you may need to download
+an updated driver or
+.Sy ice_ddp
+module.
+See the log messages for more information.
+.Pp
+You cannot update the DDP package if any PF drivers are already loaded.
+To overwrite a package, unload all PFs and then reload the driver with the
+new package.
+.Pp
+You can only use one DDP package per driver, even if you have more than one
+device installed that uses the driver.
+.Pp
+Only the first loaded PF per device can download a package for that device.
+.Ss Jumbo Frames
+Jumbo Frames support is enabled by changing the Maximum Transmission Unit (MTU)
+to a value larger than the default value of 1500.
+.Pp
+Use
+.Xr ifconfig 8
+to increase the MTU size.
+.Pp
+The maximum MTU setting for jumbo frames is 9706.
+This corresponds to the maximum jumbo frame size of 9728 bytes.
+.Pp
+This driver will attempt to use multiple page sized buffers to receive
+each jumbo packet.
+This should help to avoid buffer starvation issues when allocating receive
+packets.
+.Pp
+Packet loss may have a greater impact on throughput when you use jumbo
+frames.
+If you observe a drop in performance after enabling jumbo frames, enabling
+flow control may mitigate the issue.
+.Ss Remote Direct Memory Access
+Remote Direct Memory Access, or RDMA, allows a network device to transfer data
+directly to and from application memory on another system, increasing
+throughput and lowering latency in certain networking environments.
+.Pp
+The ice driver supports both the iWARP (Internet Wide Area RDMA Protocol) and
+RoCEv2 (RDMA over Converged Ethernet) protocols.
+The major difference is that iWARP performs RDMA over TCP, while RoCEv2 uses
+UDP.
+.Pp
+Devices based on the Intel\(rg Ethernet 800 Series do not support RDMA when
+operating in multiport mode with more than 4 ports.
+.Pp
+For detailed installation and configuration information for RDMA, see
+.Xr irdma 4 .
+.Ss RDMA Monitoring
+For debugging/testing purposes, you can use sysctl to set up a mirroring
+interface on a port.
+The interface can receive mirrored RDMA traffic for packet
+analysis tools like
+.Xr tcpdump 1 .
+This mirroring may impact performance.
+.Pp
+To use RDMA monitoring, you may need to reserve more MSI\-X interrupts.
+Before the
+.Nm
+driver loads, configure the following tunable provided by
+.Xr iflib 4 :
+.Bd -literal -offset indent
+dev.ice.<interface #>.iflib.use_extra_msix_vectors=4
+.Ed
+.Pp
+You may need to adjust the number of extra MSI\-X interrupt vectors.
+.Pp
+To create/delete the interface:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.create_interface=1
+sysctl dev.ice.<interface #>.delete_interface=1
+.Ed
+.Pp
+The mirrored interface receives both LAN and RDMA traffic.
+Additional filters can be configured in tcpdump.
+.Pp
+To differentiate the mirrored interface from the primary interface, the network
+interface naming convention is:
+.Bd -literal -offset indent
+<driver name><port number><modifier><modifier unit number>
+.Ed
+.Pp
+For example,
+.Dq Li ice0m0
+is the first mirroring interface on
+.Dq Li ice0 .
+.Ss Data Center Bridging
+Data Center Bridging (DCB) is a configuration Quality of Service
+implementation in hardware.
+It uses the VLAN priority tag (802.1p) to filter traffic.
+That means that there are 8 different priorities that traffic can be filtered
+into.
+It also enables priority flow control (802.1Qbb) which can limit or eliminate
+the number of dropped packets during network stress.
+Bandwidth can be allocated to each of these priorities, which is enforced at
+the hardware level (802.1Qaz).
+.Pp
+DCB is normally configured on the network using the DCBX protocol (802.1Qaz), a
+specialization of LLDP (802.1AB). The
+.Nm
+driver supports the following mutually exclusive variants of DCBX support:
+.Bl -bullet -compact
+.It
+Firmware\-based LLDP Agent
+.It
+Software\-based LLDP Agent
+.El
+.Pp
+In firmware\-based mode, firmware intercepts all LLDP traffic and handles DCBX
+negotiation transparently for the user.
+In this mode, the adapter operates in
+.Dq willing
+DCBX mode, receiving DCB settings from the link partner (typically a
+switch).
+The local user can only query the negotiated DCB configuration.
+For information on configuring DCBX parameters on a switch, please consult the
+switch manufacturer'ss documentation.
+.Pp
+In software\-based mode, LLDP traffic is forwarded to the network stack and user
+space, where a software agent can handle it.
+In this mode, the adapter can operate in
+.Dq nonwilling
+DCBX mode and DCB configuration can be both queried and set locally.
+This mode requires the FW\-based LLDP Agent to be disabled.
+.Pp
+Firmware\-based mode and software\-based mode are controlled by the
+.Dq fw_lldp_agent
+sysctl.
+Refer to the Firmware Link Layer Discovery Protocol Agent section for more
+information.
+.Pp
+Link\-level flow control and priority flow control are mutually exclusive.
+The ice driver will disable link flow control when priority flow control
+is enabled on any traffic class (TC).
+It will disable priority flow control when link flow control is enabled.
+.Pp
+To enable/disable priority flow control in software\-based DCBX mode:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.pfc=1 (or 0 to disable)
+.Ed
+.Pp
+Enhanced Transmission Selection (ETS) allows you to assign bandwidth to certain
+TCs, to help ensure traffic reliability.
+To view the assigned ETS configuration, use the following:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.ets_min_rate
+.Ed
+.Pp
+To set the minimum ETS bandwidth per TC, separate the values by commas.
+All values must add up to 100.
+For example, to set all TCs to a minimum bandwidth of 10% and TC 7 to 30%,
+use the following:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.ets_min_rate=10,10,10,10,10,10,10,30
+.Ed
+.Pp
+To set the User Priority (UP) to a TC mapping for a port, separate the values
+by commas.
+For example, to map UP 0 and 1 to TC 0, UP 2 and 3 to TC 1, UP 4 and
+5 to TC 2, and UP 6 and 7 to TC 3, use the following:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.up2tc_map=0,0,1,1,2,2,3,3
+.Ed
+.Ss L3 QoS mode
+The
+.Nm
+driver supports setting DSCP\-based Layer 3 Quality of Service (L3 QoS)
+in the PF driver.
+The driver initializes in L2 QoS mode by default; L3 QoS is disabled by
+default.
+Use the following sysctl to enable or disable L3 QoS:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.pfc_mode=1 (or 0 to disable)
+.Ed
+.Pp
+If you disable L3 QoS mode, it returns to L2 QoS mode.
+.Pp
+To map a DSCP value to a traffic class, separate the values by commas.
+For example, to map DSCPs 0\-3 and DSCP 8 to DCB TCs 0\-3 and 4, respectively:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.dscp2tc_map.0\-7=0,1,2,3,0,0,0,0
+sysctl dev.ice.<interface #>.dscp2tc_map.8\-15=4,0,0,0,0,0,0,0
+.Ed
+.Pp
+To change the DSCP mapping back to the default traffic class, set all the
+values back to 0.
+.Pp
+To view the currently configured mappings, use the following:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.dscp2tc_map
+.Ed
+.Pp
+L3 QoS mode is not available when FW\-LLDP is enabled.
+.Pp
+You also cannot enable FW\-LLDP if L3 QoS mode is active.
+.Pp
+Disable FW\-LLDP before switching to L3 QoS mode.
+.Pp
+Refer to the
+.Sx Firmware Link Layer Discovery Protocol Agent
+section in this README for more information on disabling FW\-LLDP.
+.Ss Firmware Link Layer Discovery Protocol Agent
+Use sysctl to change FW\-LLDP settings.
+The FW\-LLDP setting is per port and persists across boots.
+.Pp
+To enable the FW\-LLDP Agent:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.fw_lldp_agent=1
+.Ed
+.Pp
+To disable the FW\-LLDP Agebt:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.fw_lldp_agent=0
+.Ed
+.Pp
+To check the current LLDP setting:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.fw_lldp_agent
+.Ed
+.Pp
+You must enable the UEFI HII LLDP Agent attribute for this setting
+to take effect.
+If the
+.Dq LLDP AGENT
+attribute is set to disabled, you cannot enable the FW\-LLDP Agent from the
+driver.
+.Ss Link\-Level Flow Control (LFC)
+Ethernet Flow Control (IEEE 802.3x) can be configured with sysctl to enable
+receiving and transmitting pause frames for
+.Nm .
+When transmit is enabled, pause frames are generated when the receive packet
+buffer crosses a predefined threshold.
+When receive is enabled, the transmit unit will halt for the time delay
+specified in the firmware when a pause frame is received.
+.Pp
+Flow Control is disabled by default.
+.Pp
+Use sysctl to change the flow control settings for a single interface without
+reloading the driver:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.fc
+.Ed
+.Pp
+The available values for flow control are:
+.Bd -literal -offset indent
+0 = Disable flow control
+1 = Enable Rx pause
+2 = Enable Tx pause
+3 = Enable Rx and Tx pause
+.Ed
+.Pp
+Verify that link flow control was negotiated on the link by checking the
+interface entry in
+.Xr ifconfig 8
+and looking for the flags
+.Dq txpause
+and/or
+.Dq rxpause
+in the
+.Dq media
+status.
+.Pp
+The
+.Nm
+driver requires flow control on both the port and link partner.
+If flow control is disabled on one of the sides, the port may appear to
+hang on heavy traffic.
+.Pp
+For more information on priority flow control, refer to the
+.Sx Data Center Bridging
+section.
+.Pp
+The VF driver does not have access to flow control.
+It must be managed from the host side.
+.Ss Forward Error Correction
+Forward Error Correction (FEC) improves link stability but increases latency.
+Many high quality optics, direct attach cables, and backplane channels can
+provide a stable link without FEC.
+.Pp
+For devices to benefit from this feature, link partners must have FEC enabled.
+.Pp
+If you enable the sysctl
+.Em allow_no_fec_modules_in_auto
+Auto FEC negotiation will include
+.Dq No FEC
+in case your link partner does not have FEC enabled or is not FEC capable:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.allow_no_fec_modules_in_auto=1
+.Ed
+.Pp
+NOTE: This flag is currently not supported on the Intel\(rg Ethernet 830
+Series.
+.Pp
+To show the current FEC settings that are negotiated on the link:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.negotiated_fec
+.Ed
+.Pp
+To view or set the FEC setting that was requested on the link:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.requested_fec
+.Ed
+.Pp
+To see the valid FEC modes for the link:
+.Bd -literal -offset indent
+sysctl \-d dev.ice.<interface #>.requested_fec
+.Ed
+.Ss Speed and Duplex Configuration
+You cannot set duplex or autonegotiation settings.
+.Pp
+To have your device change the speeds it will use in auto-negotiation or
+force link with:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.advertise_speed=<mask>
+.Ed
+.Pp
+Supported speeds will vary by device.
+Depending on the speeds your device supports, valid bits used in a speed mask
+could include:
+.Bd -literal -offset indent
+0x0 \- Auto
+0x2 \- 100 Mbps
+0x4 \- 1 Gbps
+0x8 \- 2.5 Gbps
+0x10 \- 5 Gbps
+0x20 \- 10 Gbps
+0x80 \- 25 Gbps
+0x100 \- 40 Gbps
+0x200 \- 50 Gbps
+0x400 \- 100 Gbps
+0x800 \- 200 Gbps
+.Ed
+.Ss Disabling physical link when the interface is brought down
+When the
+.Va link_active_on_if_down
+sysctl is set to
+.Dq 0 ,
+the port's link will go down when the interface is brought down.
+By default, link will stay up.
+.Pp
+To disable link when the interface is down:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.link_active_on_if_down=0
+.Ed
+.Ss Firmware Logging
+The
+.Nm
+driver allows for the generation of firmware logs for supported categories of
+events, to help debug issues with Customer Support.
+Refer to the
+.Dq Intel\(rg Ethernet Adapters and Devices User Guide
+for an overview of this feature and additional tips.
+.Pp
+At a high level, to capture a firmware log:
+.Bl -enum -compact
+.It
+Set the configuration for the firmware log.
+.It
+Perform the necessary steps to generate the issue you are trying to debug.
+.It
+Capture the firmware log.
+.It
+Stop capturing the firmware log.
+.It
+Reset your firmware log settings as needed.
+.It
+Work with Customer Support to debug the issue.
+.El
+.Pp
+NOTE: Firmware logs are generated in a binary format and must be decoded by
+Customer Support.
+Information collected is related only to firmware and hardware for debug
+purposes.
+.Pp
+Once the driver is loaded, it will create the
+.Va fw_log
+sysctl node under the debug section of the driver's sysctl list.
+The driver groups these events into categories, called
+.Dq modules .
+Supported modules include:
+.Pp
+.Bl -tag -offset indent -compact -width "task_dispatch"
+.It Va general
+General (Bit 0)
+.It Va ctrl
+Control (Bit 1)
+.It Va link
+Link Management (Bit 2)
+.It Va link_topo
+Link Topology Detection (Bit 3)
+.It Va dnl
+Link Control Technology (Bit 4)
+.It Va i2c
+I2C (Bit 5)
+.It Va sdp
+SDP (Bit 6)
+.It Va mdio
+MDIO (Bit 7)
+.It Va adminq
+Admin Queue (Bit 8)
+.It Va hdma
+Host DMA (Bit 9)
+.It Va lldp
+LLDP (Bit 10)
+.It Va dcbx
+DCBx (Bit 11)
+.It Va dcb
+DCB (Bit 12)
+.It Va xlr
+XLR (function\-level resets; Bit 13)
+.It Va nvm
+NVM (Bit 14)
+.It Va auth
+Authentication (Bit 15)
+.It Va vpd
+Vital Product Data (Bit 16)
+.It Va iosf
+Intel On\-Chip System Fabric (Bit 17)
+.It Va parser
+Parser (Bit 18)
+.It Va sw
+Switch (Bit 19)
+.It Va scheduler
+Scheduler (Bit 20)
+.It Va txq
+TX Queue Management (Bit 21)
+.It Va acl
+ACL (Access Control List; Bit 22)
+.It Va post
+Post (Bit 23)
+.It Va watchdog
+Watchdog (Bit 24)
+.It Va task_dispatch
+Task Dispatcher (Bit 25)
+.It Va mng
+Manageability (Bit 26)
+.It Va synce
+SyncE (Bit 27)
+.It Va health
+Health (Bit 28)
+.It Va tsdrv
+Time Sync (Bit 29)
+.It Va pfreg
+PF Registration (Bit 30)
+.It Va mdlver
+Module Version (Bit 31)
+.El
+.Pp
+You can change the verbosity level of the firmware logs.
+You can set only one log level per module, and each level includes the
+verbosity levels lower than it.
+For instance, setting the level to
+.Dq normal
+will also log warning and error messages.
+Available verbosity levels are:
+.Pp
+.Bl -item -offset indent -compact
+.It
+0 = none
+.It
+1 = error
+.It
+2 = warning
+.It
+3 = normal
+.It
+4 = verbose
+.El
+.Pp
+To set the desired verbosity level for a module, use the following sysctl
+command and then register it:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.debug.fw_log.severity.<module>=<level>
+.Ed
+.Pp
+For example:
+.Bd -literal -offset indent
+sysctl dev.ice.0.debug.fw_log.severity.link=1
+sysctl dev.ice.0.debug.fw_log.severity.link_topo=2
+sysctl dev.ice.0.debug.fw_log.register=1
+.Ed
+.Pp
+To log firmware messages after booting, but before the driver initializes, use
+.Xr kenv 1
+to set the tunable.
+The
+.Va on_load
+setting tells the device to register the variable as soon as possible during
+driver load.
+For example:
+.Bd -literal -offset indent
+kenv dev.ice.0.debug.fw_log.severity.link=1
+kenv dev.ice.0.debug.fw_log.severity.link_topo=2
+kenv dev.ice.0.debug.fw_log.on_load=1
+.Ed
+.Pp
+To view the firmware logs and redirect them to a file, use the following
+command:
+.Bd -literal -offset indent
+dmesg > log_output
+.Ed
+.Pp
+NOTE: Logging a large number of modules or too high of a verbosity level will
+add extraneous messages to dmesg and could hinder debug efforts.
+.Ss Debug Dump
+Intel\(rg Ethernet 800 Series devices support debug dump, which allows you to
+obtain runtime register values from the firmware for
+.Dq clusters
+of events and then write the results to a single dump file, for debugging
+complicated issues in the field.
+.Pp
+This debug dump contains a snapshot of the device and its existing hardware
+configuration, such as switch tables, transmit scheduler tables, and other
+information.
+Debug dump captures the current state of the specified cluster(s) and is a
+stateless snapshot of the whole device.
+.Pp
+NOTE: Like with firmware logs, the contents of the debug dump are not
+human\-readable.
+You must work with Customer Support to decode the file.
+.Pp
+Debug dump is per device, not per PF.
+.Pp
+Debug dump writes all information to a single file.
+.Pp
+To generate a debug dump file in
+.Fx
+do the following:
+.Pp
+Specify the cluster(s) to include in the dump file, using a bitmask and the
+following command:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.debug.dump.clusters=<bitmask>
+.Ed
+.Pp
+To print the complete cluster bitmask and parameter list to the screen,
+pass the
+.Fl d
+argument.
+For example:
+.Bd -literal -offset indent
+sysctl \-d dev.ice.0.debug.dump.clusters
+.Ed
+.Pp
+Possible bitmask values for
+.Va clusters
+are:
+.Bl -bullet -compact
+.It
+0 \- Dump all clusters (only supported on Intel\(rg Ethernet E810 Series and
+Intel\(rg Ethernet E830 Series)
+.It
+0x1 \- Switch
+.It
+0x2 \- ACL
+.It
+0x4 \- Tx Scheduler
+.It
+0x8 \- Profile Configuration
+.It
+0x20 \- Link
+.It
+0x80 \- DCB
+.It
+0x100 \- L2P
+.It
+0x400000 \- Manageability Transactions (only supported on Intel\(rg Ethernet
+E810 Series)
+.El
+.Pp
+For example, to dump the Switch, DCB, and L2P clusters, use the following:
+.Bd -literal -offset indent
+sysctl dev.ice.0.debug.dump.clusters=0x181
+.Ed
+.Pp
+To dump all clusters, use the following:
+.Bd -literal -offset indent
+sysctl dev.ice.0.debug.dump.clusters=0
+.Ed
+.Pp
+NOTE: Using 0 will skip Manageability Transactions data.
+.Pp
+If you don't specify a cluster, the driver will dump all clusters to a
+single file.
+Issue the debug dump command, using the following:
+.Bd -literal -offset indent
+sysctl \-b dev.ice.<interface #>.debug.dump.dump=1 > dump.bin
+.Ed
+.Pp
+NOTE: The driver will not receive the command if you do not write
+.Dq 1
+to the sysctl.
+.Pp
+Replace
+.Dq dump.bin
+above with the file name you want to use.
+.Pp
+To clear the
+.Va clusters
+mask before a subsequent debug dump and then do the dump:
+.Bd -literal -offset indent
+sysctl dev.ice.0.debug.dump.clusters=0
+sysctl dev.ice.0.debug.dump.dump=1
+.Ed
+.Ss Debugging PHY Statistics
+The ice driver supports the ability to obtain the values of the PHY registers
+from Intel(R) Ethernet 810 Series devices in order to debug link and
+connection issues during runtime.
+.Pp
+The driver allows you to obtain information about:
+.Bl -bullet
+.It
+Rx and Tx Equalization parameters
+.It
+RS FEC correctable and uncorrectable block counts
+.El
+.Pp
+Use the following sysctl to read the PHY registers:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.debug.phy_statistics
+.Ed
+.Pp
+NOTE: The contents of the registers are not human\-readable.
+Like with firmware logs and debug dump, you must work with Customer Support
+to decode the file.
+.Ss Transmit Balancing
+Some Intel(R) Ethernet 800 Series devices allow you to enable a transmit
+balancing feature to improve transmit performance under certain conditions.
+When the feature is enabled, you should experience more consistent transmit
+performance across queues and/or PFs and VFs.
+.Pp
+By default, transmit balancing is disabled in the NVM.
+To enable this feature, use one of the following to persistently change the
+setting for the device:
+.Bl -bullet
+.It
+Use the Ethernet Port Configuration Tool (EPCT) to enable the
+.Va tx_balancing
+option.
+Refer to the EPCT readme for more information.
+.It
+Enable the Transmit Balancing device setting in UEFI HII.
+.El
+.Pp
+When the driver loads, it reads the transmit balancing setting from the NVM and
+configures the device accordingly.
+.Pp
+NOTE: The user selection for transmit balancing in EPCT or HII is persistent
+across reboots.
+You must reboot the system for the selected setting to take effect.
+.Pp
+This setting is device wide.
+.Pp
+The driver, NVM, and DDP package must all support this functionality to
+enable the feature.
+.Ss Thermal Monitoring
+Intel(R) Ethernet 810 Series and Intel(R) Ethernet 830 Series devices can
+display temperature data (in degrees Celsius) via:
+.Bd -literal -offset indent
+sysctl dev.ice.<interface #>.temp
+.Ed
+.Ss Network Memory Buffer Allocation
+.Fx
+may have a low number of network memory buffers (mbufs) by default.
+If the number of mbufs available is too low, it may cause the driver to fail
+to initialize and/or cause the system to become unresponsive.
+You can check to see if the system is mbuf\-starved by running
+.Ic netstat Fl m .
+Increase the number of mbufs by editing the lines below in
+.Pa /etc/sysctl.conf :
+.Bd -literal -offset indent
+kern.ipc.nmbclusters
+kern.ipc.nmbjumbop
+kern.ipc.nmbjumbo9
+kern.ipc.nmbjumbo16
+kern.ipc.nmbufs
+.Ed
+.Pp
+The amount of memory that you allocate is system specific, and may require some
+trial and error.
+Also, increasing the following in
+.Pa /etc/sysctl.conf
+could help increase network performance:
+.Bd -literal -offset indent
+kern.ipc.maxsockbuf
+net.inet.tcp.sendspace
+net.inet.tcp.recvspace
+net.inet.udp.maxdgram
+net.inet.udp.recvspace
+.Ed
.Ss Additional Utilities
There are additional tools available from Intel to help configure and update
the adapters covered by this driver.
These tools can be downloaded directly from Intel at
.Lk https://downloadcenter.intel.com ,
-by searching for their names, or by installing certain packages:
+by searching for their names:
.Bl -bullet
.It
-To change the behavior of the QSFP28 ports on E810-C adapters, use the
-Intel EPCT (Ethernet Port configuration tool); installed by the
-.Em sysutils/intel-epct
-package.
+To change the behavior of the QSFP28 ports on E810-C adapters, use the Intel
+.Sy Ethernet Port Configuration Tool - FreeBSD .
.It
-To update the firmware on an adapter, use the Intel Non-Volatile Memory (NVM)
-Update Utility for Intel Network Adapter 800 series; installed by the
-.Em sysutils/intel-nvmupdate-100g
-package.
+To update the firmware on an adapter, use the Intel
+.Sy Non-Volatile Memory (NVM) Update Utility for Intel Ethernet Network Adapters E810 series - FreeBSD
.El
.Sh HARDWARE
The
.Nm
driver supports the Intel Ethernet 800 series.
-Most adapters in this series with SFP28/QSFP28 cages
+Some adapters in this series with SFP28/QSFP28 cages
have firmware that requires that Intel qualified modules are used; these
qualified modules are listed below.
This qualification check cannot be disabled by the driver.
@@ -173,6 +899,38 @@ SFF-8472 v10.4 specifications.
.Pp
This is not an exhaustive list; please consult product documentation for an
up-to-date list of supported media.
+.Ss Fiber optics and auto\-negotiation
+Modules based on 100GBASE\-SR4, active optical cable (AOC), and active copper
+cable (ACC) do not support auto\-negotiation per the IEEE specification.
+To obtain link with these modules, auto\-negotiation must be turned off on the
+link partner's switch ports.
+.Ss PCI-Express Slot Bandwidth
+Some PCIe x8 slots are actually configured as x4 slots.
+These slots have insufficient bandwidth for full line rate with dual port and
+quad port devices.
+In addition, if you put a PCIe v4.0 or v3.0\-capable adapter into a PCIe v2.x
+slot, you cannot get full bandwidth.
+.Pp
+The driver detects this situation and writes the following message in the
+system log:
+.Bd -literal -offset indent
+PCI\-Express bandwidth available for this device may be insufficient for
+optimal performance.
+Please move the device to a different PCI\-e link with more lanes and/or
+higher transfer rate.
+.Ed
+.Pp
+If this error occurs, moving your adapter to a true PCIe x8 or x16 slot will
+resolve the issue.
+For best performance, install devices in the following PCI slots:
+.Bl -bullet
+.It
+Any 100Gbps\-capable Intel(R) Ethernet 800 Series device: Install in a
+PCIe v4.0 x8 or v3.0 x16 slot
+.It
+A 200Gbps\-capable Intel(R) Ethernet 830 Series device: Install in a
+PCIe v5.0 x8 or v4.0 x16 slot
+.El
.Sh LOADER TUNABLES
Tunables can be set at the
.Xr loader 8
@@ -182,42 +940,62 @@ See the
.Xr iflib 4
man page for more information on using iflib sysctl variables as tunables.
.Bl -tag -width indent
-.It Va hw.ice.#.enable_health_events
-TBW
-.It Va hw.ice.#.debug.enable_tx_fc_filter
-TBW
-.It Va hw.ice.#.debug.enable_tx_lldp_filter
-TBW
-.It Va hw.ice.#.debug.enable_health_events
-TBW
-.El
-.Sh SYSCTL PROCEDURES
+.It Va hw.ice.enable_health_events
+Set to 1 to enable firmware health event reporting across all devices.
+Enabled by default.
+.Pp
+If enabled, when the driver receives a firmware health event message, it will
+print out a description of the event to the kernel message buffer and if
+applicable, possible actions to take to remedy it.
+.It Va hw.ice.irdma
+Set to 1 to enable the RDMA client interface, required by the
+.Xr irdma 4
+driver.
+Enabled by default.
+.It Va hw.ice.rdma_max_msix
+Set the maximum number of per-device MSI-X vectors that are allocated for use
+by the
+.Xr irdma 4
+driver.
+Set to 64 by default.
+.It Va hw.ice.debug.enable_tx_fc_filter
+Set to 1 to enable the TX Flow Control filter across all devices.
+Enabled by default.
+.Pp
+If enabled, the hardware will drop any transmitted Ethertype 0x8808 control
+frames that do not originate from the hardware.
+.It Va hw.ice.debug.enable_tx_lldp_filter
+Set to 1 to enable the TX LLDP filter across all devices.
+Enabled by default.
+.Pp
+If enabled, the hardware will drop any transmitted Ethertype 0x88cc LLDP frames
+that do not originate from the hardware.
+This must be disabled in order to use LLDP daemon software such as
+.Xr lldpd 8 .
+.It Va hw.ice.debug.ice_tx_balance_en
+Set to 1 to allow the driver to use the 5-layer Tx Scheduler tree topology if
+configured by the DDP package.
+.Pp
+Enabled by default.
+.El
+.Sh SYSCTL VARIABLES
.Bl -tag -width indent
-.It Va dev.ice.#.fc
-Allows one to set the flow control value.
-A value of 0 disables flow control, 3 enables full, 1 is RX, and 2 is
-TX pause.
-.It Va dev.ice.#.advertise_speed
-Allows one to set advertised link speeds, this will then cause a link
-renegotiation.
.It Va dev.ice.#.current_speed
-This is a display of the current setting.
+This is a display of the current link speed of the interface.
+This is expected to match the speed of the media type in-use displayed by
+.Xr ifconfig 8 .
.It Va dev.ice.#.fw_version
Displays the current firmware and NVM versions of the adapter.
+This information should be submitted along with any support requests.
.It Va dev.ice.#.ddp_version
-TBW
-.It Va dev.ice.#.requested_fec
-TBW
-.It Va dev.ice.#.negotiated_fec
-TBW
-.It Va dev.ice.#.fw_lldp_agent
-TBW
-.It Va dev.ice.#.ets_min_rate
-TBW
-.It Va dev.ice.#.up2tc_map
-TBW
-.It Va dev.ice.#.pfc
-TBW
+Displays the current DDP package version downloaded to the adapter.
+This information should be submitted along with any support requests.
+.It Va dev.ice.#.pba_number
+Displays the Product Board Assembly Number.
+May be used to help identify the type of adapter in use.
+This sysctl may not exist depending on the adapter type.
+.It Va dev.ice.#.hw.mac.*
+This sysctl tree contains statistics collected by the hardware for the port.
.El
.Sh INTERRUPT STORMS
It is important to note that 100G operation can generate high
@@ -226,21 +1004,77 @@ a storm condition in the kernel.
It is suggested that this be resolved by setting
.Va hw.intr_storm_threshold
to 0.
+.Sh IOVCTL OPTIONS
+The driver supports additional optional parameters for created VFs
+(Virtual Functions) when using
+.Xr iovctl 8 :
+.Bl -tag -width indent
+.It mac-addr Pq unicast-mac
+Set the Ethernet MAC address that the VF will use.
+If unspecified, the VF will use a randomly generated MAC address and
+.Dq allow-set-mac
+will be set to true.
+.It mac-anti-spoof Pq bool
+Prevent the VF from sending Ethernet frames with a source address
+that does not match its own.
+Enabled by default.
+.It allow-set-mac Pq bool
+Allow the VF to set its own Ethernet MAC address.
+Disallowed by default.
+.It allow-promisc Pq bool
+Allow the VF to inspect all of the traffic sent to the port that it is created
+on.
+Disabled by default.
+.It num-queues Pq uint16_t
+Specify the number of queues the VF will have.
+By default, this is set to the number of MSI\-X vectors supported by the VF
+minus one.
+.It mirror-src-vsi Pq uint16_t
+Specify which VSI the VF will mirror traffic from by setting this to a value
+other than \-1.
+All traffic from that VSI will be mirrored to this VF.
+Can be used as an alternative method to mirror RDMA traffic to another
+interface than the method described in the
+.Sx RDMA Monitoring
+section.
+Not affected by the
+.Dq allow-promisc
+parameter.
+.It max-vlan-allowed Pq uint16_t
+Specify maximum number of VLAN filters that the VF can use.
+Receiving traffic on a VLAN requires a hardware filter which are a finite
+resource; this is used to prevent a VF from starving other VFs or the PF of
+filter resources.
+By default, this is set to 16.
+.It max-mac-filters Pq uint16_t
+Specify maximum number of MAC address filters that the VF can use.
+Each allowed MAC address requires a hardware filter which are a finite
+resource; this is used to prevent a VF from starving other VFs or the PF of
+filter resources.
+The VF's default mac address does not count towards this limit.
+By default, this is set to 64.
+.El
+.Pp
+An up to date list of parameters and their defaults can be found by using
+.Xr iovctl 8
+with the
+.Fl S
+option.
+.Pp
+For more information on standard and mandatory parameters, see
+.Xr iovctl.conf 5 .
.Sh SUPPORT
-For general information and support,
-go to the Intel support website at:
+For general information and support, go to the Intel support website at:
.Lk http://www.intel.com/support/ .
.Pp
If an issue is identified with this driver with a supported adapter,
email all the specific information related to the issue to
.Aq Mt freebsd@intel.com .
.Sh SEE ALSO
-.Xr arp 4 ,
.Xr iflib 4 ,
-.Xr netintro 4 ,
-.Xr ng_ether 4 ,
.Xr vlan 4 ,
-.Xr ifconfig 8
+.Xr ifconfig 8 ,
+.Xr sysctl 8
.Sh HISTORY
The
.Nm
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
index d008afbf8ace..d722c9902b98 100644
--- a/share/man/man4/ufshci.4
+++ b/share/man/man4/ufshci.4
@@ -7,7 +7,7 @@
.\"
.\" Author: Jaeyoon Choi <j_yoon.choi@samsung.com>
.\"
-.Dd June 24, 2025
+.Dd July 17, 2025
.Dt UFSHCI 4
.Os
.Sh NAME
@@ -28,11 +28,6 @@ ufshci_load="YES"
.Sh DESCRIPTION
Universal Flash Storage (UFS) is a low-power, high-performance storage
standard composed of a host controller and a single target device.
-The
-.Nm
-initializes both the host controller and the target device, and handles I/O.
-It currently supports the UFS/UFSHCI 4.1 specification and all earlier
-revisions.
.Pp
The driver currently provides:
.Bl -bullet
@@ -58,6 +53,11 @@ subsystem and its logical unit appears as the device node
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
diff --git a/share/man/man5/Makefile b/share/man/man5/Makefile
index e2abf1d60905..0f6559b236c6 100644
--- a/share/man/man5/Makefile
+++ b/share/man/man5/Makefile
@@ -1,14 +1,11 @@
.include <src.opts.mk>
+MANGROUPS= MAN
+
#MISSING: dump.5 plot.5
-MAN= acct.5 \
- ar.5 \
- a.out.5 \
+MAN= a.out.5 \
${_boot.config.5} \
core.5 \
- devfs.conf.5 \
- devfs.rules.5 \
- device.hints.5 \
dir.5 \
disktab.5 \
elf.5 \
@@ -16,32 +13,24 @@ MAN= acct.5 \
eui64.5 \
fbtab.5 \
forward.5 \
- fs.5 \
- fstab.5 \
group.5 \
hosts.5 \
hosts.equiv.5 \
- hosts.lpd.5 \
intro.5 \
libmap.conf.5 \
link.5 \
mailer.conf.5 \
make.conf.5 \
- moduli.5 \
motd.5 \
mount.conf.5 \
networks.5 \
- nsmb.conf.5 \
nsswitch.conf.5 \
os-release.5 \
- passwd.5 \
pbm.5 \
- periodic.conf.5 \
phones.5 \
portindex.5 \
protocols.5 \
quota.user.5 \
- rc.conf.5 \
rctl.conf.5 \
regdomain.5 \
remote.5 \
@@ -54,18 +43,6 @@ MAN= acct.5 \
style.mdoc.5 \
sysctl.conf.5 \
-MLINKS= dir.5 dirent.5
-MLINKS+=fs.5 inode.5
-MLINKS+=hosts.equiv.5 rhosts.5
-MLINKS+=passwd.5 master.passwd.5
-MLINKS+=passwd.5 pwd.db.5
-MLINKS+=passwd.5 spwd.db.5
-MLINKS+=portindex.5 INDEX.5
-MLINKS+=quota.user.5 quota.group.5
-MLINKS+=rc.conf.5 rc.conf.local.5
-MLINKS+=resolver.5 resolv.conf.5
-MLINKS+=src.conf.5 src-env.conf.5
-
.if ${MK_BLUETOOTH} != "no"
MAN+= bluetooth.device.conf.5 \
bluetooth.hosts.5 \
@@ -80,11 +57,68 @@ MAN+= freebsd-update.conf.5
MAN+= hesiod.conf.5
.endif
+MLINKS= dir.5 dirent.5
+MLINKS+=fs.5 inode.5
+MLINKS+=hosts.equiv.5 rhosts.5
+MLINKS+=portindex.5 INDEX.5
+MLINKS+=quota.user.5 quota.group.5
+MLINKS+=resolver.5 resolv.conf.5
+MLINKS+=src.conf.5 src-env.conf.5
+
+MANGROUPS+= ACCT
+ACCT= acct.5
+ACCTPACKAGE= acct
+
+MANGROUPS+= BOOTLOADER
+BOOTLOADER= device.hints.5
+BOOTLOADERPACKAGE=bootloader
+
+MANGROUPS+= CLANG
+CLANG= ar.5
+CLANGPACKAGE= clang
+
+MANGROUPS+= LP
+LP= hosts.lpd.5
+LPPACKAGE= lp
+
+MANGROUPS+= PERIODIC
+PERIODIC= periodic.conf.5
+PERIODICPACKAGE=periodic
+
.if ${MK_PF} != "no"
-MAN+= pf.conf.5 \
- pf.os.5
+MANGROUPS+= PF
+PF= pf.conf.5 \
+ pf.os.5
+PFPACKAGE= pf
.endif
+MANGROUPS+= RC
+RC= rc.conf.5
+RCLINKS= rc.conf.5 rc.conf.local.5
+RCPACKAGE= rc
+
+MANGROUPS+= RUNTIME
+RUNTIME= devfs.conf.5 \
+ devfs.rules.5 \
+ fstab.5 \
+ passwd.5
+RUNTIMELINKS= passwd.5 master.passwd.5
+RUNTIMELINKS+= passwd.5 pwd.db.5
+RUNTIMELINKS+= passwd.5 spwd.db.5
+RUNTIMEPACKAGE= runtime
+
+MANGROUPS+= SMB
+SMB= nsmb.conf.5
+SMBPACKAGE= smbutils
+
+MANGROUPS+= SSH
+SSH= moduli.5
+SSHPACKAGE= ssh
+
+MANGROUPS+= UFS
+UFS= fs.5
+UFSPACKAGE= ufs
+
# This makes more sense for amd64 and i386 but
# we decide to install all manpages in all architectures
_boot.config.5= boot.config.5
diff --git a/share/man/man5/core.5 b/share/man/man5/core.5
index 8efc8c970014..628fdb7920bb 100644
--- a/share/man/man5/core.5
+++ b/share/man/man5/core.5
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd November 12, 2023
+.Dd July 17, 2025
.Dt CORE 5
.Os
.Sh NAME
@@ -48,26 +48,6 @@ a system crash.
(In this event, the decision to save the core file is arbitrary, see
.Xr savecore 8 . )
.Pp
-The maximum size of a core file is limited by the
-.Dv RLIMIT_CORE
-.Xr setrlimit 2
-limit.
-Files which would be larger than the limit are not created.
-.Pp
-With a large limit, a process that had mapped a very large,
-and perhaps sparsely populated, virtual memory region, could take
-a very long time to create core dumps.
-The system ignores all signals sent to a process writing a core file, except
-.Dv SIGKILL
-which terminates the writing and causes immediate exit of the process.
-The behavior of
-.Dv SIGKILL
-can be disabled by setting tunable
-.Xr sysctl 8
-variable
-.Va kern.core_dump_can_intr
-to zero.
-.Pp
The name of the file is controlled via the
.Xr sysctl 8
variable
@@ -107,6 +87,26 @@ yielding the traditional
.Fx
behaviour.
.Pp
+The maximum size of a core file is limited by the
+.Dv RLIMIT_CORE
+.Xr setrlimit 2
+limit.
+Files which would be larger than the limit are not created.
+.Pp
+With a large limit, a process that had mapped a very large,
+and perhaps sparsely populated, virtual memory region, could take
+a very long time to create core dumps.
+The system ignores all signals sent to a process writing a core file, except
+.Dv SIGKILL
+which terminates the writing and causes immediate exit of the process.
+The behavior of
+.Dv SIGKILL
+can be disabled by setting tunable
+.Xr sysctl 8
+variable
+.Va kern.core_dump_can_intr
+to zero.
+.Pp
By default, a process that changes user or group credentials whether
real or effective will not create a corefile.
This behaviour can be
@@ -116,11 +116,13 @@ variable
.Va kern.sugid_coredump
to 1.
.Pp
-Corefiles can be compressed by the kernel if the following item
-is included in the kernel configuration file:
+Corefiles can be compressed by the kernel if one of the following items
+are included in the kernel configuration file:
.Bl -tag -width "1234567890" -compact -offset "12345"
.It options
GZIO
+.It options
+ZSTDIO
.El
.Pp
The following sysctl control core file compression:
diff --git a/share/man/man5/pf.conf.5 b/share/man/man5/pf.conf.5
index 11e22ebc78bf..8954e872c231 100644
--- a/share/man/man5/pf.conf.5
+++ b/share/man/man5/pf.conf.5
@@ -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.
@@ -2784,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.
@@ -3112,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/src.conf.5 b/share/man/man5/src.conf.5
index a3db00aed42f..f93d3f9fc69f 100644
--- a/share/man/man5/src.conf.5
+++ b/share/man/man5/src.conf.5
@@ -1,5 +1,5 @@
.\" DO NOT EDIT-- this file is @generated by tools/build/options/makeman.
-.Dd July 14, 2025
+.Dd July 27, 2025
.Dt SRC.CONF 5
.Os
.Sh NAME
@@ -940,8 +940,9 @@ amd64/amd64, arm64/aarch64, i386/i386, powerpc/powerpc64 and powerpc/powerpc64le
Do not build the LLD linker during the bootstrap phase of
the build.
To be able to build the system an alternate linker must be provided via XLD.
-.It Va WITHOUT_LLVM_ASSERTIONS
-Disable debugging assertions in LLVM.
+.It Va WITH_LLVM_ASSERTIONS
+Enable debugging assertions in LLVM.
+Use when working on or requesting help with LLVM components.
.It Va WITHOUT_LLVM_BINUTILS
Install ELF Tool Chain's binary utilities instead of LLVM's.
This includes
diff --git a/share/man/man7/named_attribute.7 b/share/man/man7/named_attribute.7
index 7cd778620357..4080dfce2fab 100644
--- a/share/man/man7/named_attribute.7
+++ b/share/man/man7/named_attribute.7
@@ -3,7 +3,7 @@
.\"
.\" SPDX-License-Identifier: BSD-2-Clause
.\"
-.Dd July 3, 2025
+.Dd July 20, 2025
.Dt NAMED_ATTRIBUTE 7
.Os
.Sh NAME
@@ -122,7 +122,7 @@ Although the named attribute machanism might require different internal
implementation
of extended attributes within a file system, both ZFS and NFSv4 provide
both mechanisms, which can be used interchangeably to manipulate
-extended attributes, but with a couple of limitations.
+extended attributes, but with a few limitations.
.Bl -bullet
.It
The
@@ -135,6 +135,24 @@ The named attribute interface does not support system namespace
extended attributes and,
as such, system namespace extended attributes must be manipulated via
.Xr extattr 2 .
+.It
+For ZFS, if an extended attribute with a value
+that is a small length in bytes is created when the ZFS
+.Dv xattr
+property is set to
+.Dq sa ,
+that extended attribute is only visible via
+.Xr extattr 2
+and not as a named attribute.
+Archiving/de-archiving the file via
+.Xr tar 1
+after setting the
+.Dv xattr
+property to
+.Dq dir
+will make the attribute(s) visible as both named attributes
+and via
+.Xr extattr 2 .
.El
.Pp
The named attribute mechanism/system call interface provides certain
@@ -259,6 +277,7 @@ enters the named attribute directory for the file object
.Sh SEE ALSO
.Xr bash 1 ,
.Xr runat 1 ,
+.Xr tar 1 ,
.Xr chdir 2 ,
.Xr extattr 2 ,
.Xr lseek 2 ,
diff --git a/share/man/man8/Makefile b/share/man/man8/Makefile
index bd6bdfe4ba05..c408f1b65a80 100644
--- a/share/man/man8/Makefile
+++ b/share/man/man8/Makefile
@@ -1,5 +1,7 @@
.include <src.opts.mk>
+MANGROUPS= MAN
+
MAN= \
beinstall.8 \
crash.8 \
@@ -7,29 +9,32 @@ MAN= \
diskless.8 \
intro.8 \
nanobsd.8 \
- rc.8 \
- rc.subr.8 \
rescue.8 \
- ${_uefi.8} \
+ ${_uefi.8}
MLINKS= \
beinstall.8 beinstall.sh.8 \
- nanobsd.8 nanobsd.sh.8 \
- rc.8 rc.d.8 \
- rc.8 rc.firewall.8 \
- rc.8 rc.local.8 \
- rc.8 rc.network.8 \
- rc.8 rc.pccard.8 \
- rc.8 rc.resume.8 \
- rc.8 rc.serial.8 \
- rc.8 rc.shutdown.8
+ nanobsd.8 nanobsd.sh.8
-.if ${MK_NIS} != "no"
-MAN+= yp.8
+MANGROUPS+= RC
+RC= rc.8 rc.subr.8
+RCLINKS= rc.8 rc.d.8 \
+ rc.8 rc.firewall.8 \
+ rc.8 rc.local.8 \
+ rc.8 rc.network.8 \
+ rc.8 rc.pccard.8 \
+ rc.8 rc.resume.8 \
+ rc.8 rc.serial.8 \
+ rc.8 rc.shutdown.8
+RCPACKAGE= rc
-MLINKS+=yp.8 NIS.8 \
- yp.8 nis.8 \
- yp.8 YP.8
+.if ${MK_NIS} != "no"
+MANGROUPS+= YP
+YP= yp.8
+YPLINKS= yp.8 NIS.8 \
+ yp.8 nis.8 \
+ yp.8 YP.8
+YPPACKAGE= yp
.endif
# This makes more sense for aarch 64 and amd64
diff --git a/share/man/man8/crash.8 b/share/man/man8/crash.8
index 27c9c56533a5..fdb9b7213847 100644
--- a/share/man/man8/crash.8
+++ b/share/man/man8/crash.8
@@ -30,7 +30,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 23, 2011
+.Dd July 25, 2025
.Dt CRASH 8
.Os
.Sh NAME
@@ -71,18 +71,19 @@ Left unstated in all cases is the possibility that hardware or software
error produced the message in some unexpected way.
.Pp
.Bl -diag -compact
-.It "cannot mount root"
-This panic message results from a failure to mount the root file system
-during the bootstrap process.
-Either the root file system has been corrupted,
-or the system is attempting to use the wrong device as root file system.
-Usually, an alternate copy of the system binary or an alternate root
-file system can be used to bring up the system to investigate.
-Most often
-this is done by the use of the boot floppy you used to install the system,
-and then using the
-.Dq fixit
-floppy.
+.It Mounting from <device> failed with error <err>
+The system was unable to mount the configured root filesystem.
+Either the root filesystem has been corrupted,
+or the system is attempting to use the wrong device as root filesystem.
+.Pp
+This is not a panic message; rather it is followed by an interactive
+.Sy mountroot>
+prompt where the operator can list detected devices and filesystems,
+and select an alternative root filesystem to mount.
+Alternatively, the system can be booted from recovery media to repair
+the situation.
+The system install media provides a live environment which is suitable
+for this task.
.Pp
.It "init: not found"
This is not a panic message, as reboots are likely to be futile.
@@ -108,11 +109,6 @@ after a crash, hardware failures, or other condition that should not
normally occur.
A file system check will normally correct the problem.
.Pp
-.It "timeout table full"
-This really should not be a panic, but until the data structure
-involved is made to be extensible, running out of entries causes a crash.
-If this happens, make the timeout table bigger.
-.Pp
.\" .It "trap type %d, code = %x, v = %x"
.\" An unexpected trap has occurred within the system; the trap types are:
.\" .Bl -column xxxx -offset indent
diff --git a/share/man/man9/Makefile b/share/man/man9/Makefile
index f709a4818dd5..5bcde3030ebc 100644
--- a/share/man/man9/Makefile
+++ b/share/man/man9/Makefile
@@ -1,5 +1,7 @@
.include <src.opts.mk>
+PACKAGE= kernel
+
MAN= accept_filter.9 \
accf_data.9 \
accf_dns.9 \
@@ -67,6 +69,7 @@ MAN= accept_filter.9 \
config_intrhook.9 \
contigmalloc.9 \
copy.9 \
+ coredumper_register.9 \
counter.9 \
cpu_machdep.9 \
cpuset.9 \
@@ -903,6 +906,7 @@ MLINKS+=copy.9 copyin.9 \
copy.9 copyout.9 \
copy.9 copyout_nofault.9 \
copy.9 copystr.9
+MLINKS+=coredumper_register.9 coredumper_unregister.9
MLINKS+=counter.9 counter_u64_alloc.9 \
counter.9 counter_u64_free.9 \
counter.9 counter_u64_add.9 \
diff --git a/share/man/man9/coredumper_register.9 b/share/man/man9/coredumper_register.9
new file mode 100644
index 000000000000..f4c9eb4a1bf6
--- /dev/null
+++ b/share/man/man9/coredumper_register.9
@@ -0,0 +1,168 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2025 Kyle Evans <kevans@FreeBSD.org>
+.\"
+.Dd July 23, 2025
+.Dt COREDUMPER_REGISTER 9
+.Os
+.Sh NAME
+.Nm coredumper_register ,
+.Nm coredumper_unregister
+.Nd loadable user coredumper support
+.Sh SYNOPSIS
+.In sys/ucoredump.h
+.Ft void
+.Fn coredumper_register "struct coredumper *cd"
+.Ft void
+.Fn coredumper_unregister "struct coredumper *cd"
+.Pp
+.Ft int
+.Fn coredumper_probe_fn "struct thread *td"
+.Ft int
+.Fn coredumper_handle_fn "struct thread *td" "off_t limit"
+.Bd -literal
+/* Incomplete, but the useful members are depicted here. */
+struct coredumper {
+ const char *cd_name;
+ coredumper_probe_fn *cd_probe;
+ coredumper_handle_fn *cd_handle;
+};
+.Ed
+.Pp
+.Ft int
+.Fn coredump_init_fn "const struct coredump_writer *" \
+"const struct coredump_params *"
+.Ft int
+.Fn coredump_write_fn "const struct coredump_writer *" "const void *" "size_t" \
+"off_t" "enum uio_seg" "struct ucred *" "size_t *" "struct thread *"
+.Ft int
+.Fn coredump_extend_fn "const struct coredump_writer *" "off_t" "struct ucred *"
+.Bd -literal
+struct coredump_writer {
+ void *ctx;
+ coredump_init_fn *init_fn;
+ coredump_write_fn *write_fn;
+ coredump_extend_fn *extend_fn;
+};
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+mechanism provides a path for kernel modules to register a new user process core
+dumper.
+The expected use of
+.Nm
+is for a module to define the fields of the struct coredumper listed above, then
+call
+.Fn coredumper_register
+at
+.Dv MOD_LOAD
+time.
+A corresponding
+.Fn coredumper_unregister
+should be called at
+.Dv MOD_UNLOAD
+time.
+Note that
+.Fn coredumper_unregister
+will block until the specified coredumper is no longer processing coredumps.
+.Pp
+When a user process is preparing to start dumping core, the kernel will execute
+the
+.Fn cd_probe
+function for each coredumper currently registered.
+The
+.Fn cd_probe
+function is expected to return either -1 if it would decline to dump the
+process, or a priority level greater than 0.
+The coredumper with the highest priority will handle the coredump.
+The following default priorities are defined:
+.Bl -tag -width indent
+.It Dv COREDUMPER_NOMATCH
+This dumper declines dumping the process.
+.It Dv COREDUMPER_GENERIC
+This dumper will dump the process at the lowest priority.
+This priority is not recommended, as the default vnode dumper will bid at
+.Dv COREDUMPER_GENERIC
+as well.
+.It Dv COREDUMPER_SPECIAL
+This dumper provides special behavior, and will dump the process at a higher
+priority.
+.It Dv COREDUMPER_HIGHPRIORITY
+This dumper would prefer to handle this coredump.
+This may be used by, for instance, a custom or vendor-specific coredump
+mechanism that wishes to preempt others.
+.El
+.Pp
+Note that this system has been designed such that the
+.Fn cd_probe
+function can examine the process in question and make an informed decision.
+Different processes being dumped could probe at different priorities in the
+same coredumper.
+.Pp
+Once the highest priority coredumper has been selected, the
+.Fn cd_handle
+function will be invoked.
+The
+.Fn cd_handle
+will receive both the thread and the
+.Dv RLIMIT_CORE
+.Xr setrlimit 2
+.Fa limit .
+The proc lock will be held on entry, and should be unlocked before the handler
+returns.
+The
+.Fa limit
+is typically passed to the
+.Fn sv_coredump
+that belongs to the process's
+.Va p_sysent .
+.Pp
+The
+.Fn cd_handle
+function should return either 0 if the dump was successful, or an appropriate
+.Xr errno 2
+otherwise.
+.Ss Customized Coredump Writers
+Custom coredumpers can define their own
+.Dv coredump_writer
+to pass to
+.Fn sv_coredump .
+.Pp
+The
+.Va ctx
+member is opaque and only to be used by the coredumper itself.
+.Pp
+The
+.Va init_fn
+function, if it's provided, will be called by the
+.Fn sv_coredump
+implementation before any data is to be written.
+This allows the writer implementation to record any coredump parameters that it
+might need to capture, or setup the object to be written to.
+.Pp
+The
+.Va write_fn
+function will be called by the
+.Fn sv_coredump
+implementation to write out data.
+The
+.Va extend_fn
+function will be called to enlarge the coredump, in the sense that a hole is
+created in any difference between the current size and the new size.
+For convenience, the
+.Fn core_vn_write
+and
+.Fn core_vn_extend
+functions used by the vnode coredumper are exposed in
+.In sys/ucordumper.h ,
+and the
+.Dv coredump_vnode_ctx
+defined there should be populated with the vnode to write to.
+.Sh SEE ALSO
+.Xr setrlimit 2 ,
+.Xr core 5
+.Sh AUTHORS
+This manual page was written by
+.An Kyle Evans Aq Mt kevans@FreeBSD.org .
diff --git a/share/man/man9/domainset.9 b/share/man/man9/domainset.9
index 816ce29f04f7..702c9f83a88b 100644
--- a/share/man/man9/domainset.9
+++ b/share/man/man9/domainset.9
@@ -22,7 +22,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd April 14, 2021
+.Dd June 24, 2025
.Dt DOMAINSET 9
.Os
.Sh NAME
@@ -54,6 +54,8 @@ struct domainset {
.Ft struct domainset *
.Fn domainset_create "const struct domainset *key"
.Ft int
+.Fn domainset_populate "struct domainset *domain" "domainset_t *mask" "int policy" "size_t mask_size"
+.Ft int
.Fn sysctl_handle_domainset "SYSCTL_HANDLER_ARGS"
.Sh DESCRIPTION
The
@@ -137,6 +139,7 @@ These policies should be used in preference to
to avoid blocking indefinitely on a
.Dv M_WAITOK
request.
+.Pp
The
.Fn domainset_create
function takes a partially filled in domainset as a key and returns a
@@ -148,6 +151,17 @@ is an immutable type that is shared among all matching keys and must
not be modified after return.
.Pp
The
+.Fn domainset_populate
+function fills a
+.Vt domainset
+struct using a domain mask and policy.
+It is used for validating and
+translating a domain mask and policy into a
+.Vt domainset
+struct when creating a custom domainset using
+.Vt domainset_create .
+.Pp
+The
.Fn sysctl_handle_domainset
function is provided as a convenience for modifying or viewing domainsets
that are not accessible via
diff --git a/share/man/man9/mbuf.9 b/share/man/man9/mbuf.9
index 0262c598ed18..c05505716a30 100644
--- a/share/man/man9/mbuf.9
+++ b/share/man/man9/mbuf.9
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd December 28, 2023
+.Dd July 29, 2025
.Dt MBUF 9
.Os
.\"
@@ -1091,7 +1091,7 @@ network code, when data must be encrypted or otherwise
altered prior to transmission.
.El
.Sh HARDWARE-ASSISTED CHECKSUM CALCULATION
-This section currently applies to TCP/IP only.
+This section currently applies to SCTP, TCP, and UDP over IP only.
In order to save the host CPU resources, computing checksums is
offloaded to the network interface hardware if possible.
The
@@ -1117,7 +1117,7 @@ in the
.Vt mbuf chain
containing the packet.
.Pp
-On output, checksum offloading is attempted after the outgoing
+On output, the computation of the checksum is delayed until the outgoing
interface has been determined for a packet.
The interface-specific field
.Va ifnet.if_data.ifi_hwassist
@@ -1135,12 +1135,15 @@ such actions will never be requested through
.Va csum_flags .
.Pp
The flags demanding a particular action from an interface are as follows:
-.Bl -tag -width ".Dv CSUM_TCP" -offset indent
+.Bl -tag -width ".Dv CSUM_SCTP" -offset indent
.It Dv CSUM_IP
The IP header checksum is to be computed and stored in the
corresponding field of the packet.
The hardware is expected to know the format of an IP header
to determine the offset of the IP checksum field.
+.It Dv CSUM_SCTP
+The SCTP checksum is to be computed.
+(See below.)
.It Dv CSUM_TCP
The TCP checksum is to be computed.
(See below.)
@@ -1149,14 +1152,16 @@ The UDP checksum is to be computed.
(See below.)
.El
.Pp
-Should a TCP or UDP checksum be offloaded to the hardware,
+Should a SCTP, TCP, or UDP checksum be offloaded to the hardware,
the field
.Va csum_data
will contain the byte offset of the checksum field relative to the
end of the IP header.
-In this case, the checksum field will be initially
-set by the TCP/IP module to the checksum of the pseudo header
+In the case of TCP or UDP, the checksum field will be initially
+set by the TCP or UDP implementation to the checksum of the pseudo header
defined by the TCP and UDP specifications.
+In the case of SCTP, the checksum field will be initially
+set by the SCTP implementation to 0.
.Pp
On input, an interface indicates the actions it has performed
on a packet by setting one or more of the following flags in
@@ -1187,13 +1192,13 @@ to obtain the final checksum to be used for TCP or UDP validation purposes.
.El
.Pp
If a particular network interface just indicates success or
-failure of TCP or UDP checksum validation without returning
+failure of SCTP, TCP, or UDP checksum validation without returning
the exact value of the checksum to the host CPU, its driver can mark
.Dv CSUM_DATA_VALID
-and
-.Dv CSUM_PSEUDO_HDR
in
-.Va csum_flags ,
+.Va csum_flags
+as well as, for TCP and UDP,
+.Dv CSUM_PSEUDO_HDR
and set
.Va csum_data
to
@@ -1203,6 +1208,13 @@ It is a peculiarity of the algorithm used that the Internet checksum
calculated over any valid packet will be
.Li 0xFFFF
as long as the original checksum field is included.
+Note that for SCTP the value of
+.Va csum_data
+is not relevant and
+.Dv CSUM_PSEUDO_HDR
+in
+.Va csum_flags
+is not set, since SCTP does not use a pseudo header checksum.
.Sh STRESS TESTING
When running a kernel compiled with the option
.Dv MBUF_STRESS_TEST ,
diff --git a/share/man/man9/style.9 b/share/man/man9/style.9
index 484b4f144b2e..e9f17392ae0c 100644
--- a/share/man/man9/style.9
+++ b/share/man/man9/style.9
@@ -22,7 +22,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd March 27, 2025
+.Dd July 28, 2025
.Dt STYLE 9
.Os
.Sh NAME
@@ -766,8 +766,7 @@ to any pointer type.
.Pp
Values in
.Ic return
-statements should be enclosed in parentheses where possible.
-For example, parentheses cannot be used if the value is a C++ braced-init-list.
+statements should be enclosed in parentheses.
.Pp
Use
.Xr err 3
@@ -918,6 +917,161 @@ Only use the annotation for the entire if statement,
rather than individual clauses.
Do not add these annotations without empirical evidence of the likelihood of the
branch.
+.Ss C++
+KNF style was originally defined as a style for C.
+C++ introduces several new idioms which do not have an existing corollary
+in KNF C such as inline function definitions in classes.
+C++ is also not always compatible with some KNF guidelines such as
+enclosing return values in parentheses.
+For C++ code, FreeBSD aims to follow broadly accepted C++ practices while
+also following the general shape of KNF.
+This section enumerates C++ specific guidelines that differ from KNF C.
+.Pp
+The preferred suffixes for C++ source files are
+.Dq .cc
+and
+.Dq .hh .
+Header files should always use a suffix,
+unlike headers from the C++ standard library.
+.Pp
+Return values should not be enclosed in parantheses.
+When converting existing C code to C++,
+existing return values may remain in parantheses.
+.Pp
+The opening curly brace for namespace declarations should be on the first line
+similar to structure and class definitions.
+Nested namespaces should be declared using a single namespace declaration.
+.Bd -literal
+namespace foo::bar {
+}
+.Ed
+.Pp
+Member function declarations should follow the same style used for standalone
+function protoypes except that a space should be used between a function's
+return type and name.
+.Pp
+Function definitions at the top level should use a newline after the function
+type similar to C function definitions.
+.Pp
+Nested member function definitions inside of a class, structure, or union
+should not use a newline after the function type.
+Instead, these should follow the style of member function declarations.
+This is more common C++ style and is more compact for small methods such as
+getters and setters.
+.Pp
+Inline functions whose body consists of a single statement may use a single
+line for the function body.
+Inline functions with an empty body should always use a single line.
+.Bd -literal
+struct widget {
+ int foo() { return 4; }
+ int bar();
+};
+
+int
+widget::bar()
+{
+ return 6;
+}
+.Ed
+.Pp
+Default and deleted methods should be declared as a single line.
+.Bd -literal
+class box {
+ ~box() = default;
+};
+.Ed
+.Pp
+In template declarations, the
+.Ic template
+keyword and list of template parameters should be followed by a newline
+before the templated declaration.
+.Bd -literal
+template <typename T>
+class box {
+ T data;
+};
+.Ed
+.Pp
+The
+.Ic &
+for reference variables should be placed on the variable name rather
+than the type similar to the style used with
+.Ic *
+for pointers.
+.Bd -literal
+ int x;
+ int &xp = x;
+.Ed
+.Pp
+Variables may be declared at any point within a function,
+not just at the start of blocks.
+.Pp
+Standard library containers should be used in preference to
+.Xr queue 3
+or
+.Xr tree 3
+macros.
+.Pp
+.Ic nullptr
+should be used instead of
+.Dv NULL
+or 0.
+.Pp
+Use standard library types for managing strings such as
+.Vt std::string
+and
+.Vt std::string_view
+rather than
+.Vt "char *"
+and
+.Vt "const char *" .
+C types may be used when interfacing with C code.
+.Pp
+The
+.Ic auto
+keyword can be used in various contexts which improve readability.
+Examples include iterators, non-trivial types of ranged-for values,
+and return values of obvious types,
+such as
+.Ic static_cast
+or
+.Fn std::make_unique .
+Place any qualifiers before
+.Ic auto ,
+for example:
+.Ic const auto .
+.Pp
+Use the
+.Vt std::unique_ptr
+and
+.Vt std::shared_ptr
+smart pointers to manage the lifetime of dynamically allocated objects
+instead of
+.Ic new
+and
+.Ic delete .
+Construct smart pointers with
+.Fn std::make_unique
+or
+.Fn std::make_shared .
+Do not use
+.Xr malloc 3
+except when necessary to interface with C code.
+.Pp
+Do not import any namespaces with
+.Ic using
+at global scope in header files.
+Namespaces other than the
+.Ic std
+namespace (for example,
+.Ic std::literals )
+may be imported in source files and in function scope in header files.
+.Pp
+Define type aliases using
+.Ic using
+instead of
+.Ic typedef .
.Sh FILES
.Bl -tag -width indent
.It Pa /usr/src/tools/build/checkstyle9.pl
diff --git a/share/misc/committers-ports.dot b/share/misc/committers-ports.dot
index 7bb3d936e5e5..fb6c168f1425 100644
--- a/share/misc/committers-ports.dot
+++ b/share/misc/committers-ports.dot
@@ -153,6 +153,7 @@ ak [label="Alex Kozlov\nak@FreeBSD.org\n2012/02/29"]
ale [label="Alex Dupre\nale@FreeBSD.org\n2004/01/12"]
alepulver [label="Alejandro Pulver\nalepulver@FreeBSD.org\n2006/04/01"]
alexey [label="Alexey Degtyarev\nalexey@FreeBSD.org\n2013/11/09"]
+alven [label="Älven\nalven@FreeBSD.org\n2025/07/28"]
amdmi3 [label="Dmitry Marakasov\namdmi3@FreeBSD.org\n2008/06/19"]
antoine [label="Antoine Brodin\nantoine@FreeBSD.org\n2013/04/03"]
arrowd [label="Gleb Popov\narrowd@FreeBSD.org\n2018/05/18"]
@@ -420,6 +421,7 @@ culot -> marino
culot -> pi
culot -> wg
+db -> alven
db -> tj
db -> shurd
@@ -865,6 +867,7 @@ wxs -> zi
ygy -> yasu
+yuri -> alven
yuri -> rea
zirias -> jbo
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/share/mk/Makefile b/share/mk/Makefile
index 837f7da68b4b..4ab5c8cc314b 100644
--- a/share/mk/Makefile
+++ b/share/mk/Makefile
@@ -10,6 +10,7 @@ UPDATE_DEPENDFILE= no
.include <src.opts.mk>
+PACKAGE= bmake
FILES= \
auto.obj.mk \
bsd.README \
diff --git a/share/mk/bsd.man.mk b/share/mk/bsd.man.mk
index 96b8f07c25e2..a5a4fd528268 100644
--- a/share/mk/bsd.man.mk
+++ b/share/mk/bsd.man.mk
@@ -39,6 +39,13 @@
#
# MANDOC_CMD command and flags to create preformatted pages
#
+# MANGROUPS A list of groups, each of which should be a variable containing
+# a list of manual pages in that group. By default one group is
+# defined called "MAN".
+#
+# For each group, group-specific options may be set:
+# <group>OWN, <group>GRP, <group>MODE and <group>PACKAGE.
+#
# +++ targets +++
#
# maninstall:
@@ -49,11 +56,10 @@
.error bsd.man.mk cannot be included directly.
.endif
-.if ${MK_MANSPLITPKG} == "no"
-MINSTALL?= ${INSTALL} ${TAG_ARGS} -o ${MANOWN} -g ${MANGRP} -m ${MANMODE}
-.else
-MINSTALL?= ${INSTALL} ${TAG_ARGS:D${TAG_ARGS},man} -o ${MANOWN} -g ${MANGRP} -m ${MANMODE}
-.endif
+MANGROUPS?= MAN
+
+# Backwards compatibility.
+MINSTALL?= ${MANINSTALL}
CATDIR= ${MANDIR:H:S/$/\/cat/}
CATEXT= .cat
@@ -65,18 +71,55 @@ MCOMPRESS_EXT?= ${COMPRESS_EXT}
SECTIONS= 1 2 3 4 5 6 7 8 9
.SUFFIXES: ${SECTIONS:S/^/./g}
-
# Backwards compatibility.
.if !defined(MAN)
.for __sect in ${SECTIONS}
-.if defined(MAN${__sect}) && !empty(MAN${__sect})
-MAN+= ${MAN${__sect}}
-.endif
+MANGROUPS+= MAN${__sect}
.endfor
.endif
+# Following the conventions of MANGROUPS, manpage links should be defined
+# as ${group}LINKS, which means the default groups' links would be called
+# MANLINKS. However it's actually called MLINKS, so for compatibility,
+# use ${MLINKS} as the default group's links if it's set.
+.if defined(MLINKS)
+MANLINKS= ${MLINKS}
+.endif
+
+maninstall: realmaninstall manlinksinstall .PHONY
+# Make sure all manpages are installed before we try to link any.
+.ORDER: realmaninstall manlinksinstall
+realmaninstall: .PHONY
+manlinksinstall: .PHONY
+
all-man:
+.for __group in ${MANGROUPS}
+
+realmaninstall: realmaninstall-${__group}
+manlinksinstall: manlinksinstall-${__group}
+
+${__group}OWN?= ${MANOWN}
+${__group}GRP?= ${MANGRP}
+${__group}MODE?= ${MANMODE}
+
+# Tag processing is only done for NO_ROOT installs.
+.if defined(NO_ROOT)
+
+.if !defined(${__group}TAGS) || ! ${${__group}TAGS:Mpackage=*}
+.if ${MK_MANSPLITPKG} == "no"
+${__group}TAGS+= package=${${__group}PACKAGE:U${PACKAGE:Uutilities}}
+.else
+${__group}TAGS+= package=${${__group}PACKAGE:U${PACKAGE:Uutilities}}-man
+.endif
+.endif
+
+${__group}TAG_ARGS= -T ${${__group}TAGS:[*]:S/ /,/g}
+.endif # defined(NO_ROOT)
+
+${__group}INSTALL?= ${INSTALL} ${${__group}TAG_ARGS} \
+ -o ${${__group}OWN} -g ${${__group}GRP} -m ${${__group}MODE}
+
.if ${MK_MANCOMPRESS} == "no"
# Make special arrangements to filter to a temporary file at build time
@@ -90,10 +133,10 @@ FILTEXTENSION=
ZEXT=
.if defined(MANFILTER)
-.if defined(MAN) && !empty(MAN)
-CLEANFILES+= ${MAN:T:S/$/${FILTEXTENSION}/g}
-CLEANFILES+= ${MAN:T:S/$/${CATEXT}${FILTEXTENSION}/g}
-.for __page in ${MAN}
+.if defined(${__group}) && !empty(${__group})
+CLEANFILES+= ${${__group}:T:S/$/${FILTEXTENSION}/g}
+CLEANFILES+= ${${__group}:T:S/$/${CATEXT}${FILTEXTENSION}/g}
+.for __page in ${${__group}}
.for __target in ${__page:T:S/$/${FILTEXTENSION}/g}
all-man: ${__target}
${__target}: ${__page}
@@ -107,12 +150,12 @@ ${__target}: ${__page}
.endfor
.endif
.endfor
-.endif # !empty(MAN)
+.endif # !empty(${__group})
.else # !defined(MANFILTER)
-.if defined(MAN) && !empty(MAN)
-CLEANFILES+= ${MAN:T:S/$/${CATEXT}/g}
+.if defined(${__group}) && !empty(${__group})
+CLEANFILES+= ${${__group}:T:S/$/${CATEXT}/g}
.if defined(MANBUILDCAT) && !empty(MANBUILDCAT)
-.for __page in ${MAN}
+.for __page in ${${__group}}
.for __target in ${__page:T:S/$/${CATEXT}/g}
all-man: ${__target}
${__target}: ${__page}
@@ -120,7 +163,7 @@ ${__target}: ${__page}
.endfor
.endfor
.else
-all-man: ${MAN}
+all-man: ${${__group}}
.endif
.endif
.endif # defined(MANFILTER)
@@ -129,10 +172,10 @@ all-man: ${MAN}
ZEXT= ${MCOMPRESS_EXT}
-.if defined(MAN) && !empty(MAN)
-CLEANFILES+= ${MAN:T:S/$/${MCOMPRESS_EXT}/g}
-CLEANFILES+= ${MAN:T:S/$/${CATEXT}${MCOMPRESS_EXT}/g}
-.for __page in ${MAN}
+.if defined(${__group}) && !empty(${__group})
+CLEANFILES+= ${${__group}:T:S/$/${MCOMPRESS_EXT}/g}
+CLEANFILES+= ${${__group}:T:S/$/${CATEXT}${MCOMPRESS_EXT}/g}
+.for __page in ${${__group}}
.for __target in ${__page:T:S/$/${MCOMPRESS_EXT}/}
all-man: ${__target}
${__target}: ${__page}
@@ -158,8 +201,9 @@ ${__target}: ${__page}
.endif # ${MK_MANCOMPRESS} == "no"
-.if !defined(NO_MLINKS) && defined(MLINKS) && !empty(MLINKS)
-.for _oname _osect _dname _dsect in ${MLINKS:C/\.([^.]*)$/.\1 \1/}
+_MANLINKS=
+.if !defined(NO_MLINKS) && defined(${__group}LINKS) && !empty(${__group}LINKS)
+.for _oname _osect _dname _dsect in ${${__group}LINKS:C/\.([^.]*)$/.\1 \1/}
_MANLINKS+= ${MANDIR}${_osect}${MANSUBDIR}/${_oname} \
${MANDIR}${_dsect}${MANSUBDIR}/${_dname}
.if defined(MANBUILDCAT) && !empty(MANBUILDCAT)
@@ -169,37 +213,37 @@ _MANLINKS+= ${CATDIR}${_osect}${MANSUBDIR}/${_oname} \
.endfor
.endif
-.if defined(MAN) && !empty(MAN)
+.if defined(${__group}) && !empty(${__group})
.if ${MK_STAGING_MAN} == "yes"
-STAGE_TARGETS+= stage_files
-_mansets:= ${MAN:E:O:u:M*[1-9]:@s@man$s@}
-STAGE_SETS+= ${_mansets}
-.for _page in ${MAN}
-stage_files.man${_page:T:E}: ${_page}
+STAGE_TARGETS+= stage_files.${__group}
+_mansets.${__group}:= ${${__group}:E:O:u:M*[1-9]:@s@man$s@}
+STAGE_SETS+= ${_mansets.${__group}}
+.for _page in ${${__group}}
+stage_files.${__group}.man${_page:T:E}: ${_page}
.if target(${_page}${MCOMPRESS_EXT})
-stage_files.man${_page:T:E}: ${_page}${MCOMPRESS_EXT}
+stage_files.${__group}.man${_page:T:E}: ${_page}${MCOMPRESS_EXT}
.endif
-STAGE_DIR.man${_page:T:E}?= ${STAGE_OBJTOP}${MANDIR}${_page:T:E}${MANSUBDIR}
+STAGE_DIR.${__group}.man${_page:T:E}?= ${STAGE_OBJTOP}${MANDIR}${_page:T:E}${MANSUBDIR}
.endfor
-.if !defined(NO_MLINKS) && !empty(MLINKS)
-STAGE_SETS+= mlinks
-STAGE_TARGETS+= stage_links
-STAGE_LINKS.mlinks:= ${MLINKS:M*.[1-9]:@f@${f:S,^,${MANDIR}${f:E}${MANSUBDIR}/,}@}
-stage_links.mlinks: ${_mansets:@s@stage_files.$s@}
+.if !defined(NO_MLINKS) && !empty(${__group}LINKS)
+STAGE_SETS+= mlinks.${__group}
+STAGE_TARGETS+= stage_links.${__group}
+STAGE_LINKS.mlinks.${__group}:= ${${__group}LINKS:M*.[1-9]:@f@${f:S,^,${MANDIR}${f:E}${MANSUBDIR}/,}@}
+stage_links.mlinks.${__group}: ${_mansets.${__group}:@s@stage_files.${__group}.$s@}
.endif
.endif
.endif
-maninstall:
-.if defined(MAN) && !empty(MAN)
-maninstall: ${MAN}
+realmaninstall-${__group}:
+.if defined(${__group}) && !empty(${__group})
+realmaninstall-${__group}: ${${__group}}
.if ${MK_MANCOMPRESS} == "no"
.if defined(MANFILTER)
-.for __page in ${MAN}
- ${MINSTALL} ${__page:T:S/$/${FILTEXTENSION}/g} \
+.for __page in ${${__group}}
+ ${${__group}INSTALL} ${__page:T:S/$/${FILTEXTENSION}/g} \
${DESTDIR}${MANDIR}${__page:E}${MANSUBDIR}/${__page}
.if defined(MANBUILDCAT) && !empty(MANBUILDCAT)
- ${MINSTALL} ${__page:T:S/$/${CATEXT}${FILTEXTENSION}/g} \
+ ${${__group}INSTALL} ${__page:T:S/$/${CATEXT}${FILTEXTENSION}/g} \
${DESTDIR}${CATDIR}${__page:E}${MANSUBDIR}/${__page}
.endif
.endfor
@@ -212,41 +256,39 @@ maninstall: ${MAN}
esac; \
page=$$1; shift; sect=$$1; shift; \
d=${DESTDIR}${MANDIR}$${sect}${MANSUBDIR}; \
- ${ECHO} ${MINSTALL} $${page} $${d}; \
- ${MINSTALL} $${page} $${d}; \
+ ${ECHO} ${${__group}INSTALL} $${page} $${d}; \
+ ${${__group}INSTALL} $${page} $${d}; \
done
.if defined(MANBUILDCAT) && !empty(MANBUILDCAT)
-.for __page in ${MAN}
- ${MINSTALL} ${__page:T:S/$/${CATEXT}/} \
+.for __page in ${${__group}}
+ ${${__group}INSTALL} ${__page:T:S/$/${CATEXT}/} \
${DESTDIR}${CATDIR}${__page:E}${MANSUBDIR}/${__page:T}
.endfor
.endif
.endif # defined(MANFILTER)
.else # ${MK_MANCOMPRESS} == "yes"
-.for __page in ${MAN}
- ${MINSTALL} ${__page:T:S/$/${MCOMPRESS_EXT}/g} \
+.for __page in ${${__group}}
+ ${${__group}INSTALL} ${__page:T:S/$/${MCOMPRESS_EXT}/g} \
${DESTDIR}${MANDIR}${__page:E}${MANSUBDIR}/
.if defined(MANBUILDCAT) && !empty(MANBUILDCAT)
- ${MINSTALL} ${__page:T:S/$/${CATEXT}${MCOMPRESS_EXT}/g} \
+ ${${__group}INSTALL} ${__page:T:S/$/${CATEXT}${MCOMPRESS_EXT}/g} \
${DESTDIR}${CATDIR}${__page:E}${MANSUBDIR}/${__page:T:S/$/${MCOMPRESS_EXT}/}
.endif
.endfor
.endif # ${MK_MANCOMPRESS} == "no"
.endif
+
+manlinksinstall-${__group}:
.for l t in ${_MANLINKS}
# On MacOS, assume case folding FS, and don't install links from foo.x to FOO.x.
.if ${.MAKE.OS} != "Darwin" || ${l:tu} != ${t:tu}
-.if ${MK_MANSPLITPKG} == "no"
- ${INSTALL_MANLINK} ${TAG_ARGS} ${DESTDIR}${l}${ZEXT} ${DESTDIR}${t}${ZEXT}
-.else
- ${INSTALL_MANLINK} ${TAG_ARGS:D${TAG_ARGS},man} ${DESTDIR}${l}${ZEXT} ${DESTDIR}${t}${ZEXT}
-.endif
+ ${INSTALL_MANLINK} ${${__group}TAG_ARGS} ${DESTDIR}${l}${ZEXT} ${DESTDIR}${t}${ZEXT}
.endif
.endfor
manlint:
-.if defined(MAN) && !empty(MAN)
-.for __page in ${MAN}
+.if defined(${__group}) && !empty(${__group})
+.for __page in ${${__group}}
manlint: ${__page}lint
${__page}lint: ${__page}
.if defined(MANFILTER)
@@ -256,3 +298,5 @@ ${__page}lint: ${__page}
.endif
.endfor
.endif
+
+.endfor # __group in ${MANGROUPS}
diff --git a/share/mk/bsd.subdir.mk b/share/mk/bsd.subdir.mk
index cf19c9d66201..289e3d591c8c 100644
--- a/share/mk/bsd.subdir.mk
+++ b/share/mk/bsd.subdir.mk
@@ -76,13 +76,14 @@ obj: .PHONY
.endif
.if !defined(NEED_SUBDIR)
+.if ${MK_DIRDEPS_BUILD} == "yes"
+# ignore this
+_SUBDIR:
# .MAKE.DEPENDFILE==/dev/null is set by bsd.dep.mk to avoid reading
# Makefile.depend
-.if ${.MAKE.LEVEL} == 0 && ${MK_DIRDEPS_BUILD} == "yes" && !empty(SUBDIR) && \
- ${.MAKE.DEPENDFILE} != "/dev/null"
+.if ${.MAKE.LEVEL} == 0 && !empty(SUBDIR) && ${.MAKE.DEPENDFILE} != "/dev/null"
.include <meta.subdir.mk>
-# ignore this
-_SUBDIR:
+.endif
.endif
.endif
diff --git a/share/mk/src.opts.mk b/share/mk/src.opts.mk
index 387e570f8518..77923ae7b6d1 100644
--- a/share/mk/src.opts.mk
+++ b/share/mk/src.opts.mk
@@ -123,7 +123,6 @@ __DEFAULT_YES_OPTIONS = \
LEGACY_CONSOLE \
LLD \
LLD_BOOTSTRAP \
- LLVM_ASSERTIONS \
LLVM_BINUTILS \
LLVM_COV \
LLVM_CXXFILT \
@@ -143,6 +142,7 @@ __DEFAULT_YES_OPTIONS = \
MAIL \
MAILWRAPPER \
MAKE \
+ MITKRB5 \
MLX5TOOL \
NETCAT \
NETGRAPH \
@@ -209,9 +209,9 @@ __DEFAULT_NO_OPTIONS = \
HESIOD \
LOADER_VERBOSE \
LOADER_VERIEXEC_PASS_MANIFEST \
+ LLVM_ASSERTIONS \
LLVM_FULL_DEBUGINFO \
MALLOC_PRODUCTION \
- MITKRB5 \
OFED_EXTRA \
OPENLDAP \
REPRODUCIBLE_BUILD \
diff --git a/share/termcap/termcap b/share/termcap/termcap
index 46b89d0b3ddf..44704653045d 100644
--- a/share/termcap/termcap
+++ b/share/termcap/termcap
@@ -4705,14 +4705,14 @@ xterm-termite|VTE-based terminal:\
:ti=\E[?1049h:ts=\E]2;:u6=\E[%i%d;%dR:u7=\E[6n:ue=\E[24m:\
:up=\E[A:us=\E[4m:ve=\E[?25h:vi=\E[?25l:
-# Termcap for st terminal taken from the st-0.8 sources
-st|simpleterm:\
+# Termcap for st terminal taken from the st-0.9.2 sources
+st-mono|simpleterm monocolor:\
:am:hs:mi:ms:xn:\
:co#80:it#8:li#24:\
:AL=\E[%dL:DC=\E[%dP:DL=\E[%dM:DO=\E[%dB:IC=\E[%d@:\
:K1=\E[1~:K2=\EOu:K3=\E[5~:K4=\E[4~:K5=\E[6~:LE=\E[%dD:\
- :RI=\E[%dC:SF=\E[%dS:UP=\E[%dA:ae=\E(B:al=\E[L:as=\E(0:\
- :bl=^G:bt=\E[Z:cd=\E[J:ce=\E[K:cl=\E[H\E[2J:\
+ :RI=\E[%dC:SF=\E[%dS:SR=\E[%dT:UP=\E[%dA:ae=\E(B:al=\E[L:\
+ :as=\E(0:bl=^G:bt=\E[Z:cd=\E[J:ce=\E[K:cl=\E[H\E[2J:\
:cm=\E[%i%d;%dH:cr=\r:cs=\E[%i%d;%dr:ct=\E[3g:dc=\E[P:\
:dl=\E[M:do=\n:ec=\E[%dX:ei=\E[4l:fs=^G:ho=\E[H:im=\E[4h:\
:is=\E[4l\E>\E[?1034l:k1=\EOP:k2=\EOQ:k3=\EOR:k4=\EOS:\
@@ -4725,6 +4725,14 @@ st|simpleterm:\
:ue=\E[24m:up=\E[A:us=\E[4m:vb=\E[?5h\E[?5l:\
:ve=\E[?12l\E[?25h:vi=\E[?25l:vs=\E[?25h:
+st|simpleterm:\
+ :Co#8:\
+ :AB=\E[4%dm:AF=\E[3%dm:\
+ :..Sb=\E[4%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m:\
+ :..Sf=\E[3%?%p1%{1}%=%t4%e%p1%{3}%=%t6%e%p1%{4}%=%t1%e%p1%{6}%=%t3%e%p1%d%;m:\
+ :..sa=%?%p9%t\E(0%e\E(B%;\E[0%?%p6%t;1%;%?%p2%t;4%;%?%p1%p3%|%t;7%;%?%p4%t;5%;%?%p7%t;8%;m:\
+ :tc=st-mono:
+
st-256color|simpleterm with 256 colors:\
:cc:\
:Co#256:pa#32767:\
@@ -4742,6 +4750,12 @@ st-meta-256color|simpleterm with meta key and 256 colors:\
:is=\E[4l\E>\E[?1034h:mm=\E[?1034h:mo=\E[?1034l:\
:rs=\E[4l\E>\E[?1034h:tc=st-256color:
+st-bs|simpleterm with backspace as backspace:\
+ :kD=\177:kb=^H:tc=st:
+
+st-bs-256color|simpleterm with backspace as backspace and 256colors:\
+ :kD=\177:kb=^H:tc=st-256color:
+
# From version 0.13.3
xterm-kitty|KovId's TTY:\
diff --git a/stand/common/bootstrap.h b/stand/common/bootstrap.h
index dca0cf6bb2d5..17887919089c 100644
--- a/stand/common/bootstrap.h
+++ b/stand/common/bootstrap.h
@@ -372,6 +372,8 @@ extern struct arch_switch archsw;
/* This must be provided by the MD code, but should it be in the archsw? */
void delay(int delay);
+int setprint_delay(struct env_var *ev, int flags, const void *value);
+
/* common code to set currdev variable. */
int gen_setcurrdev(struct env_var *ev, int flags, const void *value);
int mount_currdev(struct env_var *, int, const void *);
diff --git a/stand/common/console.c b/stand/common/console.c
index 82cb552b4ef2..65ab7ffad622 100644
--- a/stand/common/console.c
+++ b/stand/common/console.c
@@ -44,6 +44,8 @@ static int twiddle_set(struct env_var *ev, int flags, const void *value);
#endif
int module_verbose = MODULE_VERBOSE;
+static uint32_t print_delay_usec = 0;
+
static int
module_verbose_set(struct env_var *ev, int flags, const void *value)
{
@@ -66,6 +68,23 @@ module_verbose_set(struct env_var *ev, int flags, const void *value)
}
/*
+ * Hook to set the print delay
+ */
+int
+setprint_delay(struct env_var *ev, int flags, const void *value)
+{
+ char *end;
+ int usec = strtol(value, &end, 10);
+
+ if (*(char *)value == '\0' || *end != '\0')
+ return (EINVAL);
+ if (usec < 0)
+ return (EINVAL);
+ print_delay_usec = usec;
+ return (0);
+}
+
+/*
* Detect possible console(s) to use. If preferred console(s) have been
* specified, mark them as active. Else, mark the first probed console
* as active. Also create the console variable.
@@ -178,6 +197,10 @@ putchar(int c)
(C_PRESENTOUT | C_ACTIVEOUT))
consoles[cons]->c_out(c);
}
+
+ /* Pause after printing newline character if a print delay is set */
+ if (print_delay_usec != 0 && c == '\n')
+ delay(print_delay_usec);
}
/*
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/common/install.c b/stand/common/install.c
index 249eca1648f3..d07c4c6fc620 100644
--- a/stand/common/install.c
+++ b/stand/common/install.c
@@ -137,7 +137,9 @@ read_metatags(int fd)
}
*p++ = '\0';
- if (strcmp(tag, "KERNEL") == 0)
+ if (strncmp(tag, "ENV_", 4) == 0)
+ setenv(&tag[4], val, 1);
+ else if (strcmp(tag, "KERNEL") == 0)
error = setpath(&inst_kernel, val);
else if (strcmp(tag, "MODULES") == 0)
error = setmultipath(&inst_modules, val);
diff --git a/stand/defaults/loader.conf b/stand/defaults/loader.conf
index 1834e3ba3b34..f0843f3e930b 100644
--- a/stand/defaults/loader.conf
+++ b/stand/defaults/loader.conf
@@ -95,6 +95,8 @@ audit_event_type="etc_security_audit_event"
# Default is unset and disabled (no delay).
#autoboot_delay="10" # Delay in seconds before autobooting,
# -1 for no user interrupts, NO to disable
+#print_delay="1000000" # Slow printing of loader messages, useful for
+ # debugging. Given in microseconds.
#password="" # Prevent changes to boot options
#bootlock_password="" # Prevent booting (see check-password.4th(8))
#geom_eli_passphrase_prompt="NO" # Prompt for geli(8) passphrase to mount root
diff --git a/stand/defaults/loader.conf.5 b/stand/defaults/loader.conf.5
index 021f68f2309e..dc1c8f7f44e0 100644
--- a/stand/defaults/loader.conf.5
+++ b/stand/defaults/loader.conf.5
@@ -21,7 +21,7 @@
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
-.Dd June 5, 2025
+.Dd June 12, 2025
.Dt LOADER.CONF 5
.Os
.Sh NAME
@@ -116,6 +116,10 @@ option in this manner,
.Va beastie_disable
must be set to
.Dq Li YES .
+.It Ar print_delay
+Add a delay in microseconds after printing each line.
+Default
+.Dq Li 0 .
.It Ar boot_*
See list in
.Xr loader.efi 8
diff --git a/stand/efi/loader/main.c b/stand/efi/loader/main.c
index 3ef418d20df3..436676368447 100644
--- a/stand/efi/loader/main.c
+++ b/stand/efi/loader/main.c
@@ -1241,6 +1241,9 @@ main(int argc, CHAR16 *argv[])
#endif
cons_probe();
+ /* Set print_delay variable to have hooks in place. */
+ env_setenv("print_delay", EV_VOLATILE, "", setprint_delay, env_nounset);
+
/* Set up currdev variable to have hooks in place. */
env_setenv("currdev", EV_VOLATILE, "", gen_setcurrdev, env_nounset);
diff --git a/stand/fdt/fdt_loader_cmd.c b/stand/fdt/fdt_loader_cmd.c
index 226812a5d2a6..161c2435c410 100644
--- a/stand/fdt/fdt_loader_cmd.c
+++ b/stand/fdt/fdt_loader_cmd.c
@@ -1240,13 +1240,6 @@ fdt_cmd_ls(int argc, char *argv[])
return (CMD_OK);
}
-static __inline int
-isprint(int c)
-{
-
- return (c >= ' ' && c <= 0x7e);
-}
-
static int
fdt_isprint(const void *data, int len, int *count)
{
diff --git a/stand/i386/Makefile b/stand/i386/Makefile
index 768496598575..299e070d8cd5 100644
--- a/stand/i386/Makefile
+++ b/stand/i386/Makefile
@@ -18,7 +18,7 @@ SUBDIR.yes+= loader_simp
# special boot programs, 'self-extracting boot2+loader'
SUBDIR.${MK_LOADER_PXEBOOT}+= pxeldr
-SUBDIR.${MK_LOADER_ZFS}+= zfsboot gptzfsboot
+SUBDIR.${MK_LOADER_ZFS}+= gptzfsboot
.if defined(PXEBOOT_DEFAULT_INTERP)
L=${PXEBOOT_DEFAULT_INTERP}
diff --git a/stand/i386/common/bootargs.h b/stand/i386/common/bootargs.h
index dafcf6a55554..072f7ee505fd 100644
--- a/stand/i386/common/bootargs.h
+++ b/stand/i386/common/bootargs.h
@@ -88,7 +88,7 @@ struct bootargs
/*
* geli_boot_data is embedded in geli_boot_args (passed from gptboot to loader)
- * and in zfs_boot_args (passed from zfsboot and gptzfsboot to loader).
+ * and in zfs_boot_args (passed from gptzfsboot to loader).
*/
struct geli_boot_data
{
diff --git a/stand/i386/gptboot/Makefile b/stand/i386/gptboot/Makefile
index b91875d242f5..a829be6c745d 100644
--- a/stand/i386/gptboot/Makefile
+++ b/stand/i386/gptboot/Makefile
@@ -1,6 +1,6 @@
.include <bsd.init.mk>
-.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${SASRC}
+.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common
FILES= gptboot
MAN= gptboot.8
@@ -53,12 +53,12 @@ gptldr.out: gptldr.o
${LD} ${LD_FLAGS} -e start --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} gptldr.o
CLEANFILES+= gptboot.bin gptboot.out gptboot.o sio.o drv.o \
- cons.o ${OPENCRYPTO_XTS}
+ cons.o
gptboot.bin: gptboot.out
${OBJCOPY} -S -O binary gptboot.out ${.TARGET}
-gptboot.out: ${BTXCRT} gptboot.o sio.o drv.o cons.o ${OPENCRYPTO_XTS}
+gptboot.out: ${BTXCRT} gptboot.o sio.o drv.o cons.o
${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBSA32}
.include <bsd.prog.mk>
diff --git a/stand/i386/gptzfsboot/Makefile b/stand/i386/gptzfsboot/Makefile
index 0d9fa8b043df..0b67ff8cdaf4 100644
--- a/stand/i386/gptzfsboot/Makefile
+++ b/stand/i386/gptzfsboot/Makefile
@@ -1,7 +1,7 @@
.include <bsd.init.mk>
.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/gptboot \
- ${BOOTSRC}/i386/zfsboot ${BOOTSRC}/i386/common \
+ ${BOOTSRC}/i386/common \
${BOOTSRC}/common
FILES= gptzfsboot
@@ -65,7 +65,7 @@ gptldr.out: gptldr.o
${LD} ${LD_FLAGS} -e start --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} gptldr.o
OBJS= zfsboot.o sio.o cons.o bcache.o devopen.o disk.o part.o zfs_cmd.o misc.o
-CLEANFILES+= gptzfsboot.bin gptzfsboot.out ${OBJS} ${OPENCRYPTO_XTS}
+CLEANFILES+= gptzfsboot.bin gptzfsboot.out ${OBJS}
# i386 standalone support library
LIBI386= ${BOOTOBJ}/i386/libi386/libi386.a
@@ -73,8 +73,7 @@ LIBI386= ${BOOTOBJ}/i386/libi386/libi386.a
gptzfsboot.bin: gptzfsboot.out
${OBJCOPY} -S -O binary gptzfsboot.out ${.TARGET}
-gptzfsboot.out: ${BTXCRT} ${OBJS} \
- ${OPENCRYPTO_XTS}
+gptzfsboot.out: ${BTXCRT} ${OBJS}
${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBI386} ${LIBSA32}
zfsboot.o: ${ZFSSRC}/zfsimpl.c
diff --git a/stand/i386/zfsboot/zfsboot.c b/stand/i386/gptzfsboot/zfsboot.c
index 4c8eae9b65e5..4c8eae9b65e5 100644
--- a/stand/i386/zfsboot/zfsboot.c
+++ b/stand/i386/gptzfsboot/zfsboot.c
diff --git a/stand/i386/isoboot/Makefile b/stand/i386/isoboot/Makefile
index 7973f8029aa0..0049e7fd3e0a 100644
--- a/stand/i386/isoboot/Makefile
+++ b/stand/i386/isoboot/Makefile
@@ -1,7 +1,7 @@
.include <bsd.init.mk>
.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/gptboot \
- ${BOOTSRC}/i386/common ${SASRC}
+ ${BOOTSRC}/i386/common
FILES= isoboot
MAN= isoboot.8
@@ -51,12 +51,12 @@ gptldr.out: gptldr.o
${LD} ${LD_FLAGS} -e start --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} gptldr.o
CLEANFILES+= isoboot.bin isoboot.out isoboot.o sio.o drv.o \
- cons.o ${OPENCRYPTO_XTS}
+ cons.o
isoboot.bin: isoboot.out
${OBJCOPY} -S -O binary isoboot.out ${.TARGET}
-isoboot.out: ${BTXCRT} isoboot.o sio.o drv.o cons.o ${OPENCRYPTO_XTS}
+isoboot.out: ${BTXCRT} isoboot.o sio.o drv.o cons.o
${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBSA32}
.include <bsd.prog.mk>
diff --git a/stand/i386/libi386/Makefile b/stand/i386/libi386/Makefile
index 038557c6a826..7205d3a61988 100644
--- a/stand/i386/libi386/Makefile
+++ b/stand/i386/libi386/Makefile
@@ -7,6 +7,7 @@ SRCS+= bio.c
SRCS+= biosacpi.c
SRCS+= biosdisk.c
SRCS+= biosmem.c
+SRCS+= biosmemdisk.c
SRCS+= biospci.c
SRCS+= biospnp.c
SRCS+= biossmap.c
diff --git a/stand/i386/libi386/biosmemdisk.c b/stand/i386/libi386/biosmemdisk.c
new file mode 100644
index 000000000000..208ae289950a
--- /dev/null
+++ b/stand/i386/libi386/biosmemdisk.c
@@ -0,0 +1,140 @@
+/*-
+ * Copyright (c) 2020 Richard Russo <russor@ruka.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * Source of information: https://repo.or.cz/syslinux.git
+ *
+ * Implements the MEMDISK protocol from syslinux, found in doc/memdisk.txt
+ * (search MEMDISK info structure). Since we validate the pointer to the mBFT, a
+ * minimum version of 3.85 is needed. Note: All this could be done in the
+ * kernel, since we don't have hooks to use this inside the boot loader. The
+ * details of these structures can be found in memdisk/memdisk.inc (search
+ * for mBFT).
+ *
+ * The kernel could just grab the mBFT table, but instead relies on us finding
+ * it and setting the right env variables.
+ */
+#include <stand.h>
+#include <machine/stdarg.h>
+#include <bootstrap.h>
+#include <btxv86.h>
+#include "libi386.h"
+
+#include "platform/acfreebsd.h"
+#include "acconfig.h"
+#define ACPI_SYSTEM_XFACE
+#include "actypes.h"
+#include "actbl.h"
+
+struct memdisk_info {
+ uint32_t mdi_13h_hook_ptr; /* not included in mdi_length! */
+ uint16_t mdi_length;
+ uint8_t mdi_minor;
+ uint8_t mdi_major;
+ uint32_t mdi_disk_ptr;
+ uint32_t mdi_disk_sectors;
+ uint32_t mdi_far_ptr_cmdline;
+ uint32_t mdi_old_int13h;
+ uint32_t mdi_old_int15h;
+ uint16_t mdi_dos_mem_before;
+ uint8_t mdi_boot_loader_id;
+ uint8_t mdi_sector_size; /* Code below assumes this is last */
+} __attribute__((packed));
+
+struct safe_13h_hook {
+ char sh_jmp[3];
+ char sh_id[8];
+ char sh_vendor[8];
+ uint16_t sh_next_offset;
+ uint16_t sh_next_segment;
+ uint32_t sh_flags;
+ uint32_t sh_mbft;
+} __attribute__((packed));
+
+/*
+ * Maximum length of INT 13 entries we'll chase. Real disks are on this list,
+ * potentially, so we may have to look through them to find the memdisk.
+ */
+#define MEMDISK_MAX 32
+
+/*
+ * Scan for MEMDISK virtual block devices
+ */
+void
+biosmemdisk_detect(void)
+{
+ char line[80], scratch[80];
+ int hook = 0, count = 0, sector_size;
+ uint16_t segment, offset;
+ struct safe_13h_hook *probe;
+ ACPI_TABLE_HEADER *mbft;
+ uint8_t *cp, sum;
+ struct memdisk_info *mdi;
+
+ /*
+ * Walk through the int13 handler linked list, looking for possible
+ * MEMDISKs.
+ *
+ * The max is arbitrary to ensure termination.
+ */
+ offset = *(uint16_t *)PTOV(0x13 * 4);
+ segment = *(uint16_t *)PTOV(0x13 * 4 + 2);
+ while (hook < MEMDISK_MAX && !(segment == 0 && offset == 0)) {
+ /*
+ * Walk the linked list, making sure each node has the right
+ * signature and only looking at MEMDISK nodes.
+ */
+ probe = (struct safe_13h_hook *)PTOV(segment * 16 + offset);
+ if (memcmp(probe->sh_id, "$INT13SF", sizeof(probe->sh_id)) != 0) {
+ printf("Found int 13h unsafe hook at %p (%x:%x)\n",
+ probe, segment, offset);
+ break;
+ }
+ if (memcmp(probe->sh_vendor, "MEMDISK ", sizeof(probe->sh_vendor)) != 0)
+ goto end_of_loop;
+
+ /*
+ * If it is a memdisk, make sure the mBFT signature is correct
+ * and its checksum is right.
+ */
+ mbft = (ACPI_TABLE_HEADER *)PTOV(probe->sh_mbft);
+ if (memcmp(mbft->Signature, "mBFT", sizeof(mbft->Signature)) != 0)
+ goto end_of_loop;
+ sum = 0;
+ cp = (uint8_t *)mbft;
+ for (int idx = 0; idx < mbft->Length; ++idx)
+ sum += *(cp + idx);
+ if (sum != 0)
+ goto end_of_loop;
+
+ /*
+ * The memdisk info follows the ACPI_TABLE_HEADER in the mBFT
+ * section. If the sector size is present and non-zero use it
+ * otherwise assume 512.
+ */
+ mdi = (struct memdisk_info *)PTOV(probe->sh_mbft + sizeof(*mbft));
+ sector_size = 512;
+ if (mdi->mdi_length + sizeof(mdi->mdi_13h_hook_ptr) >= sizeof(*mdi) &&
+ mdi->mdi_sector_size != 0)
+ sector_size = 1 << mdi->mdi_sector_size;
+
+ printf("memdisk %d.%d disk at %#x (%d sectors = %d bytes)\n",
+ mdi->mdi_major, mdi->mdi_minor, mdi->mdi_disk_ptr,
+ mdi->mdi_disk_sectors, mdi->mdi_disk_sectors * sector_size);
+
+ snprintf(line, sizeof(line), "hint.md.%d.physaddr", count);
+ snprintf(scratch, sizeof(scratch), "0x%08x", mdi->mdi_disk_ptr);
+ setenv(line, scratch, 1);
+ snprintf(line, sizeof(line), "hint.md.%d.len", count);
+ snprintf(scratch, sizeof(scratch), "%d", mdi->mdi_disk_sectors * sector_size);
+ setenv(line, scratch, 1);
+ count++;
+end_of_loop:
+ hook++;
+ offset = probe->sh_next_offset;
+ segment = probe->sh_next_segment;
+ }
+}
diff --git a/stand/i386/libi386/libi386.h b/stand/i386/libi386/libi386.h
index d456ef58d7c2..caf565dd0656 100644
--- a/stand/i386/libi386/libi386.h
+++ b/stand/i386/libi386/libi386.h
@@ -149,3 +149,5 @@ int bi_load64(char *args, vm_offset_t *modulep,
vm_offset_t *kernend, int add_smap);
void pxe_enable(void *pxeinfo);
+
+void biosmemdisk_detect(void);
diff --git a/stand/i386/loader/main.c b/stand/i386/loader/main.c
index a7dfb2dde762..a70b3a253b90 100644
--- a/stand/i386/loader/main.c
+++ b/stand/i386/loader/main.c
@@ -198,7 +198,7 @@ main(void)
#ifdef LOADER_ZFS_SUPPORT
/*
- * zfsboot and gptzfsboot have always passed KARGS_FLAGS_ZFS,
+ * gptzfsboot has always passed KARGS_FLAGS_ZFS,
* so if that is set along with KARGS_FLAGS_EXTARG we know we
* can interpret the extarg data as a struct zfs_boot_args.
*/
@@ -251,6 +251,9 @@ main(void)
initial_bootinfo->bi_extmem = bios_extmem / 1024;
}
+ /* detect MEMDISK virtual disks */
+ biosmemdisk_detect();
+
/* detect SMBIOS for future reference */
smbios_detect(NULL);
diff --git a/stand/i386/zfsboot/Makefile b/stand/i386/zfsboot/Makefile
deleted file mode 100644
index b619b84c368e..000000000000
--- a/stand/i386/zfsboot/Makefile
+++ /dev/null
@@ -1,92 +0,0 @@
-.include <bsd.init.mk>
-
-.PATH: ${BOOTSRC}/i386/boot2 ${BOOTSRC}/i386/common ${BOOTSRC}/common
-
-FILES= zfsboot
-MAN= zfsboot.8
-
-BOOT_COMCONSOLE_PORT?= 0x3f8
-BOOT_COMCONSOLE_SPEED?= 115200
-B2SIOFMT?= 0x3
-
-REL1= 0x700
-ORG1= 0x7c00
-ORG2= 0x2000
-
-CFLAGS+=-DBOOTPROG=\"zfsboot\" \
- -O1 \
- -DBOOT2 \
- -DLOADER_GPT_SUPPORT \
- -DLOADER_MBR_SUPPORT \
- -DLOADER_ZFS_SUPPORT \
- -DLOADER_UFS_SUPPORT \
- -DSIOPRT=${BOOT_COMCONSOLE_PORT} \
- -DSIOFMT=${B2SIOFMT} \
- -DSIOSPD=${BOOT_COMCONSOLE_SPEED} \
- -I${LDRSRC} \
- -I${BOOTSRC}/i386/common \
- -I${BOOTSRC}/i386/libi386 \
- -I${ZFSSRC} \
- -I${SYSDIR}/crypto/skein \
- -I${SYSDIR}/cddl/boot/zfs \
- -I${SYSDIR}/contrib/openzfs/include \
- -I${SYSDIR}/contrib/openzfs/include/os/freebsd/spl \
- -I${SYSDIR}/contrib/openzfs/include/os/freebsd/zfs \
- -I${SYSDIR}/cddl/contrib/opensolaris/common/lz4 \
- -I${BOOTSRC}/i386/boot2 \
- -Wall -Waggregate-return -Wbad-function-cast -Wno-cast-align \
- -Wmissing-declarations -Wmissing-prototypes -Wnested-externs \
- -Wpointer-arith -Wshadow -Wstrict-prototypes -Wwrite-strings
-
-CFLAGS.part.c+= -DHAVE_MEMCPY -I${SRCTOP}/sys/contrib/zlib
-
-CFLAGS.gcc+= --param max-inline-insns-single=100
-
-LD_FLAGS+=${LD_FLAGS_BIN}
-
-CLEANFILES+= zfsboot
-
-zfsboot: zfsboot1 zfsboot2
- cat zfsboot1 zfsboot2 > zfsboot
-
-CLEANFILES+= zfsboot1 zfsldr.out zfsldr.o
-
-zfsboot1: zfsldr.out
- ${OBJCOPY} -S -O binary zfsldr.out ${.TARGET}
-
-zfsldr.out: zfsldr.o
- ${LD} ${LD_FLAGS} -e start --defsym ORG=${ORG1} -T ${LDSCRIPT} -o ${.TARGET} zfsldr.o
-
-OBJS= zfsboot.o sio.o cons.o bcache.o devopen.o disk.o part.o zfs_cmd.o misc.o
-CLEANFILES+= zfsboot2 zfsboot.ld zfsboot.ldr zfsboot.bin zfsboot.out \
- ${OBJS}
-
-# We currently allow 256k bytes for zfsboot - in practice it could be
-# any size up to 3.5Mb but keeping it fixed size simplifies zfsldr.
-#
-BOOT2SIZE= 262144
-
-# i386 standalone support library
-LIBI386= ${BOOTOBJ}/i386/libi386/libi386.a
-
-zfsboot2: zfsboot.ld
- @set -- `ls -l ${.ALLSRC}`; x=$$((${BOOT2SIZE}-$$5)); \
- echo "$$x bytes available"; test $$x -ge 0
- ${DD} if=${.ALLSRC} of=${.TARGET} bs=${BOOT2SIZE} conv=sync
-
-zfsboot.ld: zfsboot.ldr zfsboot.bin ${BTXKERN}
- btxld -v -E ${ORG2} -f bin -b ${BTXKERN} -l zfsboot.ldr \
- -o ${.TARGET} -P 1 zfsboot.bin
-
-zfsboot.ldr:
- :> ${.TARGET}
-
-zfsboot.bin: zfsboot.out
- ${OBJCOPY} -S -O binary zfsboot.out ${.TARGET}
-
-zfsboot.out: ${BTXCRT} ${OBJS}
- ${LD} ${LD_FLAGS} --defsym ORG=${ORG2} -T ${LDSCRIPT} -o ${.TARGET} ${.ALLSRC} ${LIBI386} ${LIBSA32}
-
-SRCS= zfsboot.c
-
-.include <bsd.prog.mk>
diff --git a/stand/i386/zfsboot/Makefile.depend b/stand/i386/zfsboot/Makefile.depend
deleted file mode 100644
index 92ab022283fd..000000000000
--- a/stand/i386/zfsboot/Makefile.depend
+++ /dev/null
@@ -1,17 +0,0 @@
-# Autogenerated - do NOT edit!
-
-DIRDEPS = \
- include \
- include/xlocale \
- lib/libmd \
- stand/i386/btx/btx \
- stand/i386/btx/lib \
- stand/libsa32 \
- stand/zfs32 \
-
-
-.include <dirdeps.mk>
-
-.if ${DEP_RELDIR} == ${_DEP_RELDIR}
-# local dependencies - needed for -jN in clean tree
-.endif
diff --git a/stand/i386/zfsboot/zfsboot.8 b/stand/i386/zfsboot/zfsboot.8
deleted file mode 100644
index a8411bc065d0..000000000000
--- a/stand/i386/zfsboot/zfsboot.8
+++ /dev/null
@@ -1,130 +0,0 @@
-.\" Copyright (c) 2014 Andriy Gapon <avg@FreeBSD.org>
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
-.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
-.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
-.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
-.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
-.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.Dd March 27, 2018
-.Dt ZFSBOOT 8
-.Os
-.Sh NAME
-.Nm zfsboot
-.Nd bootcode for ZFS on BIOS-based computers
-.Sh DESCRIPTION
-.Nm
-is used on BIOS-based computers to boot from a filesystem in
-a ZFS pool.
-.Nm
-is installed in two parts on a disk or a partition used by a ZFS pool.
-The first part, a single-sector starter boot block, is installed
-at the beginning of the disk or partition.
-The second part, a main boot block, is installed at a special offset
-within the disk or partition.
-Both areas are reserved by the ZFS on-disk specification for boot use.
-If
-.Nm
-is installed in a partition, then that partition should be made
-bootable using appropriate configuration and boot blocks described in
-.Xr boot 8 .
-.Sh BOOTING
-The
-.Nm
-boot process is very similar to that of
-.Xr gptzfsboot 8 .
-One significant difference is that
-.Nm
-does not currently support the GPT partitioning scheme.
-Thus only whole disks and MBR partitions, traditionally referred to as
-slices, are probed for ZFS disk labels.
-See the BUGS section in
-.Xr gptzfsboot 8
-for some limitations of the MBR scheme support.
-.Sh USAGE
-.Nm
-supports all the same prompt and configuration file arguments as
-.Xr gptzfsboot 8 .
-.Sh FILES
-.Bl -tag -width /boot/zfsboot -compact
-.It Pa /boot/zfsboot
-boot code binary
-.It Pa /boot.config
-parameters for the boot block
-.Pq optional
-.It Pa /boot/config
-alternative parameters for the boot block
-.Pq optional
-.El
-.Sh EXAMPLES
-.Nm
-is typically installed using
-.Xr dd 1 .
-To install
-.Nm
-on the
-.Pa ada0
-drive:
-.Bd -literal -offset indent
-dd if=/boot/zfsboot of=/dev/ada0 count=1
-dd if=/boot/zfsboot of=/dev/ada0 iseek=1 oseek=1024
-.Ed
-.Pp
-If the drive is currently in use, the GEOM safety will prevent writes
-and must be disabled before running the above commands:
-.Bd -literal -offset indent
-sysctl kern.geom.debugflags=0x10
-.Ed
-.Pp
-.Nm
-can also be installed in an MBR slice:
-.Bd -literal -offset indent
-gpart create -s mbr ada0
-gpart add -t freebsd ada0
-gpart bootcode -b /boot/boot0 ada0
-gpart set -a active -i 1 ada0
-dd if=/dev/zero of=/dev/ada0s1 count=2
-dd if=/boot/zfsboot of=/dev/ada0s1 count=1
-dd if=/boot/zfsboot of=/dev/ada0s1 iseek=1 oseek=1024
-.Ed
-.Pp
-Note that commands to create and populate a pool are not shown
-in the example above.
-.Sh SEE ALSO
-.Xr dd 1 ,
-.Xr boot.config 5 ,
-.Xr boot 8 ,
-.Xr gptzfsboot 8 ,
-.Xr loader 8 ,
-.Xr zpool 8
-.Sh HISTORY
-.Nm
-appeared in FreeBSD 7.3.
-.Sh AUTHORS
-This manual page was written by
-.An Andriy Gapon Aq avg@FreeBSD.org .
-.Sh BUGS
-Installing
-.Nm
-with
-.Xr dd 1
-is a hack.
-ZFS needs a command to properly install
-.Nm
-onto a ZFS-controlled disk or partition.
diff --git a/stand/i386/zfsboot/zfsldr.S b/stand/i386/zfsboot/zfsldr.S
deleted file mode 100644
index cd8289f952fd..000000000000
--- a/stand/i386/zfsboot/zfsldr.S
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright (c) 1998 Robert Nordier
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are freely
- * permitted provided that the above copyright notice and this
- * paragraph and the following disclaimer are duplicated in all
- * such forms.
- *
- * This software is provided "AS IS" and without any express or
- * implied warranties, including, without limitation, the implied
- * warranties of merchantability and fitness for a particular
- * purpose.
- */
-
-/* Memory Locations */
- .set MEM_ARG,0x900 # Arguments
- .set MEM_ORG,0x7c00 # Origin
- .set MEM_BUF,0x8000 # Load area
- .set MEM_BTX,0x9000 # BTX start
- .set MEM_JMP,0x9010 # BTX entry point
- .set MEM_USR,0xa000 # Client start
- .set BDA_BOOT,0x472 # Boot howto flag
-
-/* Partition Constants */
- .set PRT_OFF,0x1be # Partition offset
- .set PRT_NUM,0x4 # Partitions
- .set PRT_BSD,0xa5 # Partition type
-
-/* Misc. Constants */
- .set SIZ_PAG,0x1000 # Page size
- .set SIZ_SEC,0x200 # Sector size
- .set COPY_BLKS,0x8 # Number of blocks
- # to copy for boot2 (<= 15)
- .set COPY_BLK_SZ,0x8000 # Copy in 32k blocks; must be
- # a multiple of 16 bytes
- .set NSECT,(COPY_BLK_SZ / SIZ_SEC * COPY_BLKS)
- .globl start
- .code16
-
-/*
- * Load the rest of zfsboot2 and BTX up, copy the parts to the right locations,
- * and start it all up.
- */
-
-/*
- * Setup the segment registers to flat addressing (segment 0) and setup the
- * stack to end just below the start of our code.
- */
-start: cld # String ops inc
- xor %cx,%cx # Zero
- mov %cx,%es # Address
- mov %cx,%ds # data
- mov %cx,%ss # Set up
- mov $start,%sp # stack
-/*
- * Load the MBR and look for the first FreeBSD slice. We use the fake
- * partition entry below that points to the MBR when we call read.
- * The first pass looks for the first active FreeBSD slice. The
- * second pass looks for the first non-active FreeBSD slice if the
- * first one fails.
- */
- call check_edd # Make sure EDD works
- mov $part4,%si # Dummy partition
- xor %eax,%eax # Read MBR
- movl $MEM_BUF,%ebx # from first
- call read # sector
- mov $0x1,%cx # Two passes
-main.1: mov $MEM_BUF+PRT_OFF,%si # Partition table
- movb $0x1,%dh # Partition
-main.2: cmpb $PRT_BSD,0x4(%si) # Our partition type?
- jne main.3 # No
- jcxz main.5 # If second pass
- testb $0x80,(%si) # Active?
- jnz main.5 # Yes
-main.3: add $0x10,%si # Next entry
- incb %dh # Partition
- cmpb $0x1+PRT_NUM,%dh # In table?
- jb main.2 # Yes
- dec %cx # Do two
- jcxz main.1 # passes
-/*
- * If we get here, we didn't find any FreeBSD slices at all, so print an
- * error message and die.
- */
- mov $msg_part,%si # Message
- jmp error # Error
-
-/*
- * Ok, we have a slice and drive in %dx now, so use that to locate and
- * load boot2. %si references the start of the slice we are looking
- * for, so go ahead and load up the COPY_BLKS*COPY_BLK_SZ/SIZ_SEC sectors
- * starting at sector 1024 (i.e. after the two vdev labels). We don't
- * have do anything fancy here to allow for an extra copy of boot1 and
- * a partition table (compare to this section of the UFS bootstrap) so we
- * just load it all at 0x9000. The first part of boot2 is BTX, which wants
- * to run at 0x9000. The boot2.bin binary starts right after the end of BTX,
- * so we have to figure out where the start of it is and then move the
- * binary to 0xc000. Normally, BTX clients start at MEM_USR, or 0xa000,
- * but when we use btxld to create zfsboot2, we use an entry point of
- * 0x2000. That entry point is relative to MEM_USR; thus boot2.bin
- * starts at 0xc000.
- *
- * The load area and the target area for the client overlap so we have
- * to use a decrementing string move. We also play segment register
- * games with the destination address for the move so that the client
- * can be larger than 16k (which would overflow the zero segment since
- * the client starts at 0xc000).
- */
-main.5: mov %dx,MEM_ARG # Save args
- mov $NSECT,%cx # Sector count
- movl $1024,%eax # Offset to boot2
- mov $MEM_BTX,%ebx # Destination buffer
-main.6: pushal # Save params
- call read # Read disk
- popal # Restore
- incl %eax # Advance to
- add $SIZ_SEC,%ebx # next sector
- loop main.6 # If not last, read another
-
- mov $MEM_BTX,%bx # BTX
- mov 0xa(%bx),%si # Get BTX length and set
- add %bx,%si # %si to start of boot2
- dec %si # Set %ds:%si to point at the
- mov %si,%ax # last byte we want to copy
- shr $4,%ax # from boot2, with %si made as
- add $(COPY_BLKS*COPY_BLK_SZ/16),%ax # small as possible.
- and $0xf,%si #
- mov %ax,%ds #
- mov $(MEM_USR+2*SIZ_PAG)/16,%ax # Set %es:(-1) to point at
- add $(COPY_BLKS*COPY_BLK_SZ/16),%ax # the last byte we
- mov %ax,%es # want to copy boot2 into.
- mov $COPY_BLKS,%bx # Copy COPY_BLKS 32k blocks
-copyloop:
- add $COPY_BLK_SZ,%si # Adjust %ds:%si to point at
- mov %ds,%ax # the end of the next 32k to
- sub $COPY_BLK_SZ/16,%ax # copy from boot2
- mov %ax,%ds
- mov $COPY_BLK_SZ-1,%di # Adjust %es:%di to point at
- mov %es,%ax # the end of the next 32k into
- sub $COPY_BLK_SZ/16,%ax # which we want boot2 copied
- mov %ax,%es
- mov $COPY_BLK_SZ,%cx # Copy 32k
- std
- rep movsb
- dec %bx
- jnz copyloop
- mov %cx,%ds # Reset %ds and %es
- mov %cx,%es
- cld # Back to increment
-
-/*
- * Enable A20 so we can access memory above 1 meg.
- * Use the zero-valued %cx as a timeout for embedded hardware which do not
- * have a keyboard controller.
- */
-seta20: cli # Disable interrupts
-seta20.1: dec %cx # Timeout?
- jz seta20.3 # Yes
- inb $0x64,%al # Get status
- testb $0x2,%al # Busy?
- jnz seta20.1 # Yes
- movb $0xd1,%al # Command: Write
- outb %al,$0x64 # output port
-seta20.2: inb $0x64,%al # Get status
- testb $0x2,%al # Busy?
- jnz seta20.2 # Yes
- movb $0xdf,%al # Enable
- outb %al,$0x60 # A20
-seta20.3: sti # Enable interrupts
-
- jmp start+MEM_JMP-MEM_ORG # Start BTX
-
-
-/*
- * Read a sector from the disk. Sets up an EDD packet on the stack
- * and passes it to read. We assume that the destination address is
- * always segment-aligned.
- *
- * %eax - int - LBA to read in relative to partition start
- * %ebx - ptr - destination address
- * %dl - byte - drive to read from
- * %si - ptr - MBR partition entry
- */
-read: xor %ecx,%ecx # Get
- addl 0x8(%si),%eax # LBA
- adc $0,%ecx
- pushl %ecx # Starting absolute block
- pushl %eax # block number
- shr $4,%ebx # Convert to segment
- push %bx # Address of
- push $0 # transfer buffer
- push $0x1 # Read 1 sector
- push $0x10 # Size of packet
- mov %sp,%si # Packet pointer
- mov $0x42,%ah # BIOS: Extended
- int $0x13 # read
- jc read.1 # If error, fail
- lea 0x10(%si),%sp # Clear stack
- ret # If success, return
-read.1: mov %ah,%al # Format
- mov $read_err,%di # error
- call hex8 # code
- mov $msg_read,%si # Set the error message and
- # fall through to the error
- # routine
-/*
- * Print out the error message pointed to by %ds:(%si) followed
- * by a prompt, wait for a keypress, and then reboot the machine.
- */
-error: callw putstr # Display message
- mov $prompt,%si # Display
- callw putstr # prompt
- xorb %ah,%ah # BIOS: Get
- int $0x16 # keypress
- movw $0x1234, BDA_BOOT # Do a warm boot
- ljmp $0xffff,$0x0 # reboot the machine
-/*
- * Display a null-terminated string using the BIOS output.
- */
-putstr.0: mov $0x7,%bx # Page:attribute
- movb $0xe,%ah # BIOS: Display
- int $0x10 # character
-putstr: lodsb # Get char
- testb %al,%al # End of string?
- jne putstr.0 # No
- ret # To caller
-/*
- * Check to see if the disk supports EDD. zfsboot requires EDD and does not
- * support older C/H/S disk I/O.
- */
-check_edd: cmpb $0x80,%dl # Hard drive?
- jb check_edd.1 # No, fail to boot
- mov $0x55aa,%bx # Magic
- push %dx # Save
- movb $0x41,%ah # BIOS: Check
- int $0x13 # extensions present
- pop %dx # Restore
- jc check_edd.1 # If error, fail
- cmp $0xaa55,%bx # Magic?
- jne check_edd.1 # No, so fail
- testb $0x1,%cl # Packet interface?
- jz check_edd.1 # No, so fail
- ret # EDD ok, keep booting
-check_edd.1: mov $msg_chs,%si # Warn that CHS is
- jmp error # unsupported and fail
-/*
- * AL to hex, saving the result to [EDI].
- */
-hex8: push %ax # Save
- shrb $0x4,%al # Do upper
- call hex8.1 # 4
- pop %ax # Restore
-hex8.1: andb $0xf,%al # Get lower 4
- cmpb $0xa,%al # Convert
- sbbb $0x69,%al # to hex
- das # digit
- orb $0x20,%al # To lower case
- stosb # Save char
- ret # (Recursive)
-
-/* Messages */
-
-msg_chs: .asciz "CHS not supported"
-msg_read: .ascii "Read error: "
-read_err: .asciz "XX"
-msg_part: .asciz "Boot error"
-
-prompt: .asciz "\r\n"
-
- .org PRT_OFF,0x90
-
-/* Partition table */
-
- .fill 0x30,0x1,0x0
-part4: .byte 0x80, 0x00, 0x01, 0x00
- .byte 0xa5, 0xfe, 0xff, 0xff
- .byte 0x00, 0x00, 0x00, 0x00
- .byte 0x50, 0xc3, 0x00, 0x00 # 50000 sectors long, bleh
-
- .word 0xaa55 # Magic number
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/hexdump.c b/stand/libsa/hexdump.c
index 83fd5e277f1b..cce6e323c2cb 100644
--- a/stand/libsa/hexdump.c
+++ b/stand/libsa/hexdump.c
@@ -61,7 +61,7 @@ hexdump(caddr_t region, size_t len)
for (x = 0; x < 16; x++) {
if ((line + x) < (region + len)) {
c = *(uint8_t *)(line + x);
- if ((c < ' ') || (c > '~')) /* !isprint(c) */
+ if (!isprint(c))
c = '.';
emit("%c", c);
} else {
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..0e99d8778fa6 100644
--- a/stand/libsa/stand.h
+++ b/stand/libsa/stand.h
@@ -275,6 +275,11 @@ static __inline int ispunct(int c)
(c >= '[' && c <= '`') || (c >= '{' && c <= '~');
}
+static __inline int isprint(int c)
+{
+ return (c >= ' ') && (c <= '~');
+}
+
static __inline int toupper(int c)
{
return islower(c) ? c - 'a' + 'A' : c;
@@ -558,4 +563,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/sys/amd64/acpica/acpi_wakeup.c b/sys/amd64/acpica/acpi_wakeup.c
index 51d6d5e36840..99565fbb69ca 100644
--- a/sys/amd64/acpica/acpi_wakeup.c
+++ b/sys/amd64/acpica/acpi_wakeup.c
@@ -54,10 +54,8 @@
#include <x86/apicreg.h>
#include <x86/apicvar.h>
-#ifdef SMP
#include <machine/smp.h>
#include <machine/vmparam.h>
-#endif
#include <contrib/dev/acpica/include/acpi.h>
@@ -73,19 +71,13 @@ extern int acpi_resume_beep;
extern int acpi_reset_video;
extern int acpi_susp_bounce;
-#ifdef SMP
extern struct susppcb **susppcbs;
static cpuset_t suspcpus;
-#else
-static struct susppcb **susppcbs;
-#endif
static void acpi_stop_beep(void *);
-#ifdef SMP
static int acpi_wakeup_ap(struct acpi_softc *, int);
static void acpi_wakeup_cpus(struct acpi_softc *);
-#endif
#define ACPI_WAKEPT_PAGES 7
@@ -103,7 +95,6 @@ acpi_stop_beep(void *arg)
timer_spkr_release();
}
-#ifdef SMP
static int
acpi_wakeup_ap(struct acpi_softc *sc, int cpu)
{
@@ -177,7 +168,6 @@ acpi_wakeup_cpus(struct acpi_softc *sc)
outb(CMOS_DATA, mpbiosreason);
}
}
-#endif
int
acpi_sleep_machdep(struct acpi_softc *sc, int state)
@@ -190,10 +180,8 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
if (sc->acpi_wakeaddr == 0ul)
return (-1); /* couldn't alloc wake memory */
-#ifdef SMP
suspcpus = all_cpus;
CPU_CLR(PCPU_GET(cpuid), &suspcpus);
-#endif
if (acpi_resume_beep != 0)
timer_spkr_acquire();
@@ -208,12 +196,10 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
pcb = &susppcbs[0]->sp_pcb;
if (savectx(pcb)) {
fpususpend(susppcbs[0]->sp_fpususpend);
-#ifdef SMP
if (!CPU_EMPTY(&suspcpus) && suspend_cpus(suspcpus) == 0) {
device_printf(sc->acpi_dev, "Failed to suspend APs\n");
return (0); /* couldn't sleep */
}
-#endif
hw_ibrs_ibpb_active = 0;
hw_ssb_active = 0;
cpu_stdext_feature3 = 0;
@@ -278,16 +264,12 @@ acpi_wakeup_machdep(struct acpi_softc *sc, int state, int sleep_result,
PCPU_SET(switchtime, 0);
PCPU_SET(switchticks, ticks);
lapic_xapic_mode();
-#ifdef SMP
if (!CPU_EMPTY(&suspcpus))
acpi_wakeup_cpus(sc);
-#endif
}
-#ifdef SMP
if (!CPU_EMPTY(&suspcpus))
resume_cpus(suspcpus);
-#endif
/*
* Re-read cpu_stdext_feature3, which was zeroed-out
diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S
index 5bb877a174f7..e98bae9eb6c5 100644
--- a/sys/amd64/amd64/apic_vector.S
+++ b/sys/amd64/amd64/apic_vector.S
@@ -157,7 +157,6 @@ IDTVEC(spuriousint)
jmp doreti
#endif
-#ifdef SMP
/*
* Global address space TLB shootdown.
*/
@@ -264,5 +263,3 @@ IDTVEC(justreturn)
INTR_HANDLER justreturn1
call as_lapic_eoi
jmp doreti
-
-#endif /* SMP */
diff --git a/sys/amd64/amd64/cpu_switch.S b/sys/amd64/amd64/cpu_switch.S
index a053f6c70af1..d7e954f573b0 100644
--- a/sys/amd64/amd64/cpu_switch.S
+++ b/sys/amd64/amd64/cpu_switch.S
@@ -136,7 +136,7 @@ ctx_switch_fpusave_done:
movq %r15,TD_LOCK(%r13) /* Release the old thread */
sw1:
leaq TD_MD_PCB(%r12),%r8
-#if defined(SCHED_ULE) && defined(SMP)
+#if defined(SCHED_ULE)
movq $blocked_lock, %rdx
movq TD_LOCK(%r12),%rcx
cmpq %rcx, %rdx
@@ -492,7 +492,7 @@ ENTRY(resumectx)
END(resumectx)
/* Wait for the new thread to become unblocked */
-#if defined(SCHED_ULE) && defined(SMP)
+#if defined(SCHED_ULE)
sw1wait:
1:
pause
diff --git a/sys/amd64/amd64/exec_machdep.c b/sys/amd64/amd64/exec_machdep.c
index da68289e2c83..6752b716deb5 100644
--- a/sys/amd64/amd64/exec_machdep.c
+++ b/sys/amd64/amd64/exec_machdep.c
@@ -59,9 +59,7 @@
#include <sys/reg.h>
#include <sys/rwlock.h>
#include <sys/signalvar.h>
-#ifdef SMP
#include <sys/smp.h>
-#endif
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
diff --git a/sys/amd64/amd64/machdep.c b/sys/amd64/amd64/machdep.c
index f46462b39fa3..37c7056f649c 100644
--- a/sys/amd64/amd64/machdep.c
+++ b/sys/amd64/amd64/machdep.c
@@ -38,7 +38,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "opt_atpic.h"
#include "opt_cpu.h"
#include "opt_ddb.h"
@@ -82,9 +81,7 @@
#include <sys/rwlock.h>
#include <sys/sched.h>
#include <sys/signalvar.h>
-#ifdef SMP
#include <sys/smp.h>
-#endif
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
@@ -132,9 +129,7 @@
#include <machine/tss.h>
#include <x86/ucode.h>
#include <x86/ifunc.h>
-#ifdef SMP
#include <machine/smp.h>
-#endif
#ifdef FDT
#include <x86/fdt.h>
#endif
@@ -149,6 +144,10 @@
#include <isa/rtc.h>
#include <x86/init.h>
+#ifndef SMP
+#error amd64 requires options SMP
+#endif
+
/* Sanity check for __curthread() */
CTASSERT(offsetof(struct pcpu, pc_curthread) == 0);
diff --git a/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index 2c7777e608b9..8df082f6c5dc 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -162,9 +162,7 @@
#include <machine/msan.h>
#include <machine/pcb.h>
#include <machine/specialreg.h>
-#ifdef SMP
#include <machine/smp.h>
-#endif
#include <machine/sysarch.h>
#include <machine/tss.h>
@@ -483,6 +481,8 @@ vm_paddr_t KERNend; /* and the end */
struct kva_layout_s kva_layout = {
.kva_min = KV4ADDR(PML4PML4I, 0, 0, 0),
+ .kva_max = KV4ADDR(NPML4EPG - 1, NPDPEPG - 1,
+ NPDEPG - 1, NPTEPG - 1),
.dmap_low = KV4ADDR(DMPML4I, 0, 0, 0),
.dmap_high = KV4ADDR(DMPML4I + NDMPML4E, 0, 0, 0),
.lm_low = KV4ADDR(LMSPML4I, 0, 0, 0),
@@ -491,18 +491,36 @@ struct kva_layout_s kva_layout = {
.km_high = KV4ADDR(KPML4BASE + NKPML4E - 1, NPDPEPG - 1,
NPDEPG - 1, NPTEPG - 1),
.rec_pt = KV4ADDR(PML4PML4I, 0, 0, 0),
+ .kasan_shadow_low = KV4ADDR(KASANPML4I, 0, 0, 0),
+ .kasan_shadow_high = KV4ADDR(KASANPML4I + NKASANPML4E, 0, 0, 0),
+ .kmsan_shadow_low = KV4ADDR(KMSANSHADPML4I, 0, 0, 0),
+ .kmsan_shadow_high = KV4ADDR(KMSANSHADPML4I + NKMSANSHADPML4E,
+ 0, 0, 0),
+ .kmsan_origin_low = KV4ADDR(KMSANORIGPML4I, 0, 0, 0),
+ .kmsan_origin_high = KV4ADDR(KMSANORIGPML4I + NKMSANORIGPML4E,
+ 0, 0, 0),
};
struct kva_layout_s kva_layout_la57 = {
.kva_min = KV5ADDR(NPML5EPG / 2, 0, 0, 0, 0), /* == rec_pt */
+ .kva_max = KV5ADDR(NPML5EPG - 1, NPML4EPG - 1, NPDPEPG - 1,
+ NPDEPG - 1, NPTEPG - 1),
.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),
.rec_pt = KV5ADDR(PML5PML5I, 0, 0, 0, 0),
+ .kasan_shadow_low = KV4ADDR(KASANPML4I, 0, 0, 0),
+ .kasan_shadow_high = KV4ADDR(KASANPML4I + NKASANPML4E, 0, 0, 0),
+ .kmsan_shadow_low = KV4ADDR(KMSANSHADPML4I, 0, 0, 0),
+ .kmsan_shadow_high = KV4ADDR(KMSANSHADPML4I + NKMSANSHADPML4E,
+ 0, 0, 0),
+ .kmsan_origin_low = KV4ADDR(KMSANORIGPML4I, 0, 0, 0),
+ .kmsan_origin_high = KV4ADDR(KMSANORIGPML4I + NKMSANORIGPML4E,
+ 0, 0, 0),
};
/*
@@ -2005,7 +2023,7 @@ create_pagetables(vm_paddr_t *firstaddr)
*/
p5_p[i] = KPML5phys | X86_PG_RW | X86_PG_A |
X86_PG_M | X86_PG_V | pg_nx;
- } else if (i >= DMPML5I && i < DMPML5I + NDMPML5E) {
+ } else if (i >= DMPML5I && i < DMPML5I + ndmpml4phys) {
/* Connect DMAP pml4 pages to PML5. */
p5_p[i] = (DMPML4phys + ptoa(i - DMPML5I)) |
X86_PG_RW | X86_PG_V | pg_nx;
@@ -2475,6 +2493,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 +2619,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 +2639,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 +
@@ -3031,7 +3063,6 @@ pmap_update_pde_invalidate(pmap_t pmap, vm_offset_t va, pd_entry_t newpde)
* XXX TODO
*/
-#ifdef SMP
/*
* Interrupt the cpus that are executing in the guest context.
* This will force the vcpu to exit and the cached EPT mappings
@@ -3489,168 +3520,6 @@ pmap_update_pde(pmap_t pmap, vm_offset_t va, pd_entry_t *pde, pd_entry_t newpde)
}
sched_unpin();
}
-#else /* !SMP */
-/*
- * Normal, non-SMP, invalidation functions.
- */
-void
-pmap_invalidate_page(pmap_t pmap, vm_offset_t va)
-{
- struct invpcid_descr d;
- struct pmap_pcid *pcidp;
- uint64_t kcr3, ucr3;
- uint32_t pcid;
-
- if (pmap->pm_type == PT_RVI || pmap->pm_type == PT_EPT) {
- pmap->pm_eptgen++;
- return;
- }
- KASSERT(pmap->pm_type == PT_X86,
- ("pmap_invalidate_range: unknown type %d", pmap->pm_type));
-
- if (pmap == kernel_pmap || pmap == PCPU_GET(curpmap)) {
- invlpg(va);
- if (pmap == PCPU_GET(curpmap) && pmap_pcid_enabled &&
- pmap->pm_ucr3 != PMAP_NO_CR3) {
- critical_enter();
- pcid = pmap_get_pcid(pmap);
- if (invpcid_works) {
- d.pcid = pcid | PMAP_PCID_USER_PT;
- d.pad = 0;
- d.addr = va;
- invpcid(&d, INVPCID_ADDR);
- } else {
- kcr3 = pmap->pm_cr3 | pcid | CR3_PCID_SAVE;
- ucr3 = pmap->pm_ucr3 | pcid |
- PMAP_PCID_USER_PT | CR3_PCID_SAVE;
- pmap_pti_pcid_invlpg(ucr3, kcr3, va);
- }
- critical_exit();
- }
- } else if (pmap_pcid_enabled) {
- pcidp = zpcpu_get(pmap->pm_pcidp);
- pcidp->pm_gen = 0;
- }
-}
-
-void
-pmap_invalidate_range(pmap_t pmap, vm_offset_t sva, vm_offset_t eva)
-{
- struct invpcid_descr d;
- struct pmap_pcid *pcidp;
- vm_offset_t addr;
- uint64_t kcr3, ucr3;
- uint32_t pcid;
-
- if (pmap->pm_type == PT_RVI || pmap->pm_type == PT_EPT) {
- pmap->pm_eptgen++;
- return;
- }
- KASSERT(pmap->pm_type == PT_X86,
- ("pmap_invalidate_range: unknown type %d", pmap->pm_type));
-
- if (pmap == kernel_pmap || pmap == PCPU_GET(curpmap)) {
- for (addr = sva; addr < eva; addr += PAGE_SIZE)
- invlpg(addr);
- if (pmap == PCPU_GET(curpmap) && pmap_pcid_enabled &&
- pmap->pm_ucr3 != PMAP_NO_CR3) {
- critical_enter();
- pcid = pmap_get_pcid(pmap);
- if (invpcid_works) {
- d.pcid = pcid | PMAP_PCID_USER_PT;
- d.pad = 0;
- d.addr = sva;
- for (; d.addr < eva; d.addr += PAGE_SIZE)
- invpcid(&d, INVPCID_ADDR);
- } else {
- kcr3 = pmap->pm_cr3 | pcid | CR3_PCID_SAVE;
- ucr3 = pmap->pm_ucr3 | pcid |
- PMAP_PCID_USER_PT | CR3_PCID_SAVE;
- pmap_pti_pcid_invlrng(ucr3, kcr3, sva, eva);
- }
- critical_exit();
- }
- } else if (pmap_pcid_enabled) {
- pcidp = zpcpu_get(pmap->pm_pcidp);
- pcidp->pm_gen = 0;
- }
-}
-
-void
-pmap_invalidate_all(pmap_t pmap)
-{
- struct invpcid_descr d;
- struct pmap_pcid *pcidp;
- uint64_t kcr3, ucr3;
- uint32_t pcid;
-
- if (pmap->pm_type == PT_RVI || pmap->pm_type == PT_EPT) {
- pmap->pm_eptgen++;
- return;
- }
- KASSERT(pmap->pm_type == PT_X86,
- ("pmap_invalidate_all: unknown type %d", pmap->pm_type));
-
- if (pmap == kernel_pmap) {
- if (pmap_pcid_enabled && invpcid_works) {
- bzero(&d, sizeof(d));
- invpcid(&d, INVPCID_CTXGLOB);
- } else {
- invltlb_glob();
- }
- } else if (pmap == PCPU_GET(curpmap)) {
- if (pmap_pcid_enabled) {
- critical_enter();
- pcid = pmap_get_pcid(pmap);
- if (invpcid_works) {
- d.pcid = pcid;
- d.pad = 0;
- d.addr = 0;
- invpcid(&d, INVPCID_CTX);
- if (pmap->pm_ucr3 != PMAP_NO_CR3) {
- d.pcid |= PMAP_PCID_USER_PT;
- invpcid(&d, INVPCID_CTX);
- }
- } else {
- kcr3 = pmap->pm_cr3 | pcid;
- if (pmap->pm_ucr3 != PMAP_NO_CR3) {
- ucr3 = pmap->pm_ucr3 | pcid |
- PMAP_PCID_USER_PT;
- pmap_pti_pcid_invalidate(ucr3, kcr3);
- } else
- load_cr3(kcr3);
- }
- critical_exit();
- } else {
- invltlb();
- }
- } else if (pmap_pcid_enabled) {
- pcidp = zpcpu_get(pmap->pm_pcidp);
- pcidp->pm_gen = 0;
- }
-}
-
-void
-pmap_invalidate_cache(void)
-{
-
- wbinvd();
-}
-
-static void
-pmap_update_pde(pmap_t pmap, vm_offset_t va, pd_entry_t *pde, pd_entry_t newpde)
-{
- struct pmap_pcid *pcidp;
-
- pmap_update_pde_store(pmap, pde, newpde);
- if (pmap == kernel_pmap || pmap == PCPU_GET(curpmap))
- pmap_update_pde_invalidate(pmap, va, newpde);
- else {
- pcidp = zpcpu_get(pmap->pm_pcidp);
- pcidp->pm_gen = 0;
- }
-}
-#endif /* !SMP */
static void
pmap_invalidate_pde_page(pmap_t pmap, vm_offset_t va, pd_entry_t pde)
@@ -6093,17 +5962,18 @@ pmap_demote_pde_mpte(pmap_t pmap, pd_entry_t *pde, vm_offset_t va,
if (mpte == NULL) {
/*
* Invalidate the 2MB page mapping and return "failure" if the
- * mapping was never accessed.
+ * mapping was never accessed and not wired.
*/
if ((oldpde & PG_A) == 0) {
- KASSERT((oldpde & PG_W) == 0,
- ("pmap_demote_pde: a wired mapping is missing PG_A"));
- pmap_demote_pde_abort(pmap, va, pde, oldpde, lockp);
- return (false);
- }
-
- mpte = pmap_remove_pt_page(pmap, va);
- if (mpte == NULL) {
+ if ((oldpde & PG_W) == 0) {
+ pmap_demote_pde_abort(pmap, va, pde, oldpde,
+ lockp);
+ return (false);
+ }
+ mpte = pmap_remove_pt_page(pmap, va);
+ /* Fill the PTP with PTEs that have PG_A cleared. */
+ mpte->valid = 0;
+ } else if ((mpte = pmap_remove_pt_page(pmap, va)) == NULL) {
KASSERT((oldpde & PG_W) == 0,
("pmap_demote_pde: page table page for a wired mapping is missing"));
@@ -6155,7 +6025,7 @@ pmap_demote_pde_mpte(pmap_t pmap, pd_entry_t *pde, vm_offset_t va,
/*
* If the PTP is not leftover from an earlier promotion or it does not
* have PG_A set in every PTE, then fill it. The new PTEs will all
- * have PG_A set.
+ * have PG_A set, unless this is a wired mapping with PG_A clear.
*/
if (!vm_page_all_valid(mpte))
pmap_fill_ptp(firstpte, newpte);
@@ -7561,6 +7431,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 +7562,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,
@@ -10333,17 +10214,9 @@ pmap_activate_sw(struct thread *td)
return;
}
cpuid = PCPU_GET(cpuid);
-#ifdef SMP
CPU_SET_ATOMIC(cpuid, &pmap->pm_active);
-#else
- CPU_SET(cpuid, &pmap->pm_active);
-#endif
pmap_activate_sw_mode(td, pmap, cpuid);
-#ifdef SMP
CPU_CLR_ATOMIC(cpuid, &oldpmap->pm_active);
-#else
- CPU_CLR(cpuid, &oldpmap->pm_active);
-#endif
}
void
@@ -10384,11 +10257,7 @@ pmap_activate_boot(pmap_t pmap)
MPASS(pmap != kernel_pmap);
cpuid = PCPU_GET(cpuid);
-#ifdef SMP
CPU_SET_ATOMIC(cpuid, &pmap->pm_active);
-#else
- CPU_SET(cpuid, &pmap->pm_active);
-#endif
PCPU_SET(curpmap, pmap);
if (pti) {
kcr3 = pmap->pm_cr3;
@@ -10752,19 +10621,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));
}
@@ -12023,9 +11901,7 @@ sysctl_kmaps_dump(struct sbuf *sb, struct pmap_kernel_map_range *range,
mode, range->pdpes, range->pdes, range->ptes);
/* Reset to sentinel value. */
- range->sva = la57 ? KV5ADDR(NPML5EPG - 1, NPML4EPG - 1, NPDPEPG - 1,
- NPDEPG - 1, NPTEPG - 1) : KV4ADDR(NPML4EPG - 1, NPDPEPG - 1,
- NPDEPG - 1, NPTEPG - 1);
+ range->sva = kva_layout.kva_max;
}
/*
@@ -12066,12 +11942,18 @@ sysctl_kmaps_reinit(struct pmap_kernel_map_range *range, vm_offset_t va,
*/
static void
sysctl_kmaps_check(struct sbuf *sb, struct pmap_kernel_map_range *range,
- vm_offset_t va, pml4_entry_t pml4e, pdp_entry_t pdpe, pd_entry_t pde,
- pt_entry_t pte)
+ vm_offset_t va, pml5_entry_t pml5e, pml4_entry_t pml4e, pdp_entry_t pdpe,
+ pd_entry_t pde, pt_entry_t pte)
{
pt_entry_t attrs;
- attrs = pml4e & (X86_PG_RW | X86_PG_U | pg_nx);
+ if (la57) {
+ attrs = pml5e & (X86_PG_RW | X86_PG_U | pg_nx);
+ attrs |= pml4e & pg_nx;
+ attrs &= pg_nx | (pml4e & (X86_PG_RW | X86_PG_U));
+ } else {
+ attrs = pml4e & (X86_PG_RW | X86_PG_U | pg_nx);
+ }
attrs |= pdpe & pg_nx;
attrs &= pg_nx | (pdpe & (X86_PG_RW | X86_PG_U));
@@ -12104,13 +11986,15 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
{
struct pmap_kernel_map_range range;
struct sbuf sbuf, *sb;
+ pml5_entry_t pml5e;
pml4_entry_t pml4e;
pdp_entry_t *pdp, pdpe;
pd_entry_t *pd, pde;
pt_entry_t *pt, pte;
vm_offset_t sva;
vm_paddr_t pa;
- int error, i, j, k, l;
+ int error, j, k, l;
+ bool first;
error = sysctl_wire_old_buffer(req, 0);
if (error != 0)
@@ -12119,9 +12003,8 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
sbuf_new_for_sysctl(sb, NULL, PAGE_SIZE, req);
/* Sentinel value. */
- range.sva = la57 ? KV5ADDR(NPML5EPG - 1, NPML4EPG - 1, NPDPEPG - 1,
- NPDEPG - 1, NPTEPG - 1) : KV4ADDR(NPML4EPG - 1, NPDPEPG - 1,
- NPDEPG - 1, NPTEPG - 1);
+ range.sva = kva_layout.kva_max;
+ pml5e = 0; /* no UB for la48 */
/*
* Iterate over the kernel page tables without holding the kernel pmap
@@ -12130,41 +12013,50 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
* Within the large map, ensure that PDP and PD page addresses are
* valid before descending.
*/
- for (sva = 0, i = pmap_pml4e_index(sva); i < NPML4EPG; i++) {
- switch (i) {
- case PML4PML4I:
+ for (first = true, sva = 0; sva != 0 || first; first = false) {
+ if (sva == kva_layout.rec_pt)
sbuf_printf(sb, "\nRecursive map:\n");
- break;
- case DMPML4I:
+ else if (sva == kva_layout.dmap_low)
sbuf_printf(sb, "\nDirect map:\n");
- break;
#ifdef KASAN
- case KASANPML4I:
+ else if (sva == kva_layout.kasan_shadow_low)
sbuf_printf(sb, "\nKASAN shadow map:\n");
- break;
#endif
#ifdef KMSAN
- case KMSANSHADPML4I:
+ else if (sva == kva_layout.kmsan_shadow_low)
sbuf_printf(sb, "\nKMSAN shadow map:\n");
- break;
- case KMSANORIGPML4I:
+ else if (sva == kva_layout.kmsan_origin_low)
sbuf_printf(sb, "\nKMSAN origin map:\n");
- break;
#endif
- case KPML4BASE:
+ else if (sva == kva_layout.km_low)
sbuf_printf(sb, "\nKernel map:\n");
- break;
- case LMSPML4I:
+ else if (sva == kva_layout.lm_low)
sbuf_printf(sb, "\nLarge map:\n");
- break;
- }
/* Convert to canonical form. */
- if (sva == 1ul << 47)
- sva |= -1ul << 48;
+ if (la57) {
+ if (sva == 1ul << 56) {
+ sva |= -1ul << 57;
+ continue;
+ }
+ } else {
+ if (sva == 1ul << 47) {
+ sva |= -1ul << 48;
+ continue;
+ }
+ }
restart:
- pml4e = kernel_pml4[i];
+ if (la57) {
+ pml5e = *pmap_pml5e(kernel_pmap, sva);
+ if ((pml5e & X86_PG_V) == 0) {
+ sva = rounddown2(sva, NBPML5);
+ sysctl_kmaps_dump(sb, &range, sva);
+ sva += NBPML5;
+ continue;
+ }
+ }
+ pml4e = *pmap_pml4e(kernel_pmap, sva);
if ((pml4e & X86_PG_V) == 0) {
sva = rounddown2(sva, NBPML4);
sysctl_kmaps_dump(sb, &range, sva);
@@ -12185,8 +12077,8 @@ restart:
pa = pdpe & PG_FRAME;
if ((pdpe & PG_PS) != 0) {
sva = rounddown2(sva, NBPDP);
- sysctl_kmaps_check(sb, &range, sva, pml4e, pdpe,
- 0, 0);
+ sysctl_kmaps_check(sb, &range, sva, pml5e,
+ pml4e, pdpe, 0, 0);
range.pdpes++;
sva += NBPDP;
continue;
@@ -12198,6 +12090,7 @@ restart:
* freed. Validate the next-level address
* before descending.
*/
+ sva += NBPDP;
goto restart;
}
pd = (pd_entry_t *)PHYS_TO_DMAP(pa);
@@ -12214,7 +12107,7 @@ restart:
if ((pde & PG_PS) != 0) {
sva = rounddown2(sva, NBPDR);
sysctl_kmaps_check(sb, &range, sva,
- pml4e, pdpe, pde, 0);
+ pml5e, pml4e, pdpe, pde, 0);
range.pdes++;
sva += NBPDR;
continue;
@@ -12226,6 +12119,7 @@ restart:
* may be freed. Validate the
* next-level address before descending.
*/
+ sva += NBPDR;
goto restart;
}
pt = (pt_entry_t *)PHYS_TO_DMAP(pa);
@@ -12239,7 +12133,7 @@ restart:
continue;
}
sysctl_kmaps_check(sb, &range, sva,
- pml4e, pdpe, pde, pte);
+ pml5e, pml4e, pdpe, pde, pte);
range.ptes++;
}
}
diff --git a/sys/amd64/amd64/support.S b/sys/amd64/amd64/support.S
index c95696bbe7ef..870cd255abb7 100644
--- a/sys/amd64/amd64/support.S
+++ b/sys/amd64/amd64/support.S
@@ -934,10 +934,7 @@ ENTRY(casueword32_nosmap)
ja fusufault
movl %esi,%eax /* old */
-#ifdef SMP
- lock
-#endif
- cmpxchgl %ecx,(%rdi) /* new = %ecx */
+ lock cmpxchgl %ecx,(%rdi) /* new = %ecx */
setne %cl
/*
@@ -971,10 +968,7 @@ ENTRY(casueword32_smap)
movl %esi,%eax /* old */
stac
-#ifdef SMP
- lock
-#endif
- cmpxchgl %ecx,(%rdi) /* new = %ecx */
+ lock cmpxchgl %ecx,(%rdi) /* new = %ecx */
clac
setne %cl
@@ -1014,10 +1008,7 @@ ENTRY(casueword_nosmap)
ja fusufault
movq %rsi,%rax /* old */
-#ifdef SMP
- lock
-#endif
- cmpxchgq %rcx,(%rdi) /* new = %rcx */
+ lock cmpxchgq %rcx,(%rdi) /* new = %rcx */
setne %cl
/*
@@ -1045,10 +1036,7 @@ ENTRY(casueword_smap)
movq %rsi,%rax /* old */
stac
-#ifdef SMP
- lock
-#endif
- cmpxchgq %rcx,(%rdi) /* new = %rcx */
+ lock cmpxchgq %rcx,(%rdi) /* new = %rcx */
clac
setne %cl
diff --git a/sys/amd64/amd64/trap.c b/sys/amd64/amd64/trap.c
index eefddad2f142..f3469ed5e2bc 100644
--- a/sys/amd64/amd64/trap.c
+++ b/sys/amd64/amd64/trap.c
@@ -37,7 +37,6 @@
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
/*
* AMD64 Trap and System call handling
*/
@@ -87,9 +86,7 @@ PMC_SOFT_DEFINE( , , page_fault, write);
#include <x86/mca.h>
#include <machine/md_var.h>
#include <machine/pcb.h>
-#ifdef SMP
#include <machine/smp.h>
-#endif
#include <machine/stack.h>
#include <machine/trap.h>
#include <machine/tss.h>
@@ -900,11 +897,9 @@ trap_diag(struct trapframe *frame, vm_offset_t eva)
printf("\n\nFatal trap %d: %s while in %s mode\n", type,
type < nitems(trap_msg) ? trap_msg[type] : UNKNOWN,
TRAPF_USERMODE(frame) ? "user" : "kernel");
-#ifdef SMP
- /* two separate prints in case of a trap on an unmapped page */
- printf("cpuid = %d; ", PCPU_GET(cpuid));
- printf("apic id = %02x\n", PCPU_GET(apic_id));
-#endif
+ /* Print these separately in case pcpu accesses trap. */
+ printf("cpuid = %d; apic id = %02x\n", PCPU_GET(cpuid),
+ PCPU_GET(apic_id));
if (type == T_PAGEFLT) {
printf("fault virtual address = 0x%lx\n", eva);
printf("fault code = %s %s %s%s%s, %s\n",
@@ -1025,11 +1020,9 @@ dblfault_handler(struct trapframe *frame)
frame->tf_cs, frame->tf_ss, frame->tf_ds, frame->tf_es,
frame->tf_fs, frame->tf_gs,
rdmsr(MSR_FSBASE), rdmsr(MSR_GSBASE), rdmsr(MSR_KGSBASE));
-#ifdef SMP
- /* two separate prints in case of a trap on an unmapped page */
- printf("cpuid = %d; ", PCPU_GET(cpuid));
- printf("apic id = %02x\n", PCPU_GET(apic_id));
-#endif
+ /* Print these separately in case pcpu accesses trap. */
+ printf("cpuid = %d; apic id = %02x\n", PCPU_GET(cpuid),
+ PCPU_GET(apic_id));
panic("double fault");
}
diff --git a/sys/amd64/conf/MINIMALUP b/sys/amd64/conf/MINIMALUP
deleted file mode 100644
index 0dbddbe5b341..000000000000
--- a/sys/amd64/conf/MINIMALUP
+++ /dev/null
@@ -1,4 +0,0 @@
-include MINIMAL
-ident MINIMALUP
-nooptions SMP
-nooptions NUMA
diff --git a/sys/amd64/include/param.h b/sys/amd64/include/param.h
index 1bbb302259d6..5a9c3162e14c 100644
--- a/sys/amd64/include/param.h
+++ b/sys/amd64/include/param.h
@@ -150,8 +150,6 @@
(((va) >= kva_layout.dmap_low && (va) < kva_layout.dmap_high) || \
((va) >= kva_layout.km_low && (va) < kva_layout.km_high))
-#ifdef SMP
#define SC_TABLESIZE 1024 /* Must be power of 2. */
-#endif
#endif /* !_AMD64_INCLUDE_PARAM_H_ */
diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h
index 08e96027a5ed..e2f97442c10f 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...
@@ -552,6 +557,7 @@ pmap_pml5e_index(vm_offset_t va)
struct kva_layout_s {
vm_offset_t kva_min;
+ vm_offset_t kva_max;
vm_offset_t dmap_low; /* DMAP_MIN_ADDRESS */
vm_offset_t dmap_high; /* DMAP_MAX_ADDRESS */
vm_offset_t lm_low; /* LARGEMAP_MIN_ADDRESS */
@@ -559,6 +565,12 @@ struct kva_layout_s {
vm_offset_t km_low; /* VM_MIN_KERNEL_ADDRESS */
vm_offset_t km_high; /* VM_MAX_KERNEL_ADDRESS */
vm_offset_t rec_pt;
+ vm_offset_t kasan_shadow_low; /* KASAN_MIN_ADDRESS */
+ vm_offset_t kasan_shadow_high; /* KASAN_MAX_ADDRESS */
+ vm_offset_t kmsan_shadow_low; /* KMSAN_SHAD_MIN_ADDRESS */
+ vm_offset_t kmsan_shadow_high; /* KMSAN_SHAD_MAX_ADDRESS */
+ vm_offset_t kmsan_origin_low; /* KMSAN_ORIG_MIN_ADDRESS */
+ vm_offset_t kmsan_origin_high; /* KMSAN_ORIG_MAX_ADDRESS */
};
extern struct kva_layout_s kva_layout;
diff --git a/sys/amd64/include/smp.h b/sys/amd64/include/smp.h
index 26eb227211da..bff92570ff82 100644
--- a/sys/amd64/include/smp.h
+++ b/sys/amd64/include/smp.h
@@ -13,8 +13,6 @@
#ifdef _KERNEL
-#ifdef SMP
-
#ifndef LOCORE
#include <x86/x86_smp.h>
@@ -39,7 +37,6 @@ void invlop_handler(void);
int start_all_aps(void);
#endif /* !LOCORE */
-#endif /* SMP */
#endif /* _KERNEL */
#endif /* _MACHINE_SMP_H_ */
diff --git a/sys/amd64/include/vmm.h b/sys/amd64/include/vmm.h
index a9c73b75213b..0b3daed4f69e 100644
--- a/sys/amd64/include/vmm.h
+++ b/sys/amd64/include/vmm.h
@@ -649,6 +649,8 @@ struct vm_inout_str {
int addrsize;
enum vm_reg_name seg_name;
struct seg_desc seg_desc;
+ int cs_d;
+ uint64_t cs_base;
};
enum task_switch_reason {
diff --git a/sys/amd64/include/vmm_dev.h b/sys/amd64/include/vmm_dev.h
index 1f86538ce5f3..441330fd57b8 100644
--- a/sys/amd64/include/vmm_dev.h
+++ b/sys/amd64/include/vmm_dev.h
@@ -29,6 +29,8 @@
#ifndef _VMM_DEV_H_
#define _VMM_DEV_H_
+#include <sys/domainset.h>
+
#include <machine/vmm.h>
#include <machine/vmm_snapshot.h>
@@ -52,7 +54,10 @@ struct vm_munmap {
struct vm_memseg {
int segid;
size_t len;
- char name[VM_MAX_SUFFIXLEN + 1];
+ char name[VM_MAX_SUFFIXLEN + 1];
+ domainset_t *ds_mask;
+ size_t ds_mask_size;
+ int ds_policy;
};
struct vm_register {
diff --git a/sys/amd64/include/vmm_instruction_emul.h b/sys/amd64/include/vmm_instruction_emul.h
index d5f0363cfb41..1fb0f97682a7 100644
--- a/sys/amd64/include/vmm_instruction_emul.h
+++ b/sys/amd64/include/vmm_instruction_emul.h
@@ -31,6 +31,31 @@
#include <sys/mman.h>
+/* struct vie_op.op_type */
+enum {
+ VIE_OP_TYPE_NONE = 0,
+ VIE_OP_TYPE_MOV,
+ VIE_OP_TYPE_MOVSX,
+ VIE_OP_TYPE_MOVZX,
+ VIE_OP_TYPE_AND,
+ VIE_OP_TYPE_OR,
+ VIE_OP_TYPE_SUB,
+ VIE_OP_TYPE_TWO_BYTE,
+ VIE_OP_TYPE_PUSH,
+ VIE_OP_TYPE_CMP,
+ VIE_OP_TYPE_POP,
+ VIE_OP_TYPE_MOVS,
+ VIE_OP_TYPE_GROUP1,
+ VIE_OP_TYPE_STOS,
+ VIE_OP_TYPE_BITTEST,
+ VIE_OP_TYPE_TWOB_GRP15,
+ VIE_OP_TYPE_ADD,
+ VIE_OP_TYPE_TEST,
+ VIE_OP_TYPE_BEXTR,
+ VIE_OP_TYPE_OUTS,
+ VIE_OP_TYPE_LAST
+};
+
/*
* Callback functions to read and write memory regions.
*/
diff --git a/sys/amd64/include/vmparam.h b/sys/amd64/include/vmparam.h
index e4cc05cbb889..d2ac3c6648b2 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
@@ -200,16 +200,14 @@
#define VM_MIN_KERNEL_ADDRESS kva_layout.km_low
#define VM_MAX_KERNEL_ADDRESS kva_layout.km_high
-#define KASAN_MIN_ADDRESS KV4ADDR(KASANPML4I, 0, 0, 0)
-#define KASAN_MAX_ADDRESS KV4ADDR(KASANPML4I + NKASANPML4E, 0, 0, 0)
+#define KASAN_MIN_ADDRESS (kva_layout.kasan_shadow_low)
+#define KASAN_MAX_ADDRESS (kva_layout.kasan_shadow_high)
-#define KMSAN_SHAD_MIN_ADDRESS KV4ADDR(KMSANSHADPML4I, 0, 0, 0)
-#define KMSAN_SHAD_MAX_ADDRESS KV4ADDR(KMSANSHADPML4I + NKMSANSHADPML4E, \
- 0, 0, 0)
+#define KMSAN_SHAD_MIN_ADDRESS (kva_layout.kmsan_shadow_low)
+#define KMSAN_SHAD_MAX_ADDRESS (kva_layout.kmsan_shadow_high)
-#define KMSAN_ORIG_MIN_ADDRESS KV4ADDR(KMSANORIGPML4I, 0, 0, 0)
-#define KMSAN_ORIG_MAX_ADDRESS KV4ADDR(KMSANORIGPML4I + NKMSANORIGPML4E, \
- 0, 0, 0)
+#define KMSAN_ORIG_MIN_ADDRESS (kva_layout.kmsan_origin_low)
+#define KMSAN_ORIG_MAX_ADDRESS (kva_layout.kmsan_origin_high)
/*
* Formally kernel mapping starts at KERNBASE, but kernel linker
diff --git a/sys/amd64/vmm/amd/svm.c b/sys/amd64/vmm/amd/svm.c
index 6c16daaa47c2..2fe6a5bc3584 100644
--- a/sys/amd64/vmm/amd/svm.c
+++ b/sys/amd64/vmm/amd/svm.c
@@ -317,6 +317,33 @@ svm_set_tsc_offset(struct svm_vcpu *vcpu, uint64_t offset)
#define MSR_AMD7TH_START 0xC0010000UL
#define MSR_AMD7TH_END 0xC0011FFFUL
+static void
+svm_get_cs_info(struct vmcb *vmcb, struct vm_guest_paging *paging, int *cs_d,
+ uint64_t *base)
+{
+ struct vmcb_segment seg;
+ int error __diagused;
+
+ error = vmcb_seg(vmcb, VM_REG_GUEST_CS, &seg);
+ KASSERT(error == 0, ("%s: vmcb_seg error %d", __func__, error));
+
+ switch (paging->cpu_mode) {
+ case CPU_MODE_REAL:
+ *base = seg.base;
+ *cs_d = 0;
+ break;
+ case CPU_MODE_PROTECTED:
+ case CPU_MODE_COMPATIBILITY:
+ *cs_d = !!(seg.attrib & VMCB_CS_ATTRIB_D);
+ *base = seg.base;
+ break;
+ default:
+ *base = 0;
+ *cs_d = 0;
+ break;
+ }
+}
+
/*
* Get the index and bit position for a MSR in permission bitmap.
* Two bits are used for each MSR: lower bit for read and higher bit for write.
@@ -735,10 +762,29 @@ svm_inout_str_seginfo(struct svm_vcpu *vcpu, int64_t info1, int in,
if (in) {
vis->seg_name = VM_REG_GUEST_ES;
- } else {
- /* The segment field has standard encoding */
+ } else if (decode_assist()) {
+ /*
+ * The effective segment number in EXITINFO1[12:10] is populated
+ * only if the processor has the DecodeAssist capability.
+ *
+ * XXX this is not specified explicitly in APMv2 but can be
+ * verified empirically.
+ */
s = (info1 >> 10) & 0x7;
+
+ /* The segment field has standard encoding */
vis->seg_name = vm_segment_name(s);
+ } else {
+ /*
+ * The segment register need to be manually decoded by fetching
+ * the instructions near ip. However, we are unable to fetch it
+ * while the interrupts are disabled. Therefore, we leave the
+ * value unset until the generic ins/outs handler runs.
+ */
+ vis->seg_name = VM_REG_LAST;
+ svm_get_cs_info(vcpu->vmcb, &vis->paging, &vis->cs_d,
+ &vis->cs_base);
+ return;
}
error = svm_getdesc(vcpu, vis->seg_name, &vis->seg_desc);
@@ -798,16 +844,6 @@ svm_handle_io(struct svm_vcpu *vcpu, struct vm_exit *vmexit)
info1 = ctrl->exitinfo1;
inout_string = info1 & BIT(2) ? 1 : 0;
- /*
- * The effective segment number in EXITINFO1[12:10] is populated
- * only if the processor has the DecodeAssist capability.
- *
- * XXX this is not specified explicitly in APMv2 but can be verified
- * empirically.
- */
- if (inout_string && !decode_assist())
- return (UNHANDLED);
-
vmexit->exitcode = VM_EXITCODE_INOUT;
vmexit->u.inout.in = (info1 & BIT(0)) ? 1 : 0;
vmexit->u.inout.string = inout_string;
@@ -825,6 +861,8 @@ svm_handle_io(struct svm_vcpu *vcpu, struct vm_exit *vmexit)
vis->index = svm_inout_str_index(regs, vmexit->u.inout.in);
vis->count = svm_inout_str_count(regs, vmexit->u.inout.rep);
vis->addrsize = svm_inout_str_addrsize(info1);
+ vis->cs_d = 0;
+ vis->cs_base = 0;
svm_inout_str_seginfo(vcpu, info1, vmexit->u.inout.in, vis);
}
@@ -866,10 +904,9 @@ static void
svm_handle_inst_emul(struct vmcb *vmcb, uint64_t gpa, struct vm_exit *vmexit)
{
struct vm_guest_paging *paging;
- struct vmcb_segment seg;
struct vmcb_ctrl *ctrl;
char *inst_bytes;
- int error __diagused, inst_len;
+ int inst_len;
ctrl = &vmcb->ctrl;
paging = &vmexit->u.inst_emul.paging;
@@ -879,29 +916,8 @@ svm_handle_inst_emul(struct vmcb *vmcb, uint64_t gpa, struct vm_exit *vmexit)
vmexit->u.inst_emul.gla = VIE_INVALID_GLA;
svm_paging_info(vmcb, paging);
- error = vmcb_seg(vmcb, VM_REG_GUEST_CS, &seg);
- KASSERT(error == 0, ("%s: vmcb_seg(CS) error %d", __func__, error));
-
- switch(paging->cpu_mode) {
- case CPU_MODE_REAL:
- vmexit->u.inst_emul.cs_base = seg.base;
- vmexit->u.inst_emul.cs_d = 0;
- break;
- case CPU_MODE_PROTECTED:
- case CPU_MODE_COMPATIBILITY:
- vmexit->u.inst_emul.cs_base = seg.base;
-
- /*
- * Section 4.8.1 of APM2, Default Operand Size or D bit.
- */
- vmexit->u.inst_emul.cs_d = (seg.attrib & VMCB_CS_ATTRIB_D) ?
- 1 : 0;
- break;
- default:
- vmexit->u.inst_emul.cs_base = 0;
- vmexit->u.inst_emul.cs_d = 0;
- break;
- }
+ svm_get_cs_info(vmcb, paging, &vmexit->u.inst_emul.cs_d,
+ &vmexit->u.inst_emul.cs_base);
/*
* Copy the instruction bytes into 'vie' if available.
diff --git a/sys/amd64/vmm/intel/vmx.c b/sys/amd64/vmm/intel/vmx.c
index 957217ab2258..842281ab862e 100644
--- a/sys/amd64/vmm/intel/vmx.c
+++ b/sys/amd64/vmm/intel/vmx.c
@@ -2659,6 +2659,8 @@ vmx_exit_process(struct vmx *vmx, struct vmx_vcpu *vcpu, struct vm_exit *vmexit)
vis->index = inout_str_index(vcpu, in);
vis->count = inout_str_count(vcpu, vis->inout.rep);
vis->addrsize = inout_str_addrsize(inst_info);
+ vis->cs_d = 0;
+ vis->cs_base = 0;
inout_str_seginfo(vcpu, inst_info, in, vis);
}
SDT_PROBE3(vmm, vmx, exit, inout, vmx, vcpuid, vmexit);
diff --git a/sys/amd64/vmm/vmm_instruction_emul.c b/sys/amd64/vmm/vmm_instruction_emul.c
index c53e32889000..c54b6e6d0074 100644
--- a/sys/amd64/vmm/vmm_instruction_emul.c
+++ b/sys/amd64/vmm/vmm_instruction_emul.c
@@ -65,30 +65,6 @@
#include <x86/psl.h>
#include <x86/specialreg.h>
-/* struct vie_op.op_type */
-enum {
- VIE_OP_TYPE_NONE = 0,
- VIE_OP_TYPE_MOV,
- VIE_OP_TYPE_MOVSX,
- VIE_OP_TYPE_MOVZX,
- VIE_OP_TYPE_AND,
- VIE_OP_TYPE_OR,
- VIE_OP_TYPE_SUB,
- VIE_OP_TYPE_TWO_BYTE,
- VIE_OP_TYPE_PUSH,
- VIE_OP_TYPE_CMP,
- VIE_OP_TYPE_POP,
- VIE_OP_TYPE_MOVS,
- VIE_OP_TYPE_GROUP1,
- VIE_OP_TYPE_STOS,
- VIE_OP_TYPE_BITTEST,
- VIE_OP_TYPE_TWOB_GRP15,
- VIE_OP_TYPE_ADD,
- VIE_OP_TYPE_TEST,
- VIE_OP_TYPE_BEXTR,
- VIE_OP_TYPE_LAST
-};
-
/* struct vie_op.op_flags */
#define VIE_OP_F_IMM (1 << 0) /* 16/32-bit immediate operand */
#define VIE_OP_F_IMM8 (1 << 1) /* 8-bit immediate operand */
@@ -152,6 +128,16 @@ static const struct vie_op one_byte_opcodes[256] = {
.op_byte = 0x3B,
.op_type = VIE_OP_TYPE_CMP,
},
+ [0x6E] = {
+ .op_byte = 0x6E,
+ .op_type = VIE_OP_TYPE_OUTS,
+ .op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION,
+ },
+ [0x6F] = {
+ .op_byte = 0x6F,
+ .op_type = VIE_OP_TYPE_OUTS,
+ .op_flags = VIE_OP_F_NO_MODRM | VIE_OP_F_NO_GLA_VERIFICATION,
+ },
[0x88] = {
.op_byte = 0x88,
.op_type = VIE_OP_TYPE_MOV,
diff --git a/sys/amd64/vmm/vmm_ioport.c b/sys/amd64/vmm/vmm_ioport.c
index fc1ecab9f209..8aab28f5e68e 100644
--- a/sys/amd64/vmm/vmm_ioport.c
+++ b/sys/amd64/vmm/vmm_ioport.c
@@ -145,9 +145,49 @@ emulate_inout_port(struct vcpu *vcpu, struct vm_exit *vmexit, bool *retu)
}
static int
+decode_segment(struct vcpu *vcpu, enum vm_reg_name *segment)
+{
+ struct vm_guest_paging *paging;
+ struct vie vie;
+ struct vm_exit *vme;
+ int err;
+ int fault;
+
+ vme = vm_exitinfo(vcpu);
+ paging = &vme->u.inout_str.paging;
+
+ vie_init(&vie, NULL, 0);
+ err = vmm_fetch_instruction(vcpu, paging,
+ vme->rip + vme->u.inout_str.cs_base, VIE_INST_SIZE, &vie, &fault);
+ if (err || fault)
+ return (err);
+
+ err = vmm_decode_instruction(vcpu, VIE_INVALID_GLA, paging->cpu_mode,
+ vme->u.inout_str.cs_d, &vie);
+
+ if (err || vie.op.op_type != VIE_OP_TYPE_OUTS)
+ return (EINVAL);
+ if (vie.segment_override)
+ *segment = vie.segment_register;
+ else
+ *segment = VM_REG_GUEST_DS;
+
+ return (0);
+}
+
+static int
emulate_inout_str(struct vcpu *vcpu, struct vm_exit *vmexit, bool *retu)
{
+ int err;
+
*retu = true;
+ if (vmexit->u.inout_str.seg_name == VM_REG_LAST) {
+ err = decode_segment(vcpu, &vmexit->u.inout_str.seg_name);
+ if (err)
+ return (err);
+ return (vm_get_seg_desc(vcpu, vmexit->u.inout_str.seg_name,
+ &vmexit->u.inout_str.seg_desc));
+ }
return (0); /* Return to userspace to finish emulation */
}
diff --git a/sys/arm/allwinner/aw_mmc.c b/sys/arm/allwinner/aw_mmc.c
index 6bebf5e5fb5e..a8add957dc74 100644
--- a/sys/arm/allwinner/aw_mmc.c
+++ b/sys/arm/allwinner/aw_mmc.c
@@ -84,21 +84,26 @@
struct aw_mmc_conf {
uint32_t dma_xferlen;
+ uint32_t dma_desc_shift;
bool mask_data0;
bool can_calibrate;
bool new_timing;
+ bool zero_is_skip;
};
static const struct aw_mmc_conf a10_mmc_conf = {
.dma_xferlen = 0x2000,
+ .dma_desc_shift = 0,
};
static const struct aw_mmc_conf a13_mmc_conf = {
.dma_xferlen = 0x10000,
+ .dma_desc_shift = 0,
};
static const struct aw_mmc_conf a64_mmc_conf = {
.dma_xferlen = 0x10000,
+ .dma_desc_shift = 0,
.mask_data0 = true,
.can_calibrate = true,
.new_timing = true,
@@ -106,13 +111,24 @@ static const struct aw_mmc_conf a64_mmc_conf = {
static const struct aw_mmc_conf a64_emmc_conf = {
.dma_xferlen = 0x2000,
+ .dma_desc_shift = 0,
.can_calibrate = true,
};
+static const struct aw_mmc_conf d1_mmc_conf = {
+ .dma_xferlen = 0x1000,
+ .dma_desc_shift = 2,
+ .mask_data0 = true,
+ .can_calibrate = true,
+ .new_timing = true,
+ .zero_is_skip = true,
+};
+
static struct ofw_compat_data compat_data[] = {
{"allwinner,sun4i-a10-mmc", (uintptr_t)&a10_mmc_conf},
{"allwinner,sun5i-a13-mmc", (uintptr_t)&a13_mmc_conf},
{"allwinner,sun7i-a20-mmc", (uintptr_t)&a13_mmc_conf},
+ {"allwinner,sun20i-d1-mmc", (uintptr_t)&d1_mmc_conf},
{"allwinner,sun50i-a64-mmc", (uintptr_t)&a64_mmc_conf},
{"allwinner,sun50i-a64-emmc", (uintptr_t)&a64_emmc_conf},
{NULL, 0}
@@ -607,16 +623,18 @@ aw_dma_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int err)
dma_desc = sc->aw_dma_desc;
for (i = 0; i < nsegs; i++) {
- if (segs[i].ds_len == sc->aw_mmc_conf->dma_xferlen)
+ if ((segs[i].ds_len == sc->aw_mmc_conf->dma_xferlen) &&
+ !sc->aw_mmc_conf->zero_is_skip)
dma_desc[i].buf_size = 0; /* Size of 0 indicate max len */
else
dma_desc[i].buf_size = segs[i].ds_len;
- dma_desc[i].buf_addr = segs[i].ds_addr;
+ dma_desc[i].buf_addr = segs[i].ds_addr >>
+ sc->aw_mmc_conf->dma_desc_shift;
dma_desc[i].config = AW_MMC_DMA_CONFIG_CH |
- AW_MMC_DMA_CONFIG_OWN | AW_MMC_DMA_CONFIG_DIC;
-
- dma_desc[i].next = sc->aw_dma_desc_phys +
- ((i + 1) * sizeof(struct aw_mmc_dma_desc));
+ AW_MMC_DMA_CONFIG_OWN | AW_MMC_DMA_CONFIG_DIC;
+ dma_desc[i].next = (sc->aw_dma_desc_phys +
+ (i + 1) * sizeof(struct aw_mmc_dma_desc)) >>
+ sc->aw_mmc_conf->dma_desc_shift;
}
dma_desc[0].config |= AW_MMC_DMA_CONFIG_FD;
@@ -678,7 +696,8 @@ aw_mmc_prepare_dma(struct aw_mmc_softc *sc)
AW_MMC_WRITE_4(sc, AW_MMC_IDIE, val);
/* Set DMA descritptor list address */
- AW_MMC_WRITE_4(sc, AW_MMC_DLBA, sc->aw_dma_desc_phys);
+ AW_MMC_WRITE_4(sc, AW_MMC_DLBA, sc->aw_dma_desc_phys >>
+ sc->aw_mmc_conf->dma_desc_shift);
/* FIFO trigger level */
AW_MMC_WRITE_4(sc, AW_MMC_FWLR, AW_MMC_DMA_FTRGLEVEL);
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index a09da794e77d..2152f7fcc1c6 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,
@@ -8489,18 +8501,20 @@ pmap_demote_l2_locked(pmap_t pmap, pt_entry_t *l2, vm_offset_t va,
/*
* Invalidate the 2MB page mapping and return "failure" if the
- * mapping was never accessed.
+ * mapping was never accessed and not wired.
*/
if ((oldl2 & ATTR_AF) == 0) {
- KASSERT((oldl2 & ATTR_SW_WIRED) == 0,
- ("pmap_demote_l2: a wired mapping is missing ATTR_AF"));
- pmap_demote_l2_abort(pmap, va, l2, lockp);
- CTR2(KTR_PMAP, "pmap_demote_l2: failure for va %#lx in pmap %p",
- va, pmap);
- goto fail;
- }
-
- if ((ml3 = pmap_remove_pt_page(pmap, va)) == NULL) {
+ if ((oldl2 & ATTR_SW_WIRED) == 0) {
+ pmap_demote_l2_abort(pmap, va, l2, lockp);
+ CTR2(KTR_PMAP,
+ "pmap_demote_l2: failure for va %#lx in pmap %p",
+ va, pmap);
+ goto fail;
+ }
+ ml3 = pmap_remove_pt_page(pmap, va);
+ /* Fill the PTP with L3Es that have ATTR_AF cleared. */
+ ml3->valid = 0;
+ } else if ((ml3 = pmap_remove_pt_page(pmap, va)) == NULL) {
KASSERT((oldl2 & ATTR_SW_WIRED) == 0,
("pmap_demote_l2: page table page for a wired mapping"
" is missing"));
@@ -8556,7 +8570,7 @@ pmap_demote_l2_locked(pmap_t pmap, pt_entry_t *l2, vm_offset_t va,
/*
* If the PTP is not leftover from an earlier promotion or it does not
* have ATTR_AF set in every L3E, then fill it. The new L3Es will all
- * have ATTR_AF set.
+ * have ATTR_AF set, unless this is a wired mapping with ATTR_AF clear.
*
* When pmap_update_entry() clears the old L2 mapping, it (indirectly)
* performs a dsb(). That dsb() ensures that the stores for filling
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/arm64/include/vmm_dev.h b/sys/arm64/include/vmm_dev.h
index 938bea47c7f8..219f1116c728 100644
--- a/sys/arm64/include/vmm_dev.h
+++ b/sys/arm64/include/vmm_dev.h
@@ -27,6 +27,8 @@
#ifndef _VMM_DEV_H_
#define _VMM_DEV_H_
+#include <sys/domainset.h>
+
#include <machine/vmm.h>
struct vm_memmap {
@@ -49,6 +51,9 @@ struct vm_memseg {
int segid;
size_t len;
char name[VM_MAX_SUFFIXLEN + 1];
+ domainset_t *ds_mask;
+ size_t ds_mask_size;
+ int ds_policy;
};
struct vm_register {
diff --git a/sys/cam/cam_xpt.c b/sys/cam/cam_xpt.c
index 2ec736e7f4ac..cae29226d13c 100644
--- a/sys/cam/cam_xpt.c
+++ b/sys/cam/cam_xpt.c
@@ -2515,6 +2515,15 @@ xpt_action(union ccb *start_ccb)
("xpt_action: func %#x %s\n", start_ccb->ccb_h.func_code,
xpt_action_name(start_ccb->ccb_h.func_code)));
+ /*
+ * Either it isn't queued, or it has a real priority. There still too
+ * many places that reuse CCBs with a real priority to do immediate
+ * queries to do the other side of this assert.
+ */
+ KASSERT((start_ccb->ccb_h.func_code & XPT_FC_QUEUED) == 0 ||
+ start_ccb->ccb_h.pinfo.priority != CAM_PRIORITY_NONE,
+ ("%s: queued ccb and CAM_PRIORITY_NONE illegal.", __func__));
+
start_ccb->ccb_h.status = CAM_REQ_INPROG;
(*(start_ccb->ccb_h.path->bus->xport->ops->action))(start_ccb);
}
diff --git a/sys/cam/mmc/mmc_da.c b/sys/cam/mmc/mmc_da.c
index 7f8bf3516804..322141a72707 100644
--- a/sys/cam/mmc/mmc_da.c
+++ b/sys/cam/mmc/mmc_da.c
@@ -1081,7 +1081,7 @@ sdda_start_init_task(void *context, int pending)
CAM_DEBUG(periph->path, CAM_DEBUG_TRACE, ("sdda_start_init_task\n"));
new_ccb = xpt_alloc_ccb();
xpt_setup_ccb(&new_ccb->ccb_h, periph->path,
- CAM_PRIORITY_NONE);
+ CAM_PRIORITY_NORMAL);
cam_periph_lock(periph);
cam_periph_hold(periph, PRIBIO|PCATCH);
diff --git a/sys/cam/mmc/mmc_xpt.c b/sys/cam/mmc/mmc_xpt.c
index 4fce03004994..f5f66f5214a8 100644
--- a/sys/cam/mmc/mmc_xpt.c
+++ b/sys/cam/mmc/mmc_xpt.c
@@ -610,7 +610,6 @@ mmcprobe_start(struct cam_periph *periph, union ccb *start_ccb)
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_RESET\n"));
/* FALLTHROUGH */
case PROBE_IDENTIFY:
- xpt_path_inq(&start_ccb->cpi, periph->path);
CAM_DEBUG(start_ccb->ccb_h.path, CAM_DEBUG_PROBE, ("Start with PROBE_IDENTIFY\n"));
init_standard_ccb(start_ccb, XPT_MMC_GET_TRAN_SETTINGS);
break;
diff --git a/sys/cddl/dev/sdt/sdt.c b/sys/cddl/dev/sdt/sdt.c
index a8da618204af..0a9059104671 100644
--- a/sys/cddl/dev/sdt/sdt.c
+++ b/sys/cddl/dev/sdt/sdt.c
@@ -72,6 +72,7 @@ static void sdt_load(void);
static int sdt_unload(void);
static void sdt_create_provider(struct sdt_provider *);
static void sdt_create_probe(struct sdt_probe *);
+static void sdt_init_probe(struct sdt_probe *, linker_file_t);
static void sdt_kld_load(void *, struct linker_file *);
static void sdt_kld_unload_try(void *, struct linker_file *, int *);
@@ -204,6 +205,14 @@ sdt_create_probe(struct sdt_probe *probe)
(void)dtrace_probe_create(prov->id, mod, func, name, aframes, probe);
}
+static void
+sdt_init_probe(struct sdt_probe *probe, linker_file_t lf)
+{
+ probe->sdtp_lf = lf;
+ TAILQ_INIT(&probe->argtype_list);
+ STAILQ_INIT(&probe->tracepoint_list);
+}
+
/*
* Probes are created through the SDT module load/unload hook, so this function
* has nothing to do. It only exists because the DTrace provider framework
@@ -361,12 +370,19 @@ static void
sdt_kld_load_providers(struct linker_file *lf)
{
struct sdt_provider **prov, **begin, **end;
+ struct sdt_probe **p_begin, **p_end;
if (linker_file_lookup_set(lf, "sdt_providers_set", &begin, &end,
NULL) == 0) {
for (prov = begin; prov < end; prov++)
sdt_create_provider(*prov);
}
+
+ if (linker_file_lookup_set(lf, "sdt_probes_set", &p_begin, &p_end,
+ NULL) == 0) {
+ for (struct sdt_probe **probe = p_begin; probe < p_end; probe++)
+ sdt_init_probe(*probe, lf);
+ }
}
static void
@@ -378,13 +394,8 @@ sdt_kld_load_probes(struct linker_file *lf)
if (linker_file_lookup_set(lf, "sdt_probes_set", &p_begin, &p_end,
NULL) == 0) {
- for (struct sdt_probe **probe = p_begin; probe < p_end;
- probe++) {
- (*probe)->sdtp_lf = lf;
+ for (struct sdt_probe **probe = p_begin; probe < p_end; probe++)
sdt_create_probe(*probe);
- TAILQ_INIT(&(*probe)->argtype_list);
- STAILQ_INIT(&(*probe)->tracepoint_list);
- }
}
if (linker_file_lookup_set(lf, "sdt_argtypes_set", &a_begin, &a_end,
diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c
index cfb054235489..1c6d64d6b8bc 100644
--- a/sys/compat/linprocfs/linprocfs.c
+++ b/sys/compat/linprocfs/linprocfs.c
@@ -1911,7 +1911,7 @@ linprocfs_doproclimits(PFS_FILL_ARGS)
"kern.sigqueue.max_pending_per_proc",
&res, &size, 0, 0, 0, 0);
if (error != 0)
- goto out;
+ continue;
rl.rlim_cur = res;
rl.rlim_max = res;
break;
@@ -1919,7 +1919,7 @@ linprocfs_doproclimits(PFS_FILL_ARGS)
error = kernel_sysctlbyname(td,
"kern.ipc.msgmnb", &res, &size, 0, 0, 0, 0);
if (error != 0)
- goto out;
+ continue;
rl.rlim_cur = res;
rl.rlim_max = res;
break;
@@ -1941,9 +1941,9 @@ linprocfs_doproclimits(PFS_FILL_ARGS)
li->desc, (unsigned long long)rl.rlim_cur,
(unsigned long long)rl.rlim_max, li->unit);
}
-out:
+
lim_free(limp);
- return (error);
+ return (0);
}
/*
diff --git a/sys/compat/linux/linux_file.c b/sys/compat/linux/linux_file.c
index 86834a7ecea8..a4be5313aa96 100644
--- a/sys/compat/linux/linux_file.c
+++ b/sys/compat/linux/linux_file.c
@@ -1792,7 +1792,7 @@ linux_memfd_create(struct thread *td, struct linux_memfd_create_args *args)
if ((flags & MFD_ALLOW_SEALING) != 0)
shmflags |= SHM_ALLOW_SEALING;
return (kern_shm_open2(td, SHM_ANON, oflags, 0, shmflags, NULL,
- memfd_name));
+ memfd_name, NULL));
}
int
diff --git a/sys/conf/files b/sys/conf/files
index dd0d390962f2..b7c19fae0b8e 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3768,6 +3768,7 @@ gnu/gcov/gcov_subr.c optional gcov
kern/bus_if.m standard
kern/clock_if.m standard
+kern/coredump_vnode.c standard
kern/cpufreq_if.m standard
kern/device_if.m standard
kern/imgact_binmisc.c optional imgact_binmisc
@@ -3856,6 +3857,7 @@ kern/kern_time.c standard
kern/kern_timeout.c standard
kern/kern_tslog.c optional tslog
kern/kern_ubsan.c optional kubsan
+kern/kern_ucoredump.c standard
kern/kern_umtx.c standard
kern/kern_uuid.c standard
kern/kern_vnodedumper.c standard
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64
index 0584fc29d039..80548320c3fc 100644
--- a/sys/conf/files.amd64
+++ b/sys/conf/files.amd64
@@ -84,8 +84,8 @@ amd64/amd64/xen-locore.S optional xenhvm \
amd64/amd64/machdep.c standard
amd64/amd64/mem.c optional mem
amd64/amd64/minidump_machdep.c standard
-amd64/amd64/mp_machdep.c optional smp
-amd64/amd64/mpboot.S optional smp
+amd64/amd64/mp_machdep.c standard
+amd64/amd64/mpboot.S standard
amd64/amd64/pmap.c standard
amd64/amd64/ptrace_machdep.c standard
amd64/amd64/support.S standard
@@ -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/conf/files.arm64 b/sys/conf/files.arm64
index 901da27e63f2..641001efab5e 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -368,6 +368,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/conf/files.x86 b/sys/conf/files.x86
index df206b314b38..9976e9cfec5d 100644
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -62,6 +62,7 @@ dev/acpi_support/acpi_wmi_if.m standard
dev/agp/agp_amd64.c optional agp
dev/agp/agp_i810.c optional agp
dev/agp/agp_via.c optional agp
+dev/amdsmu/amdsmu.c optional amdsmu pci
dev/amdsbwd/amdsbwd.c optional amdsbwd
dev/amdsmn/amdsmn.c optional amdsmn | amdtemp
dev/amdtemp/amdtemp.c optional amdtemp
diff --git a/sys/dev/amdsmu/amdsmu.c b/sys/dev/amdsmu/amdsmu.c
new file mode 100644
index 000000000000..416f875c6176
--- /dev/null
+++ b/sys/dev/amdsmu/amdsmu.c
@@ -0,0 +1,466 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 The FreeBSD Foundation
+ *
+ * This software was developed by Aymeric Wibo <obiwac@freebsd.org>
+ * under sponsorship from the FreeBSD Foundation.
+ */
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/sysctl.h>
+
+#include <dev/pci/pcivar.h>
+#include <dev/amdsmu/amdsmu.h>
+
+static bool
+amdsmu_match(device_t dev, const struct amdsmu_product **product_out)
+{
+ const uint16_t vendorid = pci_get_vendor(dev);
+ const uint16_t deviceid = pci_get_device(dev);
+
+ for (size_t i = 0; i < nitems(amdsmu_products); i++) {
+ const struct amdsmu_product *prod = &amdsmu_products[i];
+
+ if (vendorid == prod->amdsmu_vendorid &&
+ deviceid == prod->amdsmu_deviceid) {
+ if (product_out != NULL)
+ *product_out = prod;
+ return (true);
+ }
+ }
+ return (false);
+}
+
+static void
+amdsmu_identify(driver_t *driver, device_t parent)
+{
+ if (device_find_child(parent, "amdsmu", -1) != NULL)
+ return;
+
+ if (amdsmu_match(parent, NULL)) {
+ if (device_add_child(parent, "amdsmu", -1) == NULL)
+ device_printf(parent, "add amdsmu child failed\n");
+ }
+}
+
+static int
+amdsmu_probe(device_t dev)
+{
+ if (resource_disabled("amdsmu", 0))
+ return (ENXIO);
+ if (!amdsmu_match(device_get_parent(dev), NULL))
+ return (ENXIO);
+ device_set_descf(dev, "AMD System Management Unit");
+
+ return (BUS_PROBE_GENERIC);
+}
+
+static enum amdsmu_res
+amdsmu_wait_res(device_t dev)
+{
+ struct amdsmu_softc *sc = device_get_softc(dev);
+ enum amdsmu_res res;
+
+ /*
+ * The SMU has a response ready for us when the response register is
+ * set. Otherwise, we must wait.
+ */
+ for (size_t i = 0; i < SMU_RES_READ_MAX; i++) {
+ res = amdsmu_read4(sc, SMU_REG_RESPONSE);
+ if (res != SMU_RES_WAIT)
+ return (res);
+ pause_sbt("amdsmu", ustosbt(SMU_RES_READ_PERIOD_US), 0,
+ C_HARDCLOCK);
+ }
+ device_printf(dev, "timed out waiting for response from SMU\n");
+ return (SMU_RES_WAIT);
+}
+
+static int
+amdsmu_cmd(device_t dev, enum amdsmu_msg msg, uint32_t arg, uint32_t *ret)
+{
+ struct amdsmu_softc *sc = device_get_softc(dev);
+ enum amdsmu_res res;
+
+ /* Wait for SMU to be ready. */
+ if (amdsmu_wait_res(dev) == SMU_RES_WAIT)
+ return (ETIMEDOUT);
+
+ /* Clear previous response. */
+ amdsmu_write4(sc, SMU_REG_RESPONSE, SMU_RES_WAIT);
+
+ /* Write out command to registers. */
+ amdsmu_write4(sc, SMU_REG_MESSAGE, msg);
+ amdsmu_write4(sc, SMU_REG_ARGUMENT, arg);
+
+ /* Wait for SMU response and handle it. */
+ res = amdsmu_wait_res(dev);
+
+ switch (res) {
+ case SMU_RES_WAIT:
+ return (ETIMEDOUT);
+ case SMU_RES_OK:
+ if (ret != NULL)
+ *ret = amdsmu_read4(sc, SMU_REG_ARGUMENT);
+ return (0);
+ case SMU_RES_REJECT_BUSY:
+ device_printf(dev, "SMU is busy\n");
+ return (EBUSY);
+ case SMU_RES_REJECT_PREREQ:
+ case SMU_RES_UNKNOWN:
+ case SMU_RES_FAILED:
+ device_printf(dev, "SMU error: %02x\n", res);
+ return (EIO);
+ }
+
+ return (EINVAL);
+}
+
+static int
+amdsmu_get_vers(device_t dev)
+{
+ int err;
+ uint32_t smu_vers;
+ struct amdsmu_softc *sc = device_get_softc(dev);
+
+ err = amdsmu_cmd(dev, SMU_MSG_GETSMUVERSION, 0, &smu_vers);
+ if (err != 0) {
+ device_printf(dev, "failed to get SMU version\n");
+ return (err);
+ }
+ sc->smu_program = (smu_vers >> 24) & 0xFF;
+ sc->smu_maj = (smu_vers >> 16) & 0xFF;
+ sc->smu_min = (smu_vers >> 8) & 0xFF;
+ sc->smu_rev = smu_vers & 0xFF;
+ device_printf(dev, "SMU version: %d.%d.%d (program %d)\n",
+ sc->smu_maj, sc->smu_min, sc->smu_rev, sc->smu_program);
+
+ return (0);
+}
+
+static int
+amdsmu_get_ip_blocks(device_t dev)
+{
+ struct amdsmu_softc *sc = device_get_softc(dev);
+ const uint16_t deviceid = pci_get_device(dev);
+ int err;
+ struct amdsmu_metrics *m = &sc->metrics;
+ bool active;
+ char sysctl_descr[32];
+
+ /* Get IP block count. */
+ switch (deviceid) {
+ case PCI_DEVICEID_AMD_REMBRANDT_ROOT:
+ sc->ip_block_count = 12;
+ break;
+ case PCI_DEVICEID_AMD_PHOENIX_ROOT:
+ sc->ip_block_count = 21;
+ break;
+ /* TODO How many IP blocks does Strix Point (and the others) have? */
+ case PCI_DEVICEID_AMD_STRIX_POINT_ROOT:
+ default:
+ sc->ip_block_count = nitems(amdsmu_ip_blocks_names);
+ }
+ KASSERT(sc->ip_block_count <= nitems(amdsmu_ip_blocks_names),
+ ("too many IP blocks for array"));
+
+ /* Get and print out IP blocks. */
+ err = amdsmu_cmd(dev, SMU_MSG_GET_SUP_CONSTRAINTS, 0,
+ &sc->active_ip_blocks);
+ if (err != 0) {
+ device_printf(dev, "failed to get IP blocks\n");
+ return (err);
+ }
+ device_printf(dev, "Active IP blocks: ");
+ for (size_t i = 0; i < sc->ip_block_count; i++) {
+ active = (sc->active_ip_blocks & (1 << i)) != 0;
+ sc->ip_blocks_active[i] = active;
+ if (!active)
+ continue;
+ printf("%s%s", amdsmu_ip_blocks_names[i],
+ i + 1 < sc->ip_block_count ? " " : "\n");
+ }
+
+ /* Create a sysctl node for IP blocks. */
+ sc->ip_blocks_sysctlnode = SYSCTL_ADD_NODE(sc->sysctlctx,
+ SYSCTL_CHILDREN(sc->sysctlnode), OID_AUTO, "ip_blocks",
+ CTLFLAG_RD, NULL, "SMU metrics");
+ if (sc->ip_blocks_sysctlnode == NULL) {
+ device_printf(dev, "could not add sysctl node for IP blocks\n");
+ return (ENOMEM);
+ }
+
+ /* Create a sysctl node for each IP block. */
+ for (size_t i = 0; i < sc->ip_block_count; i++) {
+ /* Create the sysctl node itself for the IP block. */
+ snprintf(sysctl_descr, sizeof sysctl_descr,
+ "Metrics about the %s AMD IP block",
+ amdsmu_ip_blocks_names[i]);
+ sc->ip_block_sysctlnodes[i] = SYSCTL_ADD_NODE(sc->sysctlctx,
+ SYSCTL_CHILDREN(sc->ip_blocks_sysctlnode), OID_AUTO,
+ amdsmu_ip_blocks_names[i], CTLFLAG_RD, NULL, sysctl_descr);
+ if (sc->ip_block_sysctlnodes[i] == NULL) {
+ device_printf(dev,
+ "could not add sysctl node for \"%s\"\n", sysctl_descr);
+ continue;
+ }
+ /*
+ * Create sysctls for if the IP block is currently active, last
+ * active time, and total active time.
+ */
+ SYSCTL_ADD_BOOL(sc->sysctlctx,
+ SYSCTL_CHILDREN(sc->ip_block_sysctlnodes[i]), OID_AUTO,
+ "active", CTLFLAG_RD, &sc->ip_blocks_active[i], 0,
+ "IP block is currently active");
+ SYSCTL_ADD_U64(sc->sysctlctx,
+ SYSCTL_CHILDREN(sc->ip_block_sysctlnodes[i]), OID_AUTO,
+ "last_time", CTLFLAG_RD, &m->ip_block_last_active_time[i],
+ 0, "How long the IP block was active for during the last"
+ " sleep (us)");
+#ifdef IP_BLOCK_TOTAL_ACTIVE_TIME
+ SYSCTL_ADD_U64(sc->sysctlctx,
+ SYSCTL_CHILDREN(sc->ip_block_sysctlnodes[i]), OID_AUTO,
+ "total_time", CTLFLAG_RD, &m->ip_block_total_active_time[i],
+ 0, "How long the IP block was active for during sleep in"
+ " total (us)");
+#endif
+ }
+ return (0);
+}
+
+static int
+amdsmu_init_metrics(device_t dev)
+{
+ struct amdsmu_softc *sc = device_get_softc(dev);
+ int err;
+ uint32_t metrics_addr_lo, metrics_addr_hi;
+ uint64_t metrics_addr;
+
+ /* Get physical address of logging buffer. */
+ err = amdsmu_cmd(dev, SMU_MSG_LOG_GETDRAM_ADDR_LO, 0, &metrics_addr_lo);
+ if (err != 0)
+ return (err);
+ err = amdsmu_cmd(dev, SMU_MSG_LOG_GETDRAM_ADDR_HI, 0, &metrics_addr_hi);
+ if (err != 0)
+ return (err);
+ metrics_addr = ((uint64_t) metrics_addr_hi << 32) | metrics_addr_lo;
+
+ /* Map memory of logging buffer. */
+ err = bus_space_map(sc->bus_tag, metrics_addr,
+ sizeof(struct amdsmu_metrics), 0, &sc->metrics_space);
+ if (err != 0) {
+ device_printf(dev, "could not map bus space for SMU metrics\n");
+ return (err);
+ }
+
+ /* Start logging for metrics. */
+ amdsmu_cmd(dev, SMU_MSG_LOG_RESET, 0, NULL);
+ amdsmu_cmd(dev, SMU_MSG_LOG_START, 0, NULL);
+ return (0);
+}
+
+static int
+amdsmu_dump_metrics(device_t dev)
+{
+ struct amdsmu_softc *sc = device_get_softc(dev);
+ int err;
+
+ err = amdsmu_cmd(dev, SMU_MSG_LOG_DUMP_DATA, 0, NULL);
+ if (err != 0) {
+ device_printf(dev, "failed to dump metrics\n");
+ return (err);
+ }
+ bus_space_read_region_4(sc->bus_tag, sc->metrics_space, 0,
+ (uint32_t *)&sc->metrics, sizeof(sc->metrics) / sizeof(uint32_t));
+
+ return (0);
+}
+
+static void
+amdsmu_fetch_idlemask(device_t dev)
+{
+ struct amdsmu_softc *sc = device_get_softc(dev);
+
+ sc->idlemask = amdsmu_read4(sc, SMU_REG_IDLEMASK);
+}
+
+static int
+amdsmu_attach(device_t dev)
+{
+ struct amdsmu_softc *sc = device_get_softc(dev);
+ int err;
+ uint32_t physbase_addr_lo, physbase_addr_hi;
+ uint64_t physbase_addr;
+ int rid = 0;
+ struct sysctl_oid *node;
+
+ /*
+ * Find physical base address for SMU.
+ * XXX I am a little confused about the masks here. I'm just copying
+ * what Linux does in the amd-pmc driver to get the base address.
+ */
+ pci_write_config(dev, SMU_INDEX_ADDRESS, SMU_PHYSBASE_ADDR_LO, 4);
+ physbase_addr_lo = pci_read_config(dev, SMU_INDEX_DATA, 4) & 0xFFF00000;
+
+ pci_write_config(dev, SMU_INDEX_ADDRESS, SMU_PHYSBASE_ADDR_HI, 4);
+ physbase_addr_hi = pci_read_config(dev, SMU_INDEX_DATA, 4) & 0x0000FFFF;
+
+ physbase_addr = (uint64_t)physbase_addr_hi << 32 | physbase_addr_lo;
+
+ /* Map memory for SMU and its registers. */
+ sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (sc->res == NULL) {
+ device_printf(dev, "could not allocate resource\n");
+ return (ENXIO);
+ }
+
+ sc->bus_tag = rman_get_bustag(sc->res);
+
+ if (bus_space_map(sc->bus_tag, physbase_addr,
+ SMU_MEM_SIZE, 0, &sc->smu_space) != 0) {
+ device_printf(dev, "could not map bus space for SMU\n");
+ err = ENXIO;
+ goto err_smu_space;
+ }
+ if (bus_space_map(sc->bus_tag, physbase_addr + SMU_REG_SPACE_OFF,
+ SMU_MEM_SIZE, 0, &sc->reg_space) != 0) {
+ device_printf(dev, "could not map bus space for SMU regs\n");
+ err = ENXIO;
+ goto err_reg_space;
+ }
+
+ /* sysctl stuff. */
+ sc->sysctlctx = device_get_sysctl_ctx(dev);
+ sc->sysctlnode = device_get_sysctl_tree(dev);
+
+ /* Get version & add sysctls. */
+ if ((err = amdsmu_get_vers(dev)) != 0)
+ goto err_dump;
+
+ SYSCTL_ADD_U8(sc->sysctlctx, SYSCTL_CHILDREN(sc->sysctlnode), OID_AUTO,
+ "program", CTLFLAG_RD, &sc->smu_program, 0, "SMU program number");
+ SYSCTL_ADD_U8(sc->sysctlctx, SYSCTL_CHILDREN(sc->sysctlnode), OID_AUTO,
+ "version_major", CTLFLAG_RD, &sc->smu_maj, 0,
+ "SMU firmware major version number");
+ SYSCTL_ADD_U8(sc->sysctlctx, SYSCTL_CHILDREN(sc->sysctlnode), OID_AUTO,
+ "version_minor", CTLFLAG_RD, &sc->smu_min, 0,
+ "SMU firmware minor version number");
+ SYSCTL_ADD_U8(sc->sysctlctx, SYSCTL_CHILDREN(sc->sysctlnode), OID_AUTO,
+ "version_revision", CTLFLAG_RD, &sc->smu_rev, 0,
+ "SMU firmware revision number");
+
+ /* Set up for getting metrics & add sysctls. */
+ if ((err = amdsmu_init_metrics(dev)) != 0)
+ goto err_dump;
+ if ((err = amdsmu_dump_metrics(dev)) != 0)
+ goto err_dump;
+
+ node = SYSCTL_ADD_NODE(sc->sysctlctx, SYSCTL_CHILDREN(sc->sysctlnode),
+ OID_AUTO, "metrics", CTLFLAG_RD, NULL, "SMU metrics");
+ if (node == NULL) {
+ device_printf(dev, "could not add sysctl node for metrics\n");
+ err = ENOMEM;
+ goto err_dump;
+ }
+
+ SYSCTL_ADD_U32(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "table_version", CTLFLAG_RD, &sc->metrics.table_version, 0,
+ "SMU metrics table version");
+ SYSCTL_ADD_U32(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "hint_count", CTLFLAG_RD, &sc->metrics.hint_count, 0,
+ "How many times the sleep hint was set");
+ SYSCTL_ADD_U32(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "s0i3_last_entry_status", CTLFLAG_RD,
+ &sc->metrics.s0i3_last_entry_status, 0,
+ "1 if last S0i3 entry was successful");
+ SYSCTL_ADD_U32(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "time_last_in_s0i2", CTLFLAG_RD, &sc->metrics.time_last_in_s0i2, 0,
+ "Time spent in S0i2 during last sleep (us)");
+ SYSCTL_ADD_U64(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "time_last_entering_s0i3", CTLFLAG_RD,
+ &sc->metrics.time_last_entering_s0i3, 0,
+ "Time spent entering S0i3 during last sleep (us)");
+ SYSCTL_ADD_U64(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "total_time_entering_s0i3", CTLFLAG_RD,
+ &sc->metrics.total_time_entering_s0i3, 0,
+ "Total time spent entering S0i3 (us)");
+ SYSCTL_ADD_U64(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "time_last_resuming", CTLFLAG_RD, &sc->metrics.time_last_resuming,
+ 0, "Time spent resuming from last sleep (us)");
+ SYSCTL_ADD_U64(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "total_time_resuming", CTLFLAG_RD, &sc->metrics.total_time_resuming,
+ 0, "Total time spent resuming from sleep (us)");
+ SYSCTL_ADD_U64(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "time_last_in_s0i3", CTLFLAG_RD, &sc->metrics.time_last_in_s0i3, 0,
+ "Time spent in S0i3 during last sleep (us)");
+ SYSCTL_ADD_U64(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "total_time_in_s0i3", CTLFLAG_RD, &sc->metrics.total_time_in_s0i3,
+ 0, "Total time spent in S0i3 (us)");
+ SYSCTL_ADD_U64(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "time_last_in_sw_drips", CTLFLAG_RD,
+ &sc->metrics.time_last_in_sw_drips, 0,
+ "Time spent in awake during last sleep (us)");
+ SYSCTL_ADD_U64(sc->sysctlctx, SYSCTL_CHILDREN(node), OID_AUTO,
+ "total_time_in_sw_drips", CTLFLAG_RD,
+ &sc->metrics.total_time_in_sw_drips, 0,
+ "Total time spent awake (us)");
+
+ /* Get IP blocks & add sysctls. */
+ err = amdsmu_get_ip_blocks(dev);
+ if (err != 0)
+ goto err_dump;
+
+ /* Get idlemask & add sysctl. */
+ amdsmu_fetch_idlemask(dev);
+ SYSCTL_ADD_U32(sc->sysctlctx, SYSCTL_CHILDREN(sc->sysctlnode), OID_AUTO,
+ "idlemask", CTLFLAG_RD, &sc->idlemask, 0, "SMU idlemask. This "
+ "value is not documented - only used to help AMD internally debug "
+ "issues");
+
+ return (0);
+err_dump:
+ bus_space_unmap(sc->bus_tag, sc->reg_space, SMU_MEM_SIZE);
+err_reg_space:
+ bus_space_unmap(sc->bus_tag, sc->smu_space, SMU_MEM_SIZE);
+err_smu_space:
+ bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->res);
+ return (err);
+}
+
+static int
+amdsmu_detach(device_t dev)
+{
+ struct amdsmu_softc *sc = device_get_softc(dev);
+ int rid = 0;
+
+ bus_space_unmap(sc->bus_tag, sc->smu_space, SMU_MEM_SIZE);
+ bus_space_unmap(sc->bus_tag, sc->reg_space, SMU_MEM_SIZE);
+
+ bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->res);
+ return (0);
+}
+
+static device_method_t amdsmu_methods[] = {
+ DEVMETHOD(device_identify, amdsmu_identify),
+ DEVMETHOD(device_probe, amdsmu_probe),
+ DEVMETHOD(device_attach, amdsmu_attach),
+ DEVMETHOD(device_detach, amdsmu_detach),
+ DEVMETHOD_END
+};
+
+static driver_t amdsmu_driver = {
+ "amdsmu",
+ amdsmu_methods,
+ sizeof(struct amdsmu_softc),
+};
+
+DRIVER_MODULE(amdsmu, hostb, amdsmu_driver, NULL, NULL);
+MODULE_VERSION(amdsmu, 1);
+MODULE_DEPEND(amdsmu, amdsmn, 1, 1, 1);
+MODULE_PNP_INFO("U16:vendor;U16:device", pci, amdsmu, amdsmu_products,
+ nitems(amdsmu_products));
diff --git a/sys/dev/amdsmu/amdsmu.h b/sys/dev/amdsmu/amdsmu.h
new file mode 100644
index 000000000000..025887f7fe5a
--- /dev/null
+++ b/sys/dev/amdsmu/amdsmu.h
@@ -0,0 +1,95 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 The FreeBSD Foundation
+ *
+ * This software was developed by Aymeric Wibo <obiwac@freebsd.org>
+ * under sponsorship from the FreeBSD Foundation.
+ */
+#ifndef _AMDSMU_H_
+#define _AMDSMU_H_
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <machine/bus.h>
+#include <x86/cputypes.h>
+
+#include <dev/amdsmu/amdsmu_reg.h>
+
+#define SMU_RES_READ_PERIOD_US 50
+#define SMU_RES_READ_MAX 20000
+
+static const struct amdsmu_product {
+ uint16_t amdsmu_vendorid;
+ uint16_t amdsmu_deviceid;
+} amdsmu_products[] = {
+ { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_REMBRANDT_ROOT },
+ { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_PHOENIX_ROOT },
+ { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_STRIX_POINT_ROOT },
+};
+
+static const char *const amdsmu_ip_blocks_names[] = {
+ "DISPLAY",
+ "CPU",
+ "GFX",
+ "VDD",
+ "ACP",
+ "VCN",
+ "ISP",
+ "NBIO",
+ "DF",
+ "USB3_0",
+ "USB3_1",
+ "LAPIC",
+ "USB3_2",
+ "USB3_3",
+ "USB3_4",
+ "USB4_0",
+ "USB4_1",
+ "MPM",
+ "JPEG",
+ "IPU",
+ "UMSCH",
+ "VPE",
+};
+
+CTASSERT(nitems(amdsmu_ip_blocks_names) <= 32);
+
+struct amdsmu_softc {
+ struct sysctl_ctx_list *sysctlctx;
+ struct sysctl_oid *sysctlnode;
+
+ struct resource *res;
+ bus_space_tag_t bus_tag;
+
+ bus_space_handle_t smu_space;
+ bus_space_handle_t reg_space;
+
+ uint8_t smu_program;
+ uint8_t smu_maj, smu_min, smu_rev;
+
+ uint32_t active_ip_blocks;
+ struct sysctl_oid *ip_blocks_sysctlnode;
+ size_t ip_block_count;
+ struct sysctl_oid *ip_block_sysctlnodes[nitems(amdsmu_ip_blocks_names)];
+ bool ip_blocks_active[nitems(amdsmu_ip_blocks_names)];
+
+ bus_space_handle_t metrics_space;
+ struct amdsmu_metrics metrics;
+ uint32_t idlemask;
+};
+
+static inline uint32_t
+amdsmu_read4(const struct amdsmu_softc *sc, bus_size_t reg)
+{
+ return (bus_space_read_4(sc->bus_tag, sc->reg_space, reg));
+}
+
+static inline void
+amdsmu_write4(const struct amdsmu_softc *sc, bus_size_t reg, uint32_t val)
+{
+ bus_space_write_4(sc->bus_tag, sc->reg_space, reg, val);
+}
+
+#endif /* _AMDSMU_H_ */
diff --git a/sys/dev/amdsmu/amdsmu_reg.h b/sys/dev/amdsmu/amdsmu_reg.h
new file mode 100644
index 000000000000..e685b34e6883
--- /dev/null
+++ b/sys/dev/amdsmu/amdsmu_reg.h
@@ -0,0 +1,84 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2025 The FreeBSD Foundation
+ *
+ * This software was developed by Aymeric Wibo <obiwac@freebsd.org>
+ * under sponsorship from the FreeBSD Foundation.
+ */
+#ifndef _AMDSMU_REG_H_
+#define _AMDSMU_REG_H_
+
+#include <sys/types.h>
+
+/*
+ * TODO These are in common with amdtemp; should we find a way to factor these
+ * out? Also, there are way more of these. I couldn't find a centralized place
+ * which lists them though.
+ */
+#define PCI_DEVICEID_AMD_REMBRANDT_ROOT 0x14B5
+#define PCI_DEVICEID_AMD_PHOENIX_ROOT 0x14E8
+#define PCI_DEVICEID_AMD_STRIX_POINT_ROOT 0x14A4
+
+#define SMU_INDEX_ADDRESS 0xB8
+#define SMU_INDEX_DATA 0xBC
+
+#define SMU_PHYSBASE_ADDR_LO 0x13B102E8
+#define SMU_PHYSBASE_ADDR_HI 0x13B102EC
+
+#define SMU_MEM_SIZE 0x1000
+#define SMU_REG_SPACE_OFF 0x10000
+
+#define SMU_REG_MESSAGE 0x538
+#define SMU_REG_RESPONSE 0x980
+#define SMU_REG_ARGUMENT 0x9BC
+#define SMU_REG_IDLEMASK 0xD14
+
+enum amdsmu_res {
+ SMU_RES_WAIT = 0x00,
+ SMU_RES_OK = 0x01,
+ SMU_RES_REJECT_BUSY = 0xFC,
+ SMU_RES_REJECT_PREREQ = 0xFD,
+ SMU_RES_UNKNOWN = 0xFE,
+ SMU_RES_FAILED = 0xFF,
+};
+
+enum amdsmu_msg {
+ SMU_MSG_GETSMUVERSION = 0x02,
+ SMU_MSG_LOG_GETDRAM_ADDR_HI = 0x04,
+ SMU_MSG_LOG_GETDRAM_ADDR_LO = 0x05,
+ SMU_MSG_LOG_START = 0x06,
+ SMU_MSG_LOG_RESET = 0x07,
+ SMU_MSG_LOG_DUMP_DATA = 0x08,
+ SMU_MSG_GET_SUP_CONSTRAINTS = 0x09,
+};
+
+/* XXX Copied from Linux struct smu_metrics. */
+struct amdsmu_metrics {
+ uint32_t table_version;
+ uint32_t hint_count;
+ uint32_t s0i3_last_entry_status;
+ uint32_t time_last_in_s0i2;
+ uint64_t time_last_entering_s0i3;
+ uint64_t total_time_entering_s0i3;
+ uint64_t time_last_resuming;
+ uint64_t total_time_resuming;
+ uint64_t time_last_in_s0i3;
+ uint64_t total_time_in_s0i3;
+ uint64_t time_last_in_sw_drips;
+ uint64_t total_time_in_sw_drips;
+ /*
+ * This is how long each IP block was active for (us), i.e., blocking
+ * entry to S0i3. In Linux, these are called "timecondition_notmet_*".
+ *
+ * XXX Total active time for IP blocks seems to be buggy and reporting
+ * garbage (at least on Phoenix), so it's disabled for now. The last
+ * active time for the USB4_0 IP block also seems to be buggy.
+ */
+ uint64_t ip_block_last_active_time[32];
+#ifdef IP_BLOCK_TOTAL_ACTIVE_TIME
+ uint64_t ip_block_total_active_time[32];
+#endif
+} __attribute__((packed));
+
+#endif /* _AMDSMU_REG_H_ */
diff --git a/sys/dev/cxgbe/tom/t4_cpl_io.c b/sys/dev/cxgbe/tom/t4_cpl_io.c
index 8547f21586e1..7a6b1cbdd736 100644
--- a/sys/dev/cxgbe/tom/t4_cpl_io.c
+++ b/sys/dev/cxgbe/tom/t4_cpl_io.c
@@ -703,7 +703,7 @@ t4_push_frames(struct adapter *sc, struct toepcb *toep, int drop)
for (m = sndptr; m != NULL; m = m->m_next) {
int n;
- if ((m->m_flags & M_NOTAVAIL) != 0)
+ if ((m->m_flags & M_NOTREADY) != 0)
break;
if (m->m_flags & M_EXTPG) {
#ifdef KERN_TLS
@@ -787,7 +787,7 @@ t4_push_frames(struct adapter *sc, struct toepcb *toep, int drop)
/* nothing to send */
if (plen == 0) {
- KASSERT(m == NULL || (m->m_flags & M_NOTAVAIL) != 0,
+ KASSERT(m == NULL || (m->m_flags & M_NOTREADY) != 0,
("%s: nothing to send, but m != NULL is ready",
__func__));
break;
@@ -880,7 +880,7 @@ t4_push_frames(struct adapter *sc, struct toepcb *toep, int drop)
toep->txsd_avail--;
t4_l2t_send(sc, wr, toep->l2te);
- } while (m != NULL && (m->m_flags & M_NOTAVAIL) == 0);
+ } while (m != NULL && (m->m_flags & M_NOTREADY) == 0);
/* Send a FIN if requested, but only if there's no more data to send */
if (m == NULL && toep->flags & TPF_SEND_FIN)
diff --git a/sys/dev/cxgbe/tom/t4_tls.c b/sys/dev/cxgbe/tom/t4_tls.c
index c6377980fca9..27c16b9988ae 100644
--- a/sys/dev/cxgbe/tom/t4_tls.c
+++ b/sys/dev/cxgbe/tom/t4_tls.c
@@ -563,7 +563,7 @@ t4_push_ktls(struct adapter *sc, struct toepcb *toep, int drop)
* If there is no ready data to send, wait until more
* data arrives.
*/
- if (m == NULL || (m->m_flags & M_NOTAVAIL) != 0) {
+ if (m == NULL || (m->m_flags & M_NOTREADY) != 0) {
if (sowwakeup)
sowwakeup_locked(so);
else
@@ -614,7 +614,7 @@ t4_push_ktls(struct adapter *sc, struct toepcb *toep, int drop)
/* Shove if there is no additional data pending. */
shove = ((m->m_next == NULL ||
- (m->m_next->m_flags & M_NOTAVAIL) != 0)) &&
+ (m->m_next->m_flags & M_NOTREADY) != 0)) &&
(tp->t_flags & TF_MORETOCOME) == 0;
if (sb->sb_flags & SB_AUTOSIZE &&
diff --git a/sys/dev/drm2/drm_fb_helper.c b/sys/dev/drm2/drm_fb_helper.c
index f67cc9f60d02..1f4abd255690 100644
--- a/sys/dev/drm2/drm_fb_helper.c
+++ b/sys/dev/drm2/drm_fb_helper.c
@@ -51,7 +51,7 @@ struct vt_kms_softc {
struct task fb_mode_task;
};
-/* Call restore out of vt(9) locks. */
+/* Call restore out of vt(4) locks. */
static void
vt_restore_fbdev_mode(void *arg, int pending)
{
diff --git a/sys/dev/efidev/efirt.c b/sys/dev/efidev/efirt.c
index b0fa33daeca7..b55c1c191077 100644
--- a/sys/dev/efidev/efirt.c
+++ b/sys/dev/efidev/efirt.c
@@ -107,7 +107,8 @@ static int efi_status2err[25] = {
enum efi_table_type {
TYPE_ESRT = 0,
- TYPE_PROP
+ TYPE_PROP,
+ TYPE_MEMORY_ATTR
};
static int efi_enter(void);
@@ -445,6 +446,42 @@ get_table_length(enum efi_table_type type, size_t *table_len, void **taddr)
free(buf, M_TEMP);
return (0);
}
+ case TYPE_MEMORY_ATTR:
+ {
+ efi_guid_t guid = EFI_MEMORY_ATTRIBUTES_TABLE;
+ struct efi_memory_attribute_table *tbl_addr, *mem_addr;
+ int error;
+ void *buf;
+ size_t len = sizeof(struct efi_memory_attribute_table);
+
+ error = efi_get_table(&guid, (void **)&tbl_addr);
+ if (error)
+ return (error);
+
+ buf = malloc(len, M_TEMP, M_WAITOK);
+ error = physcopyout((vm_paddr_t)tbl_addr, buf, len);
+ if (error) {
+ free(buf, M_TEMP);
+ return (error);
+ }
+
+ mem_addr = (struct efi_memory_attribute_table *)buf;
+ if (mem_addr->version != 2) {
+ free(buf, M_TEMP);
+ return (EINVAL);
+ }
+ len += mem_addr->descriptor_size * mem_addr->num_ents;
+ if (len > EFI_TABLE_ALLOC_MAX) {
+ free(buf, M_TEMP);
+ return (ENOMEM);
+ }
+
+ *table_len = len;
+ if (taddr != NULL)
+ *taddr = tbl_addr;
+ free(buf, M_TEMP);
+ return (0);
+ }
}
return (ENOENT);
}
@@ -457,7 +494,8 @@ copy_table(efi_guid_t *guid, void **buf, size_t buf_len, size_t *table_len)
enum efi_table_type type;
} tables[] = {
{ EFI_TABLE_ESRT, TYPE_ESRT },
- { EFI_PROPERTIES_TABLE, TYPE_PROP }
+ { EFI_PROPERTIES_TABLE, TYPE_PROP },
+ { EFI_MEMORY_ATTRIBUTES_TABLE, TYPE_MEMORY_ATTR }
};
size_t table_idx;
void *taddr;
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/iicbus/iichid.c b/sys/dev/iicbus/iichid.c
index 9c0324a24685..3f1d7a0cefba 100644
--- a/sys/dev/iicbus/iichid.c
+++ b/sys/dev/iicbus/iichid.c
@@ -275,62 +275,36 @@ iichid_cmd_read(struct iichid_softc* sc, void *buf, iichid_size_t maxlen,
* 6.1.3 - Retrieval of Input Reports
* DEVICE returns the length (2 Bytes) and the entire Input Report.
*/
- uint8_t actbuf[2] = { 0, 0 };
- /* Read actual input report length. */
+
+ memset(buf, 0xaa, 2); // In case nothing gets read
struct iic_msg msgs[] = {
- { sc->addr, IIC_M_RD | IIC_M_NOSTOP, sizeof(actbuf), actbuf },
+ { sc->addr, IIC_M_RD, maxlen, buf },
};
- uint16_t actlen;
int error;
error = iicbus_transfer(sc->dev, msgs, nitems(msgs));
if (error != 0)
return (error);
- actlen = actbuf[0] | actbuf[1] << 8;
-#ifdef IICHID_SAMPLING
- if ((actlen == 0 && sc->sampling_rate_slow < 0) ||
- (maxlen == 0 && sc->sampling_rate_slow >= 0)) {
-#else
+ DPRINTFN(sc, 5, "%*D\n", msgs[0].len, msgs[0].buf, " ");
+
+ uint16_t actlen = le16dec(buf);
+
if (actlen == 0) {
-#endif
- /* Read and discard reset command response. */
- msgs[0] = (struct iic_msg)
- { sc->addr, IIC_M_RD | IIC_M_NOSTART,
- le16toh(sc->desc.wMaxInputLength) - 2, sc->intr_buf };
- actlen = 0;
if (!sc->reset_acked) {
mtx_lock(&sc->mtx);
sc->reset_acked = true;
wakeup(&sc->reset_acked);
mtx_unlock(&sc->mtx);
}
-#ifdef IICHID_SAMPLING
- } else if ((actlen <= 2 || actlen == 0xFFFF) &&
- sc->sampling_rate_slow >= 0) {
- /* Read and discard 1 byte to send I2C STOP condition. */
- msgs[0] = (struct iic_msg)
- { sc->addr, IIC_M_RD | IIC_M_NOSTART, 1, actbuf };
- actlen = 0;
-#endif
- } else {
- actlen -= 2;
- if (actlen > maxlen) {
- DPRINTF(sc, "input report too big. requested=%d "
- "received=%d\n", maxlen, actlen);
- actlen = maxlen;
- }
- /* Read input report itself. */
- msgs[0] = (struct iic_msg)
- { sc->addr, IIC_M_RD | IIC_M_NOSTART, actlen, buf };
}
- error = iicbus_transfer(sc->dev, msgs, 1);
- if (error == 0 && actual_len != NULL)
+ if (actlen <= 2 || actlen > maxlen) {
+ actlen = 0;
+ }
+ if (actual_len != NULL) {
*actual_len = actlen;
-
- DPRINTFN(sc, 5,
- "%*D - %*D\n", 2, actbuf, " ", msgs[0].len, msgs[0].buf, " ");
+ }
return (error);
}
@@ -566,7 +540,7 @@ iichid_sampling_task(void *context, int pending)
error = iichid_cmd_read(sc, sc->intr_buf, sc->intr_bufsize, &actual);
if (error == 0) {
if (actual > 0) {
- sc->intr_handler(sc->intr_ctx, sc->intr_buf, actual);
+ sc->intr_handler(sc->intr_ctx, sc->intr_buf + 2, actual);
sc->missing_samples = 0;
if (sc->dup_size != actual ||
memcmp(sc->dup_buf, sc->intr_buf, actual) != 0) {
@@ -577,7 +551,7 @@ iichid_sampling_task(void *context, int pending)
++sc->dup_samples;
} else {
if (++sc->missing_samples == 1)
- sc->intr_handler(sc->intr_ctx, sc->intr_buf, 0);
+ sc->intr_handler(sc->intr_ctx, sc->intr_buf + 2, 0);
sc->dup_samples = 0;
}
} else
@@ -632,7 +606,7 @@ iichid_intr(void *context)
if (error == 0) {
if (sc->power_on && sc->open) {
if (actual != 0)
- sc->intr_handler(sc->intr_ctx, sc->intr_buf,
+ sc->intr_handler(sc->intr_ctx, sc->intr_buf + 2,
actual);
else
DPRINTF(sc, "no data received\n");
@@ -842,11 +816,12 @@ iichid_intr_setup(device_t dev, device_t child __unused, hid_intr_t intr,
sc = device_get_softc(dev);
/*
- * Do not rely on wMaxInputLength, as some devices may set it to
- * a wrong length. Find the longest input report in report descriptor.
+ * Do not rely just on wMaxInputLength, as some devices (which?)
+ * may set it to a wrong length. Also find the longest input report
+ * in report descriptor, and add two for the length field.
*/
- rdesc->rdsize =
- MAX(rdesc->isize, le16toh(sc->desc.wMaxInputLength) - 2);
+ rdesc->rdsize = 2 +
+ MAX(rdesc->isize, le16toh(sc->desc.wMaxInputLength));
/* Write and get/set_report sizes are limited by I2C-HID protocol. */
rdesc->grsize = rdesc->srsize = IICHID_SIZE_MAX;
rdesc->wrsize = IICHID_SIZE_MAX;
@@ -919,7 +894,7 @@ iichid_intr_poll(device_t dev, device_t child __unused)
sc = device_get_softc(dev);
error = iichid_cmd_read(sc, sc->intr_buf, sc->intr_bufsize, &actual);
if (error == 0 && actual != 0)
- sc->intr_handler(sc->intr_ctx, sc->intr_buf, actual);
+ sc->intr_handler(sc->intr_ctx, sc->intr_buf + 2, actual);
}
/*
@@ -946,6 +921,7 @@ iichid_read(device_t dev, device_t child __unused, void *buf,
{
struct iichid_softc *sc;
device_t parent;
+ uint8_t *tmpbuf;
int error;
if (maxlen > IICHID_SIZE_MAX)
@@ -954,8 +930,12 @@ iichid_read(device_t dev, device_t child __unused, void *buf,
parent = device_get_parent(sc->dev);
error = iicbus_request_bus(parent, sc->dev, IIC_WAIT);
if (error == 0) {
- error = iichid_cmd_read(sc, buf, maxlen, actlen);
+ tmpbuf = malloc(maxlen + 2, M_DEVBUF, M_WAITOK | M_ZERO);
+ error = iichid_cmd_read(sc, tmpbuf, maxlen + 2, actlen);
iicbus_release_bus(parent, sc->dev);
+ if (*actlen > 0)
+ memcpy(buf, tmpbuf + 2, *actlen);
+ free(tmpbuf, M_DEVBUF);
}
return (iic2errno(error));
}
diff --git a/sys/dev/md/md.c b/sys/dev/md/md.c
index 29dc0c880e3a..ec1664fac701 100644
--- a/sys/dev/md/md.c
+++ b/sys/dev/md/md.c
@@ -89,6 +89,8 @@
#include <sys/unistd.h>
#include <sys/vnode.h>
#include <sys/disk.h>
+#include <sys/param.h>
+#include <sys/bus.h>
#include <geom/geom.h>
#include <geom/geom_int.h>
@@ -2082,8 +2084,10 @@ g_md_init(struct g_class *mp __unused)
{
caddr_t mod;
u_char *ptr, *name, *type;
+ u_char scratch[40];
unsigned len;
int i;
+ vm_offset_t paddr;
/* figure out log2(NINDIR) */
for (i = NINDIR, nshift = -1; i; nshift++)
@@ -2123,6 +2127,25 @@ g_md_init(struct g_class *mp __unused)
sx_xunlock(&md_sx);
}
}
+
+ /*
+ * Load up to 32 pre-loaded disks
+ */
+ for (int i = 0; i < 32; i++) {
+ if (resource_long_value("md", i, "physaddr",
+ (long *) &paddr) != 0 ||
+ resource_int_value("md", i, "len", &len) != 0)
+ break;
+ ptr = (char *)pmap_map(NULL, paddr, paddr + len, VM_PROT_READ);
+ if (ptr != NULL && len != 0) {
+ sprintf(scratch, "preload%d 0x%016jx", i,
+ (uintmax_t)paddr);
+ sx_xlock(&md_sx);
+ md_preloaded(ptr, len, scratch);
+ sx_xunlock(&md_sx);
+ }
+ }
+
status_dev = make_dev(&mdctl_cdevsw, INT_MAX, UID_ROOT, GID_WHEEL,
0600, MDCTL_NAME);
g_topology_lock();
diff --git a/sys/dev/nvme/nvme_ctrlr.c b/sys/dev/nvme/nvme_ctrlr.c
index 73a7cee4aad0..fd7f00ced14b 100644
--- a/sys/dev/nvme/nvme_ctrlr.c
+++ b/sys/dev/nvme/nvme_ctrlr.c
@@ -48,7 +48,7 @@
#define B4_CHK_RDY_DELAY_MS 2300 /* work around controller bug */
static void nvme_ctrlr_construct_and_submit_aer(struct nvme_controller *ctrlr,
- struct nvme_async_event_request *aer);
+ struct nvme_async_event_request *aer);
static void
nvme_ctrlr_barrier(struct nvme_controller *ctrlr, int flags)
@@ -680,96 +680,6 @@ nvme_ctrlr_log_critical_warnings(struct nvme_controller *ctrlr,
}
static void
-nvme_ctrlr_async_event_log_page_cb(void *arg, const struct nvme_completion *cpl)
-{
- struct nvme_async_event_request *aer = arg;
- struct nvme_health_information_page *health_info;
- struct nvme_ns_list *nsl;
- struct nvme_error_information_entry *err;
- int i;
-
- /*
- * If the log page fetch for some reason completed with an error,
- * don't pass log page data to the consumers. In practice, this case
- * should never happen.
- */
- if (nvme_completion_is_error(cpl))
- nvme_notify_async_consumers(aer->ctrlr, &aer->cpl,
- aer->log_page_id, NULL, 0);
- else {
- /* Convert data to host endian */
- switch (aer->log_page_id) {
- case NVME_LOG_ERROR:
- err = (struct nvme_error_information_entry *)aer->log_page_buffer;
- for (i = 0; i < (aer->ctrlr->cdata.elpe + 1); i++)
- nvme_error_information_entry_swapbytes(err++);
- break;
- case NVME_LOG_HEALTH_INFORMATION:
- nvme_health_information_page_swapbytes(
- (struct nvme_health_information_page *)aer->log_page_buffer);
- break;
- case NVME_LOG_CHANGED_NAMESPACE:
- nvme_ns_list_swapbytes(
- (struct nvme_ns_list *)aer->log_page_buffer);
- break;
- case NVME_LOG_COMMAND_EFFECT:
- nvme_command_effects_page_swapbytes(
- (struct nvme_command_effects_page *)aer->log_page_buffer);
- break;
- case NVME_LOG_RES_NOTIFICATION:
- nvme_res_notification_page_swapbytes(
- (struct nvme_res_notification_page *)aer->log_page_buffer);
- break;
- case NVME_LOG_SANITIZE_STATUS:
- nvme_sanitize_status_page_swapbytes(
- (struct nvme_sanitize_status_page *)aer->log_page_buffer);
- break;
- default:
- break;
- }
-
- if (aer->log_page_id == NVME_LOG_HEALTH_INFORMATION) {
- health_info = (struct nvme_health_information_page *)
- aer->log_page_buffer;
- nvme_ctrlr_log_critical_warnings(aer->ctrlr,
- health_info->critical_warning);
- /*
- * Critical warnings reported through the
- * SMART/health log page are persistent, so
- * clear the associated bits in the async event
- * config so that we do not receive repeated
- * notifications for the same event.
- */
- aer->ctrlr->async_event_config &=
- ~health_info->critical_warning;
- nvme_ctrlr_cmd_set_async_event_config(aer->ctrlr,
- aer->ctrlr->async_event_config, NULL, NULL);
- } else if (aer->log_page_id == NVME_LOG_CHANGED_NAMESPACE &&
- !nvme_use_nvd) {
- nsl = (struct nvme_ns_list *)aer->log_page_buffer;
- for (i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) {
- if (nsl->ns[i] > NVME_MAX_NAMESPACES)
- break;
- nvme_notify_ns(aer->ctrlr, nsl->ns[i]);
- }
- }
-
- /*
- * Pass the cpl data from the original async event completion,
- * not the log page fetch.
- */
- nvme_notify_async_consumers(aer->ctrlr, &aer->cpl,
- aer->log_page_id, aer->log_page_buffer, aer->log_page_size);
- }
-
- /*
- * Repost another asynchronous event request to replace the one
- * that just completed.
- */
- nvme_ctrlr_construct_and_submit_aer(aer->ctrlr, aer);
-}
-
-static void
nvme_ctrlr_async_event_cb(void *arg, const struct nvme_completion *cpl)
{
struct nvme_async_event_request *aer = arg;
@@ -784,33 +694,18 @@ nvme_ctrlr_async_event_cb(void *arg, const struct nvme_completion *cpl)
return;
}
- /* Associated log page is in bits 23:16 of completion entry dw0. */
+ /*
+ * Save the completion status and associated log page is in bits 23:16
+ * of completion entry dw0. Print a message and queue it for further
+ * processing.
+ */
+ memcpy(&aer->cpl, cpl, sizeof(*cpl));
aer->log_page_id = NVMEV(NVME_ASYNC_EVENT_LOG_PAGE_ID, cpl->cdw0);
-
nvme_printf(aer->ctrlr, "async event occurred (type 0x%x, info 0x%02x,"
" page 0x%02x)\n", NVMEV(NVME_ASYNC_EVENT_TYPE, cpl->cdw0),
NVMEV(NVME_ASYNC_EVENT_INFO, cpl->cdw0),
aer->log_page_id);
-
- if (is_log_page_id_valid(aer->log_page_id)) {
- aer->log_page_size = nvme_ctrlr_get_log_page_size(aer->ctrlr,
- aer->log_page_id);
- memcpy(&aer->cpl, cpl, sizeof(*cpl));
- nvme_ctrlr_cmd_get_log_page(aer->ctrlr, aer->log_page_id,
- NVME_GLOBAL_NAMESPACE_TAG, aer->log_page_buffer,
- aer->log_page_size, nvme_ctrlr_async_event_log_page_cb,
- aer);
- /* Wait to notify consumers until after log page is fetched. */
- } else {
- nvme_notify_async_consumers(aer->ctrlr, cpl, aer->log_page_id,
- NULL, 0);
-
- /*
- * Repost another asynchronous event request to replace the one
- * that just completed.
- */
- nvme_ctrlr_construct_and_submit_aer(aer->ctrlr, aer);
- }
+ taskqueue_enqueue(aer->ctrlr->taskqueue, &aer->task);
}
static void
@@ -819,15 +714,21 @@ nvme_ctrlr_construct_and_submit_aer(struct nvme_controller *ctrlr,
{
struct nvme_request *req;
- aer->ctrlr = ctrlr;
/*
- * XXX-MJ this should be M_WAITOK but we might be in a non-sleepable
- * callback context. AER completions should be handled on a dedicated
- * thread.
+ * We're racing the reset thread, so let that process submit this again.
+ * XXX does this really solve that race? And is that race even possible
+ * since we only reset when we've no theard from the card in a long
+ * time. Why would we get an AER in the middle of that just before we
+ * kick off the reset?
*/
- req = nvme_allocate_request_null(M_NOWAIT, nvme_ctrlr_async_event_cb,
+ if (ctrlr->is_resetting)
+ return;
+
+ aer->ctrlr = ctrlr;
+ req = nvme_allocate_request_null(M_WAITOK, nvme_ctrlr_async_event_cb,
aer);
aer->req = req;
+ aer->log_page_id = 0; /* Not a valid page */
/*
* Disable timeout here, since asynchronous event requests should by
@@ -1203,6 +1104,140 @@ nvme_ctrlr_reset_task(void *arg, int pending)
atomic_cmpset_32(&ctrlr->is_resetting, 1, 0);
}
+static void
+nvme_ctrlr_aer_done(void *arg, const struct nvme_completion *cpl)
+{
+ struct nvme_async_event_request *aer = arg;
+
+ mtx_lock(&aer->mtx);
+ if (nvme_completion_is_error(cpl))
+ aer->log_page_size = (uint32_t)-1;
+ else
+ aer->log_page_size = nvme_ctrlr_get_log_page_size(
+ aer->ctrlr, aer->log_page_id);
+ wakeup(aer);
+ mtx_unlock(&aer->mtx);
+}
+
+static void
+nvme_ctrlr_aer_task(void *arg, int pending)
+{
+ struct nvme_async_event_request *aer = arg;
+ struct nvme_controller *ctrlr = aer->ctrlr;
+ uint32_t len;
+
+ /*
+ * We're resetting, so just punt.
+ */
+ if (ctrlr->is_resetting)
+ return;
+
+ if (!is_log_page_id_valid(aer->log_page_id)) {
+ /*
+ * Repost another asynchronous event request to replace the one
+ * that just completed.
+ */
+ nvme_notify_async_consumers(ctrlr, &aer->cpl, aer->log_page_id,
+ NULL, 0);
+ nvme_ctrlr_construct_and_submit_aer(ctrlr, aer);
+ goto out;
+ }
+
+ aer->log_page_size = 0;
+ len = nvme_ctrlr_get_log_page_size(aer->ctrlr, aer->log_page_id);
+ nvme_ctrlr_cmd_get_log_page(aer->ctrlr, aer->log_page_id,
+ NVME_GLOBAL_NAMESPACE_TAG, aer->log_page_buffer, len,
+ nvme_ctrlr_aer_done, aer);
+ mtx_lock(&aer->mtx);
+ while (aer->log_page_size == 0)
+ mtx_sleep(aer, &aer->mtx, PRIBIO, "nvme_pt", 0);
+ mtx_unlock(&aer->mtx);
+
+ if (aer->log_page_size != (uint32_t)-1) {
+ /*
+ * If the log page fetch for some reason completed with an
+ * error, don't pass log page data to the consumers. In
+ * practice, this case should never happen.
+ */
+ nvme_notify_async_consumers(aer->ctrlr, &aer->cpl,
+ aer->log_page_id, NULL, 0);
+ goto out;
+ }
+
+ /* Convert data to host endian */
+ switch (aer->log_page_id) {
+ case NVME_LOG_ERROR: {
+ struct nvme_error_information_entry *err =
+ (struct nvme_error_information_entry *)aer->log_page_buffer;
+ for (int i = 0; i < (aer->ctrlr->cdata.elpe + 1); i++)
+ nvme_error_information_entry_swapbytes(err++);
+ break;
+ }
+ case NVME_LOG_HEALTH_INFORMATION:
+ nvme_health_information_page_swapbytes(
+ (struct nvme_health_information_page *)aer->log_page_buffer);
+ break;
+ case NVME_LOG_CHANGED_NAMESPACE:
+ nvme_ns_list_swapbytes(
+ (struct nvme_ns_list *)aer->log_page_buffer);
+ break;
+ case NVME_LOG_COMMAND_EFFECT:
+ nvme_command_effects_page_swapbytes(
+ (struct nvme_command_effects_page *)aer->log_page_buffer);
+ break;
+ case NVME_LOG_RES_NOTIFICATION:
+ nvme_res_notification_page_swapbytes(
+ (struct nvme_res_notification_page *)aer->log_page_buffer);
+ break;
+ case NVME_LOG_SANITIZE_STATUS:
+ nvme_sanitize_status_page_swapbytes(
+ (struct nvme_sanitize_status_page *)aer->log_page_buffer);
+ break;
+ default:
+ break;
+ }
+
+ if (aer->log_page_id == NVME_LOG_HEALTH_INFORMATION) {
+ struct nvme_health_information_page *health_info =
+ (struct nvme_health_information_page *)aer->log_page_buffer;
+
+ /*
+ * Critical warnings reported through the SMART/health log page
+ * are persistent, so clear the associated bits in the async
+ * event config so that we do not receive repeated notifications
+ * for the same event.
+ */
+ nvme_ctrlr_log_critical_warnings(aer->ctrlr,
+ health_info->critical_warning);
+ aer->ctrlr->async_event_config &=
+ ~health_info->critical_warning;
+ nvme_ctrlr_cmd_set_async_event_config(aer->ctrlr,
+ aer->ctrlr->async_event_config, NULL, NULL);
+ } else if (aer->log_page_id == NVME_LOG_CHANGED_NAMESPACE) {
+ struct nvme_ns_list *nsl =
+ (struct nvme_ns_list *)aer->log_page_buffer;
+ for (int i = 0; i < nitems(nsl->ns) && nsl->ns[i] != 0; i++) {
+ if (nsl->ns[i] > NVME_MAX_NAMESPACES)
+ break;
+ nvme_notify_ns(aer->ctrlr, nsl->ns[i]);
+ }
+ }
+
+ /*
+ * Pass the cpl data from the original async event completion, not the
+ * log page fetch.
+ */
+ nvme_notify_async_consumers(aer->ctrlr, &aer->cpl,
+ aer->log_page_id, aer->log_page_buffer, aer->log_page_size);
+
+ /*
+ * Repost another asynchronous event request to replace the one
+ * that just completed.
+ */
+out:
+ nvme_ctrlr_construct_and_submit_aer(ctrlr, aer);
+}
+
/*
* Poll all the queues enabled on the device for completion.
*/
@@ -1574,13 +1609,8 @@ nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev)
/*
* Create 2 threads for the taskqueue. The reset thread will block when
* it detects that the controller has failed until all I/O has been
- * failed up the stack. The fail_req task needs to be able to run in
- * this case to finish the request failure for some cases.
- *
- * We could partially solve this race by draining the failed requeust
- * queue before proceding to free the sim, though nothing would stop
- * new I/O from coming in after we do that drain, but before we reach
- * cam_sim_free, so this big hammer is used instead.
+ * failed up the stack. The second thread is used for AER events, which
+ * can block, but only briefly for memory and log page fetching.
*/
ctrlr->taskqueue = taskqueue_create("nvme_taskq", M_WAITOK,
taskqueue_thread_enqueue, &ctrlr->taskqueue);
@@ -1590,7 +1620,12 @@ nvme_ctrlr_construct(struct nvme_controller *ctrlr, device_t dev)
ctrlr->is_initialized = false;
ctrlr->notification_sent = 0;
TASK_INIT(&ctrlr->reset_task, 0, nvme_ctrlr_reset_task, ctrlr);
- STAILQ_INIT(&ctrlr->fail_req);
+ for (int i = 0; i < NVME_MAX_ASYNC_EVENTS; i++) {
+ struct nvme_async_event_request *aer = &ctrlr->aer[i];
+
+ TASK_INIT(&aer->task, 0, nvme_ctrlr_aer_task, aer);
+ mtx_init(&aer->mtx, "AER mutex", NULL, MTX_DEF);
+ }
ctrlr->is_failed = false;
make_dev_args_init(&md_args);
@@ -1678,8 +1713,14 @@ nvme_ctrlr_destruct(struct nvme_controller *ctrlr, device_t dev)
}
noadminq:
- if (ctrlr->taskqueue)
+ if (ctrlr->taskqueue) {
taskqueue_free(ctrlr->taskqueue);
+ for (int i = 0; i < NVME_MAX_ASYNC_EVENTS; i++) {
+ struct nvme_async_event_request *aer = &ctrlr->aer[i];
+
+ mtx_destroy(&aer->mtx);
+ }
+ }
if (ctrlr->tag)
bus_teardown_intr(ctrlr->dev, ctrlr->res, ctrlr->tag);
diff --git a/sys/dev/nvme/nvme_private.h b/sys/dev/nvme/nvme_private.h
index 949e69ec9290..36f00fedc48e 100644
--- a/sys/dev/nvme/nvme_private.h
+++ b/sys/dev/nvme/nvme_private.h
@@ -123,6 +123,8 @@ struct nvme_request {
struct nvme_async_event_request {
struct nvme_controller *ctrlr;
struct nvme_request *req;
+ struct task task;
+ struct mtx mtx;
struct nvme_completion cpl;
uint32_t log_page_id;
uint32_t log_page_size;
@@ -307,8 +309,6 @@ struct nvme_controller {
bool isr_warned;
bool is_initialized;
- STAILQ_HEAD(, nvme_request) fail_req;
-
/* Host Memory Buffer */
int hmb_nchunks;
size_t hmb_chunk;
diff --git a/sys/dev/nvmf/controller/nvmft_subr.c b/sys/dev/nvmf/controller/nvmft_subr.c
index bb2bc0988e81..245971813854 100644
--- a/sys/dev/nvmf/controller/nvmft_subr.c
+++ b/sys/dev/nvmf/controller/nvmft_subr.c
@@ -26,46 +26,6 @@ nvmf_nqn_valid(const char *nqn)
len = strnlen(nqn, NVME_NQN_FIELD_SIZE);
if (len == 0 || len > NVMF_NQN_MAX_LEN)
return (false);
-
-#ifdef STRICT_CHECKS
- /*
- * Stricter checks from the spec. Linux does not seem to
- * require these.
- */
-
- /*
- * NVMF_NQN_MIN_LEN does not include '.', and require at least
- * one character of a domain name.
- */
- if (len < NVMF_NQN_MIN_LEN + 2)
- return (false);
- if (memcmp("nqn.", nqn, strlen("nqn.")) != 0)
- return (false);
- nqn += strlen("nqn.");
-
- /* Next 4 digits must be a year. */
- for (u_int i = 0; i < 4; i++) {
- if (!isdigit(nqn[i]))
- return (false);
- }
- nqn += 4;
-
- /* '-' between year and month. */
- if (nqn[0] != '-')
- return (false);
- nqn++;
-
- /* 2 digit month. */
- for (u_int i = 0; i < 2; i++) {
- if (!isdigit(nqn[i]))
- return (false);
- }
- nqn += 2;
-
- /* '.' between month and reverse domain name. */
- if (nqn[0] != '.')
- return (false);
-#endif
return (true);
}
diff --git a/sys/dev/ofw/ofw_bus_subr.c b/sys/dev/ofw/ofw_bus_subr.c
index 4d0479dfb957..b99d784929bc 100644
--- a/sys/dev/ofw/ofw_bus_subr.c
+++ b/sys/dev/ofw/ofw_bus_subr.c
@@ -634,11 +634,89 @@ ofw_bus_find_iparent(phandle_t node)
return (iparent);
}
+static phandle_t
+ofw_bus_search_iparent(phandle_t node)
+{
+ phandle_t iparent;
+
+ do {
+ if (OF_getencprop(node, "interrupt-parent", &iparent,
+ sizeof(iparent)) > 0) {
+ node = OF_node_from_xref(iparent);
+ } else {
+ node = OF_parent(node);
+ }
+ if (node == 0)
+ return (0);
+ } while (!OF_hasprop(node, "#interrupt-cells"));
+
+ return (OF_xref_from_node(node));
+}
+
+static int
+ofw_bus_traverse_imap(phandle_t inode, phandle_t node, uint32_t *intr,
+ int intrsz, pcell_t *res, int ressz, phandle_t *iparentp)
+{
+ struct ofw_bus_iinfo ii;
+ void *reg;
+ uint32_t *intrp;
+ phandle_t iparent;
+ int rv = 0;
+
+ /* We already have an interrupt controller */
+ if (OF_hasprop(node, "interrupt-controller"))
+ return (0);
+
+ intrp = malloc(intrsz, M_OFWPROP, M_WAITOK);
+ memcpy(intrp, intr, intrsz);
+
+ while (true) {
+ /* There is no interrupt-map to follow */
+ if (!OF_hasprop(inode, "interrupt-map")) {
+ free(intrp, M_OFWPROP);
+ return (0);
+ }
+
+ memset(&ii, 0, sizeof(ii));
+ ofw_bus_setup_iinfo(inode, &ii, sizeof(cell_t));
+
+ reg = NULL;
+ if (ii.opi_addrc > 0)
+ reg = malloc(ii.opi_addrc, M_OFWPROP, M_WAITOK);
+
+ rv = ofw_bus_lookup_imap(node, &ii, reg, ii.opi_addrc, intrp,
+ intrsz, res, ressz, &iparent);
+
+ free(reg, M_OFWPROP);
+ free(ii.opi_imap, M_OFWPROP);
+ free(ii.opi_imapmsk, M_OFWPROP);
+ free(intrp, M_OFWPROP);
+
+ if (rv == 0)
+ return (0);
+
+ node = inode;
+ inode = OF_node_from_xref(iparent);
+
+ /* Stop when we have an interrupt controller */
+ if (OF_hasprop(inode, "interrupt-controller")) {
+ *iparentp = iparent;
+ return (rv);
+ }
+
+ intrsz = rv * sizeof(pcell_t);
+ intrp = malloc(intrsz, M_OFWPROP, M_WAITOK);
+ memcpy(intrp, res, intrsz);
+ }
+}
+
int
ofw_bus_intr_to_rl(device_t dev, phandle_t node,
struct resource_list *rl, int *rlen)
{
- phandle_t iparent;
+ phandle_t iparent, iparent_node;
+ uint32_t result[16];
+ uint32_t intrpcells, *intrp;
uint32_t icells, *intr;
int err, i, irqnum, nintr, rid;
bool extended;
@@ -646,15 +724,16 @@ ofw_bus_intr_to_rl(device_t dev, phandle_t node,
nintr = OF_getencprop_alloc_multi(node, "interrupts", sizeof(*intr),
(void **)&intr);
if (nintr > 0) {
- iparent = ofw_bus_find_iparent(node);
+ iparent = ofw_bus_search_iparent(node);
if (iparent == 0) {
device_printf(dev, "No interrupt-parent found, "
"assuming direct parent\n");
iparent = OF_parent(node);
iparent = OF_xref_from_node(iparent);
}
- if (OF_searchencprop(OF_node_from_xref(iparent),
- "#interrupt-cells", &icells, sizeof(icells)) == -1) {
+ iparent_node = OF_node_from_xref(iparent);
+ if (OF_searchencprop(iparent_node, "#interrupt-cells", &icells,
+ sizeof(icells)) == -1) {
device_printf(dev, "Missing #interrupt-cells "
"property, assuming <1>\n");
icells = 1;
@@ -677,7 +756,8 @@ ofw_bus_intr_to_rl(device_t dev, phandle_t node,
for (i = 0; i < nintr; i += icells) {
if (extended) {
iparent = intr[i++];
- if (OF_searchencprop(OF_node_from_xref(iparent),
+ iparent_node = OF_node_from_xref(iparent);
+ if (OF_searchencprop(iparent_node,
"#interrupt-cells", &icells, sizeof(icells)) == -1) {
device_printf(dev, "Missing #interrupt-cells "
"property\n");
@@ -691,7 +771,16 @@ ofw_bus_intr_to_rl(device_t dev, phandle_t node,
break;
}
}
- irqnum = ofw_bus_map_intr(dev, iparent, icells, &intr[i]);
+
+ intrp = &intr[i];
+ intrpcells = ofw_bus_traverse_imap(iparent_node, node, intrp,
+ icells * sizeof(intr[0]), result, sizeof(result), &iparent);
+ if (intrpcells > 0)
+ intrp = result;
+ else
+ intrpcells = icells;
+
+ irqnum = ofw_bus_map_intr(dev, iparent, intrpcells, intrp);
resource_list_add(rl, SYS_RES_IRQ, rid++, irqnum, irqnum, 1);
}
if (rlen != NULL)
diff --git a/sys/dev/qlnx/qlnxe/qlnx_os.c b/sys/dev/qlnx/qlnxe/qlnx_os.c
index 9d23d5df1d2b..4ad190374f87 100644
--- a/sys/dev/qlnx/qlnxe/qlnx_os.c
+++ b/sys/dev/qlnx/qlnxe/qlnx_os.c
@@ -2308,8 +2308,6 @@ qlnx_init_ifnet(device_t dev, qlnx_host_t *ha)
else if (device_id == QLOGIC_PCI_DEVICE_ID_1644)
if_setbaudrate(ifp, IF_Gbps(100));
- if_setcapabilities(ifp, IFCAP_LINKSTATE);
-
if_setinitfn(ifp, qlnx_init);
if_setsoftc(ifp, ha);
if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
@@ -2343,7 +2341,6 @@ qlnx_init_ifnet(device_t dev, qlnx_host_t *ha)
if_setcapabilities(ifp, IFCAP_HWCSUM);
if_setcapabilitiesbit(ifp, IFCAP_JUMBO_MTU, 0);
-
if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0);
if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWTAGGING, 0);
if_setcapabilitiesbit(ifp, IFCAP_VLAN_HWFILTER, 0);
@@ -2352,6 +2349,8 @@ qlnx_init_ifnet(device_t dev, qlnx_host_t *ha)
if_setcapabilitiesbit(ifp, IFCAP_TSO4, 0);
if_setcapabilitiesbit(ifp, IFCAP_TSO6, 0);
if_setcapabilitiesbit(ifp, IFCAP_LRO, 0);
+ if_setcapabilitiesbit(ifp, IFCAP_LINKSTATE, 0);
+ if_setcapabilitiesbit(ifp, IFCAP_HWSTATS, 0);
if_sethwtsomax(ifp, QLNX_MAX_TSO_FRAME_SIZE -
(ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
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/vmm/vmm_dev.c b/sys/dev/vmm/vmm_dev.c
index 819debadd1ac..9f2b009d02ec 100644
--- a/sys/dev/vmm/vmm_dev.c
+++ b/sys/dev/vmm/vmm_dev.c
@@ -30,7 +30,8 @@
#include <dev/vmm/vmm_mem.h>
#include <dev/vmm/vmm_stat.h>
-#if defined(__amd64__) && defined(COMPAT_FREEBSD12)
+#ifdef __amd64__
+#ifdef COMPAT_FREEBSD12
struct vm_memseg_12 {
int segid;
size_t len;
@@ -42,7 +43,22 @@ _Static_assert(sizeof(struct vm_memseg_12) == 80, "COMPAT_FREEBSD12 ABI");
_IOW('v', IOCNUM_ALLOC_MEMSEG, struct vm_memseg_12)
#define VM_GET_MEMSEG_12 \
_IOWR('v', IOCNUM_GET_MEMSEG, struct vm_memseg_12)
-#endif
+#endif /* COMPAT_FREEBSD12 */
+#ifdef COMPAT_FREEBSD14
+struct vm_memseg_14 {
+ int segid;
+ size_t len;
+ char name[VM_MAX_SUFFIXLEN + 1];
+};
+_Static_assert(sizeof(struct vm_memseg_14) == (VM_MAX_SUFFIXLEN + 1 + 16),
+ "COMPAT_FREEBSD14 ABI");
+
+#define VM_ALLOC_MEMSEG_14 \
+ _IOW('v', IOCNUM_ALLOC_MEMSEG, struct vm_memseg_14)
+#define VM_GET_MEMSEG_14 \
+ _IOWR('v', IOCNUM_GET_MEMSEG, struct vm_memseg_14)
+#endif /* COMPAT_FREEBSD14 */
+#endif /* __amd64__ */
struct devmem_softc {
int segid;
@@ -257,7 +273,8 @@ get_memseg(struct vmmdev_softc *sc, struct vm_memseg *mseg, size_t len)
}
static int
-alloc_memseg(struct vmmdev_softc *sc, struct vm_memseg *mseg, size_t len)
+alloc_memseg(struct vmmdev_softc *sc, struct vm_memseg *mseg, size_t len,
+ struct domainset *domainset)
{
char *name;
int error;
@@ -278,8 +295,7 @@ alloc_memseg(struct vmmdev_softc *sc, struct vm_memseg *mseg, size_t len)
if (error)
goto done;
}
-
- error = vm_alloc_memseg(sc->vm, mseg->segid, mseg->len, sysmem);
+ error = vm_alloc_memseg(sc->vm, mseg->segid, mseg->len, sysmem, domainset);
if (error)
goto done;
@@ -295,6 +311,20 @@ done:
return (error);
}
+#if defined(__amd64__) && \
+ (defined(COMPAT_FREEBSD14) || defined(COMPAT_FREEBSD12))
+/*
+ * Translate pre-15.0 memory segment identifiers into their 15.0 counterparts.
+ */
+static void
+adjust_segid(struct vm_memseg *mseg)
+{
+ if (mseg->segid != VM_SYSMEM) {
+ mseg->segid += (VM_BOOTROM - 1);
+ }
+}
+#endif
+
static int
vm_get_register_set(struct vcpu *vcpu, unsigned int count, int *regnum,
uint64_t *regval)
@@ -353,10 +383,16 @@ static const struct vmmdev_ioctl vmmdev_ioctls[] = {
VMMDEV_IOCTL(VM_STATS, VMMDEV_IOCTL_LOCK_ONE_VCPU),
VMMDEV_IOCTL(VM_STAT_DESC, 0),
-#if defined(__amd64__) && defined(COMPAT_FREEBSD12)
+#ifdef __amd64__
+#ifdef COMPAT_FREEBSD12
VMMDEV_IOCTL(VM_ALLOC_MEMSEG_12,
VMMDEV_IOCTL_XLOCK_MEMSEGS | VMMDEV_IOCTL_LOCK_ALL_VCPUS),
#endif
+#ifdef COMPAT_FREEBSD14
+ VMMDEV_IOCTL(VM_ALLOC_MEMSEG_14,
+ VMMDEV_IOCTL_XLOCK_MEMSEGS | VMMDEV_IOCTL_LOCK_ALL_VCPUS),
+#endif
+#endif /* __amd64__ */
VMMDEV_IOCTL(VM_ALLOC_MEMSEG,
VMMDEV_IOCTL_XLOCK_MEMSEGS | VMMDEV_IOCTL_LOCK_ALL_VCPUS),
VMMDEV_IOCTL(VM_MMAP_MEMSEG,
@@ -366,9 +402,14 @@ static const struct vmmdev_ioctl vmmdev_ioctls[] = {
VMMDEV_IOCTL(VM_REINIT,
VMMDEV_IOCTL_XLOCK_MEMSEGS | VMMDEV_IOCTL_LOCK_ALL_VCPUS),
-#if defined(__amd64__) && defined(COMPAT_FREEBSD12)
+#ifdef __amd64__
+#if defined(COMPAT_FREEBSD12)
VMMDEV_IOCTL(VM_GET_MEMSEG_12, VMMDEV_IOCTL_SLOCK_MEMSEGS),
#endif
+#ifdef COMPAT_FREEBSD14
+ VMMDEV_IOCTL(VM_GET_MEMSEG_14, VMMDEV_IOCTL_SLOCK_MEMSEGS),
+#endif
+#endif /* __amd64__ */
VMMDEV_IOCTL(VM_GET_MEMSEG, VMMDEV_IOCTL_SLOCK_MEMSEGS),
VMMDEV_IOCTL(VM_MMAP_GETNEXT, VMMDEV_IOCTL_SLOCK_MEMSEGS),
@@ -388,6 +429,7 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
struct vmmdev_softc *sc;
struct vcpu *vcpu;
const struct vmmdev_ioctl *ioctl;
+ struct vm_memseg *mseg;
int error, vcpuid;
sc = vmmdev_lookup2(cdev);
@@ -499,20 +541,77 @@ vmmdev_ioctl(struct cdev *cdev, u_long cmd, caddr_t data, int fflag,
error = vm_munmap_memseg(sc->vm, mu->gpa, mu->len);
break;
}
-#if defined(__amd64__) && defined(COMPAT_FREEBSD12)
+#ifdef __amd64__
+#ifdef COMPAT_FREEBSD12
case VM_ALLOC_MEMSEG_12:
- error = alloc_memseg(sc, (struct vm_memseg *)data,
- sizeof(((struct vm_memseg_12 *)0)->name));
+ mseg = (struct vm_memseg *)data;
+
+ adjust_segid(mseg);
+ error = alloc_memseg(sc, mseg,
+ sizeof(((struct vm_memseg_12 *)0)->name), NULL);
break;
case VM_GET_MEMSEG_12:
- error = get_memseg(sc, (struct vm_memseg *)data,
+ mseg = (struct vm_memseg *)data;
+
+ adjust_segid(mseg);
+ error = get_memseg(sc, mseg,
sizeof(((struct vm_memseg_12 *)0)->name));
break;
-#endif
- case VM_ALLOC_MEMSEG:
- error = alloc_memseg(sc, (struct vm_memseg *)data,
- sizeof(((struct vm_memseg *)0)->name));
+#endif /* COMPAT_FREEBSD12 */
+#ifdef COMPAT_FREEBSD14
+ case VM_ALLOC_MEMSEG_14:
+ mseg = (struct vm_memseg *)data;
+
+ adjust_segid(mseg);
+ error = alloc_memseg(sc, mseg,
+ sizeof(((struct vm_memseg_14 *)0)->name), NULL);
+ break;
+ case VM_GET_MEMSEG_14:
+ mseg = (struct vm_memseg *)data;
+
+ adjust_segid(mseg);
+ error = get_memseg(sc, mseg,
+ sizeof(((struct vm_memseg_14 *)0)->name));
+ break;
+#endif /* COMPAT_FREEBSD14 */
+#endif /* __amd64__ */
+ case VM_ALLOC_MEMSEG: {
+ domainset_t *mask;
+ struct domainset *domainset, domain;
+
+ domainset = NULL;
+ mseg = (struct vm_memseg *)data;
+ if (mseg->ds_policy != DOMAINSET_POLICY_INVALID && mseg->ds_mask != NULL) {
+ if (mseg->ds_mask_size < sizeof(domainset_t) ||
+ mseg->ds_mask_size > DOMAINSET_MAXSIZE / NBBY) {
+ error = ERANGE;
+ break;
+ }
+ memset(&domain, 0, sizeof(domain));
+ mask = malloc(mseg->ds_mask_size, M_VMMDEV, M_WAITOK);
+ error = copyin(mseg->ds_mask, mask, mseg->ds_mask_size);
+ if (error) {
+ free(mask, M_VMMDEV);
+ break;
+ }
+ error = domainset_populate(&domain, mask, mseg->ds_policy,
+ mseg->ds_mask_size);
+ if (error) {
+ free(mask, M_VMMDEV);
+ break;
+ }
+ domainset = domainset_create(&domain);
+ if (domainset == NULL) {
+ error = EINVAL;
+ free(mask, M_VMMDEV);
+ break;
+ }
+ free(mask, M_VMMDEV);
+ }
+ error = alloc_memseg(sc, mseg, sizeof(mseg->name), domainset);
+
break;
+ }
case VM_GET_MEMSEG:
error = get_memseg(sc, (struct vm_memseg *)data,
sizeof(((struct vm_memseg *)0)->name));
@@ -820,7 +919,6 @@ sysctl_vmm_destroy(SYSCTL_HANDLER_ARGS)
buflen = VM_MAX_NAMELEN + 1;
buf = malloc(buflen, M_VMMDEV, M_WAITOK | M_ZERO);
- strlcpy(buf, "beavis", buflen);
error = sysctl_handle_string(oidp, buf, buflen, req);
if (error == 0 && req->newptr != NULL)
error = vmmdev_lookup_and_destroy(buf, req->td->td_ucred);
@@ -830,7 +928,7 @@ sysctl_vmm_destroy(SYSCTL_HANDLER_ARGS)
SYSCTL_PROC(_hw_vmm, OID_AUTO, destroy,
CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
NULL, 0, sysctl_vmm_destroy, "A",
- NULL);
+ "Destroy a vmm(4) instance (legacy interface)");
static struct cdevsw vmmdevsw = {
.d_name = "vmmdev",
@@ -909,7 +1007,6 @@ sysctl_vmm_create(SYSCTL_HANDLER_ARGS)
buflen = VM_MAX_NAMELEN + 1;
buf = malloc(buflen, M_VMMDEV, M_WAITOK | M_ZERO);
- strlcpy(buf, "beavis", buflen);
error = sysctl_handle_string(oidp, buf, buflen, req);
if (error == 0 && req->newptr != NULL)
error = vmmdev_create(buf, req->td->td_ucred);
@@ -919,7 +1016,7 @@ sysctl_vmm_create(SYSCTL_HANDLER_ARGS)
SYSCTL_PROC(_hw_vmm, OID_AUTO, create,
CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_PRISON | CTLFLAG_MPSAFE,
NULL, 0, sysctl_vmm_create, "A",
- NULL);
+ "Create a vmm(4) instance (legacy interface)");
static int
vmmctl_open(struct cdev *cdev, int flags, int fmt, struct thread *td)
diff --git a/sys/dev/vmm/vmm_mem.c b/sys/dev/vmm/vmm_mem.c
index c61ae2d44b96..be59e37de33d 100644
--- a/sys/dev/vmm/vmm_mem.c
+++ b/sys/dev/vmm/vmm_mem.c
@@ -7,6 +7,7 @@
#include <sys/types.h>
#include <sys/lock.h>
+#include <sys/malloc.h>
#include <sys/sx.h>
#include <sys/systm.h>
@@ -156,10 +157,11 @@ vm_mem_allocated(struct vcpu *vcpu, vm_paddr_t gpa)
}
int
-vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem)
+vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem,
+ struct domainset *obj_domainset)
{
- struct vm_mem *mem;
struct vm_mem_seg *seg;
+ struct vm_mem *mem;
vm_object_t obj;
mem = vm_mem(vm);
@@ -179,13 +181,22 @@ vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem)
return (EINVAL);
}
+ /*
+ * When given an impossible policy, signal an
+ * error to the user.
+ */
+ if (obj_domainset != NULL && domainset_empty_vm(obj_domainset))
+ return (EINVAL);
obj = vm_object_allocate(OBJT_SWAP, len >> PAGE_SHIFT);
if (obj == NULL)
return (ENOMEM);
seg->len = len;
seg->object = obj;
+ if (obj_domainset != NULL)
+ seg->object->domain.dr_policy = obj_domainset;
seg->sysmem = sysmem;
+
return (0);
}
diff --git a/sys/dev/vmm/vmm_mem.h b/sys/dev/vmm/vmm_mem.h
index a4be4c1c57aa..856470cf2590 100644
--- a/sys/dev/vmm/vmm_mem.h
+++ b/sys/dev/vmm/vmm_mem.h
@@ -8,6 +8,27 @@
#ifndef _DEV_VMM_MEM_H_
#define _DEV_VMM_MEM_H_
+/* Maximum number of NUMA domains in a guest. */
+#define VM_MAXMEMDOM 8
+#define VM_MAXSYSMEM VM_MAXMEMDOM
+
+/*
+ * Identifiers for memory segments.
+ * Each guest NUMA domain is represented by a single system
+ * memory segment from [VM_SYSMEM, VM_MAXSYSMEM).
+ * The remaining identifiers can be used to create devmem segments.
+ */
+enum {
+ VM_SYSMEM = 0,
+ VM_BOOTROM = VM_MAXSYSMEM,
+ VM_FRAMEBUFFER,
+ VM_PCIROM,
+ VM_MEMSEG_END
+};
+
+#define VM_MAX_MEMSEGS VM_MEMSEG_END
+#define VM_MAX_MEMMAPS (VM_MAX_MEMSEGS * 2)
+
#ifdef _KERNEL
#include <sys/types.h>
@@ -31,9 +52,6 @@ struct vm_mem_map {
int flags;
};
-#define VM_MAX_MEMSEGS 4
-#define VM_MAX_MEMMAPS 8
-
struct vm_mem {
struct vm_mem_map mem_maps[VM_MAX_MEMMAPS];
struct vm_mem_seg mem_segs[VM_MAX_MEMSEGS];
@@ -55,7 +73,8 @@ void vm_assert_memseg_xlocked(struct vm *vm);
int vm_mmap_memseg(struct vm *vm, vm_paddr_t gpa, int segid, vm_ooffset_t off,
size_t len, int prot, int flags);
int vm_munmap_memseg(struct vm *vm, vm_paddr_t gpa, size_t len);
-int vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem);
+int vm_alloc_memseg(struct vm *vm, int ident, size_t len, bool sysmem,
+ struct domainset *obj_domainset);
void vm_free_memseg(struct vm *vm, int ident);
/*
diff --git a/sys/dev/vt/hw/vga/vt_vga.c b/sys/dev/vt/hw/vga/vt_vga.c
index 64039575c0ad..675c0573bd7e 100644
--- a/sys/dev/vt/hw/vga/vt_vga.c
+++ b/sys/dev/vt/hw/vga/vt_vga.c
@@ -1347,7 +1347,7 @@ vga_postswitch(struct vt_device *vd)
/* Reinit VGA mode, to restore view after app which change mode. */
vga_initialize(vd, (vd->vd_flags & VDF_TEXTMODE));
- /* Ask vt(9) to update chars on visible area. */
+ /* Ask vt(4) to update chars on visible area. */
vd->vd_flags |= VDF_INVALID;
}
diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c
index b0f58b38a6f1..b51ef6766de4 100644
--- a/sys/dev/vt/vt_core.c
+++ b/sys/dev/vt/vt_core.c
@@ -125,10 +125,10 @@ static const struct terminal_class vt_termclass = {
(vw)->vw_number)
static SYSCTL_NODE(_kern, OID_AUTO, vt, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
- "vt(9) parameters");
+ "vt(4) parameters");
static VT_SYSCTL_INT(enable_altgr, 1, "Enable AltGr key (Do not assume R.Alt as Alt)");
static VT_SYSCTL_INT(enable_bell, 0, "Enable bell");
-static VT_SYSCTL_INT(debug, 0, "vt(9) debug level");
+static VT_SYSCTL_INT(debug, 0, "vt(4) debug level");
static VT_SYSCTL_INT(deadtimer, 15, "Time to wait busy process in VT_PROCESS mode");
static VT_SYSCTL_INT(suspendswitch, 1, "Switch to VT0 before suspend");
diff --git a/sys/fs/fuse/fuse_internal.h b/sys/fs/fuse/fuse_internal.h
index cddf88095840..932012b5f52a 100644
--- a/sys/fs/fuse/fuse_internal.h
+++ b/sys/fs/fuse/fuse_internal.h
@@ -208,9 +208,9 @@ fuse_match_cred(struct ucred *basecred, struct ucred *usercred)
if (basecred->cr_uid == usercred->cr_uid &&
basecred->cr_uid == usercred->cr_ruid &&
basecred->cr_uid == usercred->cr_svuid &&
- basecred->cr_groups[0] == usercred->cr_groups[0] &&
- basecred->cr_groups[0] == usercred->cr_rgid &&
- basecred->cr_groups[0] == usercred->cr_svgid)
+ basecred->cr_gid == usercred->cr_gid &&
+ basecred->cr_gid == usercred->cr_rgid &&
+ basecred->cr_gid == usercred->cr_svgid)
return (0);
return (EPERM);
diff --git a/sys/fs/fuse/fuse_ipc.c b/sys/fs/fuse/fuse_ipc.c
index 0b6048644d32..a751c09159ff 100644
--- a/sys/fs/fuse/fuse_ipc.c
+++ b/sys/fs/fuse/fuse_ipc.c
@@ -868,7 +868,7 @@ fuse_setup_ihead(struct fuse_in_header *ihead, struct fuse_ticket *ftick,
ihead->pid = pid;
ihead->uid = cred->cr_uid;
- ihead->gid = cred->cr_groups[0];
+ ihead->gid = cred->cr_gid;
}
/*
diff --git a/sys/fs/fuse/fuse_vnops.c b/sys/fs/fuse/fuse_vnops.c
index ae28617537fd..32872e8f3f3a 100644
--- a/sys/fs/fuse/fuse_vnops.c
+++ b/sys/fs/fuse/fuse_vnops.c
@@ -884,7 +884,7 @@ fuse_vnop_copy_file_range(struct vop_copy_file_range_args *ap)
return (EXTERROR(ENOSYS, "FUSE_COPY_FILE_RANGE does not "
"support different credentials for infd and outfd"));
- if (incred->cr_groups[0] != outcred->cr_groups[0])
+ if (incred->cr_gid != outcred->cr_gid)
return (EXTERROR(ENOSYS, "FUSE_COPY_FILE_RANGE does not "
"support different credentials for infd and outfd"));
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_commonport.c b/sys/fs/nfs/nfs_commonport.c
index 0c94f4e7dc52..222cfc03e4b3 100644
--- a/sys/fs/nfs/nfs_commonport.c
+++ b/sys/fs/nfs/nfs_commonport.c
@@ -379,7 +379,8 @@ newnfs_setroot(struct ucred *cred)
{
cred->cr_uid = 0;
- cred->cr_groups[0] = 0;
+ cred->cr_gid = 0;
+ /* XXXKE Fix this if cr_gid gets separated out. */
cred->cr_ngroups = 1;
}
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..36b534be531e 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);
@@ -6932,7 +6933,8 @@ nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) {
tcred = NFSNEWCRED(cred);
tcred->cr_uid = flp->nfsfl_ffm[mirror].user;
- tcred->cr_groups[0] = flp->nfsfl_ffm[mirror].group;
+ tcred->cr_gid = flp->nfsfl_ffm[mirror].group;
+ /* XXXKE Fix this if cr_gid gets separated out. */
tcred->cr_ngroups = 1;
} else
tcred = cred;
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/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c
index 0bdfedffafcb..8cd092118d0e 100644
--- a/sys/fs/pseudofs/pseudofs_vnops.c
+++ b/sys/fs/pseudofs/pseudofs_vnops.c
@@ -850,7 +850,7 @@ pfs_readdir(struct vop_readdir_args *va)
struct uio *uio;
struct pfsentry *pfsent, *pfsent2;
struct pfsdirentlist lst;
- off_t offset;
+ off_t coffset, offset;
int error, i, resid;
STAILQ_INIT(&lst);
@@ -860,6 +860,9 @@ pfs_readdir(struct vop_readdir_args *va)
PFS_TRACE(("%s pid %lu", pd->pn_name, (unsigned long)pid));
pfs_assert_not_owned(pd);
+ if (va->a_eofflag != NULL)
+ *va->a_eofflag = 0;
+
if (vn->v_type != VDIR)
PFS_RETURN (ENOTDIR);
KASSERT_PN_IS_DIR(pd);
@@ -878,6 +881,10 @@ pfs_readdir(struct vop_readdir_args *va)
if (pid != NO_PID && !pfs_lookup_proc(pid, &proc))
PFS_RETURN (ENOENT);
+ /*
+ * The allproc lock is required in pfs_iterate() for procdir
+ * directories.
+ */
sx_slock(&allproc_lock);
pfs_lock(pd);
@@ -897,23 +904,15 @@ pfs_readdir(struct vop_readdir_args *va)
}
}
- /* skip unwanted entries */
- for (pn = NULL, p = NULL; offset > 0; offset -= PFS_DELEN) {
+ for (pn = NULL, p = NULL, coffset = 0; resid >= PFS_DELEN;
+ coffset += PFS_DELEN) {
if (pfs_iterate(curthread, proc, pd, &pn, &p) == -1) {
- /* nothing left... */
- if (proc != NULL) {
- _PRELE(proc);
- PROC_UNLOCK(proc);
- }
- pfs_unlock(pd);
- sx_sunlock(&allproc_lock);
- PFS_RETURN (0);
+ if (va->a_eofflag != NULL)
+ *va->a_eofflag = 1;
+ break;
}
- }
-
- /* fill in entries */
- while (pfs_iterate(curthread, proc, pd, &pn, &p) != -1 &&
- resid >= PFS_DELEN) {
+ if (coffset < offset)
+ continue;
if ((pfsent = malloc(sizeof(struct pfsentry), M_IOV,
M_NOWAIT | M_ZERO)) == NULL) {
error = ENOMEM;
diff --git a/sys/fs/smbfs/smbfs_io.c b/sys/fs/smbfs/smbfs_io.c
index 35454998fc8e..8c484381ed59 100644
--- a/sys/fs/smbfs/smbfs_io.c
+++ b/sys/fs/smbfs/smbfs_io.c
@@ -71,7 +71,7 @@ SYSCTL_INT(_vfs_smbfs, OID_AUTO, fastlookup, CTLFLAG_RW, &smbfs_fastlookup, 0, "
#define DE_SIZE (sizeof(struct dirent))
static int
-smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
+smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred, int *eofp)
{
struct dirent de;
struct componentname cn;
@@ -86,6 +86,8 @@ smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
SMBVDEBUG("dirname='%s'\n", np->n_name);
scred = smbfs_malloc_scred();
smb_makescred(scred, uio->uio_td, cred);
+ if (eofp != NULL)
+ *eofp = 0;
offset = uio->uio_offset / DE_SIZE; /* offset in the directory */
limit = uio->uio_resid / DE_SIZE;
if (uio->uio_resid < DE_SIZE || uio->uio_offset < 0) {
@@ -138,8 +140,7 @@ smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
if (error) {
smbfs_findclose(np->n_dirseq, scred);
np->n_dirseq = NULL;
- error = ENOENT ? 0 : error;
- goto out;
+ goto out1;
}
}
error = 0;
@@ -170,16 +171,21 @@ smbfs_readvdir(struct vnode *vp, struct uio *uio, struct ucred *cred)
if (error)
break;
}
- if (error == ENOENT)
- error = 0;
uio->uio_offset = offset * DE_SIZE;
+out1:
+ if (error == ENOENT) {
+ if (eofp != NULL)
+ *eofp = 1;
+ error = 0;
+ }
out:
smbfs_free_scred(scred);
return error;
}
int
-smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred)
+smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred,
+ int *eofp)
{
struct smbmount *smp = VFSTOSMBFS(vp->v_mount);
struct smbnode *np = VTOSMB(vp);
@@ -209,7 +215,7 @@ smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred)
lks = LK_EXCLUSIVE; /* lockstatus(vp->v_vnlock); */
if (lks == LK_SHARED)
vn_lock(vp, LK_UPGRADE | LK_RETRY);
- error = smbfs_readvdir(vp, uiop, cred);
+ error = smbfs_readvdir(vp, uiop, cred, eofp);
if (lks == LK_SHARED)
vn_lock(vp, LK_DOWNGRADE | LK_RETRY);
return error;
diff --git a/sys/fs/smbfs/smbfs_node.h b/sys/fs/smbfs/smbfs_node.h
index f28f0007100a..8c8ce038b913 100644
--- a/sys/fs/smbfs/smbfs_node.h
+++ b/sys/fs/smbfs/smbfs_node.h
@@ -93,7 +93,7 @@ u_int32_t smbfs_hash(const u_char *name, int nmlen);
int smbfs_getpages(struct vop_getpages_args *);
int smbfs_putpages(struct vop_putpages_args *);
-int smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred);
+int smbfs_readvnode(struct vnode *vp, struct uio *uiop, struct ucred *cred, int *eofp);
int smbfs_writevnode(struct vnode *vp, struct uio *uiop, struct ucred *cred, int ioflag);
void smbfs_attr_cacheenter(struct vnode *vp, struct smbfattr *fap);
int smbfs_attr_cachelookup(struct vnode *vp ,struct vattr *va);
diff --git a/sys/fs/smbfs/smbfs_vnops.c b/sys/fs/smbfs/smbfs_vnops.c
index 5d412cabadb8..63b249c93771 100644
--- a/sys/fs/smbfs/smbfs_vnops.c
+++ b/sys/fs/smbfs/smbfs_vnops.c
@@ -466,7 +466,7 @@ smbfs_read(struct vop_read_args *ap)
SMBVDEBUG("\n");
if (vp->v_type != VREG && vp->v_type != VDIR)
return EPERM;
- return smbfs_readvnode(vp, uio, ap->a_cred);
+ return smbfs_readvnode(vp, uio, ap->a_cred, NULL);
}
static int
@@ -748,7 +748,6 @@ smbfs_readdir(struct vop_readdir_args *ap)
{
struct vnode *vp = ap->a_vp;
struct uio *uio = ap->a_uio;
- int error;
if (vp->v_type != VDIR)
return (EPERM);
@@ -758,8 +757,7 @@ smbfs_readdir(struct vop_readdir_args *ap)
return (EOPNOTSUPP);
}
#endif
- error = smbfs_readvnode(vp, uio, ap->a_cred);
- return error;
+ return (smbfs_readvnode(vp, uio, ap->a_cred, ap->a_eofflag));
}
/* ARGSUSED */
diff --git a/sys/geom/concat/g_concat.c b/sys/geom/concat/g_concat.c
index 2b1cb575cac8..2173a84c7acf 100644
--- a/sys/geom/concat/g_concat.c
+++ b/sys/geom/concat/g_concat.c
@@ -590,6 +590,7 @@ g_concat_add_disk(struct g_concat_softc *sc, struct g_provider *pp, u_int no)
strcmp(md.md_name, sc->sc_name) != 0 ||
md.md_id != sc->sc_id) {
G_CONCAT_DEBUG(0, "Metadata on %s changed.", pp->name);
+ error = EINVAL;
goto fail;
}
diff --git a/sys/geom/geom.h b/sys/geom/geom.h
index dcd6f793f9f7..908ce86f03a6 100644
--- a/sys/geom/geom.h
+++ b/sys/geom/geom.h
@@ -282,7 +282,7 @@ void g_detach(struct g_consumer *cp);
void g_error_provider(struct g_provider *pp, int error);
struct g_provider *g_provider_by_name(char const *arg);
int g_getattr__(const char *attr, struct g_consumer *cp, void *var, int len);
-#define g_getattr(a, c, v) g_getattr__((a), (c), (v), sizeof *(v))
+#define g_getattr(a, c, v) g_getattr__((a), (c), (v), sizeof(*(v)))
int g_handleattr(struct bio *bp, const char *attribute, const void *val,
int len);
int g_handleattr_int(struct bio *bp, const char *attribute, int val);
diff --git a/sys/geom/geom_ccd.c b/sys/geom/geom_ccd.c
index 5700399ee5d1..2140d005160e 100644
--- a/sys/geom/geom_ccd.c
+++ b/sys/geom/geom_ccd.c
@@ -730,17 +730,17 @@ g_ccd_create(struct gctl_req *req, struct g_class *mp)
int i, error;
g_topology_assert();
- unit = gctl_get_paraml(req, "unit", sizeof (*unit));
+ unit = gctl_get_paraml(req, "unit", sizeof(*unit));
if (unit == NULL) {
gctl_error(req, "unit parameter not given");
return;
}
- ileave = gctl_get_paraml(req, "ileave", sizeof (*ileave));
+ ileave = gctl_get_paraml(req, "ileave", sizeof(*ileave));
if (ileave == NULL) {
gctl_error(req, "ileave parameter not given");
return;
}
- nprovider = gctl_get_paraml(req, "nprovider", sizeof (*nprovider));
+ nprovider = gctl_get_paraml(req, "nprovider", sizeof(*nprovider));
if (nprovider == NULL) {
gctl_error(req, "nprovider parameter not given");
return;
@@ -769,7 +769,7 @@ g_ccd_create(struct gctl_req *req, struct g_class *mp)
}
gp = g_new_geomf(mp, "ccd%d", *unit);
- sc = g_malloc(sizeof *sc, M_WAITOK | M_ZERO);
+ sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
gp->softc = sc;
sc->sc_ndisks = *nprovider;
@@ -872,7 +872,7 @@ g_ccd_list(struct gctl_req *req, struct g_class *mp)
struct g_geom *gp;
int i, unit, *up;
- up = gctl_get_paraml(req, "unit", sizeof (*up));
+ up = gctl_get_paraml(req, "unit", sizeof(*up));
if (up == NULL) {
gctl_error(req, "unit parameter not given");
return;
diff --git a/sys/geom/geom_event.c b/sys/geom/geom_event.c
index 0a76fd6c6f57..341233a6ef47 100644
--- a/sys/geom/geom_event.c
+++ b/sys/geom/geom_event.c
@@ -145,7 +145,7 @@ g_attr_changed(struct g_provider *pp, const char *attr, int flag)
struct g_attrchanged_args *args;
int error;
- args = g_malloc(sizeof *args, flag);
+ args = g_malloc(sizeof(*args), flag);
if (args == NULL)
return (ENOMEM);
args->pp = pp;
diff --git a/sys/geom/geom_io.c b/sys/geom/geom_io.c
index 8d6b9a926e1d..247a623bf1bf 100644
--- a/sys/geom/geom_io.c
+++ b/sys/geom/geom_io.c
@@ -278,7 +278,7 @@ g_io_init(void)
g_bioq_init(&g_bio_run_down);
g_bioq_init(&g_bio_run_up);
- biozone = uma_zcreate("g_bio", sizeof (struct bio),
+ biozone = uma_zcreate("g_bio", sizeof(struct bio),
NULL, NULL,
NULL, NULL,
0, 0);
diff --git a/sys/geom/geom_slice.c b/sys/geom/geom_slice.c
index 8cfffc478849..0491b0069be4 100644
--- a/sys/geom/geom_slice.c
+++ b/sys/geom/geom_slice.c
@@ -57,7 +57,7 @@ g_slice_alloc(unsigned nslice, unsigned scsize)
{
struct g_slicer *gsp;
- gsp = g_malloc(sizeof *gsp, M_WAITOK | M_ZERO);
+ gsp = g_malloc(sizeof(*gsp), M_WAITOK | M_ZERO);
if (scsize > 0)
gsp->softc = g_malloc(scsize, M_WAITOK | M_ZERO);
else
@@ -463,9 +463,9 @@ g_slice_conf_hot(struct g_geom *gp, u_int idx, off_t offset, off_t length, int r
}
gsl = gsp->hotspot;
if(idx >= gsp->nhotspot) {
- gsl2 = g_malloc((idx + 1) * sizeof *gsl2, M_WAITOK | M_ZERO);
+ gsl2 = g_malloc((idx + 1) * sizeof(*gsl2), M_WAITOK | M_ZERO);
if (gsp->hotspot != NULL)
- bcopy(gsp->hotspot, gsl2, gsp->nhotspot * sizeof *gsl2);
+ bcopy(gsp->hotspot, gsl2, gsp->nhotspot * sizeof(*gsl2));
gsp->hotspot = gsl2;
if (gsp->hotspot != NULL)
g_free(gsl);
diff --git a/sys/geom/geom_subr.c b/sys/geom/geom_subr.c
index 41cc115225f9..1429c84942ed 100644
--- a/sys/geom/geom_subr.c
+++ b/sys/geom/geom_subr.c
@@ -267,7 +267,7 @@ g_modevent(module_t mod, int type, void *data)
switch (type) {
case MOD_LOAD:
g_trace(G_T_TOPOLOGY, "g_modevent(%s, LOAD)", mp->name);
- hh = g_malloc(sizeof *hh, M_WAITOK | M_ZERO);
+ hh = g_malloc(sizeof(*hh), M_WAITOK | M_ZERO);
hh->mp = mp;
/*
* Once the system is not cold, MOD_LOAD calls will be
@@ -351,7 +351,7 @@ g_retaste(struct g_class *mp)
if (mp->taste == NULL)
return (EINVAL);
- hh = g_malloc(sizeof *hh, M_WAITOK | M_ZERO);
+ hh = g_malloc(sizeof(*hh), M_WAITOK | M_ZERO);
hh->mp = mp;
if (cold) {
@@ -381,8 +381,8 @@ g_new_geomf(struct g_class *mp, const char *fmt, ...)
sbuf_vprintf(sb, fmt, ap);
va_end(ap);
sbuf_finish(sb);
- gp = g_malloc(sizeof *gp, M_WAITOK | M_ZERO);
- gp->name = g_malloc(sbuf_len(sb) + 1, M_WAITOK | M_ZERO);
+ gp = g_malloc(sizeof(*gp) + sbuf_len(sb) + 1, M_WAITOK | M_ZERO);
+ gp->name = (char *)(gp + 1);
gp->class = mp;
gp->rank = 1;
LIST_INIT(&gp->consumer);
@@ -420,7 +420,6 @@ g_destroy_geom(struct g_geom *gp)
g_cancel_event(gp);
LIST_REMOVE(gp, geom);
TAILQ_REMOVE(&geoms, gp, geoms);
- g_free(gp->name);
g_free(gp);
}
@@ -528,7 +527,7 @@ g_new_consumer(struct g_geom *gp)
("g_new_consumer on geom(%s) (class %s) without orphan",
gp->name, gp->class->name));
- cp = g_malloc(sizeof *cp, M_WAITOK | M_ZERO);
+ cp = g_malloc(sizeof(*cp), M_WAITOK | M_ZERO);
cp->geom = gp;
cp->stat = devstat_new_entry(cp, -1, 0, DEVSTAT_ALL_SUPPORTED,
DEVSTAT_TYPE_DIRECT, DEVSTAT_PRIORITY_MAX);
@@ -617,7 +616,7 @@ g_new_providerf(struct g_geom *gp, const char *fmt, ...)
sbuf_vprintf(sb, fmt, ap);
va_end(ap);
sbuf_finish(sb);
- pp = g_malloc(sizeof *pp + sbuf_len(sb) + 1, M_WAITOK | M_ZERO);
+ pp = g_malloc(sizeof(*pp) + sbuf_len(sb) + 1, M_WAITOK | M_ZERO);
pp->name = (char *)(pp + 1);
strcpy(pp->name, sbuf_data(sb));
sbuf_delete(sb);
@@ -749,7 +748,7 @@ g_resize_provider(struct g_provider *pp, off_t size)
if (size == pp->mediasize)
return;
- hh = g_malloc(sizeof *hh, M_WAITOK | M_ZERO);
+ hh = g_malloc(sizeof(*hh), M_WAITOK | M_ZERO);
hh->pp = pp;
hh->size = size;
g_post_event(g_resize_provider_event, hh, M_WAITOK, NULL);
@@ -1083,21 +1082,21 @@ int
g_handleattr_int(struct bio *bp, const char *attribute, int val)
{
- return (g_handleattr(bp, attribute, &val, sizeof val));
+ return (g_handleattr(bp, attribute, &val, sizeof(val)));
}
int
g_handleattr_uint16_t(struct bio *bp, const char *attribute, uint16_t val)
{
- return (g_handleattr(bp, attribute, &val, sizeof val));
+ return (g_handleattr(bp, attribute, &val, sizeof(val)));
}
int
g_handleattr_off_t(struct bio *bp, const char *attribute, off_t val)
{
- return (g_handleattr(bp, attribute, &val, sizeof val));
+ return (g_handleattr(bp, attribute, &val, sizeof(val)));
}
int
diff --git a/sys/geom/multipath/g_multipath.c b/sys/geom/multipath/g_multipath.c
index 23088c895541..a4935df7eaa1 100644
--- a/sys/geom/multipath/g_multipath.c
+++ b/sys/geom/multipath/g_multipath.c
@@ -321,7 +321,7 @@ g_multipath_resize(struct g_consumer *cp)
if (sc->sc_uuid[0] != 0) {
pp = cp->provider;
strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
- memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid));
+ memcpy(md.md_uuid, sc->sc_uuid, sizeof(sc->sc_uuid));
strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name));
md.md_version = G_MULTIPATH_VERSION;
md.md_size = size;
@@ -552,8 +552,8 @@ g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md)
gp = g_new_geomf(mp, "%s", md->md_name);
sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
mtx_init(&sc->sc_mtx, "multipath", NULL, MTX_DEF);
- memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid));
- memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name));
+ memcpy(sc->sc_uuid, md->md_uuid, sizeof(sc->sc_uuid));
+ memcpy(sc->sc_name, md->md_name, sizeof(sc->sc_name));
sc->sc_active_active = md->md_active_active;
sc->sc_size = md->md_size;
gp->softc = sc;
@@ -906,7 +906,7 @@ g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
char buf[16];
u_long rand = random();
- snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand);
+ snprintf(buf, sizeof(buf), "%s-%lu", md.md_name, rand);
printf("GEOM_MULTIPATH: geom %s/%s exists already\n",
sc->sc_name, sc->sc_uuid);
printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n",
@@ -1200,7 +1200,7 @@ g_multipath_ctl_configure(struct gctl_req *req, struct g_class *mp)
cp = sc->sc_active;
pp = cp->provider;
strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
- memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid));
+ memcpy(md.md_uuid, sc->sc_uuid, sizeof(sc->sc_uuid));
strlcpy(md.md_name, name, sizeof(md.md_name));
md.md_version = G_MULTIPATH_VERSION;
md.md_size = pp->mediasize;
diff --git a/sys/geom/virstor/g_virstor.c b/sys/geom/virstor/g_virstor.c
index b8cf32875660..c7d737493f11 100644
--- a/sys/geom/virstor/g_virstor.c
+++ b/sys/geom/virstor/g_virstor.c
@@ -202,7 +202,7 @@ virstor_ctl_stop(struct gctl_req *req, struct g_class *cp)
int *force, *nargs;
int i;
- nargs = gctl_get_paraml(req, "nargs", sizeof *nargs);
+ nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
if (nargs == NULL) {
gctl_error(req, "Error fetching argument '%s'", "nargs");
return;
@@ -211,7 +211,7 @@ virstor_ctl_stop(struct gctl_req *req, struct g_class *cp)
gctl_error(req, "Invalid number of arguments");
return;
}
- force = gctl_get_paraml(req, "force", sizeof *force);
+ force = gctl_get_paraml(req, "force", sizeof(*force));
if (force == NULL) {
gctl_error(req, "Error fetching argument '%s'", "force");
return;
@@ -315,7 +315,7 @@ virstor_ctl_add(struct gctl_req *req, struct g_class *cp)
u_int nc;
u_int j;
- snprintf(aname, sizeof aname, "arg%d", i);
+ snprintf(aname, sizeof(aname), "arg%d", i);
pp = gctl_get_provider(req, aname);
if (pp == NULL) {
/* This is the most common error so be verbose about it */
@@ -487,12 +487,12 @@ fill_metadata(struct g_virstor_softc *sc, struct g_virstor_metadata *md,
{
struct g_virstor_component *c;
- bzero(md, sizeof *md);
+ bzero(md, sizeof(*md));
c = &sc->components[nc];
- strncpy(md->md_magic, G_VIRSTOR_MAGIC, sizeof md->md_magic);
+ strncpy(md->md_magic, G_VIRSTOR_MAGIC, sizeof(md->md_magic));
md->md_version = G_VIRSTOR_VERSION;
- strncpy(md->md_name, sc->geom->name, sizeof md->md_name);
+ strncpy(md->md_name, sc->geom->name, sizeof(md->md_name));
md->md_id = sc->id;
md->md_virsize = sc->virsize;
md->md_chunk_size = sc->chunk_size;
@@ -500,7 +500,7 @@ fill_metadata(struct g_virstor_softc *sc, struct g_virstor_metadata *md,
if (hardcode) {
strncpy(md->provider, c->gcons->provider->name,
- sizeof md->provider);
+ sizeof(md->provider));
}
md->no = nc;
md->provsize = c->gcons->provider->mediasize;
@@ -589,7 +589,7 @@ virstor_ctl_remove(struct gctl_req *req, struct g_class *cp)
M_GVIRSTOR, M_WAITOK | M_ZERO);
bcopy(sc->components, newcomp, found * sizeof(*sc->components));
bcopy(&sc->components[found + 1], newcomp + found,
- found * sizeof(*sc->components));
+ (sc->n_components - (found + 1)) * sizeof(*sc->components));
if ((sc->components[j].flags & VIRSTOR_PROVIDER_ALLOCATED) != 0) {
LOG_MSG(LVL_ERROR, "Allocated provider %s cannot be "
"removed from %s",
@@ -959,7 +959,7 @@ virstor_geom_destroy(struct g_virstor_softc *sc, boolean_t force,
free(sc->map, M_GVIRSTOR);
free(sc->components, M_GVIRSTOR);
- bzero(sc, sizeof *sc);
+ bzero(sc, sizeof(*sc));
free(sc, M_GVIRSTOR);
pp = LIST_FIRST(&gp->provider); /* We only offer one provider */
@@ -1213,7 +1213,7 @@ virstor_check_and_run(struct g_virstor_softc *sc)
sc->provider->name,
sc->chunk_count * (off_t)sc->chunk_size);
}
- sc->map_size = sc->chunk_count * sizeof *(sc->map);
+ sc->map_size = sc->chunk_count * sizeof(*(sc->map));
/* The following allocation is in order of 4MB - 8MB */
sc->map = malloc(sc->map_size, M_GVIRSTOR, M_WAITOK);
KASSERT(sc->map != NULL, ("%s: Memory allocation error (%zu bytes) for %s",
@@ -1267,7 +1267,7 @@ virstor_check_and_run(struct g_virstor_softc *sc)
bcopy(mapbuf, &sc->map[n], bs);
off += bs;
count += bs;
- n += bs / sizeof *(sc->map);
+ n += bs / sizeof(*(sc->map));
g_free(mapbuf);
}
g_access(sc->components[0].gcons, -1, 0, 0);
@@ -1306,8 +1306,8 @@ virstor_check_and_run(struct g_virstor_softc *sc)
sc->components[index].chunk_next);
}
- sc->me_per_sector = sc->sectorsize / sizeof *(sc->map);
- if (sc->sectorsize % sizeof *(sc->map) != 0) {
+ sc->me_per_sector = sc->sectorsize / sizeof(*(sc->map));
+ if (sc->sectorsize % sizeof(*(sc->map)) != 0) {
LOG_MSG(LVL_ERROR,
"%s: Map entries don't fit exactly in a sector (%s)",
__func__, sc->geom->name);
@@ -1653,7 +1653,7 @@ g_virstor_start(struct bio *b)
* XXX: this will prevent the fs from
* being umounted! */
struct g_virstor_bio_q *biq;
- biq = malloc(sizeof *biq, M_GVIRSTOR,
+ biq = malloc(sizeof(*biq), M_GVIRSTOR,
M_NOWAIT);
if (biq == NULL) {
bioq_dismantle(&bq);
@@ -1703,7 +1703,7 @@ g_virstor_start(struct bio *b)
* map array.
* sc_offset will end up pointing to the drive
* sector. */
- s_offset = chunk_index * sizeof *me;
+ s_offset = chunk_index * sizeof(*me);
s_offset = rounddown(s_offset, sc->sectorsize);
/* data_me points to map entry sector
diff --git a/sys/kern/coredump_vnode.c b/sys/kern/coredump_vnode.c
new file mode 100644
index 000000000000..8b857e9aa4a2
--- /dev/null
+++ b/sys/kern/coredump_vnode.c
@@ -0,0 +1,562 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause
+ *
+ * Copyright (c) 1982, 1986, 1989, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * - kern_sig.c
+ */
+/*
+ * Copyright (c) 1993, David Greenman
+ * 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.
+ * -kern_exec.c
+ */
+
+#include <sys/systm.h>
+#include <sys/acct.h>
+#include <sys/compressor.h>
+#include <sys/devctl.h>
+#include <sys/fcntl.h>
+#include <sys/jail.h>
+#include <sys/limits.h>
+#include <sys/namei.h>
+#include <sys/proc.h>
+#include <sys/sbuf.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/sysent.h>
+#include <sys/syslog.h>
+#include <sys/ucoredump.h>
+#include <sys/unistd.h>
+#include <sys/vnode.h>
+
+#include <security/audit/audit.h>
+
+#define GZIP_SUFFIX ".gz"
+#define ZSTD_SUFFIX ".zst"
+
+#define MAX_NUM_CORE_FILES 100000
+#ifndef NUM_CORE_FILES
+#define NUM_CORE_FILES 5
+#endif
+
+static coredumper_handle_fn coredump_vnode;
+static struct coredumper vnode_coredumper = {
+ .cd_name = "vnode_coredumper",
+ .cd_handle = coredump_vnode,
+};
+
+SYSINIT(vnode_coredumper_register, SI_SUB_EXEC, SI_ORDER_ANY,
+ coredumper_register, &vnode_coredumper);
+
+_Static_assert(NUM_CORE_FILES >= 0 && NUM_CORE_FILES <= MAX_NUM_CORE_FILES,
+ "NUM_CORE_FILES is out of range (0 to " __STRING(MAX_NUM_CORE_FILES) ")");
+static int num_cores = NUM_CORE_FILES;
+
+static int capmode_coredump;
+SYSCTL_INT(_kern, OID_AUTO, capmode_coredump, CTLFLAG_RWTUN,
+ &capmode_coredump, 0, "Allow processes in capability mode to dump core");
+
+static int set_core_nodump_flag = 0;
+SYSCTL_INT(_kern, OID_AUTO, nodump_coredump, CTLFLAG_RW, &set_core_nodump_flag,
+ 0, "Enable setting the NODUMP flag on coredump files");
+
+static int coredump_devctl = 0;
+SYSCTL_INT(_kern, OID_AUTO, coredump_devctl, CTLFLAG_RW, &coredump_devctl,
+ 0, "Generate a devctl notification when processes coredump");
+
+/*
+ * corefilename[] is protected by the allproc_lock.
+ */
+static char corefilename[MAXPATHLEN] = { "%N.core" };
+TUNABLE_STR("kern.corefile", corefilename, sizeof(corefilename));
+
+static int
+sysctl_kern_corefile(SYSCTL_HANDLER_ARGS)
+{
+ int error;
+
+ sx_xlock(&allproc_lock);
+ error = sysctl_handle_string(oidp, corefilename, sizeof(corefilename),
+ req);
+ sx_xunlock(&allproc_lock);
+
+ return (error);
+}
+SYSCTL_PROC(_kern, OID_AUTO, corefile, CTLTYPE_STRING | CTLFLAG_RW |
+ CTLFLAG_MPSAFE, 0, 0, sysctl_kern_corefile, "A",
+ "Process corefile name format string");
+
+static int
+sysctl_debug_num_cores_check (SYSCTL_HANDLER_ARGS)
+{
+ int error;
+ int new_val;
+
+ new_val = num_cores;
+ error = sysctl_handle_int(oidp, &new_val, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ if (new_val > MAX_NUM_CORE_FILES)
+ new_val = MAX_NUM_CORE_FILES;
+ if (new_val < 0)
+ new_val = 0;
+ num_cores = new_val;
+ return (0);
+}
+SYSCTL_PROC(_debug, OID_AUTO, ncores,
+ CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, sizeof(int),
+ sysctl_debug_num_cores_check, "I",
+ "Maximum number of generated process corefiles while using index format");
+
+static void
+vnode_close_locked(struct thread *td, struct vnode *vp)
+{
+
+ VOP_UNLOCK(vp);
+ vn_close(vp, FWRITE, td->td_ucred, td);
+}
+
+int
+core_vn_write(const struct coredump_writer *cdw, const void *base, size_t len,
+ off_t offset, enum uio_seg seg, struct ucred *cred, size_t *resid,
+ struct thread *td)
+{
+ struct coredump_vnode_ctx *ctx = cdw->ctx;
+
+ return (vn_rdwr_inchunks(UIO_WRITE, ctx->vp, __DECONST(void *, base),
+ len, offset, seg, IO_UNIT | IO_DIRECT | IO_RANGELOCKED,
+ cred, ctx->fcred, resid, td));
+}
+
+int
+core_vn_extend(const struct coredump_writer *cdw, off_t newsz,
+ struct ucred *cred)
+{
+ struct coredump_vnode_ctx *ctx = cdw->ctx;
+ struct mount *mp;
+ int error;
+
+ error = vn_start_write(ctx->vp, &mp, V_WAIT);
+ if (error != 0)
+ return (error);
+ vn_lock(ctx->vp, LK_EXCLUSIVE | LK_RETRY);
+ error = vn_truncate_locked(ctx->vp, newsz, false, cred);
+ VOP_UNLOCK(ctx->vp);
+ vn_finished_write(mp);
+ return (error);
+}
+
+/*
+ * If the core format has a %I in it, then we need to check
+ * for existing corefiles before defining a name.
+ * To do this we iterate over 0..ncores to find a
+ * non-existing core file name to use. If all core files are
+ * already used we choose the oldest one.
+ */
+static int
+corefile_open_last(struct thread *td, char *name, int indexpos,
+ int indexlen, int ncores, struct vnode **vpp)
+{
+ struct vnode *oldvp, *nextvp, *vp;
+ struct vattr vattr;
+ struct nameidata nd;
+ int error, i, flags, oflags, cmode;
+ char ch;
+ struct timespec lasttime;
+
+ nextvp = oldvp = NULL;
+ cmode = S_IRUSR | S_IWUSR;
+ oflags = VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE |
+ (capmode_coredump ? VN_OPEN_NOCAPCHECK : 0);
+
+ for (i = 0; i < ncores; i++) {
+ flags = O_CREAT | FWRITE | O_NOFOLLOW;
+
+ ch = name[indexpos + indexlen];
+ (void)snprintf(name + indexpos, indexlen + 1, "%.*u", indexlen,
+ i);
+ name[indexpos + indexlen] = ch;
+
+ NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name);
+ error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred,
+ NULL);
+ if (error != 0)
+ break;
+
+ vp = nd.ni_vp;
+ NDFREE_PNBUF(&nd);
+ if ((flags & O_CREAT) == O_CREAT) {
+ nextvp = vp;
+ break;
+ }
+
+ error = VOP_GETATTR(vp, &vattr, td->td_ucred);
+ if (error != 0) {
+ vnode_close_locked(td, vp);
+ break;
+ }
+
+ if (oldvp == NULL ||
+ lasttime.tv_sec > vattr.va_mtime.tv_sec ||
+ (lasttime.tv_sec == vattr.va_mtime.tv_sec &&
+ lasttime.tv_nsec >= vattr.va_mtime.tv_nsec)) {
+ if (oldvp != NULL)
+ vn_close(oldvp, FWRITE, td->td_ucred, td);
+ oldvp = vp;
+ VOP_UNLOCK(oldvp);
+ lasttime = vattr.va_mtime;
+ } else {
+ vnode_close_locked(td, vp);
+ }
+ }
+
+ if (oldvp != NULL) {
+ if (nextvp == NULL) {
+ if ((td->td_proc->p_flag & P_SUGID) != 0) {
+ error = EFAULT;
+ vn_close(oldvp, FWRITE, td->td_ucred, td);
+ } else {
+ nextvp = oldvp;
+ error = vn_lock(nextvp, LK_EXCLUSIVE);
+ if (error != 0) {
+ vn_close(nextvp, FWRITE, td->td_ucred,
+ td);
+ nextvp = NULL;
+ }
+ }
+ } else {
+ vn_close(oldvp, FWRITE, td->td_ucred, td);
+ }
+ }
+ if (error != 0) {
+ if (nextvp != NULL)
+ vnode_close_locked(td, oldvp);
+ } else {
+ *vpp = nextvp;
+ }
+
+ return (error);
+}
+
+/*
+ * corefile_open(comm, uid, pid, td, compress, vpp, namep)
+ * Expand the name described in corefilename, using name, uid, and pid
+ * and open/create core file.
+ * corefilename is a printf-like string, with three format specifiers:
+ * %N name of process ("name")
+ * %P process id (pid)
+ * %U user id (uid)
+ * For example, "%N.core" is the default; they can be disabled completely
+ * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
+ * This is controlled by the sysctl variable kern.corefile (see above).
+ */
+static int
+corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td,
+ int compress, int signum, struct vnode **vpp, char **namep)
+{
+ struct sbuf sb;
+ struct nameidata nd;
+ const char *format;
+ char *hostname, *name;
+ int cmode, error, flags, i, indexpos, indexlen, oflags, ncores;
+
+ hostname = NULL;
+ format = corefilename;
+ name = malloc(MAXPATHLEN, M_TEMP, M_WAITOK | M_ZERO);
+ indexlen = 0;
+ indexpos = -1;
+ ncores = num_cores;
+ (void)sbuf_new(&sb, name, MAXPATHLEN, SBUF_FIXEDLEN);
+ sx_slock(&allproc_lock);
+ for (i = 0; format[i] != '\0'; i++) {
+ switch (format[i]) {
+ case '%': /* Format character */
+ i++;
+ switch (format[i]) {
+ case '%':
+ sbuf_putc(&sb, '%');
+ break;
+ case 'H': /* hostname */
+ if (hostname == NULL) {
+ hostname = malloc(MAXHOSTNAMELEN,
+ M_TEMP, M_WAITOK);
+ }
+ getcredhostname(td->td_ucred, hostname,
+ MAXHOSTNAMELEN);
+ sbuf_cat(&sb, hostname);
+ break;
+ case 'I': /* autoincrementing index */
+ if (indexpos != -1) {
+ sbuf_printf(&sb, "%%I");
+ break;
+ }
+
+ indexpos = sbuf_len(&sb);
+ sbuf_printf(&sb, "%u", ncores - 1);
+ indexlen = sbuf_len(&sb) - indexpos;
+ break;
+ case 'N': /* process name */
+ sbuf_printf(&sb, "%s", comm);
+ break;
+ case 'P': /* process id */
+ sbuf_printf(&sb, "%u", pid);
+ break;
+ case 'S': /* signal number */
+ sbuf_printf(&sb, "%i", signum);
+ break;
+ case 'U': /* user id */
+ sbuf_printf(&sb, "%u", uid);
+ break;
+ default:
+ log(LOG_ERR,
+ "Unknown format character %c in "
+ "corename `%s'\n", format[i], format);
+ break;
+ }
+ break;
+ default:
+ sbuf_putc(&sb, format[i]);
+ break;
+ }
+ }
+ sx_sunlock(&allproc_lock);
+ free(hostname, M_TEMP);
+ if (compress == COMPRESS_GZIP)
+ sbuf_cat(&sb, GZIP_SUFFIX);
+ else if (compress == COMPRESS_ZSTD)
+ sbuf_cat(&sb, ZSTD_SUFFIX);
+ if (sbuf_error(&sb) != 0) {
+ log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too "
+ "long\n", (long)pid, comm, (u_long)uid);
+ sbuf_delete(&sb);
+ free(name, M_TEMP);
+ return (ENOMEM);
+ }
+ sbuf_finish(&sb);
+ sbuf_delete(&sb);
+
+ if (indexpos != -1) {
+ error = corefile_open_last(td, name, indexpos, indexlen, ncores,
+ vpp);
+ if (error != 0) {
+ log(LOG_ERR,
+ "pid %d (%s), uid (%u): Path `%s' failed "
+ "on initial open test, error = %d\n",
+ pid, comm, uid, name, error);
+ }
+ } else {
+ cmode = S_IRUSR | S_IWUSR;
+ oflags = VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE |
+ (capmode_coredump ? VN_OPEN_NOCAPCHECK : 0);
+ flags = O_CREAT | FWRITE | O_NOFOLLOW;
+ if ((td->td_proc->p_flag & P_SUGID) != 0)
+ flags |= O_EXCL;
+
+ NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name);
+ error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred,
+ NULL);
+ if (error == 0) {
+ *vpp = nd.ni_vp;
+ NDFREE_PNBUF(&nd);
+ }
+ }
+
+ if (error != 0) {
+#ifdef AUDIT
+ audit_proc_coredump(td, name, error);
+#endif
+ free(name, M_TEMP);
+ return (error);
+ }
+ *namep = name;
+ return (0);
+}
+
+/*
+ * The vnode dumper is the traditional coredump handler. Our policy and limits
+ * are generally checked already, so it creates the coredump name and passes on
+ * a vnode and a size limit to the process-specific coredump routine if there is
+ * one. If there _is not_ one, it returns ENOSYS; otherwise it returns the
+ * error from the process-specific routine.
+ */
+static int
+coredump_vnode(struct thread *td, off_t limit)
+{
+ struct proc *p = td->td_proc;
+ struct ucred *cred = td->td_ucred;
+ struct vnode *vp;
+ struct coredump_vnode_ctx wctx;
+ struct coredump_writer cdw = { };
+ struct flock lf;
+ struct vattr vattr;
+ size_t fullpathsize;
+ int error, error1, jid, locked, ppid, sig;
+ char *name; /* name of corefile */
+ void *rl_cookie;
+ char *fullpath, *freepath = NULL;
+ struct sbuf *sb;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+
+ ppid = p->p_oppid;
+ sig = p->p_sig;
+ jid = p->p_ucred->cr_prison->pr_id;
+ PROC_UNLOCK(p);
+
+ error = corefile_open(p->p_comm, cred->cr_uid, p->p_pid, td,
+ compress_user_cores, sig, &vp, &name);
+ if (error != 0)
+ return (error);
+
+ /*
+ * Don't dump to non-regular files or files with links.
+ * Do not dump into system files. Effective user must own the corefile.
+ */
+ if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 ||
+ vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0 ||
+ vattr.va_uid != cred->cr_uid) {
+ VOP_UNLOCK(vp);
+ error = EFAULT;
+ goto out;
+ }
+
+ VOP_UNLOCK(vp);
+
+ /* Postpone other writers, including core dumps of other processes. */
+ rl_cookie = vn_rangelock_wlock(vp, 0, OFF_MAX);
+
+ lf.l_whence = SEEK_SET;
+ lf.l_start = 0;
+ lf.l_len = 0;
+ lf.l_type = F_WRLCK;
+ locked = (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &lf, F_FLOCK) == 0);
+
+ VATTR_NULL(&vattr);
+ vattr.va_size = 0;
+ if (set_core_nodump_flag)
+ vattr.va_flags = UF_NODUMP;
+ vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
+ VOP_SETATTR(vp, &vattr, cred);
+ VOP_UNLOCK(vp);
+ PROC_LOCK(p);
+ p->p_acflag |= ACORE;
+ PROC_UNLOCK(p);
+
+ wctx.vp = vp;
+ wctx.fcred = NOCRED;
+
+ cdw.ctx = &wctx;
+ cdw.write_fn = core_vn_write;
+ cdw.extend_fn = core_vn_extend;
+
+ if (p->p_sysent->sv_coredump != NULL) {
+ error = p->p_sysent->sv_coredump(td, &cdw, limit, 0);
+ } else {
+ error = ENOSYS;
+ }
+
+ if (locked) {
+ lf.l_type = F_UNLCK;
+ VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_FLOCK);
+ }
+ vn_rangelock_unlock(vp, rl_cookie);
+
+ /*
+ * Notify the userland helper that a process triggered a core dump.
+ * This allows the helper to run an automated debugging session.
+ */
+ if (error != 0 || coredump_devctl == 0)
+ goto out;
+ sb = sbuf_new_auto();
+ if (vn_fullpath_global(p->p_textvp, &fullpath, &freepath) != 0)
+ goto out2;
+ sbuf_cat(sb, "comm=\"");
+ devctl_safe_quote_sb(sb, fullpath);
+ free(freepath, M_TEMP);
+ sbuf_cat(sb, "\" core=\"");
+
+ /*
+ * We can't lookup core file vp directly. When we're replacing a core, and
+ * other random times, we flush the name cache, so it will fail. Instead,
+ * if the path of the core is relative, add the current dir in front if it.
+ */
+ if (name[0] != '/') {
+ fullpathsize = MAXPATHLEN;
+ freepath = malloc(fullpathsize, M_TEMP, M_WAITOK);
+ if (vn_getcwd(freepath, &fullpath, &fullpathsize) != 0) {
+ free(freepath, M_TEMP);
+ goto out2;
+ }
+ devctl_safe_quote_sb(sb, fullpath);
+ free(freepath, M_TEMP);
+ sbuf_putc(sb, '/');
+ }
+ devctl_safe_quote_sb(sb, name);
+ sbuf_putc(sb, '"');
+
+ sbuf_printf(sb, " jid=%d pid=%d ppid=%d signo=%d",
+ jid, p->p_pid, ppid, sig);
+ if (sbuf_finish(sb) == 0)
+ devctl_notify("kernel", "signal", "coredump", sbuf_data(sb));
+out2:
+ sbuf_delete(sb);
+out:
+ error1 = vn_close(vp, FWRITE, cred, td);
+ if (error == 0)
+ error = error1;
+#ifdef AUDIT
+ audit_proc_coredump(td, name, error);
+#endif
+ free(name, M_TEMP);
+ return (error);
+}
diff --git a/sys/kern/imgact_elf.c b/sys/kern/imgact_elf.c
index b7ffbe68b483..2690ad3b2679 100644
--- a/sys/kern/imgact_elf.c
+++ b/sys/kern/imgact_elf.c
@@ -64,6 +64,7 @@
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/sysent.h>
+#include <sys/ucoredump.h>
#include <sys/vnode.h>
#include <sys/syslog.h>
#include <sys/eventhandler.h>
@@ -1562,9 +1563,6 @@ struct note_info {
TAILQ_HEAD(note_info_list, note_info);
-extern int compress_user_cores;
-extern int compress_user_cores_level;
-
static void cb_put_phdr(vm_map_entry_t, void *);
static void cb_size_segment(vm_map_entry_t, void *);
static void each_dumpable_segment(struct thread *, segment_callback, void *,
@@ -1595,7 +1593,7 @@ core_compressed_write(void *base, size_t len, off_t offset, void *arg)
}
int
-__elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
+__elfN(coredump)(struct thread *td, struct coredump_writer *cdw, off_t limit, int flags)
{
struct ucred *cred = td->td_ucred;
int compm, error = 0;
@@ -1625,9 +1623,8 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
/* Set up core dump parameters. */
params.offset = 0;
params.active_cred = cred;
- params.file_cred = NOCRED;
params.td = td;
- params.vp = vp;
+ params.cdw = cdw;
params.comp = NULL;
#ifdef RACCT
@@ -1662,6 +1659,12 @@ __elfN(coredump)(struct thread *td, struct vnode *vp, off_t limit, int flags)
tmpbuf = malloc(CORE_BUF_SIZE, M_TEMP, M_WAITOK | M_ZERO);
}
+ if (cdw->init_fn != NULL) {
+ error = (*cdw->init_fn)(cdw, &params);
+ if (error != 0)
+ goto done;
+ }
+
/*
* Allocate memory for building the header, fill it up,
* and write it out following the notes.
diff --git a/sys/kern/kern_cpuset.c b/sys/kern/kern_cpuset.c
index 5d9e2f2f326b..d7eb82d5f259 100644
--- a/sys/kern/kern_cpuset.c
+++ b/sys/kern/kern_cpuset.c
@@ -530,7 +530,7 @@ _domainset_create(struct domainset *domain, struct domainlist *freelist)
* remove them and update the domainset accordingly. If only empty
* domains are present, we must return failure.
*/
-static bool
+bool
domainset_empty_vm(struct domainset *domain)
{
domainset_t empty;
@@ -2409,82 +2409,92 @@ sys_cpuset_setdomain(struct thread *td, struct cpuset_setdomain_args *uap)
}
int
-kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which,
- id_t id, size_t domainsetsize, const domainset_t *maskp, int policy,
- const struct cpuset_copy_cb *cb)
+domainset_populate(struct domainset *domain, const domainset_t *mask, int policy,
+ size_t mask_size)
{
- struct cpuset *nset;
- struct cpuset *set;
- struct thread *ttd;
- struct proc *p;
- struct domainset domain;
- domainset_t *mask;
- int error;
- if (domainsetsize < sizeof(domainset_t) ||
- domainsetsize > DOMAINSET_MAXSIZE / NBBY)
- return (ERANGE);
if (policy <= DOMAINSET_POLICY_INVALID ||
- policy > DOMAINSET_POLICY_MAX)
+ policy > DOMAINSET_POLICY_MAX) {
return (EINVAL);
- error = cpuset_check_capabilities(td, level, which, id);
- if (error != 0)
- return (error);
- memset(&domain, 0, sizeof(domain));
- mask = malloc(domainsetsize, M_TEMP, M_WAITOK | M_ZERO);
- error = cb->cpuset_copyin(maskp, mask, domainsetsize);
- if (error)
- goto out;
+ }
+
/*
* Verify that no high bits are set.
*/
- if (domainsetsize > sizeof(domainset_t)) {
- char *end;
- char *cp;
+ if (mask_size > sizeof(domainset_t)) {
+ const char *end;
+ const char *cp;
- end = cp = (char *)&mask->__bits;
- end += domainsetsize;
+ end = cp = (const char *)&mask->__bits;
+ end += mask_size;
cp += sizeof(domainset_t);
- while (cp != end)
+ while (cp != end) {
if (*cp++ != 0) {
- error = EINVAL;
- goto out;
+ return (EINVAL);
}
+ }
}
if (DOMAINSET_EMPTY(mask)) {
- error = EDEADLK;
- goto out;
+ return (EDEADLK);
}
- DOMAINSET_COPY(mask, &domain.ds_mask);
- domain.ds_policy = policy;
+ DOMAINSET_COPY(mask, &domain->ds_mask);
+ domain->ds_policy = policy;
/*
* Sanitize the provided mask.
*/
- if (!DOMAINSET_SUBSET(&all_domains, &domain.ds_mask)) {
- error = EINVAL;
- goto out;
+ if (!DOMAINSET_SUBSET(&all_domains, &domain->ds_mask)) {
+ return (EINVAL);
}
/* Translate preferred policy into a mask and fallback. */
if (policy == DOMAINSET_POLICY_PREFER) {
/* Only support a single preferred domain. */
- if (DOMAINSET_COUNT(&domain.ds_mask) != 1) {
- error = EINVAL;
- goto out;
+ if (DOMAINSET_COUNT(&domain->ds_mask) != 1) {
+ return (EINVAL);
}
- domain.ds_prefer = DOMAINSET_FFS(&domain.ds_mask) - 1;
+ domain->ds_prefer = DOMAINSET_FFS(&domain->ds_mask) - 1;
/* This will be constrained by domainset_shadow(). */
- DOMAINSET_COPY(&all_domains, &domain.ds_mask);
+ DOMAINSET_COPY(&all_domains, &domain->ds_mask);
}
+ return (0);
+}
+
+int
+kern_cpuset_setdomain(struct thread *td, cpulevel_t level, cpuwhich_t which,
+ id_t id, size_t domainsetsize, const domainset_t *maskp, int policy,
+ const struct cpuset_copy_cb *cb)
+{
+ struct cpuset *nset;
+ struct cpuset *set;
+ struct thread *ttd;
+ struct proc *p;
+ struct domainset domain;
+ domainset_t *mask;
+ int error;
+
+ error = cpuset_check_capabilities(td, level, which, id);
+ if (error != 0)
+ return (error);
+ if (domainsetsize < sizeof(domainset_t) ||
+ domainsetsize > DOMAINSET_MAXSIZE / NBBY)
+ return (ERANGE);
+ memset(&domain, 0, sizeof(domain));
+ mask = malloc(domainsetsize, M_TEMP, M_WAITOK | M_ZERO);
+ error = cb->cpuset_copyin(maskp, mask, domainsetsize);
+ if (error)
+ goto out;
+ error = domainset_populate(&domain, mask, policy, domainsetsize);
+ if (error)
+ goto out;
+
/*
* When given an impossible policy, fall back to interleaving
* across all domains.
*/
if (domainset_empty_vm(&domain))
domainset_copy(domainset2, &domain);
-
switch (level) {
case CPU_LEVEL_ROOT:
case CPU_LEVEL_CPUSET:
diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c
index 03268365891e..0fc2d0e7f1bc 100644
--- a/sys/kern/kern_exec.c
+++ b/sys/kern/kern_exec.c
@@ -70,6 +70,7 @@
#include <sys/sysent.h>
#include <sys/sysproto.h>
#include <sys/timers.h>
+#include <sys/ucoredump.h>
#include <sys/umtxvar.h>
#include <sys/vnode.h>
#include <sys/wait.h>
@@ -2002,10 +2003,14 @@ int
core_write(struct coredump_params *cp, const void *base, size_t len,
off_t offset, enum uio_seg seg, size_t *resid)
{
+ return ((*cp->cdw->write_fn)(cp->cdw, base, len, offset, seg,
+ cp->active_cred, resid, cp->td));
+}
- return (vn_rdwr_inchunks(UIO_WRITE, cp->vp, __DECONST(void *, base),
- len, offset, seg, IO_UNIT | IO_DIRECT | IO_RANGELOCKED,
- cp->active_cred, cp->file_cred, resid, cp->td));
+static int
+core_extend(struct coredump_params *cp, off_t newsz)
+{
+ return ((*cp->cdw->extend_fn)(cp->cdw, newsz, cp->active_cred));
}
int
@@ -2013,7 +2018,6 @@ core_output(char *base, size_t len, off_t offset, struct coredump_params *cp,
void *tmpbuf)
{
vm_map_t map;
- struct mount *mp;
size_t resid, runlen;
int error;
bool success;
@@ -2068,14 +2072,7 @@ core_output(char *base, size_t len, off_t offset, struct coredump_params *cp,
}
}
if (!success) {
- error = vn_start_write(cp->vp, &mp, V_WAIT);
- if (error != 0)
- break;
- vn_lock(cp->vp, LK_EXCLUSIVE | LK_RETRY);
- error = vn_truncate_locked(cp->vp, offset + runlen,
- false, cp->td->td_ucred);
- VOP_UNLOCK(cp->vp);
- vn_finished_write(mp);
+ error = core_extend(cp, offset + runlen);
if (error != 0)
break;
}
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index d4529e096929..7ef1d19f0ea8 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -3466,7 +3466,7 @@ prison_check_af(struct ucred *cred, int af)
pr = cred->cr_prison;
#ifdef VIMAGE
/* Prisons with their own network stack are not limited. */
- if (prison_owns_vnet(cred))
+ if (prison_owns_vnet(pr))
return (0);
#endif
@@ -3531,7 +3531,7 @@ prison_if(struct ucred *cred, const struct sockaddr *sa)
KASSERT(sa != NULL, ("%s: sa is NULL", __func__));
#ifdef VIMAGE
- if (prison_owns_vnet(cred))
+ if (prison_owns_vnet(cred->cr_prison))
return (0);
#endif
@@ -3648,7 +3648,7 @@ jailed_without_vnet(struct ucred *cred)
if (!jailed(cred))
return (false);
#ifdef VIMAGE
- if (prison_owns_vnet(cred))
+ if (prison_owns_vnet(cred->cr_prison))
return (false);
#endif
@@ -3711,20 +3711,17 @@ getjailname(struct ucred *cred, char *name, size_t len)
#ifdef VIMAGE
/*
- * Determine whether the prison represented by cred owns
- * its vnet rather than having it inherited.
- *
- * Returns true in case the prison owns the vnet, false otherwise.
+ * Determine whether the prison owns its VNET.
*/
bool
-prison_owns_vnet(struct ucred *cred)
+prison_owns_vnet(struct prison *pr)
{
/*
* vnets cannot be added/removed after jail creation,
* so no need to lock here.
*/
- return ((cred->cr_prison->pr_flags & PR_VNET) != 0);
+ return ((pr->pr_flags & PR_VNET) != 0);
}
#endif
@@ -4425,7 +4422,7 @@ sysctl_jail_vnet(SYSCTL_HANDLER_ARGS)
#ifdef VIMAGE
struct ucred *cred = req->td->td_ucred;
- havevnet = jailed(cred) && prison_owns_vnet(cred);
+ havevnet = jailed(cred) && prison_owns_vnet(cred->cr_prison);
#else
havevnet = 0;
#endif
diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
index d9aeec68e620..0f0bc056cafd 100644
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -287,7 +287,7 @@ sys_getgid(struct thread *td, struct getgid_args *uap)
td->td_retval[0] = td->td_ucred->cr_rgid;
#if defined(COMPAT_43)
- td->td_retval[1] = td->td_ucred->cr_groups[0];
+ td->td_retval[1] = td->td_ucred->cr_gid;
#endif
return (0);
}
@@ -307,7 +307,7 @@ int
sys_getegid(struct thread *td, struct getegid_args *uap)
{
- td->td_retval[0] = td->td_ucred->cr_groups[0];
+ td->td_retval[0] = td->td_ucred->cr_gid;
return (0);
}
@@ -1080,7 +1080,7 @@ sys_setgid(struct thread *td, struct setgid_args *uap)
gid != oldcred->cr_svgid && /* allow setgid(saved gid) */
#endif
#ifdef POSIX_APPENDIX_B_4_2_2 /* Use BSD-compat clause from B.4.2.2 */
- gid != oldcred->cr_groups[0] && /* allow setgid(getegid()) */
+ gid != oldcred->cr_gid && /* allow setgid(getegid()) */
#endif
(error = priv_check_cred(oldcred, PRIV_CRED_SETGID)) != 0)
goto fail;
@@ -1092,7 +1092,7 @@ sys_setgid(struct thread *td, struct setgid_args *uap)
*/
if (
#ifdef POSIX_APPENDIX_B_4_2_2 /* use the clause from B.4.2.2 */
- gid == oldcred->cr_groups[0] ||
+ gid == oldcred->cr_gid ||
#endif
/* We are using privs. */
priv_check_cred(oldcred, PRIV_CRED_SETGID) == 0)
@@ -1121,7 +1121,7 @@ sys_setgid(struct thread *td, struct setgid_args *uap)
* In all cases permitted cases, we are changing the egid.
* Copy credentials so other references do not see our changes.
*/
- if (oldcred->cr_groups[0] != gid) {
+ if (oldcred->cr_gid != gid) {
change_egid(newcred, gid);
setsugid(p);
}
@@ -1167,7 +1167,7 @@ sys_setegid(struct thread *td, struct setegid_args *uap)
(error = priv_check_cred(oldcred, PRIV_CRED_SETEGID)) != 0)
goto fail;
- if (oldcred->cr_groups[0] != egid) {
+ if (oldcred->cr_gid != egid) {
change_egid(newcred, egid);
setsugid(p);
}
@@ -1393,12 +1393,12 @@ sys_setregid(struct thread *td, struct setregid_args *uap)
if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
rgid != oldcred->cr_svgid) ||
- (egid != (gid_t)-1 && egid != oldcred->cr_groups[0] &&
+ (egid != (gid_t)-1 && egid != oldcred->cr_gid &&
egid != oldcred->cr_rgid && egid != oldcred->cr_svgid)) &&
(error = priv_check_cred(oldcred, PRIV_CRED_SETREGID)) != 0)
goto fail;
- if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
+ if (egid != (gid_t)-1 && oldcred->cr_gid != egid) {
change_egid(newcred, egid);
setsugid(p);
}
@@ -1406,9 +1406,9 @@ sys_setregid(struct thread *td, struct setregid_args *uap)
change_rgid(newcred, rgid);
setsugid(p);
}
- if ((rgid != (gid_t)-1 || newcred->cr_groups[0] != newcred->cr_rgid) &&
- newcred->cr_svgid != newcred->cr_groups[0]) {
- change_svgid(newcred, newcred->cr_groups[0]);
+ if ((rgid != (gid_t)-1 || newcred->cr_gid != newcred->cr_rgid) &&
+ newcred->cr_svgid != newcred->cr_gid) {
+ change_svgid(newcred, newcred->cr_gid);
setsugid(p);
}
proc_set_cred(p, newcred);
@@ -1547,17 +1547,17 @@ sys_setresgid(struct thread *td, struct setresgid_args *uap)
if (((rgid != (gid_t)-1 && rgid != oldcred->cr_rgid &&
rgid != oldcred->cr_svgid &&
- rgid != oldcred->cr_groups[0]) ||
+ rgid != oldcred->cr_gid) ||
(egid != (gid_t)-1 && egid != oldcred->cr_rgid &&
egid != oldcred->cr_svgid &&
- egid != oldcred->cr_groups[0]) ||
+ egid != oldcred->cr_gid) ||
(sgid != (gid_t)-1 && sgid != oldcred->cr_rgid &&
sgid != oldcred->cr_svgid &&
- sgid != oldcred->cr_groups[0])) &&
+ sgid != oldcred->cr_gid)) &&
(error = priv_check_cred(oldcred, PRIV_CRED_SETRESGID)) != 0)
goto fail;
- if (egid != (gid_t)-1 && oldcred->cr_groups[0] != egid) {
+ if (egid != (gid_t)-1 && oldcred->cr_gid != egid) {
change_egid(newcred, egid);
setsugid(p);
}
@@ -1626,8 +1626,8 @@ sys_getresgid(struct thread *td, struct getresgid_args *uap)
error1 = copyout(&cred->cr_rgid,
uap->rgid, sizeof(cred->cr_rgid));
if (uap->egid)
- error2 = copyout(&cred->cr_groups[0],
- uap->egid, sizeof(cred->cr_groups[0]));
+ error2 = copyout(&cred->cr_gid,
+ uap->egid, sizeof(cred->cr_gid));
if (uap->sgid)
error3 = copyout(&cred->cr_svgid,
uap->sgid, sizeof(cred->cr_svgid));
@@ -1737,7 +1737,7 @@ groupmember(gid_t gid, const struct ucred *cred)
groups_check_positive_len(cred->cr_ngroups);
- if (gid == cred->cr_groups[0])
+ if (gid == cred->cr_gid)
return (true);
return (group_is_supplementary(gid, cred));
@@ -3015,7 +3015,7 @@ void
change_egid(struct ucred *newcred, gid_t egid)
{
- newcred->cr_groups[0] = egid;
+ newcred->cr_gid = egid;
}
/*-
diff --git a/sys/kern/kern_sendfile.c b/sys/kern/kern_sendfile.c
index 35b258e68701..8438298afc0e 100644
--- a/sys/kern/kern_sendfile.c
+++ b/sys/kern/kern_sendfile.c
@@ -698,10 +698,13 @@ sendfile_wait_generic(struct socket *so, off_t need, int *space)
*/
error = 0;
SOCK_SENDBUF_LOCK(so);
- if (so->so_snd.sb_lowat < so->so_snd.sb_hiwat / 2)
- so->so_snd.sb_lowat = so->so_snd.sb_hiwat / 2;
- if (so->so_snd.sb_lowat < PAGE_SIZE && so->so_snd.sb_hiwat >= PAGE_SIZE)
- so->so_snd.sb_lowat = PAGE_SIZE;
+ if (so->so_snd.sb_flags & SB_AUTOLOWAT) {
+ if (so->so_snd.sb_lowat < so->so_snd.sb_hiwat / 2)
+ so->so_snd.sb_lowat = so->so_snd.sb_hiwat / 2;
+ if (so->so_snd.sb_lowat < PAGE_SIZE &&
+ so->so_snd.sb_hiwat >= PAGE_SIZE)
+ so->so_snd.sb_lowat = PAGE_SIZE;
+ }
retry_space:
if (so->so_snd.sb_state & SBS_CANTSENDMORE) {
error = EPIPE;
diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c
index 5d51aa675cb7..da0efac0598d 100644
--- a/sys/kern/kern_sig.c
+++ b/sys/kern/kern_sig.c
@@ -45,10 +45,10 @@
#include <sys/vnode.h>
#include <sys/acct.h>
#include <sys/capsicum.h>
-#include <sys/compressor.h>
#include <sys/condvar.h>
#include <sys/devctl.h>
#include <sys/event.h>
+#include <sys/exec.h>
#include <sys/fcntl.h>
#include <sys/imgact.h>
#include <sys/jail.h>
@@ -80,6 +80,7 @@
#include <sys/syslog.h>
#include <sys/sysproto.h>
#include <sys/timers.h>
+#include <sys/ucoredump.h>
#include <sys/unistd.h>
#include <sys/vmmeter.h>
#include <sys/wait.h>
@@ -101,7 +102,6 @@ SDT_PROBE_DEFINE2(proc, , , signal__clear,
SDT_PROBE_DEFINE3(proc, , , signal__discard,
"struct thread *", "struct proc *", "int");
-static int coredump(struct thread *);
static int killpg1(struct thread *td, int sig, int pgid, int all,
ksiginfo_t *ksi);
static int issignal(struct thread *td);
@@ -126,11 +126,6 @@ const struct filterops sig_filtops = {
.f_event = filt_signal,
};
-static int kern_logsigexit = 1;
-SYSCTL_INT(_kern, KERN_LOGSIGEXIT, logsigexit, CTLFLAG_RW,
- &kern_logsigexit, 0,
- "Log processes quitting on abnormal signals to syslog(3)");
-
static int kern_forcesigexit = 1;
SYSCTL_INT(_kern, OID_AUTO, forcesigexit, CTLFLAG_RW,
&kern_forcesigexit, 0, "Force trap signal to be handled");
@@ -193,26 +188,6 @@ SYSINIT(signal, SI_SUB_P1003_1B, SI_ORDER_FIRST+3, sigqueue_start, NULL);
(cr1)->cr_ruid == (cr2)->cr_uid || \
(cr1)->cr_uid == (cr2)->cr_uid)
-static int sugid_coredump;
-SYSCTL_INT(_kern, OID_AUTO, sugid_coredump, CTLFLAG_RWTUN,
- &sugid_coredump, 0, "Allow setuid and setgid processes to dump core");
-
-static int capmode_coredump;
-SYSCTL_INT(_kern, OID_AUTO, capmode_coredump, CTLFLAG_RWTUN,
- &capmode_coredump, 0, "Allow processes in capability mode to dump core");
-
-static int do_coredump = 1;
-SYSCTL_INT(_kern, OID_AUTO, coredump, CTLFLAG_RW,
- &do_coredump, 0, "Enable/Disable coredumps");
-
-static int set_core_nodump_flag = 0;
-SYSCTL_INT(_kern, OID_AUTO, nodump_coredump, CTLFLAG_RW, &set_core_nodump_flag,
- 0, "Enable setting the NODUMP flag on coredump files");
-
-static int coredump_devctl = 0;
-SYSCTL_INT(_kern, OID_AUTO, coredump_devctl, CTLFLAG_RW, &coredump_devctl,
- 0, "Generate a devctl notification when processes coredump");
-
/*
* Signal properties and actions.
* The array below categorizes the signals and their default actions
@@ -784,6 +759,13 @@ sigprop(int sig)
return (0);
}
+bool
+sig_do_core(int sig)
+{
+
+ return ((sigprop(sig) & SIGPROP_CORE) != 0);
+}
+
static bool
sigact_flag_test(const struct sigaction *act, int flag)
{
@@ -2665,6 +2647,8 @@ static void
ptrace_coredumpreq(struct thread *td, struct proc *p,
struct thr_coredump_req *tcq)
{
+ struct coredump_vnode_ctx wctx;
+ struct coredump_writer cdw;
void *rl_cookie;
if (p->p_sysent->sv_coredump == NULL) {
@@ -2672,8 +2656,15 @@ ptrace_coredumpreq(struct thread *td, struct proc *p,
return;
}
+ wctx.vp = tcq->tc_vp;
+ wctx.fcred = NOCRED;
+
+ cdw.ctx = &wctx;
+ cdw.write_fn = core_vn_write;
+ cdw.extend_fn = core_vn_extend;
+
rl_cookie = vn_rangelock_wlock(tcq->tc_vp, 0, OFF_MAX);
- tcq->tc_error = p->p_sysent->sv_coredump(td, tcq->tc_vp,
+ tcq->tc_error = p->p_sysent->sv_coredump(td, &cdw,
tcq->tc_limit, tcq->tc_flags);
vn_rangelock_unlock(tcq->tc_vp, rl_cookie);
}
@@ -3635,82 +3626,6 @@ killproc(struct proc *p, const char *why)
}
/*
- * Force the current process to exit with the specified signal, dumping core
- * if appropriate. We bypass the normal tests for masked and caught signals,
- * allowing unrecoverable failures to terminate the process without changing
- * signal state. Mark the accounting record with the signal termination.
- * If dumping core, save the signal number for the debugger. Calls exit and
- * does not return.
- */
-void
-sigexit(struct thread *td, int sig)
-{
- struct proc *p = td->td_proc;
- const char *coreinfo;
- int rv;
- bool logexit;
-
- PROC_LOCK_ASSERT(p, MA_OWNED);
- proc_set_p2_wexit(p);
-
- p->p_acflag |= AXSIG;
- if ((p->p_flag2 & P2_LOGSIGEXIT_CTL) == 0)
- logexit = kern_logsigexit != 0;
- else
- logexit = (p->p_flag2 & P2_LOGSIGEXIT_ENABLE) != 0;
-
- /*
- * We must be single-threading to generate a core dump. This
- * ensures that the registers in the core file are up-to-date.
- * Also, the ELF dump handler assumes that the thread list doesn't
- * change out from under it.
- *
- * XXX If another thread attempts to single-thread before us
- * (e.g. via fork()), we won't get a dump at all.
- */
- if ((sigprop(sig) & SIGPROP_CORE) &&
- thread_single(p, SINGLE_NO_EXIT) == 0) {
- p->p_sig = sig;
- /*
- * Log signals which would cause core dumps
- * (Log as LOG_INFO to appease those who don't want
- * these messages.)
- * XXX : Todo, as well as euid, write out ruid too
- * Note that coredump() drops proc lock.
- */
- rv = coredump(td);
- switch (rv) {
- case 0:
- sig |= WCOREFLAG;
- coreinfo = " (core dumped)";
- break;
- case EFAULT:
- coreinfo = " (no core dump - bad address)";
- break;
- case EINVAL:
- coreinfo = " (no core dump - invalid argument)";
- break;
- case EFBIG:
- coreinfo = " (no core dump - too large)";
- break;
- default:
- coreinfo = " (no core dump - other error)";
- break;
- }
- if (logexit)
- log(LOG_INFO,
- "pid %d (%s), jid %d, uid %d: exited on "
- "signal %d%s\n", p->p_pid, p->p_comm,
- p->p_ucred->cr_prison->pr_id,
- td->td_ucred->cr_uid,
- sig &~ WCOREFLAG, coreinfo);
- } else
- PROC_UNLOCK(p);
- exit1(td, 0, sig);
- /* NOTREACHED */
-}
-
-/*
* Send queued SIGCHLD to parent when child process's state
* is changed.
*/
@@ -3803,477 +3718,6 @@ childproc_exited(struct proc *p)
sigparent(p, reason, status);
}
-#define MAX_NUM_CORE_FILES 100000
-#ifndef NUM_CORE_FILES
-#define NUM_CORE_FILES 5
-#endif
-CTASSERT(NUM_CORE_FILES >= 0 && NUM_CORE_FILES <= MAX_NUM_CORE_FILES);
-static int num_cores = NUM_CORE_FILES;
-
-static int
-sysctl_debug_num_cores_check (SYSCTL_HANDLER_ARGS)
-{
- int error;
- int new_val;
-
- new_val = num_cores;
- error = sysctl_handle_int(oidp, &new_val, 0, req);
- if (error != 0 || req->newptr == NULL)
- return (error);
- if (new_val > MAX_NUM_CORE_FILES)
- new_val = MAX_NUM_CORE_FILES;
- if (new_val < 0)
- new_val = 0;
- num_cores = new_val;
- return (0);
-}
-SYSCTL_PROC(_debug, OID_AUTO, ncores,
- CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, 0, sizeof(int),
- sysctl_debug_num_cores_check, "I",
- "Maximum number of generated process corefiles while using index format");
-
-#define GZIP_SUFFIX ".gz"
-#define ZSTD_SUFFIX ".zst"
-
-int compress_user_cores = 0;
-
-static int
-sysctl_compress_user_cores(SYSCTL_HANDLER_ARGS)
-{
- int error, val;
-
- val = compress_user_cores;
- error = sysctl_handle_int(oidp, &val, 0, req);
- if (error != 0 || req->newptr == NULL)
- return (error);
- if (val != 0 && !compressor_avail(val))
- return (EINVAL);
- compress_user_cores = val;
- return (error);
-}
-SYSCTL_PROC(_kern, OID_AUTO, compress_user_cores,
- CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int),
- sysctl_compress_user_cores, "I",
- "Enable compression of user corefiles ("
- __XSTRING(COMPRESS_GZIP) " = gzip, "
- __XSTRING(COMPRESS_ZSTD) " = zstd)");
-
-int compress_user_cores_level = 6;
-SYSCTL_INT(_kern, OID_AUTO, compress_user_cores_level, CTLFLAG_RWTUN,
- &compress_user_cores_level, 0,
- "Corefile compression level");
-
-/*
- * Protect the access to corefilename[] by allproc_lock.
- */
-#define corefilename_lock allproc_lock
-
-static char corefilename[MAXPATHLEN] = {"%N.core"};
-TUNABLE_STR("kern.corefile", corefilename, sizeof(corefilename));
-
-static int
-sysctl_kern_corefile(SYSCTL_HANDLER_ARGS)
-{
- int error;
-
- sx_xlock(&corefilename_lock);
- error = sysctl_handle_string(oidp, corefilename, sizeof(corefilename),
- req);
- sx_xunlock(&corefilename_lock);
-
- return (error);
-}
-SYSCTL_PROC(_kern, OID_AUTO, corefile, CTLTYPE_STRING | CTLFLAG_RW |
- CTLFLAG_MPSAFE, 0, 0, sysctl_kern_corefile, "A",
- "Process corefile name format string");
-
-static void
-vnode_close_locked(struct thread *td, struct vnode *vp)
-{
-
- VOP_UNLOCK(vp);
- vn_close(vp, FWRITE, td->td_ucred, td);
-}
-
-/*
- * If the core format has a %I in it, then we need to check
- * for existing corefiles before defining a name.
- * To do this we iterate over 0..ncores to find a
- * non-existing core file name to use. If all core files are
- * already used we choose the oldest one.
- */
-static int
-corefile_open_last(struct thread *td, char *name, int indexpos,
- int indexlen, int ncores, struct vnode **vpp)
-{
- struct vnode *oldvp, *nextvp, *vp;
- struct vattr vattr;
- struct nameidata nd;
- int error, i, flags, oflags, cmode;
- char ch;
- struct timespec lasttime;
-
- nextvp = oldvp = NULL;
- cmode = S_IRUSR | S_IWUSR;
- oflags = VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE |
- (capmode_coredump ? VN_OPEN_NOCAPCHECK : 0);
-
- for (i = 0; i < ncores; i++) {
- flags = O_CREAT | FWRITE | O_NOFOLLOW;
-
- ch = name[indexpos + indexlen];
- (void)snprintf(name + indexpos, indexlen + 1, "%.*u", indexlen,
- i);
- name[indexpos + indexlen] = ch;
-
- NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name);
- error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred,
- NULL);
- if (error != 0)
- break;
-
- vp = nd.ni_vp;
- NDFREE_PNBUF(&nd);
- if ((flags & O_CREAT) == O_CREAT) {
- nextvp = vp;
- break;
- }
-
- error = VOP_GETATTR(vp, &vattr, td->td_ucred);
- if (error != 0) {
- vnode_close_locked(td, vp);
- break;
- }
-
- if (oldvp == NULL ||
- lasttime.tv_sec > vattr.va_mtime.tv_sec ||
- (lasttime.tv_sec == vattr.va_mtime.tv_sec &&
- lasttime.tv_nsec >= vattr.va_mtime.tv_nsec)) {
- if (oldvp != NULL)
- vn_close(oldvp, FWRITE, td->td_ucred, td);
- oldvp = vp;
- VOP_UNLOCK(oldvp);
- lasttime = vattr.va_mtime;
- } else {
- vnode_close_locked(td, vp);
- }
- }
-
- if (oldvp != NULL) {
- if (nextvp == NULL) {
- if ((td->td_proc->p_flag & P_SUGID) != 0) {
- error = EFAULT;
- vn_close(oldvp, FWRITE, td->td_ucred, td);
- } else {
- nextvp = oldvp;
- error = vn_lock(nextvp, LK_EXCLUSIVE);
- if (error != 0) {
- vn_close(nextvp, FWRITE, td->td_ucred,
- td);
- nextvp = NULL;
- }
- }
- } else {
- vn_close(oldvp, FWRITE, td->td_ucred, td);
- }
- }
- if (error != 0) {
- if (nextvp != NULL)
- vnode_close_locked(td, oldvp);
- } else {
- *vpp = nextvp;
- }
-
- return (error);
-}
-
-/*
- * corefile_open(comm, uid, pid, td, compress, vpp, namep)
- * Expand the name described in corefilename, using name, uid, and pid
- * and open/create core file.
- * corefilename is a printf-like string, with three format specifiers:
- * %N name of process ("name")
- * %P process id (pid)
- * %U user id (uid)
- * For example, "%N.core" is the default; they can be disabled completely
- * by using "/dev/null", or all core files can be stored in "/cores/%U/%N-%P".
- * This is controlled by the sysctl variable kern.corefile (see above).
- */
-static int
-corefile_open(const char *comm, uid_t uid, pid_t pid, struct thread *td,
- int compress, int signum, struct vnode **vpp, char **namep)
-{
- struct sbuf sb;
- struct nameidata nd;
- const char *format;
- char *hostname, *name;
- int cmode, error, flags, i, indexpos, indexlen, oflags, ncores;
-
- hostname = NULL;
- format = corefilename;
- name = malloc(MAXPATHLEN, M_TEMP, M_WAITOK | M_ZERO);
- indexlen = 0;
- indexpos = -1;
- ncores = num_cores;
- (void)sbuf_new(&sb, name, MAXPATHLEN, SBUF_FIXEDLEN);
- sx_slock(&corefilename_lock);
- for (i = 0; format[i] != '\0'; i++) {
- switch (format[i]) {
- case '%': /* Format character */
- i++;
- switch (format[i]) {
- case '%':
- sbuf_putc(&sb, '%');
- break;
- case 'H': /* hostname */
- if (hostname == NULL) {
- hostname = malloc(MAXHOSTNAMELEN,
- M_TEMP, M_WAITOK);
- }
- getcredhostname(td->td_ucred, hostname,
- MAXHOSTNAMELEN);
- sbuf_cat(&sb, hostname);
- break;
- case 'I': /* autoincrementing index */
- if (indexpos != -1) {
- sbuf_printf(&sb, "%%I");
- break;
- }
-
- indexpos = sbuf_len(&sb);
- sbuf_printf(&sb, "%u", ncores - 1);
- indexlen = sbuf_len(&sb) - indexpos;
- break;
- case 'N': /* process name */
- sbuf_printf(&sb, "%s", comm);
- break;
- case 'P': /* process id */
- sbuf_printf(&sb, "%u", pid);
- break;
- case 'S': /* signal number */
- sbuf_printf(&sb, "%i", signum);
- break;
- case 'U': /* user id */
- sbuf_printf(&sb, "%u", uid);
- break;
- default:
- log(LOG_ERR,
- "Unknown format character %c in "
- "corename `%s'\n", format[i], format);
- break;
- }
- break;
- default:
- sbuf_putc(&sb, format[i]);
- break;
- }
- }
- sx_sunlock(&corefilename_lock);
- free(hostname, M_TEMP);
- if (compress == COMPRESS_GZIP)
- sbuf_cat(&sb, GZIP_SUFFIX);
- else if (compress == COMPRESS_ZSTD)
- sbuf_cat(&sb, ZSTD_SUFFIX);
- if (sbuf_error(&sb) != 0) {
- log(LOG_ERR, "pid %ld (%s), uid (%lu): corename is too "
- "long\n", (long)pid, comm, (u_long)uid);
- sbuf_delete(&sb);
- free(name, M_TEMP);
- return (ENOMEM);
- }
- sbuf_finish(&sb);
- sbuf_delete(&sb);
-
- if (indexpos != -1) {
- error = corefile_open_last(td, name, indexpos, indexlen, ncores,
- vpp);
- if (error != 0) {
- log(LOG_ERR,
- "pid %d (%s), uid (%u): Path `%s' failed "
- "on initial open test, error = %d\n",
- pid, comm, uid, name, error);
- }
- } else {
- cmode = S_IRUSR | S_IWUSR;
- oflags = VN_OPEN_NOAUDIT | VN_OPEN_NAMECACHE |
- (capmode_coredump ? VN_OPEN_NOCAPCHECK : 0);
- flags = O_CREAT | FWRITE | O_NOFOLLOW;
- if ((td->td_proc->p_flag & P_SUGID) != 0)
- flags |= O_EXCL;
-
- NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_SYSSPACE, name);
- error = vn_open_cred(&nd, &flags, cmode, oflags, td->td_ucred,
- NULL);
- if (error == 0) {
- *vpp = nd.ni_vp;
- NDFREE_PNBUF(&nd);
- }
- }
-
- if (error != 0) {
-#ifdef AUDIT
- audit_proc_coredump(td, name, error);
-#endif
- free(name, M_TEMP);
- return (error);
- }
- *namep = name;
- return (0);
-}
-
-/*
- * Dump a process' core. The main routine does some
- * policy checking, and creates the name of the coredump;
- * then it passes on a vnode and a size limit to the process-specific
- * coredump routine if there is one; if there _is not_ one, it returns
- * ENOSYS; otherwise it returns the error from the process-specific routine.
- */
-
-static int
-coredump(struct thread *td)
-{
- struct proc *p = td->td_proc;
- struct ucred *cred = td->td_ucred;
- struct vnode *vp;
- struct flock lf;
- struct vattr vattr;
- size_t fullpathsize;
- int error, error1, jid, locked, ppid, sig;
- char *name; /* name of corefile */
- void *rl_cookie;
- off_t limit;
- char *fullpath, *freepath = NULL;
- struct sbuf *sb;
-
- PROC_LOCK_ASSERT(p, MA_OWNED);
- MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td);
-
- if (!do_coredump || (!sugid_coredump && (p->p_flag & P_SUGID) != 0) ||
- (p->p_flag2 & P2_NOTRACE) != 0) {
- PROC_UNLOCK(p);
- return (EFAULT);
- }
-
- /*
- * Note that the bulk of limit checking is done after
- * the corefile is created. The exception is if the limit
- * for corefiles is 0, in which case we don't bother
- * creating the corefile at all. This layout means that
- * a corefile is truncated instead of not being created,
- * if it is larger than the limit.
- */
- limit = (off_t)lim_cur(td, RLIMIT_CORE);
- if (limit == 0 || racct_get_available(p, RACCT_CORE) == 0) {
- PROC_UNLOCK(p);
- return (EFBIG);
- }
-
- ppid = p->p_oppid;
- sig = p->p_sig;
- jid = p->p_ucred->cr_prison->pr_id;
- PROC_UNLOCK(p);
-
- error = corefile_open(p->p_comm, cred->cr_uid, p->p_pid, td,
- compress_user_cores, p->p_sig, &vp, &name);
- if (error != 0)
- return (error);
-
- /*
- * Don't dump to non-regular files or files with links.
- * Do not dump into system files. Effective user must own the corefile.
- */
- if (vp->v_type != VREG || VOP_GETATTR(vp, &vattr, cred) != 0 ||
- vattr.va_nlink != 1 || (vp->v_vflag & VV_SYSTEM) != 0 ||
- vattr.va_uid != cred->cr_uid) {
- VOP_UNLOCK(vp);
- error = EFAULT;
- goto out;
- }
-
- VOP_UNLOCK(vp);
-
- /* Postpone other writers, including core dumps of other processes. */
- rl_cookie = vn_rangelock_wlock(vp, 0, OFF_MAX);
-
- lf.l_whence = SEEK_SET;
- lf.l_start = 0;
- lf.l_len = 0;
- lf.l_type = F_WRLCK;
- locked = (VOP_ADVLOCK(vp, (caddr_t)p, F_SETLK, &lf, F_FLOCK) == 0);
-
- VATTR_NULL(&vattr);
- vattr.va_size = 0;
- if (set_core_nodump_flag)
- vattr.va_flags = UF_NODUMP;
- vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
- VOP_SETATTR(vp, &vattr, cred);
- VOP_UNLOCK(vp);
- PROC_LOCK(p);
- p->p_acflag |= ACORE;
- PROC_UNLOCK(p);
-
- if (p->p_sysent->sv_coredump != NULL) {
- error = p->p_sysent->sv_coredump(td, vp, limit, 0);
- } else {
- error = ENOSYS;
- }
-
- if (locked) {
- lf.l_type = F_UNLCK;
- VOP_ADVLOCK(vp, (caddr_t)p, F_UNLCK, &lf, F_FLOCK);
- }
- vn_rangelock_unlock(vp, rl_cookie);
-
- /*
- * Notify the userland helper that a process triggered a core dump.
- * This allows the helper to run an automated debugging session.
- */
- if (error != 0 || coredump_devctl == 0)
- goto out;
- sb = sbuf_new_auto();
- if (vn_fullpath_global(p->p_textvp, &fullpath, &freepath) != 0)
- goto out2;
- sbuf_cat(sb, "comm=\"");
- devctl_safe_quote_sb(sb, fullpath);
- free(freepath, M_TEMP);
- sbuf_cat(sb, "\" core=\"");
-
- /*
- * We can't lookup core file vp directly. When we're replacing a core, and
- * other random times, we flush the name cache, so it will fail. Instead,
- * if the path of the core is relative, add the current dir in front if it.
- */
- if (name[0] != '/') {
- fullpathsize = MAXPATHLEN;
- freepath = malloc(fullpathsize, M_TEMP, M_WAITOK);
- if (vn_getcwd(freepath, &fullpath, &fullpathsize) != 0) {
- free(freepath, M_TEMP);
- goto out2;
- }
- devctl_safe_quote_sb(sb, fullpath);
- free(freepath, M_TEMP);
- sbuf_putc(sb, '/');
- }
- devctl_safe_quote_sb(sb, name);
- sbuf_putc(sb, '"');
-
- sbuf_printf(sb, " jid=%d pid=%d ppid=%d signo=%d",
- jid, p->p_pid, ppid, sig);
- if (sbuf_finish(sb) == 0)
- devctl_notify("kernel", "signal", "coredump", sbuf_data(sb));
-out2:
- sbuf_delete(sb);
-out:
- error1 = vn_close(vp, FWRITE, cred, td);
- if (error == 0)
- error = error1;
-#ifdef AUDIT
- audit_proc_coredump(td, name, error);
-#endif
- free(name, M_TEMP);
- return (error);
-}
-
/*
* Nonexistent system call-- signal process (may want to handle it). Flag
* error in case process won't see signal immediately (blocked or ignored).
diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c
index 46226cc31980..25da134661e9 100644
--- a/sys/kern/kern_sysctl.c
+++ b/sys/kern/kern_sysctl.c
@@ -2368,7 +2368,7 @@ sysctl_root(SYSCTL_HANDLER_ARGS)
priv = PRIV_SYSCTL_WRITEJAIL;
#ifdef VIMAGE
else if ((oid->oid_kind & CTLFLAG_VNET) &&
- prison_owns_vnet(req->td->td_ucred))
+ prison_owns_vnet(req->td->td_ucred->cr_prison))
priv = PRIV_SYSCTL_WRITEJAIL;
#endif
else
diff --git a/sys/kern/kern_ucoredump.c b/sys/kern/kern_ucoredump.c
new file mode 100644
index 000000000000..d425596b5f24
--- /dev/null
+++ b/sys/kern/kern_ucoredump.c
@@ -0,0 +1,299 @@
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1982, 1986, 1989, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <sys/acct.h>
+#include <sys/compressor.h>
+#include <sys/jail.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/proc.h>
+#include <sys/signalvar.h>
+#include <sys/racct.h>
+#include <sys/resourcevar.h>
+#include <sys/rmlock.h>
+#include <sys/sysctl.h>
+#include <sys/syslog.h>
+#include <sys/ucoredump.h>
+#include <sys/wait.h>
+
+static int coredump(struct thread *td, const char **);
+
+int compress_user_cores = 0;
+
+static SLIST_HEAD(, coredumper) coredumpers =
+ SLIST_HEAD_INITIALIZER(coredumpers);
+static struct rmlock coredump_rmlock;
+RM_SYSINIT(coredump_lock, &coredump_rmlock, "coredump_lock");
+
+static int kern_logsigexit = 1;
+SYSCTL_INT(_kern, KERN_LOGSIGEXIT, logsigexit, CTLFLAG_RW,
+ &kern_logsigexit, 0,
+ "Log processes quitting on abnormal signals to syslog(3)");
+
+static int sugid_coredump;
+SYSCTL_INT(_kern, OID_AUTO, sugid_coredump, CTLFLAG_RWTUN,
+ &sugid_coredump, 0, "Allow setuid and setgid processes to dump core");
+
+static int do_coredump = 1;
+SYSCTL_INT(_kern, OID_AUTO, coredump, CTLFLAG_RW,
+ &do_coredump, 0, "Enable/Disable coredumps");
+
+static int
+sysctl_compress_user_cores(SYSCTL_HANDLER_ARGS)
+{
+ int error, val;
+
+ val = compress_user_cores;
+ error = sysctl_handle_int(oidp, &val, 0, req);
+ if (error != 0 || req->newptr == NULL)
+ return (error);
+ if (val != 0 && !compressor_avail(val))
+ return (EINVAL);
+ compress_user_cores = val;
+ return (error);
+}
+SYSCTL_PROC(_kern, OID_AUTO, compress_user_cores,
+ CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int),
+ sysctl_compress_user_cores, "I",
+ "Enable compression of user corefiles ("
+ __XSTRING(COMPRESS_GZIP) " = gzip, "
+ __XSTRING(COMPRESS_ZSTD) " = zstd)");
+
+int compress_user_cores_level = 6;
+SYSCTL_INT(_kern, OID_AUTO, compress_user_cores_level, CTLFLAG_RWTUN,
+ &compress_user_cores_level, 0,
+ "Corefile compression level");
+
+void
+coredumper_register(struct coredumper *cd)
+{
+
+ blockcount_init(&cd->cd_refcount);
+ rm_wlock(&coredump_rmlock);
+ SLIST_INSERT_HEAD(&coredumpers, cd, cd_entry);
+ rm_wunlock(&coredump_rmlock);
+}
+
+void
+coredumper_unregister(struct coredumper *cd)
+{
+
+ rm_wlock(&coredump_rmlock);
+ SLIST_REMOVE(&coredumpers, cd, coredumper, cd_entry);
+ rm_wunlock(&coredump_rmlock);
+
+ /*
+ * Wait for any in-process coredumps to finish before returning.
+ */
+ blockcount_wait(&cd->cd_refcount, NULL, "dumpwait", 0);
+}
+
+/*
+ * Force the current process to exit with the specified signal, dumping core
+ * if appropriate. We bypass the normal tests for masked and caught signals,
+ * allowing unrecoverable failures to terminate the process without changing
+ * signal state. Mark the accounting record with the signal termination.
+ * If dumping core, save the signal number for the debugger. Calls exit and
+ * does not return.
+ */
+void
+sigexit(struct thread *td, int sig)
+{
+ struct proc *p = td->td_proc;
+ int rv;
+ bool logexit;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ proc_set_p2_wexit(p);
+
+ p->p_acflag |= AXSIG;
+ if ((p->p_flag2 & P2_LOGSIGEXIT_CTL) == 0)
+ logexit = kern_logsigexit != 0;
+ else
+ logexit = (p->p_flag2 & P2_LOGSIGEXIT_ENABLE) != 0;
+
+ /*
+ * We must be single-threading to generate a core dump. This
+ * ensures that the registers in the core file are up-to-date.
+ * Also, the ELF dump handler assumes that the thread list doesn't
+ * change out from under it.
+ *
+ * XXX If another thread attempts to single-thread before us
+ * (e.g. via fork()), we won't get a dump at all.
+ */
+ if (sig_do_core(sig) && thread_single(p, SINGLE_NO_EXIT) == 0) {
+ const char *err = NULL;
+
+ p->p_sig = sig;
+ /*
+ * Log signals which would cause core dumps
+ * (Log as LOG_INFO to appease those who don't want
+ * these messages.)
+ * XXX : Todo, as well as euid, write out ruid too
+ * Note that coredump() drops proc lock.
+ */
+ rv = coredump(td, &err);
+ if (rv == 0) {
+ MPASS(err == NULL);
+ sig |= WCOREFLAG;
+ } else if (err == NULL) {
+ switch (rv) {
+ case EFAULT:
+ err = "bad address";
+ break;
+ case EINVAL:
+ err = "invalild argument";
+ break;
+ case EFBIG:
+ err = "too large";
+ break;
+ default:
+ err = "other error";
+ break;
+ }
+ }
+ if (logexit)
+ log(LOG_INFO,
+ "pid %d (%s), jid %d, uid %d: exited on "
+ "signal %d (%s%s)\n", p->p_pid, p->p_comm,
+ p->p_ucred->cr_prison->pr_id,
+ td->td_ucred->cr_uid, sig &~ WCOREFLAG,
+ err != NULL ? "no core dump - " : "core dumped",
+ err != NULL ? err : "");
+ } else
+ PROC_UNLOCK(p);
+ exit1(td, 0, sig);
+ /* NOTREACHED */
+}
+
+
+/*
+ * Dump a process' core. The main routine does some
+ * policy checking, and creates the name of the coredump;
+ * then it passes on a vnode and a size limit to the process-specific
+ * coredump routine if there is one; if there _is not_ one, it returns
+ * ENOSYS; otherwise it returns the error from the process-specific routine.
+ */
+static int
+coredump(struct thread *td, const char **errmsg)
+{
+ struct coredumper *iter, *chosen;
+ struct proc *p = td->td_proc;
+ struct rm_priotracker tracker;
+ off_t limit;
+ int error, priority;
+
+ PROC_LOCK_ASSERT(p, MA_OWNED);
+ MPASS((p->p_flag & P_HADTHREADS) == 0 || p->p_singlethread == td);
+
+ if (!do_coredump || (!sugid_coredump && (p->p_flag & P_SUGID) != 0) ||
+ (p->p_flag2 & P2_NOTRACE) != 0) {
+ PROC_UNLOCK(p);
+
+ if (!do_coredump)
+ *errmsg = "denied by kern.coredump";
+ else if ((p->p_flag2 & P2_NOTRACE) != 0)
+ *errmsg = "process has trace disabled";
+ else
+ *errmsg = "sugid process denied by kern.sugid_coredump";
+ return (EFAULT);
+ }
+
+ /*
+ * Note that the bulk of limit checking is done after
+ * the corefile is created. The exception is if the limit
+ * for corefiles is 0, in which case we don't bother
+ * creating the corefile at all. This layout means that
+ * a corefile is truncated instead of not being created,
+ * if it is larger than the limit.
+ */
+ limit = (off_t)lim_cur(td, RLIMIT_CORE);
+ if (limit == 0 || racct_get_available(p, RACCT_CORE) == 0) {
+ PROC_UNLOCK(p);
+ *errmsg = "coredumpsize limit is 0";
+ return (EFBIG);
+ }
+
+ rm_rlock(&coredump_rmlock, &tracker);
+ priority = -1;
+ chosen = NULL;
+ SLIST_FOREACH(iter, &coredumpers, cd_entry) {
+ if (iter->cd_probe == NULL) {
+ /*
+ * If we haven't found anything of a higher priority
+ * yet, we'll call this a GENERIC. Ideally, we want
+ * coredumper modules to include a probe function.
+ */
+ if (priority < 0) {
+ priority = COREDUMPER_GENERIC;
+ chosen = iter;
+ }
+
+ continue;
+ }
+
+ error = (*iter->cd_probe)(td);
+ if (error < 0)
+ continue;
+
+ /*
+ * Higher priority than previous options.
+ */
+ if (error > priority) {
+ priority = error;
+ chosen = iter;
+ }
+ }
+
+ /*
+ * Acquire our refcount before we drop the lock so that
+ * coredumper_unregister() can safely assume that the refcount will only
+ * go down once it's dropped the rmlock.
+ */
+ blockcount_acquire(&chosen->cd_refcount, 1);
+ rm_runlock(&coredump_rmlock, &tracker);
+
+ /* Currently, we always have the vnode dumper built in. */
+ MPASS(chosen != NULL);
+ error = ((*chosen->cd_handle)(td, limit));
+ PROC_LOCK_ASSERT(p, MA_NOTOWNED);
+
+ blockcount_release(&chosen->cd_refcount, 1);
+
+ return (error);
+}
diff --git a/sys/kern/subr_compressor.c b/sys/kern/subr_compressor.c
index 280264881241..5d59622e0455 100644
--- a/sys/kern/subr_compressor.c
+++ b/sys/kern/subr_compressor.c
@@ -538,6 +538,12 @@ compressor_init(compressor_cb_t cb, int format, size_t maxiosize, int level,
return (s);
}
+int
+compressor_format(const struct compressor *stream)
+{
+ return (stream->methods->format);
+}
+
void
compressor_reset(struct compressor *stream)
{
diff --git a/sys/kern/sys_generic.c b/sys/kern/sys_generic.c
index b472aaea89e6..5606b36f772f 100644
--- a/sys/kern/sys_generic.c
+++ b/sys/kern/sys_generic.c
@@ -2269,6 +2269,7 @@ exterr_copyout(struct thread *td)
ue.error = 0;
sz = sizeof(ue.error);
} else {
+ ktrexterr(td);
sz = sizeof(ue) - __offsetof(struct uexterror, error);
}
error = copyout(&ue.error, uloc, sz);
@@ -2335,7 +2336,6 @@ exterr_set(int eerror, int category, const char *mmsg, uintptr_t pp1,
td->td_kexterr.p1 = pp1;
td->td_kexterr.p2 = pp2;
td->td_kexterr.src_line = line;
- ktrexterr(td);
}
return (eerror);
}
diff --git a/sys/kern/uipc_ktls.c b/sys/kern/uipc_ktls.c
index ce09042abdac..66ce1b5a081d 100644
--- a/sys/kern/uipc_ktls.c
+++ b/sys/kern/uipc_ktls.c
@@ -1207,7 +1207,7 @@ sb_mark_notready(struct sockbuf *sb)
for (; m != NULL; m = m->m_next) {
KASSERT(m->m_nextpkt == NULL, ("%s: m_nextpkt != NULL",
__func__));
- KASSERT((m->m_flags & M_NOTAVAIL) == 0, ("%s: mbuf not avail",
+ KASSERT((m->m_flags & M_NOTREADY) == 0, ("%s: mbuf not ready",
__func__));
KASSERT(sb->sb_acc >= m->m_len, ("%s: sb_acc < m->m_len",
__func__));
diff --git a/sys/kern/uipc_shm.c b/sys/kern/uipc_shm.c
index 6f83b875a6b6..85fe48ddd466 100644
--- a/sys/kern/uipc_shm.c
+++ b/sys/kern/uipc_shm.c
@@ -1134,10 +1134,10 @@ shm_doremove(struct shm_mapping *map)
int
kern_shm_open2(struct thread *td, const char *userpath, int flags, mode_t mode,
- int shmflags, struct filecaps *fcaps, const char *name __unused)
+ int shmflags, struct filecaps *fcaps, const char *name __unused,
+ struct shmfd *shmfd)
{
struct pwddesc *pdp;
- struct shmfd *shmfd;
struct file *fp;
char *path;
void *rl_cookie;
@@ -1214,23 +1214,41 @@ kern_shm_open2(struct thread *td, const char *userpath, int flags, mode_t mode,
if (error != 0)
goto outnofp;
- /* A SHM_ANON path pointer creates an anonymous object. */
+ /*
+ * A SHM_ANON path pointer creates an anonymous object. We allow other
+ * parts of the kernel to pre-populate a shmfd and then materialize an
+ * fd for it here as a means to pass data back up to userland. This
+ * doesn't really make sense for named shm objects, but it makes plenty
+ * of sense for anonymous objects.
+ */
if (userpath == SHM_ANON) {
- /* A read-only anonymous object is pointless. */
- if ((flags & O_ACCMODE) == O_RDONLY) {
- error = EINVAL;
- goto out;
- }
- shmfd = shm_alloc(td->td_ucred, cmode, largepage);
- if (shmfd == NULL) {
- error = ENOMEM;
- goto out;
+ if (shmfd != NULL) {
+ shm_hold(shmfd);
+ } else {
+ /*
+ * A read-only anonymous object is pointless, unless it
+ * was pre-populated by the kernel with the expectation
+ * that a shmfd would later be created for userland to
+ * access it through.
+ */
+ if ((flags & O_ACCMODE) == O_RDONLY) {
+ error = EINVAL;
+ goto out;
+ }
+ shmfd = shm_alloc(td->td_ucred, cmode, largepage);
+ if (shmfd == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+
+ shmfd->shm_seals = initial_seals;
+ shmfd->shm_flags = shmflags;
}
- shmfd->shm_seals = initial_seals;
- shmfd->shm_flags = shmflags;
} else {
fnv = fnv_32_str(path, FNV1_32_INIT);
sx_xlock(&shm_dict_lock);
+
+ MPASS(shmfd == NULL);
shmfd = shm_lookup(path, fnv);
if (shmfd == NULL) {
/* Object does not yet exist, create it if requested. */
@@ -2173,7 +2191,7 @@ kern_shm_open(struct thread *td, const char *path, int flags, mode_t mode,
struct filecaps *caps)
{
- return (kern_shm_open2(td, path, flags, mode, 0, caps, NULL));
+ return (kern_shm_open2(td, path, flags, mode, 0, caps, NULL, NULL));
}
/*
@@ -2191,7 +2209,7 @@ sys_shm_open2(struct thread *td, struct shm_open2_args *uap)
{
return (kern_shm_open2(td, uap->path, uap->flags, uap->mode,
- uap->shmflags, NULL, uap->name));
+ uap->shmflags, NULL, uap->name, NULL));
}
int
diff --git a/sys/kern/uipc_sockbuf.c b/sys/kern/uipc_sockbuf.c
index ec00878cd9a5..745702bd4a4f 100644
--- a/sys/kern/uipc_sockbuf.c
+++ b/sys/kern/uipc_sockbuf.c
@@ -195,14 +195,14 @@ int
sbready(struct sockbuf *sb, struct mbuf *m0, int count)
{
struct mbuf *m;
- u_int blocker;
+ bool blocker;
SOCKBUF_LOCK_ASSERT(sb);
KASSERT(sb->sb_fnrdy != NULL, ("%s: sb %p NULL fnrdy", __func__, sb));
KASSERT(count > 0, ("%s: invalid count %d", __func__, count));
m = m0;
- blocker = (sb->sb_fnrdy == m) ? M_BLOCKED : 0;
+ blocker = (sb->sb_fnrdy == m);
while (count > 0) {
KASSERT(m->m_flags & M_NOTREADY,
@@ -217,8 +217,7 @@ sbready(struct sockbuf *sb, struct mbuf *m0, int count)
m->m_epg_nrdy = 0;
} else
count--;
-
- m->m_flags &= ~(M_NOTREADY | blocker);
+ m->m_flags &= ~M_NOTREADY;
if (blocker)
sb->sb_acc += m->m_len;
m = m->m_next;
@@ -240,12 +239,8 @@ sbready(struct sockbuf *sb, struct mbuf *m0, int count)
}
/* This one was blocking all the queue. */
- for (; m && (m->m_flags & M_NOTREADY) == 0; m = m->m_next) {
- KASSERT(m->m_flags & M_BLOCKED,
- ("%s: m %p !M_BLOCKED", __func__, m));
- m->m_flags &= ~M_BLOCKED;
+ for (; m && (m->m_flags & M_NOTREADY) == 0; m = m->m_next)
sb->sb_acc += m->m_len;
- }
sb->sb_fnrdy = m;
sbready_compress(sb, m0, m);
@@ -269,8 +264,7 @@ sballoc(struct sockbuf *sb, struct mbuf *m)
sb->sb_fnrdy = m;
else
sb->sb_acc += m->m_len;
- } else
- m->m_flags |= M_BLOCKED;
+ }
if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
sb->sb_ctl += m->m_len;
@@ -287,29 +281,29 @@ sballoc(struct sockbuf *sb, struct mbuf *m)
void
sbfree(struct sockbuf *sb, struct mbuf *m)
{
+ struct mbuf *n;
#if 0 /* XXX: not yet: soclose() call path comes here w/o lock. */
SOCKBUF_LOCK_ASSERT(sb);
#endif
-
sb->sb_ccc -= m->m_len;
- if (!(m->m_flags & M_NOTAVAIL))
- sb->sb_acc -= m->m_len;
-
if (m == sb->sb_fnrdy) {
- struct mbuf *n;
-
KASSERT(m->m_flags & M_NOTREADY,
("%s: m %p !M_NOTREADY", __func__, m));
n = m->m_next;
while (n != NULL && !(n->m_flags & M_NOTREADY)) {
- n->m_flags &= ~M_BLOCKED;
sb->sb_acc += n->m_len;
n = n->m_next;
}
sb->sb_fnrdy = n;
+ } else {
+ /* Assert that mbuf is not behind sb_fnrdy. */
+ for (n = sb->sb_fnrdy; n != NULL; n = n->m_next)
+ KASSERT(n != m, ("%s: sb %p freeing %p behind sb_fnrdy",
+ __func__, sb, m));
+ sb->sb_acc -= m->m_len;
}
if (m->m_type != MT_DATA && m->m_type != MT_OOBDATA)
@@ -779,6 +773,7 @@ sbsetopt(struct socket *so, struct sockopt *sopt)
* high-water.
*/
*lowat = (cc > *hiwat) ? *hiwat : cc;
+ *flags &= ~SB_AUTOLOWAT;
break;
}
@@ -1128,13 +1123,7 @@ sbcheck(struct sockbuf *sb, const char *file, int line)
}
fnrdy = m;
}
- if (fnrdy) {
- if (!(m->m_flags & M_NOTAVAIL)) {
- printf("sb %p: fnrdy %p, m %p is avail\n",
- sb, sb->sb_fnrdy, m);
- goto fail;
- }
- } else
+ if (fnrdy == NULL)
acc += m->m_len;
ccc += m->m_len;
mbcnt += MSIZE;
@@ -1601,8 +1590,8 @@ sbcut_internal(struct sockbuf *sb, int len)
next = m->m_nextpkt;
}
if (m->m_len > len) {
- KASSERT(!(m->m_flags & M_NOTAVAIL),
- ("%s: m %p M_NOTAVAIL", __func__, m));
+ KASSERT(!(m->m_flags & M_NOTREADY),
+ ("%s: m %p M_NOTREADY", __func__, m));
m->m_len -= len;
m->m_data += len;
sb->sb_ccc -= len;
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 6c9eb7139cd1..fe2d8d056062 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1211,7 +1211,8 @@ solisten_clone(struct socket *head)
so->so_rcv.sb_timeo = head->sol_sbrcv_timeo;
so->so_snd.sb_timeo = head->sol_sbsnd_timeo;
so->so_rcv.sb_flags = head->sol_sbrcv_flags & SB_AUTOSIZE;
- so->so_snd.sb_flags = head->sol_sbsnd_flags & SB_AUTOSIZE;
+ so->so_snd.sb_flags = head->sol_sbsnd_flags &
+ (SB_AUTOSIZE | SB_AUTOLOWAT);
if ((so->so_proto->pr_flags & PR_SOCKBUF) == 0) {
so->so_snd.sb_mtx = &so->so_snd_mtx;
so->so_rcv.sb_mtx = &so->so_rcv_mtx;
@@ -2988,8 +2989,8 @@ dontblock:
*/
moff = 0;
offset = 0;
- while (m != NULL && !(m->m_flags & M_NOTAVAIL) && uio->uio_resid > 0
- && error == 0) {
+ while (m != NULL && !(m->m_flags & M_NOTREADY) && uio->uio_resid > 0 &&
+ error == 0) {
/*
* If the type of mbuf has changed since the last mbuf
* examined ('type'), end the receive operation.
@@ -3341,7 +3342,7 @@ deliver:
for (m = sb->sb_mb;
m != NULL && m->m_len <= len;
m = m->m_next) {
- KASSERT(!(m->m_flags & M_NOTAVAIL),
+ KASSERT(!(m->m_flags & M_NOTREADY),
("%s: m %p not available", __func__, m));
len -= m->m_len;
uio->uio_resid -= m->m_len;
@@ -4514,6 +4515,9 @@ sokqfilter_generic(struct socket *so, struct knote *kn)
SOCK_BUF_LOCK(so, which);
knlist_add(knl, kn, 1);
sb->sb_flags |= SB_KNOTE;
+ if ((kn->kn_sfflags & NOTE_LOWAT) &&
+ (sb->sb_flags & SB_AUTOLOWAT))
+ sb->sb_flags &= ~SB_AUTOLOWAT;
SOCK_BUF_UNLOCK(so, which);
}
SOCK_UNLOCK(so);
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/kern/vfs_subr.c b/sys/kern/vfs_subr.c
index 918b256e6c59..29774cf87393 100644
--- a/sys/kern/vfs_subr.c
+++ b/sys/kern/vfs_subr.c
@@ -6533,17 +6533,6 @@ vop_read_pgcache_post(void *ap, int rc)
VFS_KNOTE_UNLOCKED(a->a_vp, NOTE_READ);
}
-void
-vop_readdir_post(void *ap, int rc)
-{
- struct vop_readdir_args *a = ap;
-
- if (!rc) {
- VFS_KNOTE_LOCKED(a->a_vp, NOTE_READ);
- INOTIFY(a->a_vp, IN_ACCESS);
- }
-}
-
static struct knlist fs_knlist;
static void
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index c71e0d9ee569..25d40a9806cb 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -2253,10 +2253,10 @@ kern_accessat(struct thread *td, int fd, const char *path,
cred = td->td_ucred;
if ((flag & AT_EACCESS) == 0 &&
((cred->cr_uid != cred->cr_ruid ||
- cred->cr_rgid != cred->cr_groups[0]))) {
+ cred->cr_rgid != cred->cr_gid))) {
usecred = crdup(cred);
usecred->cr_uid = cred->cr_ruid;
- usecred->cr_groups[0] = cred->cr_rgid;
+ usecred->cr_gid = cred->cr_rgid;
td->td_ucred = usecred;
} else
usecred = cred;
diff --git a/sys/kern/vnode_if.src b/sys/kern/vnode_if.src
index 38138a4af921..2e63215b2f97 100644
--- a/sys/kern/vnode_if.src
+++ b/sys/kern/vnode_if.src
@@ -242,8 +242,8 @@ vop_read_pgcache {
%% write vp L L L
-%! write pre VOP_WRITE_PRE
-%! write post VOP_WRITE_POST
+%! write pre vop_write_pre
+%! write post vop_write_post
vop_write {
IN struct vnode *vp;
@@ -380,6 +380,7 @@ vop_symlink {
%% readdir vp L L L
+%! readdir pre vop_readdir_pre
%! readdir post vop_readdir_post
vop_readdir {
diff --git a/sys/modules/Makefile b/sys/modules/Makefile
index 7cb6e2124326..99c9ec9dcd01 100644
--- a/sys/modules/Makefile
+++ b/sys/modules/Makefile
@@ -34,6 +34,7 @@ SUBDIR= \
alq \
${_amd_ecc_inject} \
${_amdgpio} \
+ ${_amdsmu} \
${_amdsbwd} \
${_amdsmn} \
${_amdtemp} \
@@ -772,6 +773,7 @@ _acpi= acpi
_aesni= aesni
.endif
_amd_ecc_inject=amd_ecc_inject
+_amdsmu= amdsmu
_amdsbwd= amdsbwd
_amdsmn= amdsmn
_amdtemp= amdtemp
diff --git a/sys/modules/amdsmu/Makefile b/sys/modules/amdsmu/Makefile
new file mode 100644
index 000000000000..752f57173d61
--- /dev/null
+++ b/sys/modules/amdsmu/Makefile
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2025 The FreeBSD Foundation
+#
+# This software was developed by Aymeric Wibo <obiwac@freebsd.org>
+# under sponsorship from the FreeBSD Foundation.
+
+.PATH: ${SRCTOP}/sys/dev/amdsmu
+
+KMOD= amdsmu
+SRCS= amdsmu.c
+SRCS+= bus_if.h device_if.h pci_if.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/modules/efirt/Makefile b/sys/modules/efirt/Makefile
index 4738996fd4e6..c46484465b68 100644
--- a/sys/modules/efirt/Makefile
+++ b/sys/modules/efirt/Makefile
@@ -9,7 +9,7 @@ SRCS+= device_if.h bus_if.h clock_if.h
DPSRCS+= assym.inc
.if ${MACHINE_CPUARCH} == "amd64"
-SRCS+= opt_hwpmc_hooks.h opt_kstack_pages.h
+SRCS+= opt_acpi.h opt_hwpmc_hooks.h opt_kstack_pages.h
.endif
efirt_support.o: efirt_support.S assym.inc
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/net/if_bridge.c b/sys/net/if_bridge.c
index 5b3ee740d75e..0a35fb4095fb 100644
--- a/sys/net/if_bridge.c
+++ b/sys/net/if_bridge.c
@@ -76,31 +76,34 @@
* heterogeneous bridges).
*/
-#include <sys/cdefs.h>
#include "opt_inet.h"
#include "opt_inet6.h"
+#define EXTERR_CATEGORY EXTERR_CAT_BRIDGE
+
#include <sys/param.h>
+#include <sys/ctype.h> /* string functions */
#include <sys/eventhandler.h>
-#include <sys/mbuf.h>
+#include <sys/exterrvar.h>
+#include <sys/jail.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/priv.h>
+#include <sys/proc.h>
#include <sys/protosw.h>
+#include <sys/random.h>
#include <sys/systm.h>
-#include <sys/jail.h>
-#include <sys/time.h>
#include <sys/socket.h> /* for net/if.h */
#include <sys/sockio.h>
-#include <sys/ctype.h> /* string functions */
-#include <sys/kernel.h>
-#include <sys/random.h>
#include <sys/syslog.h>
#include <sys/sysctl.h>
+#include <sys/time.h>
+
#include <vm/uma.h>
-#include <sys/module.h>
-#include <sys/priv.h>
-#include <sys/proc.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
#include <net/bpf.h>
#include <net/if.h>
@@ -254,8 +257,8 @@ struct bridge_iflist {
uint32_t bif_addrcnt; /* cur. # of addresses */
uint32_t bif_addrexceeded;/* # of address violations */
struct epoch_context bif_epoch_ctx;
- ether_vlanid_t bif_untagged; /* untagged vlan id */
- ifbvlan_set_t bif_vlan_set; /* allowed tagged vlans */
+ ether_vlanid_t bif_pvid; /* port vlan id */
+ ifbvlan_set_t bif_vlan_set; /* if allowed tagged vlans */
};
/*
@@ -404,7 +407,7 @@ static int bridge_ioctl_sma(struct bridge_softc *, void *);
static int bridge_ioctl_sifprio(struct bridge_softc *, void *);
static int bridge_ioctl_sifcost(struct bridge_softc *, void *);
static int bridge_ioctl_sifmaxaddr(struct bridge_softc *, void *);
-static int bridge_ioctl_sifuntagged(struct bridge_softc *, void *);
+static int bridge_ioctl_sifpvid(struct bridge_softc *, void *);
static int bridge_ioctl_sifvlanset(struct bridge_softc *, void *);
static int bridge_ioctl_gifvlanset(struct bridge_softc *, void *);
static int bridge_ioctl_addspan(struct bridge_softc *, void *);
@@ -625,7 +628,7 @@ static const struct bridge_control bridge_control_table[] = {
{ bridge_ioctl_sifmaxaddr, sizeof(struct ifbreq),
BC_F_COPYIN|BC_F_SUSER },
- { bridge_ioctl_sifuntagged, sizeof(struct ifbreq),
+ { bridge_ioctl_sifpvid, sizeof(struct ifbreq),
BC_F_COPYIN|BC_F_SUSER },
{ bridge_ioctl_sifvlanset, sizeof(struct ifbif_vlan_req),
@@ -986,31 +989,37 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case SIOCGDRVSPEC:
case SIOCSDRVSPEC:
if (ifd->ifd_cmd >= bridge_control_table_size) {
- error = EINVAL;
+ error = EXTERROR(EINVAL, "Invalid control command");
break;
}
bc = &bridge_control_table[ifd->ifd_cmd];
if (cmd == SIOCGDRVSPEC &&
(bc->bc_flags & BC_F_COPYOUT) == 0) {
- error = EINVAL;
+ error = EXTERROR(EINVAL,
+ "Inappropriate ioctl for command "
+ "(expected SIOCSDRVSPEC)");
break;
}
else if (cmd == SIOCSDRVSPEC &&
(bc->bc_flags & BC_F_COPYOUT) != 0) {
- error = EINVAL;
+ error = EXTERROR(EINVAL,
+ "Inappropriate ioctl for command "
+ "(expected SIOCGDRVSPEC)");
break;
}
if (bc->bc_flags & BC_F_SUSER) {
error = priv_check(td, PRIV_NET_BRIDGE);
- if (error)
+ if (error) {
+ EXTERROR(error, "PRIV_NET_BRIDGE required");
break;
+ }
}
if (ifd->ifd_len != bc->bc_argsize ||
ifd->ifd_len > sizeof(args)) {
- error = EINVAL;
+ error = EXTERROR(EINVAL, "Invalid argument size");
break;
}
@@ -1062,7 +1071,8 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
oldmtu = sc->sc_ifp->if_mtu;
if (ifr->ifr_mtu < IF_MINMTU) {
- error = EINVAL;
+ error = EXTERROR(EINVAL,
+ "Requested MTU is lower than IF_MINMTU");
break;
}
if (CK_LIST_EMPTY(&sc->sc_iflist)) {
@@ -1088,6 +1098,8 @@ bridge_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
(*bif->bif_ifp->if_ioctl)(bif->bif_ifp,
SIOCSIFMTU, (caddr_t)ifr);
}
+ EXTERROR(error,
+ "Failed to set MTU on member interface");
} else {
sc->sc_ifp->if_mtu = ifr->ifr_mtu;
}
@@ -1125,14 +1137,14 @@ bridge_mutecaps(struct bridge_softc *sc)
mask = BRIDGE_IFCAPS_MASK;
CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
- /* Every member must support it or its disabled */
+ /* Every member must support it or it's disabled */
mask &= bif->bif_savedcaps;
}
CK_LIST_FOREACH(bif, &sc->sc_iflist, bif_next) {
enabled = bif->bif_ifp->if_capenable;
enabled &= ~BRIDGE_IFCAPS_STRIP;
- /* strip off mask bits and enable them again if allowed */
+ /* Strip off mask bits and enable them again if allowed */
enabled &= ~BRIDGE_IFCAPS_MASK;
enabled |= mask;
bridge_set_ifcap(sc, bif, enabled);
@@ -1282,7 +1294,7 @@ bridge_delete_member(struct bridge_softc *sc, struct bridge_iflist *bif,
#endif
break;
}
- /* reneable any interface capabilities */
+ /* Re-enable any interface capabilities */
bridge_set_ifcap(sc, bif, bif->bif_savedcaps);
}
bstp_destroy(&bif->bif_stp); /* prepare to free */
@@ -1318,21 +1330,48 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
ifs = ifunit(req->ifbr_ifsname);
if (ifs == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "No such interface",
+ req->ifbr_ifsname));
if (ifs->if_ioctl == NULL) /* must be supported */
- return (EINVAL);
+ return (EXTERROR(EINVAL, "Interface must support ioctl(2)"));
+
+ /*
+ * If the new interface is a vlan(4), it could be a bridge SVI.
+ * Don't allow such things to be added to bridges.
+ */
+ if (ifs->if_type == IFT_L2VLAN) {
+ struct ifnet *parent;
+ struct epoch_tracker et;
+ bool is_bridge;
+
+ /*
+ * Entering NET_EPOCH with BRIDGE_LOCK held, but this is okay
+ * since we don't sleep here.
+ */
+ NET_EPOCH_ENTER(et);
+ parent = VLAN_TRUNKDEV(ifs);
+ is_bridge = (parent != NULL && parent->if_type == IFT_BRIDGE);
+ NET_EPOCH_EXIT(et);
+
+ if (is_bridge)
+ return (EXTERROR(EINVAL,
+ "Bridge SVI cannot be added to a bridge"));
+ }
/* If it's in the span list, it can't be a member. */
CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
if (ifs == bif->bif_ifp)
- return (EBUSY);
+ return (EXTERROR(EBUSY,
+ "Span interface cannot be a member"));
if (ifs->if_bridge) {
struct bridge_iflist *sbif = ifs->if_bridge;
if (sbif->bif_sc == sc)
- return (EEXIST);
+ return (EXTERROR(EEXIST,
+ "Interface is already a member of this bridge"));
- return (EBUSY);
+ return (EXTERROR(EBUSY,
+ "Interface is already a member of another bridge"));
}
switch (ifs->if_type) {
@@ -1342,7 +1381,7 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
/* permitted interface types */
break;
default:
- return (EINVAL);
+ return (EXTERROR(EINVAL, "Unsupported interface type"));
}
#ifdef INET6
@@ -1394,11 +1433,15 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
CK_STAILQ_FOREACH(ifa, &ifs->if_addrhead, ifa_link) {
#ifdef INET
if (ifa->ifa_addr->sa_family == AF_INET)
- return (EINVAL);
+ return (EXTERROR(EINVAL,
+ "Member interface may not have "
+ "an IPv4 address configured"));
#endif
#ifdef INET6
if (ifa->ifa_addr->sa_family == AF_INET6)
- return (EINVAL);
+ return (EXTERROR(EINVAL,
+ "Member interface may not have "
+ "an IPv6 address configured"));
#endif
}
}
@@ -1420,7 +1463,8 @@ bridge_ioctl_add(struct bridge_softc *sc, void *arg)
" new member %s\n", sc->sc_ifp->if_xname,
ifr.ifr_mtu,
ifs->if_xname);
- return (EINVAL);
+ return (EXTERROR(EINVAL,
+ "Failed to set MTU on new member"));
}
}
@@ -1482,7 +1526,7 @@ bridge_ioctl_del(struct bridge_softc *sc, void *arg)
bif = bridge_lookup_member(sc, req->ifbr_ifsname);
if (bif == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "Interface is not a bridge member"));
bridge_delete_member(sc, bif, 0);
@@ -1498,7 +1542,7 @@ bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
bif = bridge_lookup_member(sc, req->ifbr_ifsname);
if (bif == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "Interface is not a bridge member"));
bp = &bif->bif_stp;
req->ifbr_ifsflags = bif->bif_flags;
@@ -1512,7 +1556,7 @@ bridge_ioctl_gifflags(struct bridge_softc *sc, void *arg)
req->ifbr_addrcnt = bif->bif_addrcnt;
req->ifbr_addrmax = bif->bif_addrmax;
req->ifbr_addrexceeded = bif->bif_addrexceeded;
- req->ifbr_untagged = bif->bif_untagged;
+ req->ifbr_pvid = bif->bif_pvid;
/* Copy STP state options as flags */
if (bp->bp_operedge)
@@ -1541,12 +1585,12 @@ bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
bif = bridge_lookup_member(sc, req->ifbr_ifsname);
if (bif == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "Interface is not a bridge member"));
bp = &bif->bif_stp;
if (req->ifbr_ifsflags & IFBIF_SPAN)
/* SPAN is readonly */
- return (EINVAL);
+ return (EXTERROR(EINVAL, "Span interface cannot be modified"));
NET_EPOCH_ENTER(et);
@@ -1555,7 +1599,8 @@ bridge_ioctl_sifflags(struct bridge_softc *sc, void *arg)
error = bstp_enable(&bif->bif_stp);
if (error) {
NET_EPOCH_EXIT(et);
- return (error);
+ return (EXTERROR(error,
+ "Failed to enable STP"));
}
}
} else {
@@ -1724,7 +1769,7 @@ bridge_ioctl_saddr(struct bridge_softc *sc, void *arg)
bif = bridge_lookup_member(sc, req->ifba_ifsname);
if (bif == NULL) {
NET_EPOCH_EXIT(et);
- return (ENOENT);
+ return (EXTERROR(ENOENT, "Interface is not a bridge member"));
}
/* bridge_rtupdate() may acquire the lock. */
@@ -1858,7 +1903,7 @@ bridge_ioctl_sifprio(struct bridge_softc *sc, void *arg)
bif = bridge_lookup_member(sc, req->ifbr_ifsname);
if (bif == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "Interface is not a bridge member"));
return (bstp_set_port_priority(&bif->bif_stp, req->ifbr_priority));
}
@@ -1871,7 +1916,7 @@ bridge_ioctl_sifcost(struct bridge_softc *sc, void *arg)
bif = bridge_lookup_member(sc, req->ifbr_ifsname);
if (bif == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "Interface is not a bridge member"));
return (bstp_set_path_cost(&bif->bif_stp, req->ifbr_path_cost));
}
@@ -1884,28 +1929,28 @@ bridge_ioctl_sifmaxaddr(struct bridge_softc *sc, void *arg)
bif = bridge_lookup_member(sc, req->ifbr_ifsname);
if (bif == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "Interface is not a bridge member"));
bif->bif_addrmax = req->ifbr_addrmax;
return (0);
}
static int
-bridge_ioctl_sifuntagged(struct bridge_softc *sc, void *arg)
+bridge_ioctl_sifpvid(struct bridge_softc *sc, void *arg)
{
struct ifbreq *req = arg;
struct bridge_iflist *bif;
bif = bridge_lookup_member(sc, req->ifbr_ifsname);
if (bif == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "Interface is not a bridge member"));
- if (req->ifbr_untagged > DOT1Q_VID_MAX)
- return (EINVAL);
+ if (req->ifbr_pvid > DOT1Q_VID_MAX)
+ return (EXTERROR(EINVAL, "Invalid VLAN ID"));
- if (req->ifbr_untagged != DOT1Q_VID_NULL)
+ if (req->ifbr_pvid != DOT1Q_VID_NULL)
bif->bif_flags |= IFBIF_VLANFILTER;
- bif->bif_untagged = req->ifbr_untagged;
+ bif->bif_pvid = req->ifbr_pvid;
return (0);
}
@@ -1917,12 +1962,12 @@ bridge_ioctl_sifvlanset(struct bridge_softc *sc, void *arg)
bif = bridge_lookup_member(sc, req->bv_ifname);
if (bif == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "Interface is not a bridge member"));
/* Reject invalid VIDs. */
if (BRVLAN_TEST(&req->bv_set, DOT1Q_VID_NULL) ||
BRVLAN_TEST(&req->bv_set, DOT1Q_VID_RSVD_IMPL))
- return (EINVAL);
+ return (EXTERROR(EINVAL, "Invalid VLAN ID in set"));
switch (req->bv_op) {
/* Replace the existing vlan set with the new set */
@@ -1942,7 +1987,8 @@ bridge_ioctl_sifvlanset(struct bridge_softc *sc, void *arg)
/* Invalid or unknown operation */
default:
- return (EINVAL);
+ return (EXTERROR(EINVAL,
+ "Unsupported BRDGSIFVLANSET operation"));
}
/*
@@ -1962,7 +2008,7 @@ bridge_ioctl_gifvlanset(struct bridge_softc *sc, void *arg)
bif = bridge_lookup_member(sc, req->bv_ifname);
if (bif == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "Interface is not a bridge member"));
BIT_COPY(BRVLAN_SETSIZE, &bif->bif_vlan_set, &req->bv_set);
return (0);
@@ -1977,14 +2023,16 @@ bridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
ifs = ifunit(req->ifbr_ifsname);
if (ifs == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "No such interface"));
CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
if (ifs == bif->bif_ifp)
- return (EBUSY);
+ return (EXTERROR(EBUSY,
+ "Interface is already a span port"));
if (ifs->if_bridge != NULL)
- return (EBUSY);
+ return (EXTERROR(EEXIST,
+ "Interface is already a bridge member"));
switch (ifs->if_type) {
case IFT_ETHER:
@@ -1992,7 +2040,7 @@ bridge_ioctl_addspan(struct bridge_softc *sc, void *arg)
case IFT_L2VLAN:
break;
default:
- return (EINVAL);
+ return (EXTERROR(EINVAL, "Unsupported interface type"));
}
bif = malloc(sizeof(*bif), M_DEVBUF, M_NOWAIT|M_ZERO);
@@ -2016,14 +2064,14 @@ bridge_ioctl_delspan(struct bridge_softc *sc, void *arg)
ifs = ifunit(req->ifbr_ifsname);
if (ifs == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "No such interface"));
CK_LIST_FOREACH(bif, &sc->sc_spanlist, bif_next)
if (ifs == bif->bif_ifp)
break;
if (bif == NULL)
- return (ENOENT);
+ return (EXTERROR(ENOENT, "Interface is not a span port"));
bridge_delete_span(sc, bif);
@@ -2278,8 +2326,8 @@ bridge_enqueue(struct bridge_softc *sc, struct ifnet *dst_ifp, struct mbuf *m,
* the VLAN header.
*/
if ((bif->bif_flags & IFBIF_VLANFILTER) &&
- bif->bif_untagged != DOT1Q_VID_NULL &&
- VLANTAGOF(m) == bif->bif_untagged) {
+ bif->bif_pvid != DOT1Q_VID_NULL &&
+ VLANTAGOF(m) == bif->bif_pvid) {
m->m_flags &= ~M_VLANTAG;
m->m_pkthdr.ether_vtag = 0;
}
@@ -3145,14 +3193,14 @@ bridge_vfilter_in(const struct bridge_iflist *sbif, struct mbuf *m)
* The frame doesn't have a tag. If the interface does not
* have an untagged vlan configured, drop the frame.
*/
- if (sbif->bif_untagged == DOT1Q_VID_NULL)
+ if (sbif->bif_pvid == DOT1Q_VID_NULL)
return (false);
/*
* Otherwise, insert a new tag based on the interface's
* untagged vlan id.
*/
- m->m_pkthdr.ether_vtag = sbif->bif_untagged;
+ m->m_pkthdr.ether_vtag = sbif->bif_pvid;
m->m_flags |= M_VLANTAG;
} else {
/*
@@ -3213,7 +3261,7 @@ bridge_vfilter_out(const struct bridge_iflist *dbif, const struct mbuf *m)
* If the frame's vlan matches the interfaces's untagged vlan,
* allow it.
*/
- if (vlan == dbif->bif_untagged)
+ if (vlan == dbif->bif_pvid)
return (true);
/*
@@ -3244,10 +3292,11 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst,
BRIDGE_LOCK_OR_NET_EPOCH_ASSERT(sc);
/* Check the source address is valid and not multicast. */
- if (ETHER_IS_MULTICAST(dst) ||
- (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
- dst[3] == 0 && dst[4] == 0 && dst[5] == 0) != 0)
- return (EINVAL);
+ if (ETHER_IS_MULTICAST(dst))
+ return (EXTERROR(EINVAL, "Multicast address not permitted"));
+ if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
+ dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
+ return (EXTERROR(EINVAL, "Zero address not permitted"));
/*
* A route for this destination might already exist. If so,
@@ -3266,13 +3315,14 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst,
if (sc->sc_brtcnt >= sc->sc_brtmax) {
sc->sc_brtexceeded++;
BRIDGE_RT_UNLOCK(sc);
- return (ENOSPC);
+ return (EXTERROR(ENOSPC, "Address table is full"));
}
/* Check per interface address limits (if enabled) */
if (bif->bif_addrmax && bif->bif_addrcnt >= bif->bif_addrmax) {
bif->bif_addrexceeded++;
BRIDGE_RT_UNLOCK(sc);
- return (ENOSPC);
+ return (EXTERROR(ENOSPC,
+ "Interface address limit exceeded"));
}
/*
@@ -3283,7 +3333,8 @@ bridge_rtupdate(struct bridge_softc *sc, const uint8_t *dst,
brt = uma_zalloc(V_bridge_rtnode_zone, M_NOWAIT | M_ZERO);
if (brt == NULL) {
BRIDGE_RT_UNLOCK(sc);
- return (ENOMEM);
+ return (EXTERROR(ENOMEM,
+ "Cannot allocate address node"));
}
brt->brt_vnet = curvnet;
@@ -3631,7 +3682,7 @@ bridge_rtnode_insert(struct bridge_softc *sc, struct bridge_rtnode *brt)
do {
dir = bridge_rtnode_addr_cmp(brt->brt_addr, lbrt->brt_addr);
if (dir == 0 && brt->brt_vlan == lbrt->brt_vlan)
- return (EEXIST);
+ return (EXTERROR(EEXIST, "Address already exists"));
if (dir > 0) {
CK_LIST_INSERT_BEFORE(lbrt, brt, brt_hash);
goto out;
diff --git a/sys/net/if_bridgevar.h b/sys/net/if_bridgevar.h
index 97b63e3d4416..c458dcc152a0 100644
--- a/sys/net/if_bridgevar.h
+++ b/sys/net/if_bridgevar.h
@@ -124,7 +124,7 @@
#define BRDGSPROTO 28 /* set protocol (ifbrparam) */
#define BRDGSTXHC 29 /* set tx hold count (ifbrparam) */
#define BRDGSIFAMAX 30 /* set max interface addrs (ifbreq) */
-#define BRDGSIFUNTAGGED 31 /* set if untagged vlan */
+#define BRDGSIFPVID 31 /* set if PVID */
#define BRDGSIFVLANSET 32 /* set if vlan set */
#define BRDGGIFVLANSET 33 /* get if vlan set */
@@ -144,7 +144,7 @@ struct ifbreq {
uint32_t ifbr_addrcnt; /* member if addr number */
uint32_t ifbr_addrmax; /* member if addr max */
uint32_t ifbr_addrexceeded; /* member if addr violations */
- ether_vlanid_t ifbr_untagged; /* member if untagged vlan */
+ ether_vlanid_t ifbr_pvid; /* member if PVID */
uint8_t pad[32];
};
diff --git a/sys/net/if_gif.h b/sys/net/if_gif.h
index 3c1846b8f82a..c6692d3dd6bc 100644
--- a/sys/net/if_gif.h
+++ b/sys/net/if_gif.h
@@ -120,7 +120,8 @@ int in6_gif_setopts(struct gif_softc *, u_int);
#define GIFGOPTS _IOWR('i', 150, struct ifreq)
#define GIFSOPTS _IOW('i', 151, struct ifreq)
+#define GIF_NOCLAMP 0x0001
#define GIF_IGNORE_SOURCE 0x0002
-#define GIF_OPTMASK (GIF_IGNORE_SOURCE)
+#define GIF_OPTMASK (GIF_NOCLAMP|GIF_IGNORE_SOURCE)
#endif /* _NET_IF_GIF_H_ */
diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c
index 7bdbc565f4ca..fe3e7bbd7fff 100644
--- a/sys/net/if_ovpn.c
+++ b/sys/net/if_ovpn.c
@@ -34,11 +34,13 @@
#include <sys/epoch.h>
#include <sys/file.h>
#include <sys/filedesc.h>
+#include <sys/jail.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/mbuf.h>
#include <sys/module.h>
#include <sys/nv.h>
+#include <sys/osd.h>
#include <sys/priv.h>
#include <sys/protosw.h>
#include <sys/rmlock.h>
@@ -79,7 +81,6 @@
#include "if_ovpn.h"
struct ovpn_kkey_dir {
- int refcount;
uint8_t key[32];
uint8_t keylen;
uint8_t nonce[8];
@@ -132,6 +133,9 @@ struct ovpn_notification {
/* Delete notification */
enum ovpn_del_reason del_reason;
struct ovpn_peer_counters counters;
+
+ /* Float notification */
+ struct sockaddr_storage address;
};
struct ovpn_softc;
@@ -196,6 +200,10 @@ struct ovpn_softc {
struct epoch_context epoch_ctx;
};
+struct ovpn_mtag {
+ struct sockaddr_storage addr;
+};
+
static struct ovpn_kpeer *ovpn_find_peer(struct ovpn_softc *, uint32_t);
static bool ovpn_udp_input(struct mbuf *, int, struct inpcb *,
const struct sockaddr *, void *);
@@ -205,7 +213,10 @@ static int ovpn_encap(struct ovpn_softc *, uint32_t, struct mbuf *);
static int ovpn_get_af(struct mbuf *);
static void ovpn_free_kkey_dir(struct ovpn_kkey_dir *);
static bool ovpn_check_replay(struct ovpn_kkey_dir *, uint32_t);
-static int ovpn_peer_compare(struct ovpn_kpeer *, struct ovpn_kpeer *);
+static int ovpn_peer_compare(const struct ovpn_kpeer *,
+ const struct ovpn_kpeer *);
+static bool ovpn_sockaddr_compare(const struct sockaddr *,
+ const struct sockaddr *);
static RB_PROTOTYPE(ovpn_kpeers, ovpn_kpeer, tree, ovpn_peer_compare);
static RB_GENERATE(ovpn_kpeers, ovpn_kpeer, tree, ovpn_peer_compare);
@@ -278,11 +289,48 @@ SYSCTL_INT(_net_link_openvpn, OID_AUTO, netisr_queue,
"Use netisr_queue() rather than netisr_dispatch().");
static int
-ovpn_peer_compare(struct ovpn_kpeer *a, struct ovpn_kpeer *b)
+ovpn_peer_compare(const struct ovpn_kpeer *a, const struct ovpn_kpeer *b)
{
return (a->peerid - b->peerid);
}
+static bool
+ovpn_sockaddr_compare(const struct sockaddr *a,
+ const struct sockaddr *b)
+{
+ if (a->sa_family != b->sa_family)
+ return (false);
+ MPASS(a->sa_len == b->sa_len);
+
+ switch (a->sa_family) {
+ case AF_INET: {
+ const struct sockaddr_in *a4, *b4;
+
+ a4 = (const struct sockaddr_in *)a;
+ b4 = (const struct sockaddr_in *)b;
+
+ if (a4->sin_port != b4->sin_port)
+ return (false);
+
+ return (a4->sin_addr.s_addr == b4->sin_addr.s_addr);
+ }
+ case AF_INET6: {
+ const struct sockaddr_in6 *a6, *b6;
+
+ a6 = (const struct sockaddr_in6 *)a;
+ b6 = (const struct sockaddr_in6 *)b;
+
+ if (a6->sin6_port != b6->sin6_port)
+ return (false);
+
+ return (memcmp(&a6->sin6_addr, &b6->sin6_addr,
+ sizeof(a6->sin6_addr)) == 0);
+ }
+ default:
+ panic("Unknown address family %d", a->sa_family);
+ }
+}
+
static struct ovpn_kpeer *
ovpn_find_peer(struct ovpn_softc *sc, uint32_t peerid)
{
@@ -304,15 +352,15 @@ ovpn_find_only_peer(struct ovpn_softc *sc)
}
static uint16_t
-ovpn_get_port(struct sockaddr_storage *s)
+ovpn_get_port(const struct sockaddr_storage *s)
{
switch (s->ss_family) {
case AF_INET: {
- struct sockaddr_in *in = (struct sockaddr_in *)s;
+ const struct sockaddr_in *in = (const struct sockaddr_in *)s;
return (in->sin_port);
}
case AF_INET6: {
- struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)s;
+ const struct sockaddr_in6 *in6 = (const struct sockaddr_in6 *)s;
return (in6->sin6_port);
}
default:
@@ -320,6 +368,25 @@ ovpn_get_port(struct sockaddr_storage *s)
}
}
+static void
+ovpn_set_port(struct sockaddr_storage *s, unsigned short port)
+{
+ switch (s->ss_family) {
+ case AF_INET: {
+ struct sockaddr_in *in = (struct sockaddr_in *)s;
+ in->sin_port = port;
+ break;
+ }
+ case AF_INET6: {
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)s;
+ in6->sin6_port = port;
+ break;
+ }
+ default:
+ panic("Unsupported address family %d", s->ss_family);
+ }
+}
+
static int
ovpn_nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *sa)
{
@@ -333,14 +400,16 @@ ovpn_nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *sa)
return (EINVAL);
af = nvlist_get_number(nvl, "af");
-
switch (af) {
#ifdef INET
case AF_INET: {
struct sockaddr_in *in = (struct sockaddr_in *)sa;
size_t len;
const void *addr = nvlist_get_binary(nvl, "address", &len);
+
+ memset(in, 0, sizeof(*in));
in->sin_family = af;
+ in->sin_len = sizeof(*in);
if (len != sizeof(in->sin_addr))
return (EINVAL);
@@ -354,7 +423,10 @@ ovpn_nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *sa)
struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
size_t len;
const void *addr = nvlist_get_binary(nvl, "address", &len);
+
+ memset(in6, 0, sizeof(*in6));
in6->sin6_family = af;
+ in6->sin6_len = sizeof(*in6);
if (len != sizeof(in6->sin6_addr))
return (EINVAL);
@@ -370,31 +442,42 @@ ovpn_nvlist_to_sockaddr(const nvlist_t *nvl, struct sockaddr_storage *sa)
return (0);
}
-static bool
-ovpn_has_peers(struct ovpn_softc *sc)
+static int
+ovpn_add_sockaddr(nvlist_t *parent, const char *name, const struct sockaddr *s)
{
- OVPN_ASSERT(sc);
-
- return (sc->peercount > 0);
-}
+ nvlist_t *nvl;
-static void
-ovpn_rele_so(struct ovpn_softc *sc)
-{
- bool has_peers;
+ nvl = nvlist_create(0);
+ if (nvl == NULL)
+ return (ENOMEM);
- OVPN_WASSERT(sc);
+ nvlist_add_number(nvl, "af", s->sa_family);
- if (sc->so == NULL)
- return;
+ switch (s->sa_family) {
+ case AF_INET: {
+ const struct sockaddr_in *s4 = (const struct sockaddr_in *)s;
- has_peers = ovpn_has_peers(sc);
+ nvlist_add_number(nvl, "port", s4->sin_port);
+ nvlist_add_binary(nvl, "address", &s4->sin_addr,
+ sizeof(s4->sin_addr));
+ break;
+ }
+ case AF_INET6: {
+ const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *)s;
- if (! has_peers) {
- MPASS(sc->peercount == 0);
- } else {
- MPASS(sc->peercount > 0);
+ nvlist_add_number(nvl, "port", s6->sin6_port);
+ nvlist_add_binary(nvl, "address", &s6->sin6_addr,
+ sizeof(s6->sin6_addr));
+ break;
+ }
+ default:
+ nvlist_destroy(nvl);
+ return (EINVAL);
}
+
+ nvlist_move_nvlist(parent, name, nvl);
+
+ return (0);
}
static void
@@ -449,6 +532,33 @@ ovpn_notify_key_rotation(struct ovpn_softc *sc, struct ovpn_kpeer *peer)
}
}
+static int
+ovpn_notify_float(struct ovpn_softc *sc, uint32_t peerid,
+ const struct sockaddr_storage *remote)
+{
+ struct ovpn_notification *n;
+
+ n = malloc(sizeof(*n), M_OVPN, M_NOWAIT | M_ZERO);
+ if (n == NULL)
+ return (ENOMEM);
+
+ n->peerid = peerid;
+ n->type = OVPN_NOTIF_FLOAT;
+ memcpy(&n->address, remote, sizeof(n->address));
+
+ if (buf_ring_enqueue(sc->notifring, n) != 0) {
+ free(n, M_OVPN);
+ return (ENOMEM);
+ } else if (sc->so != NULL) {
+ /* Wake up userspace */
+ sc->so->so_error = EAGAIN;
+ sorwakeup(sc->so);
+ sowwakeup(sc->so);
+ }
+
+ return (0);
+}
+
static void
ovpn_peer_release_ref(struct ovpn_kpeer *peer, bool locked)
{
@@ -485,8 +595,6 @@ ovpn_peer_release_ref(struct ovpn_kpeer *peer, bool locked)
ovpn_free_kkey_dir(peer->keys[i].decrypt);
}
- ovpn_rele_so(sc);
-
callout_stop(&peer->ping_send);
callout_stop(&peer->ping_rcv);
uma_zfree_pcpu(pcpu_zone_4, peer->last_active);
@@ -502,7 +610,7 @@ ovpn_new_peer(struct ifnet *ifp, const nvlist_t *nvl)
#ifdef INET6
struct epoch_tracker et;
#endif
- struct sockaddr_storage remote;
+ struct sockaddr_storage local, remote;
struct ovpn_kpeer *peer = NULL;
struct file *fp = NULL;
struct ovpn_softc *sc = ifp->if_softc;
@@ -571,20 +679,37 @@ ovpn_new_peer(struct ifnet *ifp, const nvlist_t *nvl)
callout_init_rm(&peer->ping_send, &sc->lock, CALLOUT_SHAREDLOCK);
callout_init_rm(&peer->ping_rcv, &sc->lock, 0);
- peer->local.ss_len = sizeof(peer->local);
- ret = sosockaddr(so, (struct sockaddr *)&peer->local);
- if (ret)
+ memset(&local, 0, sizeof(local));
+ local.ss_len = sizeof(local);
+ ret = sosockaddr(so, (struct sockaddr *)&local);
+ if (ret != 0)
goto error;
+ if (nvlist_exists_nvlist(nvl, "local")) {
+ struct sockaddr_storage local1;
+
+ ret = ovpn_nvlist_to_sockaddr(nvlist_get_nvlist(nvl, "local"),
+ &local1);
+ if (ret != 0)
+ goto error;
- if (ovpn_get_port(&peer->local) == 0) {
+ /*
+ * openvpn doesn't provide a port here when in multihome mode,
+ * just steal the one the socket is bound to.
+ */
+ if (ovpn_get_port(&local1) == 0)
+ ovpn_set_port(&local1, ovpn_get_port(&local));
+ memcpy(&local, &local1, sizeof(local1));
+ }
+ if (ovpn_get_port(&local) == 0) {
ret = EINVAL;
goto error;
}
- if (peer->local.ss_family != remote.ss_family) {
+ if (local.ss_family != remote.ss_family) {
ret = EINVAL;
goto error;
}
+ memcpy(&peer->local, &local, sizeof(local));
memcpy(&peer->remote, &remote, sizeof(remote));
#ifdef INET6
@@ -633,6 +758,7 @@ ovpn_new_peer(struct ifnet *ifp, const nvlist_t *nvl)
* a new one.
*/
ret = udp_set_kernel_tunneling(sc->so, NULL, NULL, NULL);
+ MPASS(ret == 0);
sorele(sc->so);
sc->so = NULL;
}
@@ -1364,12 +1490,36 @@ opvn_get_pkt(struct ovpn_softc *sc, nvlist_t **onvl)
}
nvlist_add_number(nvl, "peerid", n->peerid);
nvlist_add_number(nvl, "notification", n->type);
- if (n->type == OVPN_NOTIF_DEL_PEER) {
+ switch (n->type) {
+ case OVPN_NOTIF_DEL_PEER: {
nvlist_add_number(nvl, "del_reason", n->del_reason);
/* No error handling, because we want to send the notification
* even if we can't attach the counters. */
ovpn_notif_add_counters(nvl, n);
+ break;
+ }
+ case OVPN_NOTIF_FLOAT: {
+ int ret;
+
+ ret = ovpn_add_sockaddr(nvl, "address",
+ (struct sockaddr *)&n->address);
+
+ if (ret) {
+ /*
+ * Try to re-enqueue the notification. Maybe we'll
+ * have better luck next time. No error handling,
+ * because if we fail to re-enqueue there's nothing we can do.
+ */
+ (void)ovpn_notify_float(sc, n->peerid, &n->address);
+ nvlist_destroy(nvl);
+ free(n, M_OVPN);
+ return (ret);
+ }
+ break;
+ }
+ default:
+ break;
}
free(n, M_OVPN);
@@ -1525,6 +1675,7 @@ ovpn_finish_rx(struct ovpn_softc *sc, struct mbuf *m,
struct rm_priotracker *_ovpn_lock_trackerp)
{
uint32_t af;
+ struct m_tag *mtag;
OVPN_RASSERT(sc);
NET_EPOCH_ASSERT();
@@ -1543,6 +1694,38 @@ ovpn_finish_rx(struct ovpn_softc *sc, struct mbuf *m,
OVPN_RUNLOCK(sc);
+ /* Check if the peer changed to a new source address. */
+ mtag = m_tag_find(m, PACKET_TAG_OVPN, NULL);
+ if (mtag != NULL) {
+ struct ovpn_mtag *ot = (struct ovpn_mtag *)(mtag + 1);
+
+ OVPN_WLOCK(sc);
+
+ /*
+ * Check the address against the peer's remote again, because we may race
+ * against ourselves (i.e. we may have tagged multiple packets to indicate we
+ * floated).
+ */
+ if (ovpn_sockaddr_compare((struct sockaddr *)&ot->addr,
+ (struct sockaddr *)&peer->remote)) {
+ OVPN_WUNLOCK(sc);
+ goto skip_float;
+ }
+
+ /* And notify userspace. */
+ if (ovpn_notify_float(sc, peer->peerid, &ot->addr) == 0) {
+ /*
+ * Update the 'remote' for this peer, but only if
+ * we've actually enqueued the notification.
+ * Otherwise we can try again later.
+ */
+ memcpy(&peer->remote, &ot->addr, sizeof(peer->remote));
+ }
+
+ OVPN_WUNLOCK(sc);
+ }
+
+skip_float:
OVPN_COUNTER_ADD(sc, received_data_pkts, 1);
OVPN_COUNTER_ADD(sc, tunnel_bytes_received, m->m_pkthdr.len);
OVPN_PEER_COUNTER_ADD(peer, pkt_in, 1);
@@ -2305,6 +2488,29 @@ ovpn_udp_input(struct mbuf *m, int off, struct inpcb *inp,
return (true);
}
+ /*
+ * If we got this from a different address than we expected tag the packet.
+ * We'll deal with notifiying userspace later, after we've decrypted and
+ * verified.
+ */
+ if (! ovpn_sockaddr_compare((struct sockaddr *)&peer->remote, sa)) {
+ struct m_tag *mt;
+ struct ovpn_mtag *ot;
+
+ MPASS(sa->sa_len <= sizeof(ot->addr));
+ mt = m_tag_get(PACKET_TAG_OVPN, sizeof(*ot), M_NOWAIT);
+ /*
+ * If we fail to allocate here we'll just try again on the next
+ * packet.
+ */
+ if (mt != NULL) {
+ ot = (struct ovpn_mtag *)(mt + 1);
+ memcpy(&ot->addr, sa, sa->sa_len);
+
+ m_tag_prepend(m, mt);
+ }
+ }
+
if (key->decrypt->cipher == OVPN_CIPHER_ALG_NONE) {
/* Now remove the outer headers */
m_adj_decap(m, sizeof(struct udphdr) + ohdrlen);
@@ -2519,6 +2725,7 @@ ovpn_clone_destroy_cb(struct epoch_context *ctx)
COUNTER_ARRAY_FREE(sc->counters, OVPN_COUNTER_SIZE);
+ rm_destroy(&sc->lock);
if_free(sc->ifp);
free(sc, M_OVPN);
}
@@ -2579,23 +2786,53 @@ vnet_ovpn_init(const void *unused __unused)
VNET_SYSINIT(vnet_ovpn_init, SI_SUB_PSEUDO, SI_ORDER_ANY,
vnet_ovpn_init, NULL);
-static void
-vnet_ovpn_uninit(const void *unused __unused)
+static int
+ovpn_prison_remove(void *obj, void *data __unused)
{
- if_clone_detach(V_ovpn_cloner);
+#ifdef VIMAGE
+ struct prison *pr;
+
+ pr = obj;
+ if (prison_owns_vnet(pr)) {
+ CURVNET_SET(pr->pr_vnet);
+ if (V_ovpn_cloner != NULL) {
+ ifc_detach_cloner(V_ovpn_cloner);
+ V_ovpn_cloner = NULL;
+ }
+ CURVNET_RESTORE();
+ }
+#endif
+ return (0);
}
-VNET_SYSUNINIT(vnet_ovpn_uninit, SI_SUB_PSEUDO, SI_ORDER_ANY,
- vnet_ovpn_uninit, NULL);
static int
ovpnmodevent(module_t mod, int type, void *data)
{
+ static int ovpn_osd_jail_slot;
+
switch (type) {
- case MOD_LOAD:
- /* Done in vnet_ovpn_init() */
+ case MOD_LOAD: {
+ /*
+ * Registration is handled in vnet_ovpn_init(), but cloned
+ * interfaces must be destroyed via PR_METHOD_REMOVE since they
+ * hold a reference to the prison via the UDP socket, which
+ * prevents the prison from being destroyed.
+ */
+ osd_method_t methods[PR_MAXMETHOD] = {
+ [PR_METHOD_REMOVE] = ovpn_prison_remove,
+ };
+ ovpn_osd_jail_slot = osd_jail_register(NULL, methods);
break;
+ }
case MOD_UNLOAD:
- /* Done in vnet_ovpn_uninit() */
+ if (ovpn_osd_jail_slot != 0)
+ osd_jail_deregister(ovpn_osd_jail_slot);
+ CURVNET_SET(vnet0);
+ if (V_ovpn_cloner != NULL) {
+ ifc_detach_cloner(V_ovpn_cloner);
+ V_ovpn_cloner = NULL;
+ }
+ CURVNET_RESTORE();
break;
default:
return (EOPNOTSUPP);
diff --git a/sys/net/if_ovpn.h b/sys/net/if_ovpn.h
index 2d6b8c1e7eff..2a24c35788a9 100644
--- a/sys/net/if_ovpn.h
+++ b/sys/net/if_ovpn.h
@@ -37,6 +37,7 @@
enum ovpn_notif_type {
OVPN_NOTIF_DEL_PEER,
OVPN_NOTIF_ROTATE_KEY,
+ OVPN_NOTIF_FLOAT,
};
enum ovpn_del_reason {
diff --git a/sys/net/if_tuntap.c b/sys/net/if_tuntap.c
index 3bab04aa4d38..5e6f65c04b2f 100644
--- a/sys/net/if_tuntap.c
+++ b/sys/net/if_tuntap.c
@@ -74,6 +74,7 @@
#include <sys/malloc.h>
#include <sys/random.h>
#include <sys/ctype.h>
+#include <sys/osd.h>
#include <net/ethernet.h>
#include <net/if.h>
@@ -178,6 +179,7 @@ struct tuntap_softc {
static struct mtx tunmtx;
static eventhandler_tag arrival_tag;
static eventhandler_tag clone_tag;
+static int tuntap_osd_jail_slot;
static const char tunname[] = "tun";
static const char tapname[] = "tap";
static const char vmnetname[] = "vmnet";
@@ -497,6 +499,10 @@ vmnet_clone_match(struct if_clone *ifc, const char *name)
return (0);
}
+/*
+ * Create a clone via the ifnet cloning mechanism. Note that this is invoked
+ * indirectly by tunclone() below.
+ */
static int
tun_clone_create(struct if_clone *ifc, char *name, size_t len,
struct ifc_data *ifd, struct ifnet **ifpp)
@@ -532,15 +538,19 @@ tun_clone_create(struct if_clone *ifc, char *name, size_t len,
if (i != 0)
i = tun_create_device(drv, unit, NULL, &dev, name);
if (i == 0) {
- dev_ref(dev);
+ struct tuntap_softc *tp;
+
tuncreate(dev);
- struct tuntap_softc *tp = dev->si_drv1;
+ tp = dev->si_drv1;
*ifpp = tp->tun_ifp;
}
return (i);
}
+/*
+ * Create a clone via devfs access.
+ */
static void
tunclone(void *arg, struct ucred *cred, char *name, int namelen,
struct cdev **dev)
@@ -595,11 +605,12 @@ tunclone(void *arg, struct ucred *cred, char *name, int namelen,
}
i = tun_create_device(drv, u, cred, dev, name);
- }
- if (i == 0) {
+ } else {
+ /* Consumed by the dev_clone invoker. */
dev_ref(*dev);
- if_clone_create(name, namelen, NULL);
}
+ if (i == 0)
+ if_clone_create(name, namelen, NULL);
out:
CURVNET_RESTORE();
}
@@ -670,16 +681,6 @@ VNET_SYSINIT(vnet_tun_init, SI_SUB_PROTO_IF, SI_ORDER_ANY,
vnet_tun_init, NULL);
static void
-vnet_tun_uninit(const void *unused __unused)
-{
-
- for (u_int i = 0; i < NDRV; ++i)
- if_clone_detach(V_tuntap_driver_cloners[i]);
-}
-VNET_SYSUNINIT(vnet_tun_uninit, SI_SUB_PROTO_IF, SI_ORDER_ANY,
- vnet_tun_uninit, NULL);
-
-static void
tun_uninit(const void *unused __unused)
{
struct tuntap_driver *drv;
@@ -689,6 +690,16 @@ tun_uninit(const void *unused __unused)
EVENTHANDLER_DEREGISTER(ifnet_arrival_event, arrival_tag);
EVENTHANDLER_DEREGISTER(dev_clone, clone_tag);
+ CURVNET_SET(vnet0);
+ for (u_int i = 0; i < NDRV; i++) {
+ if_clone_detach(V_tuntap_driver_cloners[i]);
+ V_tuntap_driver_cloners[i] = NULL;
+ }
+ CURVNET_RESTORE();
+
+ if (tuntap_osd_jail_slot != 0)
+ osd_jail_deregister(tuntap_osd_jail_slot);
+
mtx_lock(&tunmtx);
while ((tp = TAILQ_FIRST(&tunhead)) != NULL) {
TAILQ_REMOVE(&tunhead, tp, tun_list);
@@ -724,6 +735,30 @@ tuntap_driver_from_ifnet(const struct ifnet *ifp)
return (NULL);
}
+/*
+ * Remove devices that were created by devfs cloning, as they hold references
+ * which prevent the prison from collapsing, in which state VNET sysuninits will
+ * not be invoked.
+ */
+static int
+tuntap_prison_remove(void *obj, void *data __unused)
+{
+#ifdef VIMAGE
+ struct prison *pr;
+
+ pr = obj;
+ if (prison_owns_vnet(pr)) {
+ CURVNET_SET(pr->pr_vnet);
+ for (u_int i = 0; i < NDRV; i++) {
+ if_clone_detach(V_tuntap_driver_cloners[i]);
+ V_tuntap_driver_cloners[i] = NULL;
+ }
+ CURVNET_RESTORE();
+ }
+#endif
+ return (0);
+}
+
static int
tuntapmodevent(module_t mod, int type, void *data)
{
@@ -738,8 +773,12 @@ tuntapmodevent(module_t mod, int type, void *data)
clone_setup(&drv->clones);
drv->unrhdr = new_unrhdr(0, IF_MAXUNIT, &tunmtx);
}
+ osd_method_t methods[PR_MAXMETHOD] = {
+ [PR_METHOD_REMOVE] = tuntap_prison_remove,
+ };
+ tuntap_osd_jail_slot = osd_jail_register(NULL, methods);
arrival_tag = EVENTHANDLER_REGISTER(ifnet_arrival_event,
- tunrename, 0, 1000);
+ tunrename, 0, 1000);
if (arrival_tag == NULL)
return (ENOMEM);
clone_tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000);
@@ -747,7 +786,7 @@ tuntapmodevent(module_t mod, int type, void *data)
return (ENOMEM);
break;
case MOD_UNLOAD:
- /* See tun_uninit, so it's done after the vnet_sysuninit() */
+ /* See tun_uninit(). */
break;
default:
return EOPNOTSUPP;
@@ -798,6 +837,8 @@ tun_create_device(struct tuntap_driver *drv, int unit, struct ucred *cr,
args.mda_si_drv1 = tp;
error = make_dev_s(&args, dev, "%s", name);
if (error != 0) {
+ mtx_destroy(&tp->tun_mtx);
+ cv_destroy(&tp->tun_cv);
free(tp, M_TUN);
return (error);
}
@@ -914,7 +955,6 @@ tap_transmit(struct ifnet *ifp, struct mbuf *m)
return (error);
}
-/* XXX: should return an error code so it can fail. */
static void
tuncreate(struct cdev *dev)
{
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index 22fcb7bf7c64..61000018e5a4 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -2336,6 +2336,18 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
error = ENOENT;
break;
}
+
+ /*
+ * If the ifp is in a bridge, do not allow setting the device
+ * to a bridge; this prevents having a bridge SVI as a bridge
+ * member (which is not permitted).
+ */
+ if (ifp->if_bridge != NULL && p->if_type == IFT_BRIDGE) {
+ if_rele(p);
+ error = EINVAL;
+ break;
+ }
+
if (vlr.vlr_proto == 0)
vlr.vlr_proto = ETHERTYPE_VLAN;
oldmtu = ifp->if_mtu;
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 452a8eb4024b..d55afe750869 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -331,6 +331,14 @@ MALLOC_DECLARE(M_PF_RULE_ITEM);
SDT_PROVIDER_DECLARE(pf);
SDT_PROBE_DECLARE(pf, , test, reason_set);
+SDT_PROBE_DECLARE(pf, , log, log);
+
+#define DPFPRINTF(n, fmt, x...) \
+ do { \
+ SDT_PROBE2(pf, , log, log, (n), fmt); \
+ if (V_pf_status.debug >= (n)) \
+ printf(fmt "\n", ##x); \
+ } while (0)
struct pfi_dynaddr {
TAILQ_ENTRY(pfi_dynaddr) entry;
@@ -1676,6 +1684,9 @@ struct pf_pdesc {
u_int32_t fragoff; /* fragment header offset */
u_int32_t jumbolen; /* length from v6 jumbo header */
u_int32_t badopts; /* v4 options or v6 routing headers */
+#define PF_OPT_OTHER 0x0001
+#define PF_OPT_JUMBO 0x0002
+#define PF_OPT_ROUTER_ALERT 0x0004
u_int16_t *ip_sum;
u_int16_t flags; /* Let SCRUB trigger behavior in
diff --git a/sys/netinet/icmp_var.h b/sys/netinet/icmp_var.h
index b1f2b0ebf911..d6b75e482e35 100644
--- a/sys/netinet/icmp_var.h
+++ b/sys/netinet/icmp_var.h
@@ -104,11 +104,10 @@ extern int badport_bandlim(int);
#define BANDLIM_ICMP_UNREACH 0
#define BANDLIM_ICMP_ECHO 1
#define BANDLIM_ICMP_TSTAMP 2
-#define BANDLIM_RST_CLOSEDPORT 3 /* No connection, and no listeners */
-#define BANDLIM_RST_OPENPORT 4 /* No connection, listener */
-#define BANDLIM_ICMP6_UNREACH 5
-#define BANDLIM_SCTP_OOTB 6
-#define BANDLIM_MAX 7
+#define BANDLIM_TCP_RST 3
+#define BANDLIM_ICMP6_UNREACH 4
+#define BANDLIM_SCTP_OOTB 5
+#define BANDLIM_MAX 6
#endif
#endif
diff --git a/sys/netinet/in_fib_dxr.c b/sys/netinet/in_fib_dxr.c
index b889131b544b..538cd43a88a3 100644
--- a/sys/netinet/in_fib_dxr.c
+++ b/sys/netinet/in_fib_dxr.c
@@ -345,7 +345,7 @@ initheap(struct dxr_aux *da, uint32_t dst_u32, uint32_t chunk)
struct heap_entry *fhp = &da->heap[0];
struct rtentry *rt;
struct route_nhop_data rnd;
-
+
da->heap_index = 0;
da->dst.sin_addr.s_addr = htonl(dst_u32);
rt = fib4_lookup_rt(da->fibnum, da->dst.sin_addr, 0, NHR_UNLOCKED,
@@ -1143,7 +1143,7 @@ dxr_destroy(void *data)
free(da, M_DXRAUX);
}
-static void
+static void
epoch_dxr_destroy(epoch_context_t ctx)
{
struct dxr *dxr = __containerof(ctx, struct dxr, epoch_ctx);
@@ -1202,7 +1202,7 @@ dxr_dump_end(void *data, struct fib_dp *dp)
static enum flm_op_result
dxr_dump_rib_item(struct rtentry *rt, void *data)
{
-
+
return (FLM_SUCCESS);
}
diff --git a/sys/netinet/ip_icmp.c b/sys/netinet/ip_icmp.c
index cb4b6df57c57..71b75d18efd0 100644
--- a/sys/netinet/ip_icmp.c
+++ b/sys/netinet/ip_icmp.c
@@ -1097,8 +1097,7 @@ static const char *icmp_rate_descrs[BANDLIM_MAX] = {
[BANDLIM_ICMP_UNREACH] = "icmp unreach",
[BANDLIM_ICMP_ECHO] = "icmp ping",
[BANDLIM_ICMP_TSTAMP] = "icmp tstamp",
- [BANDLIM_RST_CLOSEDPORT] = "closed port RST",
- [BANDLIM_RST_OPENPORT] = "open port RST",
+ [BANDLIM_TCP_RST] = "tcp reset",
[BANDLIM_ICMP6_UNREACH] = "icmp6 unreach",
[BANDLIM_SCTP_OOTB] = "sctp ootb",
};
diff --git a/sys/netinet/sctp_timer.c b/sys/netinet/sctp_timer.c
index 66af716eea52..7d8cb965ab09 100644
--- a/sys/netinet/sctp_timer.c
+++ b/sys/netinet/sctp_timer.c
@@ -35,7 +35,6 @@
#define _IP_VHL
#include <netinet/sctp_os.h>
#include <netinet/sctp_pcb.h>
-
#include <netinet/sctp_var.h>
#include <netinet/sctp_sysctl.h>
#include <netinet/sctp_timer.h>
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..de428ae1af6f 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -621,6 +621,7 @@ tcp_input_with_port(struct mbuf **mp, int *offp, int proto, uint16_t port)
#endif /* INET6 */
struct tcpopt to; /* options in this segment */
char *s = NULL; /* address and port logging */
+ bool closed_port = false; /* segment is hitting a closed port */
NET_EPOCH_ASSERT();
@@ -907,7 +908,8 @@ findpcb:
log(LOG_INFO, "%s; %s: Connection attempt "
"to closed port\n", s, __func__);
}
- rstreason = BANDLIM_RST_CLOSEDPORT;
+ rstreason = BANDLIM_TCP_RST;
+ closed_port = true;
goto dropwithreset;
}
INP_LOCK_ASSERT(inp);
@@ -998,12 +1000,14 @@ findpcb:
* down or it is in the CLOSED state. Either way we drop the
* segment and send an appropriate response.
*/
- rstreason = BANDLIM_RST_CLOSEDPORT;
+ rstreason = BANDLIM_TCP_RST;
+ closed_port = true;
goto dropwithreset;
}
if ((tp->t_port != port) && (tp->t_state > TCPS_LISTEN)) {
- rstreason = BANDLIM_RST_CLOSEDPORT;
+ rstreason = BANDLIM_TCP_RST;
+ closed_port = true;
goto dropwithreset;
}
@@ -1055,6 +1059,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 +1070,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 +1079,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
@@ -1092,7 +1098,7 @@ findpcb:
* of the failure cause.
*/
INP_WUNLOCK(inp);
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
lookupflag &= ~INPLOOKUP_WILDCARD;
goto findpcb;
}
@@ -1183,7 +1189,7 @@ tfo_socket_result:
s, __func__);
syncache_badack(&inc, port); /* XXX: Not needed! */
TCPSTAT_INC(tcps_badsyn);
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
goto dropwithreset;
}
/*
@@ -1259,7 +1265,7 @@ tfo_socket_result:
"Connection attempt to deprecated "
"IPv6 address rejected\n",
s, __func__);
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
goto dropwithreset;
}
}
@@ -1380,9 +1386,10 @@ dropwithreset:
* When blackholing do not respond with a RST but
* completely ignore the segment and drop it.
*/
- if (((rstreason == BANDLIM_RST_OPENPORT && V_blackhole == 3) ||
- (rstreason == BANDLIM_RST_CLOSEDPORT &&
- ((V_blackhole == 1 && (thflags & TH_SYN)) || V_blackhole > 1))) &&
+ if (rstreason == BANDLIM_TCP_RST &&
+ ((!closed_port && V_blackhole == 3) ||
+ (closed_port &&
+ ((V_blackhole == 1 && (thflags & TH_SYN)) || V_blackhole > 1))) &&
(V_blackhole_local || (
#ifdef INET6
isipv6 ? !in6_localip(&ip6->ip6_src) :
@@ -1515,7 +1522,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 +1763,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) &&
@@ -1963,7 +1972,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
if ((thflags & TH_ACK) &&
(SEQ_LEQ(th->th_ack, tp->snd_una) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
goto dropwithreset;
}
@@ -1976,7 +1985,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
* FIN, or a RST.
*/
if ((thflags & (TH_SYN|TH_ACK)) == (TH_SYN|TH_ACK)) {
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
goto dropwithreset;
} else if (thflags & TH_SYN) {
@@ -2244,7 +2253,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
* for the "LAND" DoS attack.
*/
if (tp->t_state == TCPS_SYN_RECEIVED && SEQ_LT(th->th_seq, tp->irs)) {
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
goto dropwithreset;
}
@@ -2557,7 +2566,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 +3122,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;
@@ -3424,7 +3432,7 @@ dropafterack:
if (tp->t_state == TCPS_SYN_RECEIVED && (thflags & TH_ACK) &&
(SEQ_GT(tp->snd_una, th->th_ack) ||
SEQ_GT(th->th_ack, tp->snd_max)) ) {
- rstreason = BANDLIM_RST_OPENPORT;
+ rstreason = BANDLIM_TCP_RST;
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
goto dropwithreset;
}
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..f8c064b6a104 100644
--- a/sys/netinet/tcp_log_buf.h
+++ b/sys/netinet/tcp_log_buf.h
@@ -377,12 +377,12 @@ extern int32_t tcp_trace_point_count;
/*
* Returns true if any sort of BB logging is enabled,
- * commonly used throughout the codebase.
+ * commonly used throughout the codebase.
*/
static inline int
tcp_bblogging_on(struct tcpcb *tp)
{
- if (tp->_t_logstate <= TCP_LOG_STATE_OFF)
+ if (tp->_t_logstate <= TCP_LOG_STATE_OFF)
return (0);
if (tp->_t_logstate == TCP_LOG_VIA_BBPOINTS)
return (0);
@@ -427,7 +427,7 @@ tcp_set_bblog_state(struct tcpcb *tp, uint8_t ls, uint8_t bbpoint)
}
}
-static inline uint32_t
+static inline uint32_t
tcp_get_bblog_state(struct tcpcb *tp)
{
return (tp->_t_logstate);
@@ -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/netinet/tcp_lro.c b/sys/netinet/tcp_lro.c
index 10afed17bf3b..7512679bd4e9 100644
--- a/sys/netinet/tcp_lro.c
+++ b/sys/netinet/tcp_lro.c
@@ -1301,9 +1301,9 @@ tcp_lro_rx_common(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum, bool use_h
return (TCP_LRO_CANNOT);
#endif
if (((m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) !=
- ((CSUM_DATA_VALID | CSUM_PSEUDO_HDR))) ||
+ ((CSUM_DATA_VALID | CSUM_PSEUDO_HDR))) ||
(m->m_pkthdr.csum_data != 0xffff)) {
- /*
+ /*
* The checksum either did not have hardware offload
* or it was a bad checksum. We can't LRO such
* a packet.
@@ -1334,7 +1334,7 @@ tcp_lro_rx_common(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum, bool use_h
#endif
/* If no hardware or arrival stamp on the packet add timestamp */
if ((m->m_flags & (M_TSTMP_LRO | M_TSTMP)) == 0) {
- m->m_pkthdr.rcv_tstmp = bintime2ns(&lc->lro_last_queue_time);
+ m->m_pkthdr.rcv_tstmp = bintime2ns(&lc->lro_last_queue_time);
m->m_flags |= M_TSTMP_LRO;
}
@@ -1429,9 +1429,9 @@ tcp_lro_rx(struct lro_ctrl *lc, struct mbuf *m, uint32_t csum)
int error;
if (((m->m_pkthdr.csum_flags & (CSUM_DATA_VALID | CSUM_PSEUDO_HDR)) !=
- ((CSUM_DATA_VALID | CSUM_PSEUDO_HDR))) ||
+ ((CSUM_DATA_VALID | CSUM_PSEUDO_HDR))) ||
(m->m_pkthdr.csum_data != 0xffff)) {
- /*
+ /*
* The checksum either did not have hardware offload
* or it was a bad checksum. We can't LRO such
* a packet.
@@ -1481,7 +1481,7 @@ tcp_lro_queue_mbuf(struct lro_ctrl *lc, struct mbuf *mb)
((mb->m_flags & M_TSTMP) == 0)) {
/* Add in an LRO time since no hardware */
binuptime(&lc->lro_last_queue_time);
- mb->m_pkthdr.rcv_tstmp = bintime2ns(&lc->lro_last_queue_time);
+ mb->m_pkthdr.rcv_tstmp = bintime2ns(&lc->lro_last_queue_time);
mb->m_flags |= M_TSTMP_LRO;
}
diff --git a/sys/netinet/tcp_sack.c b/sys/netinet/tcp_sack.c
index 90d789f0e224..4405098a8620 100644
--- a/sys/netinet/tcp_sack.c
+++ b/sys/netinet/tcp_sack.c
@@ -744,7 +744,7 @@ tcp_sack_doack(struct tcpcb *tp, struct tcpopt *to, tcp_seq th_ack)
while (cur != NULL) {
if (!(sblkp >= sack_blocks)) {
if (((loss_sblks >= tcprexmtthresh) ||
- (loss_thresh > (tcprexmtthresh-1)*tp->t_maxseg)))
+ (loss_thresh > (tcprexmtthresh-1)*tp->t_maxseg)))
break;
loss_thresh += loss_hiack - cur->end;
loss_hiack = cur->start;
diff --git a/sys/netinet/tcp_stacks/bbr.c b/sys/netinet/tcp_stacks/bbr.c
index e2cfec5c9275..b232d3f08fe6 100644
--- a/sys/netinet/tcp_stacks/bbr.c
+++ b/sys/netinet/tcp_stacks/bbr.c
@@ -5126,8 +5126,8 @@ bbr_timeout_rxt(struct tcpcb *tp, struct tcp_bbr *bbr, uint32_t cts)
tp->t_maxseg = tp->t_pmtud_saved_maxseg;
if (tp->t_maxseg < V_tcp_mssdflt) {
/*
- * The MSS is so small we should not
- * process incoming SACK's since we are
+ * The MSS is so small we should not
+ * process incoming SACK's since we are
* subject to attack in such a case.
*/
tp->t_flags2 |= TF2_PROC_SACK_PROHIBIT;
@@ -8763,7 +8763,7 @@ bbr_do_syn_sent(struct mbuf *m, struct tcphdr *th, struct socket *so,
(SEQ_LEQ(th->th_ack, tp->iss) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if ((thflags & (TH_ACK | TH_RST)) == (TH_ACK | TH_RST)) {
@@ -8965,7 +8965,7 @@ bbr_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
(SEQ_LEQ(th->th_ack, tp->snd_una) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if (tp->t_flags & TF_FASTOPEN) {
@@ -8977,7 +8977,7 @@ bbr_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
*/
if ((thflags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
} else if (thflags & TH_SYN) {
/* non-initial SYN is ignored */
@@ -9010,7 +9010,7 @@ bbr_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
*/
if (SEQ_LT(th->th_seq, tp->irs)) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if (ctf_drop_checks(to, m, th, tp, &tlen, &thflags, &drop_hdrlen, &ret_val)) {
@@ -9288,7 +9288,7 @@ bbr_do_established(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -9385,7 +9385,7 @@ bbr_do_close_wait(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -9535,7 +9535,7 @@ bbr_do_fin_wait_1(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -9637,7 +9637,7 @@ bbr_do_closing(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -9739,7 +9739,7 @@ bbr_do_lastack(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -9848,7 +9848,7 @@ bbr_do_fin_wait_2(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
bbr_log_progress_event(bbr, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -10141,7 +10141,7 @@ bbr_init(struct tcpcb *tp, void **ptr)
* flags.
*/
bbr_stop_all_timers(tp, bbr);
- /*
+ /*
* Validate the timers are not in usec, if they are convert.
* BBR should in theory move to USEC and get rid of a
* lot of the TICKS_2 calls.. but for now we stay
@@ -11510,7 +11510,7 @@ bbr_do_segment_nounlock(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
if ((tp->t_state == TCPS_SYN_SENT) && (thflags & TH_ACK) &&
(SEQ_LEQ(th->th_ack, tp->iss) || SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if (tiwin > bbr->r_ctl.rc_high_rwnd)
@@ -11544,7 +11544,7 @@ bbr_do_segment_nounlock(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
bbr_check_bbr_for_state(bbr, cts, __LINE__, (bbr->r_ctl.rc_lost - lost));
if (nxt_pkt == 0) {
if ((bbr->r_wanted_output != 0) ||
- (tp->t_flags & TF_ACKNOW)) {
+ (tp->t_flags & TF_ACKNOW)) {
bbr->rc_output_starts_timer = 0;
did_out = 1;
@@ -13172,11 +13172,7 @@ send:
mb, moff, &len,
if_hw_tsomaxsegcount,
if_hw_tsomaxsegsize, msb,
- ((rsm == NULL) ? hw_tls : 0)
-#ifdef NETFLIX_COPY_ARGS
- , NULL, NULL
-#endif
- );
+ ((rsm == NULL) ? hw_tls : 0));
if (len <= maxseg) {
/*
* Must have ran out of mbufs for the copy
@@ -13806,8 +13802,8 @@ nomore:
tp->t_maxseg = old_maxseg - 40;
if (tp->t_maxseg < V_tcp_mssdflt) {
/*
- * The MSS is so small we should not
- * process incoming SACK's since we are
+ * The MSS is so small we should not
+ * process incoming SACK's since we are
* subject to attack in such a case.
*/
tp->t_flags2 |= TF2_PROC_SACK_PROHIBIT;
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
index 8e05498863b9..940a4024bb73 100644
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -40,7 +40,6 @@
#endif
#include <sys/lock.h>
#include <sys/malloc.h>
-#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/mbuf.h>
#include <sys/proc.h> /* for proc0 declaration */
@@ -198,7 +197,7 @@ static uint32_t rack_pcm_blast = 0;
static uint32_t rack_pcm_is_enabled = 1;
static uint8_t rack_ssthresh_rest_rto_rec = 0; /* Do we restore ssthresh when we have rec -> rto -> rec */
-static uint32_t rack_gp_gain_req = 1200; /* Amount percent wise required to gain to record a round has "gaining" */
+static uint32_t rack_gp_gain_req = 1200; /* Amount percent wise required to gain to record a round as "gaining" */
static uint32_t rack_rnd_cnt_req = 0x10005; /* Default number of rounds if we are below rack_gp_gain_req where we exit ss */
@@ -938,7 +937,7 @@ rack_init_sysctls(void)
SYSCTL_ADD_U32(&rack_sysctl_ctx,
SYSCTL_CHILDREN(rack_probertt),
OID_AUTO, "time_between", CTLFLAG_RW,
- & rack_time_between_probertt, 96000000,
+ &rack_time_between_probertt, 96000000,
"How many useconds between the lowest rtt falling must past before we enter probertt");
SYSCTL_ADD_U32(&rack_sysctl_ctx,
SYSCTL_CHILDREN(rack_probertt),
@@ -3480,9 +3479,9 @@ static void
rack_free(struct tcp_rack *rack, struct rack_sendmap *rsm)
{
if (rsm->r_flags & RACK_APP_LIMITED) {
- if (rack->r_ctl.rc_app_limited_cnt > 0) {
- rack->r_ctl.rc_app_limited_cnt--;
- }
+ KASSERT((rack->r_ctl.rc_app_limited_cnt > 0),
+ ("app_cnt %u, rsm %p", rack->r_ctl.rc_app_limited_cnt, rsm));
+ rack->r_ctl.rc_app_limited_cnt--;
}
if (rsm->r_limit_type) {
/* currently there is only one limit type */
@@ -3554,8 +3553,7 @@ rack_get_measure_window(struct tcpcb *tp, struct tcp_rack *rack)
* earlier.
*
* So lets calculate the BDP with the "known" b/w using
- * the SRTT has our rtt and then multiply it by the
- * goal.
+ * the SRTT as our rtt and then multiply it by the goal.
*/
bw = rack_get_bw(rack);
srtt = (uint64_t)tp->t_srtt;
@@ -5793,7 +5791,7 @@ rack_cong_signal(struct tcpcb *tp, uint32_t type, uint32_t ack, int line)
tp->t_badrxtwin = 0;
break;
}
- if ((CC_ALGO(tp)->cong_signal != NULL) &&
+ if ((CC_ALGO(tp)->cong_signal != NULL) &&
(type != CC_RTO)){
tp->t_ccv.curack = ack;
CC_ALGO(tp)->cong_signal(&tp->t_ccv, type);
@@ -5904,7 +5902,7 @@ rack_calc_thresh_rack(struct tcp_rack *rack, uint32_t srtt, uint32_t cts, int li
*
* If reorder-fade is configured, then we track the last time we saw
* re-ordering occur. If we reach the point where enough time as
- * passed we no longer consider reordering has occuring.
+ * passed we no longer consider reordering as occurring.
*
* Or if reorder-face is 0, then once we see reordering we consider
* the connection to alway be subject to reordering and just set lro
@@ -7045,6 +7043,9 @@ rack_clone_rsm(struct tcp_rack *rack, struct rack_sendmap *nrsm,
/* Push bit must go to the right edge as well */
if (rsm->r_flags & RACK_HAD_PUSH)
rsm->r_flags &= ~RACK_HAD_PUSH;
+ /* Update the count if app limited */
+ if (nrsm->r_flags & RACK_APP_LIMITED)
+ rack->r_ctl.rc_app_limited_cnt++;
/* Clone over the state of the hw_tls flag */
nrsm->r_hw_tls = rsm->r_hw_tls;
/*
@@ -7096,7 +7097,7 @@ rack_merge_rsm(struct tcp_rack *rack,
l_rsm->r_flags |= RACK_TLP;
if (r_rsm->r_flags & RACK_RWND_COLLAPSED)
l_rsm->r_flags |= RACK_RWND_COLLAPSED;
- if ((r_rsm->r_flags & RACK_APP_LIMITED) &&
+ if ((r_rsm->r_flags & RACK_APP_LIMITED) &&
((l_rsm->r_flags & RACK_APP_LIMITED) == 0)) {
/*
* If both are app-limited then let the
@@ -7887,8 +7888,8 @@ drop_it:
tp->t_maxseg = tp->t_pmtud_saved_maxseg;
if (tp->t_maxseg < V_tcp_mssdflt) {
/*
- * The MSS is so small we should not
- * process incoming SACK's since we are
+ * The MSS is so small we should not
+ * process incoming SACK's since we are
* subject to attack in such a case.
*/
tp->t_flags2 |= TF2_PROC_SACK_PROHIBIT;
@@ -8137,7 +8138,7 @@ rack_update_rsm(struct tcpcb *tp, struct tcp_rack *rack,
* remove the lost desgination and reduce the
* bytes considered lost.
*/
- rsm->r_flags &= ~RACK_WAS_LOST;
+ rsm->r_flags &= ~RACK_WAS_LOST;
KASSERT((rack->r_ctl.rc_considered_lost >= (rsm->r_end - rsm->r_start)),
("rsm:%p rack:%p rc_considered_lost goes negative", rsm, rack));
if (rack->r_ctl.rc_considered_lost >= (rsm->r_end - rsm->r_start))
@@ -8832,7 +8833,7 @@ rack_apply_updated_usrtt(struct tcp_rack *rack, uint32_t us_rtt, uint32_t us_cts
val = rack_probertt_lower_within * rack_time_between_probertt;
val /= 100;
- if ((rack->in_probe_rtt == 0) &&
+ if ((rack->in_probe_rtt == 0) &&
(rack->rc_skip_timely == 0) &&
((us_cts - rack->r_ctl.rc_lower_rtt_us_cts) >= (rack_time_between_probertt - val))) {
rack_enter_probertt(rack, us_cts);
@@ -10369,7 +10370,7 @@ more:
* and yet before retransmitting we get an ack
* which can happen due to reordering.
*/
- rsm->r_flags &= ~RACK_WAS_LOST;
+ rsm->r_flags &= ~RACK_WAS_LOST;
KASSERT((rack->r_ctl.rc_considered_lost >= (rsm->r_end - rsm->r_start)),
("rsm:%p rack:%p rc_considered_lost goes negative", rsm, rack));
if (rack->r_ctl.rc_considered_lost >= (rsm->r_end - rsm->r_start))
@@ -11065,7 +11066,7 @@ rack_strike_dupack(struct tcp_rack *rack, tcp_seq th_ack)
* We need to skip anything already set
* to be retransmitted.
*/
- if ((rsm->r_dupack >= DUP_ACK_THRESHOLD) ||
+ if ((rsm->r_dupack >= DUP_ACK_THRESHOLD) ||
(rsm->r_flags & RACK_MUST_RXT)) {
rsm = TAILQ_NEXT(rsm, r_tnext);
continue;
@@ -12875,7 +12876,7 @@ rack_do_syn_sent(struct mbuf *m, struct tcphdr *th, struct socket *so,
(SEQ_LEQ(th->th_ack, tp->iss) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if ((thflags & (TH_ACK | TH_RST)) == (TH_ACK | TH_RST)) {
@@ -13089,7 +13090,7 @@ rack_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
(SEQ_LEQ(th->th_ack, tp->snd_una) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if (tp->t_flags & TF_FASTOPEN) {
@@ -13102,7 +13103,7 @@ rack_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
*/
if ((thflags & (TH_SYN | TH_ACK)) == (TH_SYN | TH_ACK)) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
} else if (thflags & TH_SYN) {
/* non-initial SYN is ignored */
@@ -13136,7 +13137,7 @@ rack_do_syn_recv(struct mbuf *m, struct tcphdr *th, struct socket *so,
*/
if (SEQ_LT(th->th_seq, tp->irs)) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
if (ctf_drop_checks(to, m, th, tp, &tlen, &thflags, &drop_hdrlen, &ret_val)) {
@@ -13399,7 +13400,7 @@ rack_do_established(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (sbavail(&so->so_snd)) {
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event(rack, tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -13495,7 +13496,7 @@ rack_do_close_wait(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -13645,7 +13646,7 @@ rack_do_fin_wait_1(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -13746,7 +13747,7 @@ rack_do_closing(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -13848,7 +13849,7 @@ rack_do_lastack(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -13952,7 +13953,7 @@ rack_do_fin_wait_2(struct mbuf *m, struct tcphdr *th, struct socket *so,
if (ctf_progress_timeout_check(tp, true)) {
rack_log_progress_event((struct tcp_rack *)tp->t_fb_ptr,
tp, tick, PROGRESS_DROP, __LINE__);
- ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset_conn(m, tp, th, BANDLIM_TCP_RST, tlen);
return (1);
}
}
@@ -14637,9 +14638,6 @@ rack_init(struct tcpcb *tp, void **ptr)
if (rack->r_ctl.pcm_s == NULL) {
rack->r_ctl.pcm_i.cnt_alloc = 0;
}
-#ifdef NETFLIX_STATS
- rack->r_ctl.side_chan_dis_mask = tcp_sidechannel_disable_mask;
-#endif
rack->r_ctl.rack_per_upper_bound_ss = (uint8_t)rack_per_upper_bound_ss;
rack->r_ctl.rack_per_upper_bound_ca = (uint8_t)rack_per_upper_bound_ca;
if (rack_enable_shared_cwnd)
@@ -15563,7 +15561,7 @@ rack_log_pcm(struct tcp_rack *rack, uint8_t mod, uint32_t flex1, uint32_t flex2,
if (tcp_bblogging_on(rack->rc_tp)) {
union tcp_log_stackspecific log;
struct timeval tv;
-
+
(void)tcp_get_usecs(&tv);
memset(&log, 0, sizeof(log));
log.u_bbr.timeStamp = tcp_tv_to_usectick(&tv);
@@ -16655,7 +16653,7 @@ rack_do_segment_nounlock(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
if ((tp->t_state == TCPS_SYN_SENT) && (thflags & TH_ACK) &&
(SEQ_LEQ(th->th_ack, tp->iss) || SEQ_GT(th->th_ack, tp->snd_max))) {
tcp_log_end_status(tp, TCP_EI_STATUS_RST_IN_FRONT);
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
#ifdef TCP_ACCOUNTING
sched_unpin();
#endif
@@ -16919,7 +16917,7 @@ do_output_now:
} else if ((nxt_pkt == 0) && (tp->t_flags & TF_ACKNOW)) {
goto do_output_now;
} else if ((no_output == 1) &&
- (nxt_pkt == 0) &&
+ (nxt_pkt == 0) &&
(tcp_in_hpts(rack->rc_tp) == 0)) {
/*
* We are not in hpts and we had a pacing timer up. Use
@@ -17546,7 +17544,7 @@ rack_get_pacing_delay(struct tcp_rack *rack, struct tcpcb *tp, uint32_t len, str
rack->r_ctl.rc_last_us_rtt,
88, __LINE__, NULL, gain);
}
- if (((bw_est == 0) || (rate_wanted == 0) || (rack->gp_ready == 0)) &&
+ if (((bw_est == 0) || (rate_wanted == 0) || (rack->gp_ready == 0)) &&
(rack->use_fixed_rate == 0)) {
/*
* No way yet to make a b/w estimate or
@@ -17986,7 +17984,7 @@ start_set:
tp->gput_ack = tp->gput_seq + rack_get_measure_window(tp, rack);
rack->r_ctl.rc_gp_cumack_ts = 0;
if ((rack->r_ctl.cleared_app_ack == 1) &&
- (SEQ_GEQ(rack->r_ctl.cleared_app_ack, tp->gput_seq))) {
+ (SEQ_GEQ(tp->gput_seq, rack->r_ctl.cleared_app_ack_seq))) {
/*
* We just cleared an application limited period
* so the next seq out needs to skip the first
@@ -19914,7 +19912,7 @@ rack_output(struct tcpcb *tp)
goto nomore;
} else {
/* Return == 0, if there is more we can send tot_len wise fall through and send */
- if (tot_len_this_send >= pace_max_seg)
+ if (tot_len_this_send >= pace_max_seg)
return (ret);
#ifdef TCP_ACCOUNTING
/* We need to re-pin since fast_output un-pined */
@@ -20043,7 +20041,7 @@ again:
rack->r_ctl.pcm_max_seg = ctf_fixed_maxseg(tp) * 10;
}
}
- if ((rack->r_ctl.pcm_max_seg != 0) && (rack->pcm_needed == 1)) {
+ if ((rack->r_ctl.pcm_max_seg != 0) && (rack->pcm_needed == 1)) {
uint32_t rw_avail, cwa;
if (tp->snd_wnd > ctf_outstanding(tp))
@@ -21031,7 +21029,7 @@ just_return_nolock:
} else
log = 1;
}
- /* Mark the last packet has app limited */
+ /* Mark the last packet as app limited */
rsm = tqhash_max(rack->r_ctl.tqh);
if (rsm && ((rsm->r_flags & RACK_APP_LIMITED) == 0)) {
if (rack->r_ctl.rc_app_limited_cnt == 0)
@@ -21555,11 +21553,7 @@ send:
m->m_next = tcp_m_copym(
mb, moff, &len,
if_hw_tsomaxsegcount, if_hw_tsomaxsegsize, msb,
- ((rsm == NULL) ? hw_tls : 0)
-#ifdef NETFLIX_COPY_ARGS
- , &s_mb, &s_moff
-#endif
- );
+ ((rsm == NULL) ? hw_tls : 0));
if (len <= (tp->t_maxseg - optlen)) {
/*
* Must have ran out of mbufs for the copy
diff --git a/sys/netinet/tcp_stacks/rack_bbr_common.c b/sys/netinet/tcp_stacks/rack_bbr_common.c
index da26b8cb1f9b..d1c4ba58bf55 100644
--- a/sys/netinet/tcp_stacks/rack_bbr_common.c
+++ b/sys/netinet/tcp_stacks/rack_bbr_common.c
@@ -672,7 +672,7 @@ ctf_do_dropafterack(struct mbuf *m, struct tcpcb *tp, struct tcphdr *th, int32_t
(SEQ_GT(tp->snd_una, th->th_ack) ||
SEQ_GT(th->th_ack, tp->snd_max))) {
*ret_val = 1;
- ctf_do_dropwithreset(m, tp, th, BANDLIM_RST_OPENPORT, tlen);
+ ctf_do_dropwithreset(m, tp, th, BANDLIM_TCP_RST, tlen);
return;
} else
*ret_val = 0;
diff --git a/sys/netinet/tcp_stacks/rack_pcm.c b/sys/netinet/tcp_stacks/rack_pcm.c
index b0e300847c4a..101e6826536c 100644
--- a/sys/netinet/tcp_stacks/rack_pcm.c
+++ b/sys/netinet/tcp_stacks/rack_pcm.c
@@ -172,7 +172,7 @@ rack_update_pcm_ack(struct tcp_rack *rack, int was_cumack, uint32_t start, uint3
goto skip_ack_accounting;
}
/*
- * Record ACK data.
+ * Record ACK data.
*/
ack_arrival = tcp_tv_to_lusectick(&rack->r_ctl.act_rcv_time);
if (SEQ_GT(end, rack->r_ctl.pcm_i.eseq)) {
@@ -305,7 +305,7 @@ skip_ack_accounting:
0, &log, false, NULL, NULL, 0, &tv);
}
}
- /*
+ /*
* Here we need a lot to be added including:
* 1) Some form of measurement, where if we think the measurement
* is valid we iterate over the PCM data and come up with a path
diff --git a/sys/netinet/tcp_stacks/sack_filter.c b/sys/netinet/tcp_stacks/sack_filter.c
index fc9ee8454a1e..2b70548f3cc6 100644
--- a/sys/netinet/tcp_stacks/sack_filter.c
+++ b/sys/netinet/tcp_stacks/sack_filter.c
@@ -400,7 +400,7 @@ sack_filter_run(struct sack_filter *sf, struct sackblk *in, int numblks, tcp_seq
break;
}
/* Copy it out to the outbound */
- memcpy(&in[at], &blkboard[i], sizeof(struct sackblk));
+ memcpy(&in[at], &blkboard[i], sizeof(struct sackblk));
at++;
room--;
/* now lets add it to our sack-board */
@@ -588,7 +588,7 @@ sack_filter_blks(struct tcpcb *tp, struct sack_filter *sf, struct sackblk *in, i
sf->sf_ack = th_ack;
for(i=0, sf->sf_cur=0; i<numblks; i++) {
- if ((in[i].end != tp->snd_max) &&
+ if ((in[i].end != tp->snd_max) &&
((in[i].end - in[i].start) < segmax)) {
/*
* We do not accept blocks less than a MSS minus all
@@ -707,7 +707,7 @@ main(int argc, char **argv)
out = stdout;
memset(&tp, 0, sizeof(tp));
tp.t_maxseg = 1460;
-
+
while ((i = getopt(argc, argv, "dIi:o:?hS:")) != -1) {
switch (i) {
case 'S':
@@ -883,7 +883,7 @@ main(int argc, char **argv)
} else {
printf("can't open sack_setup.bin -- sorry no load\n");
}
-
+
} else if (strncmp(buffer, "help", 4) == 0) {
help:
fprintf(out, "You can input:\n");
diff --git a/sys/netinet/tcp_stacks/sack_filter.h b/sys/netinet/tcp_stacks/sack_filter.h
index b12fcf84567c..a1c0684a4359 100644
--- a/sys/netinet/tcp_stacks/sack_filter.h
+++ b/sys/netinet/tcp_stacks/sack_filter.h
@@ -42,7 +42,7 @@
* previously processed sack information.
*
* The second thing that the sack filter does is help protect against malicious
- * attackers that are trying to attack any linked lists (or other data structures)
+ * attackers that are trying to attack any linked lists (or other data structures)
* that are used in sack processing. Consider an attacker sending in sacks for
* every other byte of data outstanding. This could in theory drastically split
* up any scoreboard you are maintaining and make you search through a very large
diff --git a/sys/netinet/tcp_subr.c b/sys/netinet/tcp_subr.c
index db415f6bdf03..26e7e53d540c 100644
--- a/sys/netinet/tcp_subr.c
+++ b/sys/netinet/tcp_subr.c
@@ -4537,7 +4537,7 @@ tcp_change_time_units(struct tcpcb *tp, int granularity)
panic("Unknown granularity:%d tp:%p",
granularity, tp);
}
-#endif
+#endif
}
void
diff --git a/sys/netinet/tcp_timer.c b/sys/netinet/tcp_timer.c
index 32ce3001929c..3b9fe7a317b0 100644
--- a/sys/netinet/tcp_timer.c
+++ b/sys/netinet/tcp_timer.c
@@ -757,8 +757,8 @@ tcp_timer_rexmt(struct tcpcb *tp)
tp->t_maxseg = tp->t_pmtud_saved_maxseg;
if (tp->t_maxseg < V_tcp_mssdflt) {
/*
- * The MSS is so small we should not
- * process incoming SACK's since we are
+ * The MSS is so small we should not
+ * process incoming SACK's since we are
* subject to attack in such a case.
*/
tp->t_flags2 |= TF2_PROC_SACK_PROHIBIT;
diff --git a/sys/netinet/tcp_usrreq.c b/sys/netinet/tcp_usrreq.c
index 687b0d538666..98c934955121 100644
--- a/sys/netinet/tcp_usrreq.c
+++ b/sys/netinet/tcp_usrreq.c
@@ -164,7 +164,7 @@ tcp_usr_attach(struct socket *so, int proto, struct thread *td)
goto out;
so->so_rcv.sb_flags |= SB_AUTOSIZE;
- so->so_snd.sb_flags |= SB_AUTOSIZE;
+ so->so_snd.sb_flags |= (SB_AUTOLOWAT | SB_AUTOSIZE);
error = in_pcballoc(so, &V_tcbinfo);
if (error)
goto out;
@@ -1768,9 +1768,9 @@ tcp_ctloutput_set(struct inpcb *inp, struct sockopt *sopt)
/*
* Release the ref count the lookup
* acquired.
- */
+ */
refcount_release(&blk->tfb_refcnt);
- /*
+ /*
* Now there is a chance that the
* init() function mucked with some
* things before it failed, such as
@@ -1800,7 +1800,7 @@ tcp_ctloutput_set(struct inpcb *inp, struct sockopt *sopt)
* new one already.
*/
refcount_release(&tp->t_fb->tfb_refcnt);
- /*
+ /*
* Set in the new stack.
*/
tp->t_fb = blk;
@@ -1934,7 +1934,7 @@ tcp_set_cc_mod(struct inpcb *inp, struct sockopt *sopt)
CC_LIST_RUNLOCK();
return(ESRCH);
}
- /*
+ /*
* With a reference the algorithm cannot be removed
* so we hold a reference through the change process.
*/
diff --git a/sys/netinet/tcp_var.h b/sys/netinet/tcp_var.h
index 059b2aff689d..b90f65e83cb1 100644
--- a/sys/netinet/tcp_var.h
+++ b/sys/netinet/tcp_var.h
@@ -182,7 +182,7 @@ struct tcp_sendfile_track {
* snd_una). When the response comes back indicating
* that there was data (return value 1), then the caller
* can build a sendmap entry based on the range and the
- * times. The next query would then be done at the
+ * times. The next query would then be done at the
* newly created sendmap_end. Repeated until sendmap_end == snd_max.
*
* Flags in sendmap_flags are defined below as well.
@@ -197,7 +197,7 @@ struct tcp_sendfile_track {
* The rack_times are a misc collection of information that
* the old stack might possibly fill in. Of course its possible
* that an old stack may not have a piece of information. If so
- * then setting that value to zero is advised. Setting any
+ * then setting that value to zero is advised. Setting any
* timestamp passed should only place a zero in it when it
* is unfilled. This may mean that a time is off by a micro-second
* but this is ok in the grand scheme of things.
@@ -205,13 +205,13 @@ struct tcp_sendfile_track {
* When switching stacks it is desireable to get as much information
* from the old stack to the new stack as possible. Though not always
* will the stack be compatible in the types of information. The
- * init() function needs to take care when it begins changing
+ * init() function needs to take care when it begins changing
* things such as inp_flags2 and the timer units to position these
* changes at a point where it is unlikely they will fail after
* making such changes. A stack optionally can have an "undo"
- * function
+ * function
*
- * To transfer information to the old stack from the new in
+ * To transfer information to the old stack from the new in
* respect to LRO and the inp_flags2, the new stack should set
* the inp_flags2 to what it supports. The old stack in its
* fini() function should call the tcp_handle_orphaned_packets()
@@ -544,13 +544,13 @@ typedef enum {
* do is:
* a) Make sure that the inp_flags2 is setup correctly
* for LRO. There are two flags that the previous
- * stack may have set INP_MBUF_ACKCMP and
+ * stack may have set INP_MBUF_ACKCMP and
* INP_SUPPORTS_MBUFQ. If the new stack does not
* support these it *should* clear the flags.
* b) Make sure that the timers are in the proper
* granularity that the stack wants. The stack
* should check the t_tmr_granularity field. Currently
- * there are two values that it may hold
+ * there are two values that it may hold
* TCP_TMR_GRANULARITY_TICKS and TCP_TMR_GRANULARITY_USEC.
* Use the functions tcp_timer_convert(tp, granularity);
* to move the timers to the correct format for your stack.
@@ -558,14 +558,14 @@ typedef enum {
* The new stack may also optionally query the tfb_chg_query
* function if the old stack has one. The new stack may ask
* for one of three entries and can also state to the old
- * stack its support for the INP_MBUF_ACKCMP and
+ * stack its support for the INP_MBUF_ACKCMP and
* INP_SUPPORTS_MBUFQ. This is important since if there are
* queued ack's without that statement the old stack will
* be forced to discard the queued acks. The requests that
* can be made for information by the new stacks are:
*
* Note also that the tfb_tcp_fb_init() when called can
- * determine if a query is needed by looking at the
+ * determine if a query is needed by looking at the
* value passed in the ptr. The ptr is designed to be
* set in with any allocated memory, but the address
* of the condtion (ptr == &tp->t_fb_ptr) will be
@@ -573,17 +573,17 @@ typedef enum {
* setup of a tcb (which means no query would be needed).
* If, however, the value is not t_fb_ptr, then the caller
* is in the middle of a stack switch and is the new stack.
- * A query would be appropriate (if the new stack support
+ * A query would be appropriate (if the new stack support
* the query mechanism).
*
* TCP_QUERY_SENDMAP - Query of outstanding data.
* TCP_QUERY_TIMERS_UP - Query about running timers.
- * TCP_SUPPORTED_LRO - Declaration in req_param of
- * the inp_flags2 supported by
+ * TCP_SUPPORTED_LRO - Declaration in req_param of
+ * the inp_flags2 supported by
* the new stack.
* TCP_QUERY_RACK_TIMES - Enquire about various timestamps
* and states the old stack may be in.
- *
+ *
* tfb_tcp_fb_fini is changed to add a flag to tell
* the old stack if the tcb is being destroyed or
* not. A one in the flag means the TCB is being
diff --git a/sys/netinet/udp_usrreq.c b/sys/netinet/udp_usrreq.c
index dafbaf6dc672..42cfb919e263 100644
--- a/sys/netinet/udp_usrreq.c
+++ b/sys/netinet/udp_usrreq.c
@@ -243,7 +243,6 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
struct sockaddr_in6 udp_in6;
#endif
struct udpcb *up;
- bool filtered;
INP_LOCK_ASSERT(inp);
@@ -252,13 +251,19 @@ udp_append(struct inpcb *inp, struct ip *ip, struct mbuf *n, int off,
*/
up = intoudpcb(inp);
if (up->u_tun_func != NULL) {
+ bool filtered;
+
in_pcbref(inp);
INP_RUNLOCK(inp);
filtered = (*up->u_tun_func)(n, off, inp, (struct sockaddr *)&udp_in[0],
up->u_tun_ctx);
INP_RLOCK(inp);
- if (filtered)
- return (in_pcbrele_rlocked(inp));
+ if (in_pcbrele_rlocked(inp))
+ return (1);
+ if (filtered) {
+ INP_RUNLOCK(inp);
+ return (1);
+ }
}
off += sizeof(struct udphdr);
diff --git a/sys/netinet6/in6_gif.c b/sys/netinet6/in6_gif.c
index d476829e8e3b..2bab1c57ce2a 100644
--- a/sys/netinet6/in6_gif.c
+++ b/sys/netinet6/in6_gif.c
@@ -194,6 +194,11 @@ in6_gif_setopts(struct gif_softc *sc, u_int options)
sc->gif_options = options;
in6_gif_attach(sc);
}
+
+ if ((options & GIF_NOCLAMP) !=
+ (sc->gif_options & GIF_NOCLAMP)) {
+ sc->gif_options = options;
+ }
return (0);
}
@@ -289,6 +294,7 @@ in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn)
{
struct gif_softc *sc = ifp->if_softc;
struct ip6_hdr *ip6;
+ u_long mtu;
/* prepend new IP header */
NET_EPOCH_ASSERT();
@@ -304,11 +310,15 @@ in6_gif_output(struct ifnet *ifp, struct mbuf *m, int proto, uint8_t ecn)
ip6->ip6_nxt = proto;
ip6->ip6_hlim = V_ip6_gif_hlim;
/*
- * force fragmentation to minimum MTU, to avoid path MTU discovery.
- * it is too painful to ask for resend of inner packet, to achieve
- * path MTU discovery for encapsulated packets.
+ * Enforce fragmentation to minimum MTU, even if the interface MTU
+ * is larger, to avoid path MTU discovery when NOCLAMP is not
+ * set (default). IPv6 does not allow fragmentation on intermediate
+ * router nodes, so it is too painful to ask for resend of inner
+ * packet, to achieve path MTU discovery for encapsulated packets.
*/
- return (ip6_output(m, 0, NULL, IPV6_MINMTU, 0, NULL, NULL));
+ mtu = ((sc->gif_options & GIF_NOCLAMP) == 0) ? IPV6_MINMTU : 0;
+
+ return (ip6_output(m, 0, NULL, mtu, 0, NULL, NULL));
}
static int
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/udp6_usrreq.c b/sys/netinet6/udp6_usrreq.c
index 304effa26e01..b3ed16fda713 100644
--- a/sys/netinet6/udp6_usrreq.c
+++ b/sys/netinet6/udp6_usrreq.c
@@ -142,7 +142,6 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off,
struct socket *so;
struct mbuf *opts = NULL, *tmp_opts;
struct udpcb *up;
- bool filtered;
INP_LOCK_ASSERT(inp);
@@ -151,13 +150,19 @@ udp6_append(struct inpcb *inp, struct mbuf *n, int off,
*/
up = intoudpcb(inp);
if (up->u_tun_func != NULL) {
+ bool filtered;
+
in_pcbref(inp);
INP_RUNLOCK(inp);
filtered = (*up->u_tun_func)(n, off, inp,
(struct sockaddr *)&fromsa[0], up->u_tun_ctx);
INP_RLOCK(inp);
- if (filtered)
- return (in_pcbrele_rlocked(inp));
+ if (in_pcbrele_rlocked(inp))
+ return (1);
+ if (filtered) {
+ INP_RUNLOCK(inp);
+ return (1);
+ }
}
off += sizeof(struct udphdr);
diff --git a/sys/netpfil/ipfw/ip_fw2.c b/sys/netpfil/ipfw/ip_fw2.c
index 923633d76df7..c129c8c49921 100644
--- a/sys/netpfil/ipfw/ip_fw2.c
+++ b/sys/netpfil/ipfw/ip_fw2.c
@@ -196,7 +196,7 @@ SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
"Firewall");
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, one_pass,
CTLFLAG_VNET | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_one_pass), 0,
- "Only do a single pass through ipfw when using dummynet(4)");
+ "Only do a single pass through ipfw when using dummynet(4), ipfw_nat or other divert(4)-like interfaces");
SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step,
CTLFLAG_VNET | CTLFLAG_RW, &VNET_NAME(autoinc_step), 0,
"Rule number auto-increment step");
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 4e03584b8f85..ee10a997c977 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -110,8 +110,6 @@
#include <netpfil/pf/pfsync_nv.h>
-#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
-
struct pfsync_bucket;
struct pfsync_softc;
@@ -597,9 +595,9 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
if ((rpool_first == NULL) ||
(TAILQ_NEXT(rpool_first, entries) != NULL)) {
DPFPRINTF(PF_DEBUG_MISC,
- ("%s: can't recover routing information "
- "because of empty or bad redirection pool\n",
- __func__));
+ "%s: can't recover routing information "
+ "because of empty or bad redirection pool",
+ __func__);
return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0);
}
rt = r->rt;
@@ -610,8 +608,8 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
* give up on recovering.
*/
DPFPRINTF(PF_DEBUG_MISC,
- ("%s: can't recover routing information "
- "because of different ruleset\n", __func__));
+ "%s: can't recover routing information "
+ "because of different ruleset", __func__);
return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0);
}
break;
@@ -624,8 +622,8 @@ pfsync_state_import(union pfsync_state_union *sp, int flags, int msg_version)
rt_kif = pfi_kkif_find(sp->pfs_1400.rt_ifname);
if (rt_kif == NULL) {
DPFPRINTF(PF_DEBUG_MISC,
- ("%s: unknown route interface: %s\n",
- __func__, sp->pfs_1400.rt_ifname));
+ "%s: unknown route interface: %s",
+ __func__, sp->pfs_1400.rt_ifname);
return ((flags & PFSYNC_SI_IOCTL) ? EINVAL : 0);
}
rt = sp->pfs_1400.rt;
diff --git a/sys/netpfil/pf/pf.c b/sys/netpfil/pf/pf.c
index 009f7e4d78b1..41e9ca27912d 100644
--- a/sys/netpfil/pf/pf.c
+++ b/sys/netpfil/pf/pf.c
@@ -119,8 +119,6 @@
#include <machine/in_cksum.h>
#include <security/mac/mac_framework.h>
-#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
-
SDT_PROVIDER_DEFINE(pf);
SDT_PROBE_DEFINE2(pf, , test, reason_set, "int", "int");
SDT_PROBE_DEFINE4(pf, ip, test, done, "int", "int", "struct pf_krule *",
@@ -161,6 +159,7 @@ SDT_PROBE_DEFINE2(pf, eth, test_rule, match, "int", "struct pf_keth_rule *");
SDT_PROBE_DEFINE2(pf, eth, test_rule, final_match,
"int", "struct pf_keth_rule *");
SDT_PROBE_DEFINE2(pf, purge, state, rowcount, "int", "size_t");
+SDT_PROBE_DEFINE2(pf, , log, log, "int", "const char *");
/*
* Global variables
@@ -375,6 +374,8 @@ static u_int16_t pf_calc_mss(struct pf_addr *, sa_family_t,
int, u_int16_t);
static int pf_check_proto_cksum(struct mbuf *, int, int,
u_int8_t, sa_family_t);
+static int pf_walk_option(struct pf_pdesc *, struct ip *,
+ int, int, u_short *);
static int pf_walk_header(struct pf_pdesc *, struct ip *, u_short *);
#ifdef INET6
static int pf_walk_option6(struct pf_pdesc *, struct ip6_hdr *,
@@ -4615,8 +4616,8 @@ pf_match_rcvif(struct mbuf *m, struct pf_krule *r)
if (kif == NULL) {
DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: kif == NULL, @%d via %s\n", __func__, r->nr,
- r->rcv_ifname));
+ "%s: kif == NULL, @%d via %s", __func__, r->nr,
+ r->rcv_ifname);
return (0);
}
@@ -4975,7 +4976,7 @@ pf_socket_lookup(struct pf_pdesc *pd)
}
INP_RLOCK_ASSERT(inp);
pd->lookup.uid = inp->inp_cred->cr_uid;
- pd->lookup.gid = inp->inp_cred->cr_groups[0];
+ pd->lookup.gid = inp->inp_cred->cr_gid;
INP_RUNLOCK(inp);
return (1);
@@ -5242,8 +5243,8 @@ pf_test_eth_rule(int dir, struct pfi_kkif *kif, struct mbuf **m0)
if (__predict_false(m->m_len < sizeof(struct ether_header)) &&
(m = *m0 = m_pullup(*m0, sizeof(struct ether_header))) == NULL) {
DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: m_len < sizeof(struct ether_header)"
- ", pullup failed\n", __func__));
+ "%s: m_len < sizeof(struct ether_header)"
+ ", pullup failed", __func__);
return (PF_DROP);
}
e = mtod(m, struct ether_header *);
@@ -5759,7 +5760,7 @@ pf_test_rule(struct pf_krule **rm, struct pf_kstate **sm,
if (inp != NULL) {
INP_LOCK_ASSERT(inp);
pd->lookup.uid = inp->inp_cred->cr_uid;
- pd->lookup.gid = inp->inp_cred->cr_groups[0];
+ pd->lookup.gid = inp->inp_cred->cr_gid;
pd->lookup.done = 1;
}
@@ -6168,8 +6169,8 @@ pf_create_state(struct pf_krule *r, struct pf_test_ctx *ctx,
&s->src, &s->dst, &ctx->rewrite)) {
/* This really shouldn't happen!!! */
DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: tcp normalize failed on first "
- "pkt\n", __func__));
+ "%s: tcp normalize failed on first "
+ "pkt", __func__);
goto csfailed;
}
} else if (pd->proto == IPPROTO_SCTP) {
@@ -7965,8 +7966,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
if (!pf_pull_hdr(pd->m, ipoff2, &h2, sizeof(h2),
NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: ICMP error message too short "
- "(ip)\n"));
+ "pf: ICMP error message too short "
+ "(ip)");
return (PF_DROP);
}
/*
@@ -7996,8 +7997,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
if (!pf_pull_hdr(pd->m, ipoff2, &h2_6, sizeof(h2_6),
NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: ICMP error message too short "
- "(ip6)\n"));
+ "pf: ICMP error message too short "
+ "(ip6)");
return (PF_DROP);
}
pd2.off = ipoff2;
@@ -8049,8 +8050,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
if (!pf_pull_hdr(pd->m, pd2.off, th, 8, NULL, reason,
pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: ICMP error message too short "
- "(tcp)\n"));
+ "pf: ICMP error message too short "
+ "(tcp)");
return (PF_DROP);
}
pd2.pcksum = &pd2.hdr.tcp.th_sum;
@@ -8244,8 +8245,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
if (!pf_pull_hdr(pd->m, pd2.off, uh, sizeof(*uh),
NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: ICMP error message too short "
- "(udp)\n"));
+ "pf: ICMP error message too short "
+ "(udp)");
return (PF_DROP);
}
pd2.pcksum = &pd2.hdr.udp.uh_sum;
@@ -8376,8 +8377,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
if (! pf_pull_hdr(pd->m, pd2.off, sh, sizeof(*sh), NULL, reason,
pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: ICMP error message too short "
- "(sctp)\n"));
+ "pf: ICMP error message too short "
+ "(sctp)");
return (PF_DROP);
}
pd2.pcksum = &pd2.sctp_dummy_sum;
@@ -8407,8 +8408,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
if (src->scrub->pfss_v_tag != sh->v_tag) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: ICMP error message has incorrect "
- "SCTP v_tag\n"));
+ "pf: ICMP error message has incorrect "
+ "SCTP v_tag");
return (PF_DROP);
}
@@ -8531,8 +8532,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
if (!pf_pull_hdr(pd->m, pd2.off, iih, ICMP_MINLEN,
NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: ICMP error message too short i"
- "(icmp)\n"));
+ "pf: ICMP error message too short i"
+ "(icmp)");
return (PF_DROP);
}
pd2.pcksum = &pd2.hdr.icmp.icmp_cksum;
@@ -8651,8 +8652,8 @@ pf_test_state_icmp(struct pf_kstate **state, struct pf_pdesc *pd,
if (!pf_pull_hdr(pd->m, pd2.off, iih,
sizeof(struct icmp6_hdr), NULL, reason, pd2.af)) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: ICMP error message too short "
- "(icmp6)\n"));
+ "pf: ICMP error message too short "
+ "(icmp6)");
return (PF_DROP);
}
pd2.pcksum = &pd2.hdr.icmp6.icmp6_cksum;
@@ -9082,7 +9083,7 @@ pf_route(struct pf_krule *r, struct ifnet *oifp,
}
if (m0->m_len < sizeof(struct ip)) {
DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: m0->m_len < sizeof(struct ip)\n", __func__));
+ "%s: m0->m_len < sizeof(struct ip)", __func__);
SDT_PROBE1(pf, ip, route_to, drop, __LINE__);
goto bad;
}
@@ -9387,8 +9388,8 @@ pf_route6(struct pf_krule *r, struct ifnet *oifp,
}
if (m0->m_len < sizeof(struct ip6_hdr)) {
DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: m0->m_len < sizeof(struct ip6_hdr)\n",
- __func__));
+ "%s: m0->m_len < sizeof(struct ip6_hdr)",
+ __func__);
SDT_PROBE1(pf, ip6, route_to, drop, __LINE__);
goto bad;
}
@@ -9683,7 +9684,7 @@ pf_test_eth(int dir, int pflags, struct ifnet *ifp, struct mbuf **m0,
if (kif == NULL) {
DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: kif == NULL, if_xname %s\n", __func__, ifp->if_xname));
+ "%s: kif == NULL, if_xname %s", __func__, ifp->if_xname);
return (PF_DROP);
}
if (kif->pfik_flags & PFI_IFLAG_SKIP)
@@ -9798,6 +9799,62 @@ pf_dummynet_route(struct pf_pdesc *pd, struct pf_kstate *s,
}
static int
+pf_walk_option(struct pf_pdesc *pd, struct ip *h, int off, int end,
+ u_short *reason)
+{
+ uint8_t type, length, opts[15 * 4 - sizeof(struct ip)];
+
+ /* IP header in payload of ICMP packet may be too short */
+ if (pd->m->m_pkthdr.len < end) {
+ DPFPRINTF(PF_DEBUG_MISC, "IP option too short");
+ REASON_SET(reason, PFRES_SHORT);
+ return (PF_DROP);
+ }
+
+ MPASS(end - off <= sizeof(opts));
+ m_copydata(pd->m, off, end - off, opts);
+ end -= off;
+ off = 0;
+
+ while (off < end) {
+ type = opts[off];
+ if (type == IPOPT_EOL)
+ break;
+ if (type == IPOPT_NOP) {
+ off++;
+ continue;
+ }
+ if (off + 2 > end) {
+ DPFPRINTF(PF_DEBUG_MISC, "IP length opt");
+ REASON_SET(reason, PFRES_IPOPTIONS);
+ return (PF_DROP);
+ }
+ length = opts[off + 1];
+ if (length < 2) {
+ DPFPRINTF(PF_DEBUG_MISC, "IP short opt");
+ REASON_SET(reason, PFRES_IPOPTIONS);
+ return (PF_DROP);
+ }
+ if (off + length > end) {
+ DPFPRINTF(PF_DEBUG_MISC, "IP long opt");
+ REASON_SET(reason, PFRES_IPOPTIONS);
+ return (PF_DROP);
+ }
+ switch (type) {
+ case IPOPT_RA:
+ pd->badopts |= PF_OPT_ROUTER_ALERT;
+ break;
+ default:
+ pd->badopts |= PF_OPT_OTHER;
+ break;
+ }
+ off += length;
+ }
+
+ return (PF_PASS);
+}
+
+static int
pf_walk_header(struct pf_pdesc *pd, struct ip *h, u_short *reason)
{
struct ah ext;
@@ -9809,11 +9866,28 @@ pf_walk_header(struct pf_pdesc *pd, struct ip *h, u_short *reason)
REASON_SET(reason, PFRES_SHORT);
return (PF_DROP);
}
- if (hlen != sizeof(struct ip))
- pd->badopts++;
+ if (hlen != sizeof(struct ip)) {
+ if (pf_walk_option(pd, h, pd->off + sizeof(struct ip),
+ pd->off + hlen, reason) != PF_PASS)
+ return (PF_DROP);
+ /* header options which contain only padding is fishy */
+ if (pd->badopts == 0)
+ pd->badopts |= PF_OPT_OTHER;
+ }
end = pd->off + ntohs(h->ip_len);
pd->off += hlen;
pd->proto = h->ip_p;
+ /* IGMP packets have router alert options, allow them */
+ if (pd->proto == IPPROTO_IGMP) {
+ /* According to RFC 1112 ttl must be set to 1. */
+ if ((h->ip_ttl != 1) ||
+ !IN_MULTICAST(ntohl(h->ip_dst.s_addr))) {
+ DPFPRINTF(PF_DEBUG_MISC, "Invalid IGMP");
+ REASON_SET(reason, PFRES_IPOPTIONS);
+ return (PF_DROP);
+ }
+ pd->badopts &= ~PF_OPT_ROUTER_ALERT;
+ }
/* stop walking over non initial fragments */
if ((h->ip_off & htons(IP_OFFMASK)) != 0)
return (PF_PASS);
@@ -9826,7 +9900,7 @@ pf_walk_header(struct pf_pdesc *pd, struct ip *h, u_short *reason)
return (PF_PASS);
if (!pf_pull_hdr(pd->m, pd->off, &ext, sizeof(ext),
NULL, reason, AF_INET)) {
- DPFPRINTF(PF_DEBUG_MISC, ("IP short exthdr"));
+ DPFPRINTF(PF_DEBUG_MISC, "IP short exthdr");
return (PF_DROP);
}
pd->off += (ext.ah_len + 2) * 4;
@@ -9836,7 +9910,7 @@ pf_walk_header(struct pf_pdesc *pd, struct ip *h, u_short *reason)
return (PF_PASS);
}
}
- DPFPRINTF(PF_DEBUG_MISC, ("IPv4 nested authentication header limit"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv4 nested authentication header limit");
REASON_SET(reason, PFRES_IPOPTIONS);
return (PF_DROP);
}
@@ -9852,7 +9926,7 @@ pf_walk_option6(struct pf_pdesc *pd, struct ip6_hdr *h, int off, int end,
while (off < end) {
if (!pf_pull_hdr(pd->m, off, &opt.ip6o_type,
sizeof(opt.ip6o_type), NULL, reason, AF_INET6)) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 short opt type"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 short opt type");
return (PF_DROP);
}
if (opt.ip6o_type == IP6OPT_PAD1) {
@@ -9861,41 +9935,48 @@ pf_walk_option6(struct pf_pdesc *pd, struct ip6_hdr *h, int off, int end,
}
if (!pf_pull_hdr(pd->m, off, &opt, sizeof(opt), NULL,
reason, AF_INET6)) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 short opt"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 short opt");
return (PF_DROP);
}
if (off + sizeof(opt) + opt.ip6o_len > end) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 long opt"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 long opt");
REASON_SET(reason, PFRES_IPOPTIONS);
return (PF_DROP);
}
switch (opt.ip6o_type) {
+ case IP6OPT_PADN:
+ break;
case IP6OPT_JUMBO:
+ pd->badopts |= PF_OPT_JUMBO;
if (pd->jumbolen != 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 multiple jumbo"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 multiple jumbo");
REASON_SET(reason, PFRES_IPOPTIONS);
return (PF_DROP);
}
if (ntohs(h->ip6_plen) != 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 bad jumbo plen"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 bad jumbo plen");
REASON_SET(reason, PFRES_IPOPTIONS);
return (PF_DROP);
}
if (!pf_pull_hdr(pd->m, off, &jumbo, sizeof(jumbo), NULL,
reason, AF_INET6)) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 short jumbo"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 short jumbo");
return (PF_DROP);
}
memcpy(&pd->jumbolen, jumbo.ip6oj_jumbo_len,
sizeof(pd->jumbolen));
pd->jumbolen = ntohl(pd->jumbolen);
if (pd->jumbolen < IPV6_MAXPACKET) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 short jumbolen"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 short jumbolen");
REASON_SET(reason, PFRES_IPOPTIONS);
return (PF_DROP);
}
break;
+ case IP6OPT_ROUTER_ALERT:
+ pd->badopts |= PF_OPT_ROUTER_ALERT;
+ break;
default:
+ pd->badopts |= PF_OPT_OTHER;
break;
}
off += sizeof(opt) + opt.ip6o_len;
@@ -9909,6 +9990,7 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason)
{
struct ip6_frag frag;
struct ip6_ext ext;
+ struct icmp6_hdr icmp6;
struct ip6_rthdr rthdr;
uint32_t end;
int hdr_cnt, fraghdr_cnt = 0, rthdr_cnt = 0;
@@ -9920,27 +10002,40 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason)
for (hdr_cnt = 0; hdr_cnt < PF_HDR_LIMIT; hdr_cnt++) {
switch (pd->proto) {
case IPPROTO_ROUTING:
- case IPPROTO_HOPOPTS:
case IPPROTO_DSTOPTS:
- pd->badopts++;
+ pd->badopts |= PF_OPT_OTHER;
+ break;
+ case IPPROTO_HOPOPTS:
+ if (!pf_pull_hdr(pd->m, pd->off, &ext, sizeof(ext),
+ NULL, reason, AF_INET6)) {
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 short exthdr");
+ return (PF_DROP);
+ }
+ if (pf_walk_option6(pd, h, pd->off + sizeof(ext),
+ pd->off + (ext.ip6e_len + 1) * 8,
+ reason) != PF_PASS)
+ return (PF_DROP);
+ /* option header which contains only padding is fishy */
+ if (pd->badopts == 0)
+ pd->badopts |= PF_OPT_OTHER;
break;
}
switch (pd->proto) {
case IPPROTO_FRAGMENT:
if (fraghdr_cnt++) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 multiple fragment"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 multiple fragment");
REASON_SET(reason, PFRES_FRAG);
return (PF_DROP);
}
/* jumbo payload packets cannot be fragmented */
if (pd->jumbolen != 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 fragmented jumbo"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 fragmented jumbo");
REASON_SET(reason, PFRES_FRAG);
return (PF_DROP);
}
if (!pf_pull_hdr(pd->m, pd->off, &frag, sizeof(frag),
NULL, reason, AF_INET6)) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 short fragment"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 short fragment");
return (PF_DROP);
}
/* stop walking over non initial fragments */
@@ -9956,7 +10051,7 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason)
break;
case IPPROTO_ROUTING:
if (rthdr_cnt++) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 multiple rthdr"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 multiple rthdr");
REASON_SET(reason, PFRES_IPOPTIONS);
return (PF_DROP);
}
@@ -9968,11 +10063,11 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason)
}
if (!pf_pull_hdr(pd->m, pd->off, &rthdr, sizeof(rthdr),
NULL, reason, AF_INET6)) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 short rthdr"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 short rthdr");
return (PF_DROP);
}
if (rthdr.ip6r_type == IPV6_RTHDR_TYPE_0) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 rthdr0"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 rthdr0");
REASON_SET(reason, PFRES_IPOPTIONS);
return (PF_DROP);
}
@@ -9980,7 +10075,7 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason)
case IPPROTO_HOPOPTS:
/* RFC2460 4.1: Hop-by-Hop only after IPv6 header */
if (pd->proto == IPPROTO_HOPOPTS && hdr_cnt > 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 hopopts not first"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 hopopts not first");
REASON_SET(reason, PFRES_IPOPTIONS);
return (PF_DROP);
}
@@ -9989,7 +10084,7 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason)
case IPPROTO_DSTOPTS:
if (!pf_pull_hdr(pd->m, pd->off, &ext, sizeof(ext),
NULL, reason, AF_INET6)) {
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 short exthdr"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 short exthdr");
return (PF_DROP);
}
/* fragments may be short */
@@ -10001,18 +10096,11 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason)
/* reassembly needs the ext header before the frag */
if (pd->fragoff == 0)
pd->extoff = pd->off;
- if (pd->proto == IPPROTO_HOPOPTS && pd->fragoff == 0) {
- if (pf_walk_option6(pd, h,
- pd->off + sizeof(ext),
- pd->off + (ext.ip6e_len + 1) * 8, reason)
- != PF_PASS)
- return (PF_DROP);
- if (ntohs(h->ip6_plen) == 0 && pd->jumbolen != 0) {
- DPFPRINTF(PF_DEBUG_MISC,
- ("IPv6 missing jumbo"));
- REASON_SET(reason, PFRES_IPOPTIONS);
- return (PF_DROP);
- }
+ if (pd->proto == IPPROTO_HOPOPTS && pd->fragoff == 0 &&
+ ntohs(h->ip6_plen) == 0 && pd->jumbolen != 0) {
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 missing jumbo");
+ REASON_SET(reason, PFRES_IPOPTIONS);
+ return (PF_DROP);
}
if (pd->proto == IPPROTO_AH)
pd->off += (ext.ip6e_len + 2) * 4;
@@ -10020,10 +10108,45 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason)
pd->off += (ext.ip6e_len + 1) * 8;
pd->proto = ext.ip6e_nxt;
break;
+ case IPPROTO_ICMPV6:
+ /* fragments may be short, ignore inner header then */
+ if (pd->fragoff != 0 && end < pd->off + sizeof(icmp6)) {
+ pd->off = pd->fragoff;
+ pd->proto = IPPROTO_FRAGMENT;
+ return (PF_PASS);
+ }
+ if (!pf_pull_hdr(pd->m, pd->off, &icmp6, sizeof(icmp6),
+ NULL, reason, AF_INET6)) {
+ DPFPRINTF(PF_DEBUG_MISC,
+ "IPv6 short icmp6hdr");
+ return (PF_DROP);
+ }
+ /* ICMP multicast packets have router alert options */
+ switch (icmp6.icmp6_type) {
+ case MLD_LISTENER_QUERY:
+ case MLD_LISTENER_REPORT:
+ case MLD_LISTENER_DONE:
+ case MLDV2_LISTENER_REPORT:
+ /*
+ * According to RFC 2710 all MLD messages are
+ * sent with hop-limit (ttl) set to 1, and link
+ * local source address. If either one is
+ * missing then MLD message is invalid and
+ * should be discarded.
+ */
+ if ((h->ip6_hlim != 1) ||
+ !IN6_IS_ADDR_LINKLOCAL(&h->ip6_src)) {
+ DPFPRINTF(PF_DEBUG_MISC, "Invalid MLD");
+ REASON_SET(reason, PFRES_IPOPTIONS);
+ return (PF_DROP);
+ }
+ pd->badopts &= ~PF_OPT_ROUTER_ALERT;
+ break;
+ }
+ return (PF_PASS);
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_SCTP:
- case IPPROTO_ICMPV6:
/* fragments may be short, ignore inner header then */
if (pd->fragoff != 0 && end < pd->off +
(pd->proto == IPPROTO_TCP ? sizeof(struct tcphdr) :
@@ -10038,7 +10161,7 @@ pf_walk_header6(struct pf_pdesc *pd, struct ip6_hdr *h, u_short *reason)
return (PF_PASS);
}
}
- DPFPRINTF(PF_DEBUG_MISC, ("IPv6 nested extension header limit"));
+ DPFPRINTF(PF_DEBUG_MISC, "IPv6 nested extension header limit");
REASON_SET(reason, PFRES_IPOPTIONS);
return (PF_DROP);
}
@@ -10083,8 +10206,15 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
if (__predict_false((*m0)->m_len < sizeof(struct ip)) &&
(pd->m = *m0 = m_pullup(*m0, sizeof(struct ip))) == NULL) {
DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: m_len < sizeof(struct ip), pullup failed\n",
- __func__));
+ "%s: m_len < sizeof(struct ip), pullup failed",
+ __func__);
+ *action = PF_DROP;
+ REASON_SET(reason, PFRES_SHORT);
+ return (-1);
+ }
+
+ h = mtod(pd->m, struct ip *);
+ if (pd->m->m_pkthdr.len < ntohs(h->ip_len)) {
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
return (-1);
@@ -10097,13 +10227,7 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
return (-1);
}
*m0 = pd->m;
-
h = mtod(pd->m, struct ip *);
- if (pd->m->m_pkthdr.len < ntohs(h->ip_len)) {
- *action = PF_DROP;
- REASON_SET(reason, PFRES_SHORT);
- return (-1);
- }
if (pf_walk_header(pd, h, reason) != PF_PASS) {
*action = PF_DROP;
@@ -10133,8 +10257,8 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
if (__predict_false((*m0)->m_len < sizeof(struct ip6_hdr)) &&
(pd->m = *m0 = m_pullup(*m0, sizeof(struct ip6_hdr))) == NULL) {
DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: m_len < sizeof(struct ip6_hdr)"
- ", pullup failed\n", __func__));
+ "%s: m_len < sizeof(struct ip6_hdr)"
+ ", pullup failed", __func__);
*action = PF_DROP;
REASON_SET(reason, PFRES_SHORT);
return (-1);
@@ -10148,6 +10272,15 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
return (-1);
}
+ /*
+ * we do not support jumbogram. if we keep going, zero ip6_plen
+ * will do something bad, so drop the packet for now.
+ */
+ if (htons(h->ip6_plen) == 0) {
+ *action = PF_DROP;
+ return (-1);
+ }
+
if (pf_walk_header6(pd, h, reason) != PF_PASS) {
*action = PF_DROP;
return (-1);
@@ -10167,15 +10300,6 @@ pf_setup_pdesc(sa_family_t af, int dir, struct pf_pdesc *pd, struct mbuf **m0,
pd->virtual_proto = (pd->fragoff != 0) ?
PF_VPROTO_FRAGMENT : pd->proto;
- /*
- * we do not support jumbogram. if we keep going, zero ip6_plen
- * will do something bad, so drop the packet for now.
- */
- if (htons(h->ip6_plen) == 0) {
- *action = PF_DROP;
- return (-1);
- }
-
/* We do IP header normalization and packet reassembly here */
if (pf_normalize_ip6(pd->fragoff, reason, pd) !=
PF_PASS) {
@@ -10494,8 +10618,8 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
if (__predict_false(kif == NULL)) {
DPFPRINTF(PF_DEBUG_URGENT,
- ("%s: kif == NULL, if_xname %s\n",
- __func__, ifp->if_xname));
+ "%s: kif == NULL, if_xname %s",
+ __func__, ifp->if_xname);
return (PF_DROP);
}
if (kif->pfik_flags & PFI_IFLAG_SKIP) {
@@ -10699,14 +10823,14 @@ pf_test(sa_family_t af, int dir, int pflags, struct ifnet *ifp, struct mbuf **m0
action = PF_DROP;
REASON_SET(&reason, PFRES_NORM);
DPFPRINTF(PF_DEBUG_MISC,
- ("dropping IPv6 packet with ICMPv4 payload"));
+ "dropping IPv6 packet with ICMPv4 payload");
break;
}
if (pd.virtual_proto == IPPROTO_ICMPV6 && af != AF_INET6) {
action = PF_DROP;
REASON_SET(&reason, PFRES_NORM);
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: dropping IPv4 packet with ICMPv6 payload\n"));
+ "pf: dropping IPv4 packet with ICMPv6 payload");
break;
}
action = pf_test_state_icmp(&s, &pd, &reason);
@@ -10732,12 +10856,12 @@ done:
if (s)
memcpy(&pd.act, &s->act, sizeof(s->act));
- if (action == PF_PASS && pd.badopts && !pd.act.allow_opts) {
+ if (action == PF_PASS && pd.badopts != 0 && !pd.act.allow_opts) {
action = PF_DROP;
REASON_SET(&reason, PFRES_IPOPTIONS);
pd.act.log = PF_LOG_FORCE;
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: dropping packet with dangerous headers\n"));
+ "pf: dropping packet with dangerous headers");
}
if (pd.act.max_pkt_size && pd.act.max_pkt_size &&
@@ -10746,7 +10870,7 @@ done:
REASON_SET(&reason, PFRES_NORM);
pd.act.log = PF_LOG_FORCE;
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: dropping overly long packet\n"));
+ "pf: dropping overly long packet");
}
if (s) {
@@ -10778,7 +10902,7 @@ done:
REASON_SET(&reason, PFRES_MEMORY);
pd.act.log = PF_LOG_FORCE;
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: failed to allocate 802.1q mtag\n"));
+ "pf: failed to allocate 802.1q mtag");
}
}
@@ -10835,7 +10959,7 @@ done:
REASON_SET(&reason, PFRES_MEMORY);
pd.act.log = PF_LOG_FORCE;
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: failed to allocate tag\n"));
+ "pf: failed to allocate tag");
} else {
pd.pf_mtag->flags |=
PF_MTAG_FLAG_FASTFWD_OURS_PRESENT;
@@ -10852,7 +10976,7 @@ done:
REASON_SET(&reason, PFRES_MEMORY);
pd.act.log = PF_LOG_FORCE;
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: failed to allocate divert tag\n"));
+ "pf: failed to allocate divert tag");
}
}
/* XXX: Anybody working on it?! */
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 3caa0d2e3b11..9abc07c36788 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -217,8 +217,6 @@ static u_int16_t tagname2tag(struct pf_tagset *, const char *);
static u_int16_t pf_tagname2tag(const char *);
static void tag_unref(struct pf_tagset *, u_int16_t);
-#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
-
struct cdev *pf_dev;
/*
@@ -2042,6 +2040,34 @@ pf_ioctl_getrules(struct pfioc_rule *pr)
}
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]);
@@ -2066,17 +2092,18 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
int rs_num;
int error = 0;
- if ((rule->return_icmp >> 8) > ICMP_MAXTYPE) {
- error = EINVAL;
- goto errout_unlocked;
- }
+#define ERROUT(x) ERROUT_FUNCTION(errout, x)
+#define ERROUT_UNLOCKED(x) ERROUT_FUNCTION(errout_unlocked, x)
-#define ERROUT(x) ERROUT_FUNCTION(errout, x)
+ if ((rule->return_icmp >> 8) > ICMP_MAXTYPE)
+ ERROUT_UNLOCKED(EINVAL);
+ if ((error = pf_rule_checkaf(rule)))
+ ERROUT_UNLOCKED(error);
if (pf_validate_range(rule->src.port_op, rule->src.port))
- ERROUT(EINVAL);
+ ERROUT_UNLOCKED(EINVAL);
if (pf_validate_range(rule->dst.port_op, rule->dst.port))
- ERROUT(EINVAL);
+ ERROUT_UNLOCKED(EINVAL);
if (rule->ifname[0])
kif = pf_kkif_create(M_WAITOK);
@@ -2113,14 +2140,14 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
ERROUT(EINVAL);
if (ticket != ruleset->rules[rs_num].inactive.ticket) {
DPFPRINTF(PF_DEBUG_MISC,
- ("ticket: %d != [%d]%d\n", ticket, rs_num,
- ruleset->rules[rs_num].inactive.ticket));
+ "ticket: %d != [%d]%d", ticket, rs_num,
+ ruleset->rules[rs_num].inactive.ticket);
ERROUT(EBUSY);
}
if (pool_ticket != V_ticket_pabuf) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pool_ticket: %d != %d\n", pool_ticket,
- V_ticket_pabuf));
+ "pool_ticket: %d != %d", pool_ticket,
+ V_ticket_pabuf);
ERROUT(EBUSY);
}
/*
@@ -2266,6 +2293,7 @@ pf_ioctl_addrule(struct pf_krule *rule, uint32_t ticket,
return (0);
#undef ERROUT
+#undef ERROUT_UNLOCKED
errout:
PF_RULES_WUNLOCK();
PF_CONFIG_UNLOCK();
@@ -2439,7 +2467,7 @@ pf_start(void)
V_pf_status.since = time_uptime;
new_unrhdr64(&V_pf_stateid, time_second);
- DPFPRINTF(PF_DEBUG_MISC, ("pf: started\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "pf: started");
}
sx_xunlock(&V_pf_ioctl_lock);
@@ -2459,7 +2487,7 @@ pf_stop(void)
dehook_pf();
dehook_pf_eth();
V_pf_status.since = time_uptime;
- DPFPRINTF(PF_DEBUG_MISC, ("pf: stopped\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "pf: stopped");
}
sx_xunlock(&V_pf_ioctl_lock);
@@ -3234,9 +3262,9 @@ DIOCGETETHRULE_error:
if (nvlist_get_number(nvl, "ticket") !=
ruleset->inactive.ticket) {
DPFPRINTF(PF_DEBUG_MISC,
- ("ticket: %d != %d\n",
+ "ticket: %d != %d",
(u_int32_t)nvlist_get_number(nvl, "ticket"),
- ruleset->inactive.ticket));
+ ruleset->inactive.ticket);
ERROUT(EBUSY);
}
@@ -3567,7 +3595,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';
@@ -3726,11 +3754,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) {
@@ -3738,9 +3766,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);
@@ -3888,7 +3920,7 @@ DIOCGETRULENV_error:
pf_free_rule(newrule);
PF_RULES_WUNLOCK();
PF_CONFIG_UNLOCK();
- break;
+ goto fail;
}
newrule->nat.cur = TAILQ_FIRST(&newrule->nat.list);
@@ -3915,7 +3947,7 @@ DIOCGETRULENV_error:
PF_RULES_WUNLOCK();
PF_CONFIG_UNLOCK();
error = EINVAL;
- break;
+ goto fail;
}
}
@@ -3933,7 +3965,7 @@ DIOCGETRULENV_error:
PF_RULES_WUNLOCK();
PF_CONFIG_UNLOCK();
error = EEXIST;
- break;
+ goto fail;
}
if (oldrule == NULL)
@@ -3989,7 +4021,7 @@ DIOCCHANGERULE_error:
if (sp->timeout >= PFTM_MAX) {
error = EINVAL;
- break;
+ goto fail;
}
if (V_pfsync_state_import_ptr != NULL) {
PF_RULES_RLOCK();
@@ -4009,7 +4041,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,
@@ -4088,7 +4120,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:
@@ -4108,7 +4140,7 @@ DIOCGETSTATES_full:
if (ps->ps_req_version > PF_STATE_VERSION) {
error = ENOTSUP;
- break;
+ goto fail;
}
if (ps->ps_len <= 0) {
@@ -4166,7 +4198,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:
@@ -4272,12 +4304,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 =
@@ -4306,7 +4338,7 @@ DIOCGETSTATESV2_full:
if (error == 0)
V_pf_altq_running = 1;
PF_RULES_WUNLOCK();
- DPFPRINTF(PF_DEBUG_MISC, ("altq: started\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "altq: started");
break;
}
@@ -4325,7 +4357,7 @@ DIOCGETSTATESV2_full:
if (error == 0)
V_pf_altq_running = 0;
PF_RULES_WUNLOCK();
- DPFPRINTF(PF_DEBUG_MISC, ("altq: stopped\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "altq: stopped");
break;
}
@@ -4338,7 +4370,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();
@@ -4346,7 +4378,7 @@ DIOCGETSTATESV2_full:
PF_RULES_WUNLOCK();
free(altq, M_PFALTQ);
error = EBUSY;
- break;
+ goto fail;
}
/*
@@ -4358,7 +4390,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) {
@@ -4378,7 +4410,7 @@ DIOCGETSTATESV2_full:
if (error) {
PF_RULES_WUNLOCK();
free(altq, M_PFALTQ);
- break;
+ goto fail;
}
if (altq->qname[0] != 0)
@@ -4416,13 +4448,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();
@@ -4446,20 +4478,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)
@@ -4528,30 +4560,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);
@@ -4674,7 +4706,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,
@@ -4690,13 +4722,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);
@@ -4705,7 +4737,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,
@@ -4722,13 +4754,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);
@@ -4737,7 +4769,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,
@@ -4755,14 +4787,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);
@@ -4773,7 +4805,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);
@@ -4792,7 +4824,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_tstats)) {
error = ENODEV;
- break;
+ goto fail;
}
PF_TABLE_STATS_LOCK();
PF_RULES_RLOCK();
@@ -4801,7 +4833,7 @@ DIOCCHANGEADDR_error:
PF_RULES_RUNLOCK();
PF_TABLE_STATS_UNLOCK();
error = EINVAL;
- break;
+ goto fail;
}
io->pfrio_size = min(io->pfrio_size, n);
@@ -4812,7 +4844,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);
@@ -4831,7 +4863,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 ||
@@ -4840,7 +4872,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);
@@ -4849,7 +4881,7 @@ DIOCCHANGEADDR_error:
error = copyin(io->pfrio_buffer, pfrts, totlen);
if (error) {
free(pfrts, M_TEMP);
- break;
+ goto fail;
}
PF_TABLE_STATS_LOCK();
@@ -4870,7 +4902,7 @@ DIOCCHANGEADDR_error:
if (io->pfrio_esize != sizeof(struct pfr_table)) {
error = ENODEV;
- break;
+ goto fail;
}
PF_RULES_RLOCK();
@@ -4878,7 +4910,7 @@ DIOCCHANGEADDR_error:
if (n < 0) {
PF_RULES_RUNLOCK();
error = EINVAL;
- break;
+ goto fail;
}
io->pfrio_size = min(io->pfrio_size, n);
@@ -4890,7 +4922,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,
@@ -4906,7 +4938,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,
@@ -4922,13 +4954,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),
@@ -4936,7 +4968,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,
@@ -4956,13 +4988,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),
@@ -4970,7 +5002,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,
@@ -4990,17 +5022,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,
@@ -5008,7 +5040,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,
@@ -5029,13 +5061,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),
@@ -5057,13 +5089,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,
@@ -5085,13 +5117,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),
@@ -5099,7 +5131,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,
@@ -5119,13 +5151,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),
@@ -5133,7 +5165,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,
@@ -5153,13 +5185,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),
@@ -5167,7 +5199,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,
@@ -5202,13 +5234,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),
@@ -5216,7 +5248,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++) {
@@ -5283,13 +5315,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),
@@ -5297,7 +5329,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++) {
@@ -5366,14 +5398,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;
@@ -5382,7 +5414,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. */
@@ -5523,7 +5555,7 @@ DIOCCHANGEADDR_error:
if (psn->psn_len == 0) {
psn->psn_len = sizeof(struct pf_src_node) * nr;
- break;
+ goto fail;
}
nr = 0;
@@ -5548,7 +5580,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);
@@ -5604,14 +5636,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';
@@ -6423,9 +6455,9 @@ shutdown_pf(void)
for (rs_num = 0; rs_num < PF_RULESET_MAX; ++rs_num) {
if ((error = pf_begin_rules(&t[rs_num], rs_num,
anchor->path)) != 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("%s: "
- "anchor.path=%s rs_num=%d\n",
- __func__, anchor->path, rs_num));
+ DPFPRINTF(PF_DEBUG_MISC, "%s: "
+ "anchor.path=%s rs_num=%d",
+ __func__, anchor->path, rs_num);
goto error; /* XXX: rollback? */
}
}
@@ -6447,9 +6479,9 @@ shutdown_pf(void)
eth_anchor->refcnt = 1;
if ((error = pf_begin_eth(&t[0], eth_anchor->path))
!= 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("%s: eth "
- "anchor.path=%s\n", __func__,
- eth_anchor->path));
+ DPFPRINTF(PF_DEBUG_MISC, "%s: eth "
+ "anchor.path=%s", __func__,
+ eth_anchor->path);
goto error;
}
error = pf_commit_eth(t[0], eth_anchor->path);
@@ -6458,27 +6490,27 @@ shutdown_pf(void)
if ((error = pf_begin_rules(&t[0], PF_RULESET_SCRUB, &nn))
!= 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("%s: SCRUB\n", __func__));
+ DPFPRINTF(PF_DEBUG_MISC, "%s: SCRUB", __func__);
break;
}
if ((error = pf_begin_rules(&t[1], PF_RULESET_FILTER, &nn))
!= 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("%s: FILTER\n", __func__));
+ DPFPRINTF(PF_DEBUG_MISC, "%s: FILTER", __func__);
break; /* XXX: rollback? */
}
if ((error = pf_begin_rules(&t[2], PF_RULESET_NAT, &nn))
!= 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("%s: NAT\n", __func__));
+ DPFPRINTF(PF_DEBUG_MISC, "%s: NAT", __func__);
break; /* XXX: rollback? */
}
if ((error = pf_begin_rules(&t[3], PF_RULESET_BINAT, &nn))
!= 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("%s: BINAT\n", __func__));
+ DPFPRINTF(PF_DEBUG_MISC, "%s: BINAT", __func__);
break; /* XXX: rollback? */
}
if ((error = pf_begin_rules(&t[4], PF_RULESET_RDR, &nn))
!= 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("%s: RDR\n", __func__));
+ DPFPRINTF(PF_DEBUG_MISC, "%s: RDR", __func__);
break; /* XXX: rollback? */
}
@@ -6497,7 +6529,7 @@ shutdown_pf(void)
break;
if ((error = pf_begin_eth(&t[0], &nn)) != 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("%s: eth\n", __func__));
+ DPFPRINTF(PF_DEBUG_MISC, "%s: eth", __func__);
break;
}
error = pf_commit_eth(t[0], &nn);
@@ -6505,7 +6537,7 @@ shutdown_pf(void)
#ifdef ALTQ
if ((error = pf_begin_altq(&t[0])) != 0) {
- DPFPRINTF(PF_DEBUG_MISC, ("%s: ALTQ\n", __func__));
+ DPFPRINTF(PF_DEBUG_MISC, "%s: ALTQ", __func__);
break;
}
pf_commit_altq(t[0]);
diff --git a/sys/netpfil/pf/pf_lb.c b/sys/netpfil/pf/pf_lb.c
index 26f7ab41eef4..ea0d6facf695 100644
--- a/sys/netpfil/pf/pf_lb.c
+++ b/sys/netpfil/pf/pf_lb.c
@@ -71,8 +71,6 @@
#define V_pf_rdr_srcport_rewrite_tries VNET(pf_rdr_srcport_rewrite_tries)
VNET_DEFINE_STATIC(int, pf_rdr_srcport_rewrite_tries) = 16;
-#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
-
static uint64_t pf_hash(struct pf_addr *, struct pf_addr *,
struct pf_poolhashkey *, sa_family_t);
struct pf_krule *pf_match_translation(int, struct pf_test_ctx *);
@@ -904,19 +902,19 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
if (pf_get_mape_sport(pd, r, naddr, nportp,
&ctx->udp_mapping, rpool)) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: MAP-E port allocation (%u/%u/%u)"
- " failed\n",
+ "pf: MAP-E port allocation (%u/%u/%u)"
+ " failed",
rpool->mape.offset,
rpool->mape.psidlen,
- rpool->mape.psid));
+ rpool->mape.psid);
reason = PFRES_MAPFAILED;
goto notrans;
}
} else if (pf_get_sport(pd, r, naddr, nportp, low, high,
rpool, &ctx->udp_mapping, PF_SN_NAT)) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: NAT proxy port allocation (%u-%u) failed\n",
- rpool->proxy_port[0], rpool->proxy_port[1]));
+ "pf: NAT proxy port allocation (%u-%u) failed",
+ rpool->proxy_port[0], rpool->proxy_port[1]);
reason = PFRES_MAPFAILED;
goto notrans;
}
@@ -1012,10 +1010,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;
+
+ 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])) %
- (rpool->proxy_port[1] - rpool->proxy_port[0] +
- 1)) + rpool->proxy_port[0];
+ tmp_nport = ((ntohs(pd->ndport) - ntohs(r->dst.port[0])) % div) +
+ rpool->proxy_port[0];
/* Wrap around if necessary. */
if (tmp_nport > 65535)
@@ -1082,13 +1083,13 @@ pf_get_transaddr(struct pf_test_ctx *ctx, struct pf_krule *r,
* the state may be reused if the TCP state is terminal.
*/
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: RDR source port allocation failed\n"));
+ "pf: RDR source port allocation failed");
break;
out:
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: RDR source port allocation %u->%u\n",
- ntohs(pd->nsport), ntohs(ctx->nk->port[0])));
+ "pf: RDR source port allocation %u->%u",
+ ntohs(pd->nsport), ntohs(ctx->nk->port[0]));
break;
}
default:
@@ -1137,8 +1138,8 @@ pf_get_transaddr_af(struct pf_krule *r, struct pf_pdesc *pd)
if (pf_get_sport(pd, r, &nsaddr, &nport, r->nat.proxy_port[0],
r->nat.proxy_port[1], &r->nat, NULL, PF_SN_NAT)) {
DPFPRINTF(PF_DEBUG_MISC,
- ("pf: af-to NAT proxy port allocation (%u-%u) failed",
- r->nat.proxy_port[0], r->nat.proxy_port[1]));
+ "pf: af-to NAT proxy port allocation (%u-%u) failed",
+ r->nat.proxy_port[0], r->nat.proxy_port[1]);
return (-1);
}
diff --git a/sys/netpfil/pf/pf_norm.c b/sys/netpfil/pf/pf_norm.c
index 369292ca365e..8cea9557633c 100644
--- a/sys/netpfil/pf/pf_norm.c
+++ b/sys/netpfil/pf/pf_norm.c
@@ -160,13 +160,6 @@ static int pf_reassemble6(struct mbuf **,
struct ip6_frag *, uint16_t, uint16_t, u_short *);
#endif /* INET6 */
-#define DPFPRINTF(x) do { \
- if (V_pf_status.debug >= PF_DEBUG_MISC) { \
- printf("%s: ", __func__); \
- printf x ; \
- } \
-} while(0)
-
#ifdef INET
static void
pf_ip2key(struct ip *ip, struct pf_frnode *key)
@@ -262,7 +255,8 @@ pf_purge_fragments(uint32_t expire)
if (frag->fr_timeout > expire)
break;
- DPFPRINTF(("expiring %d(%p)\n", frag->fr_id, frag));
+ DPFPRINTF(PF_DEBUG_MISC, "expiring %d(%p)",
+ frag->fr_id, frag);
pf_free_fragment(frag);
}
@@ -281,7 +275,7 @@ pf_flush_fragments(void)
PF_FRAG_ASSERT();
goal = uma_zone_get_cur(V_pf_frent_z) * 9 / 10;
- DPFPRINTF(("trying to free %d frag entriess\n", goal));
+ DPFPRINTF(PF_DEBUG_MISC, "trying to free %d frag entriess", goal);
while (goal < uma_zone_get_cur(V_pf_frent_z)) {
frag = TAILQ_LAST(&V_pf_fragqueue, pf_fragqueue);
if (frag)
@@ -573,26 +567,30 @@ pf_fillup_fragment(struct pf_frnode *key, uint32_t id,
/* No empty fragments. */
if (frent->fe_len == 0) {
- DPFPRINTF(("bad fragment: len 0\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "bad fragment: len 0");
goto bad_fragment;
}
/* All fragments are 8 byte aligned. */
if (frent->fe_mff && (frent->fe_len & 0x7)) {
- DPFPRINTF(("bad fragment: mff and len %d\n", frent->fe_len));
+ DPFPRINTF(PF_DEBUG_MISC, "bad fragment: mff and len %d",
+ frent->fe_len);
goto bad_fragment;
}
/* Respect maximum length, IP_MAXPACKET == IPV6_MAXPACKET. */
if (frent->fe_off + frent->fe_len > IP_MAXPACKET) {
- DPFPRINTF(("bad fragment: max packet %d\n",
- frent->fe_off + frent->fe_len));
+ DPFPRINTF(PF_DEBUG_MISC, "bad fragment: max packet %d",
+ frent->fe_off + frent->fe_len);
goto bad_fragment;
}
- DPFPRINTF((key->fn_af == AF_INET ?
- "reass frag %d @ %d-%d\n" : "reass frag %#08x @ %d-%d\n",
- id, frent->fe_off, frent->fe_off + frent->fe_len));
+ if (key->fn_af == AF_INET)
+ DPFPRINTF(PF_DEBUG_MISC, "reass frag %d @ %d-%d\n",
+ id, frent->fe_off, frent->fe_off + frent->fe_len);
+ else
+ DPFPRINTF(PF_DEBUG_MISC, "reass frag %#08x @ %d-%d",
+ id, frent->fe_off, frent->fe_off + frent->fe_len);
/* Fully buffer all of the fragments in this fragment queue. */
frag = pf_find_fragment(key, id);
@@ -690,10 +688,10 @@ pf_fillup_fragment(struct pf_frnode *key, uint32_t id,
precut = prev->fe_off + prev->fe_len - frent->fe_off;
if (precut >= frent->fe_len) {
- DPFPRINTF(("new frag overlapped\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "new frag overlapped");
goto drop_fragment;
}
- DPFPRINTF(("frag head overlap %d\n", precut));
+ DPFPRINTF(PF_DEBUG_MISC, "frag head overlap %d", precut);
m_adj(frent->fe_m, precut);
frent->fe_off += precut;
frent->fe_len -= precut;
@@ -705,7 +703,8 @@ pf_fillup_fragment(struct pf_frnode *key, uint32_t id,
aftercut = frent->fe_off + frent->fe_len - after->fe_off;
if (aftercut < after->fe_len) {
- DPFPRINTF(("frag tail overlap %d", aftercut));
+ DPFPRINTF(PF_DEBUG_MISC, "frag tail overlap %d",
+ aftercut);
m_adj(after->fe_m, aftercut);
/* Fragment may switch queue as fe_off changes */
pf_frent_remove(frag, after);
@@ -713,7 +712,8 @@ pf_fillup_fragment(struct pf_frnode *key, uint32_t id,
after->fe_len -= aftercut;
/* Insert into correct queue */
if (pf_frent_insert(frag, after, prev)) {
- DPFPRINTF(("fragment requeue limit exceeded"));
+ DPFPRINTF(PF_DEBUG_MISC,
+ "fragment requeue limit exceeded");
m_freem(after->fe_m);
uma_zfree(V_pf_frent_z, after);
/* There is not way to recover */
@@ -723,7 +723,7 @@ pf_fillup_fragment(struct pf_frnode *key, uint32_t id,
}
/* This fragment is completely overlapped, lose it. */
- DPFPRINTF(("old frag overlapped\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "old frag overlapped");
next = TAILQ_NEXT(after, fr_next);
pf_frent_remove(frag, after);
m_freem(after->fe_m);
@@ -732,7 +732,7 @@ pf_fillup_fragment(struct pf_frnode *key, uint32_t id,
/* If part of the queue gets too long, there is not way to recover. */
if (pf_frent_insert(frag, frent, prev)) {
- DPFPRINTF(("fragment queue limit exceeded\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "fragment queue limit exceeded");
goto bad_fragment;
}
@@ -748,7 +748,7 @@ free_fragment:
* fragment, the entire datagram (and any constituent fragments) MUST
* be silently discarded.
*/
- DPFPRINTF(("flush overlapping fragments\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "flush overlapping fragments");
pf_free_fragment(frag);
bad_fragment:
@@ -826,7 +826,8 @@ pf_reassemble(struct mbuf **m0, u_short *reason)
m = *m0 = NULL;
if (frag->fr_holes) {
- DPFPRINTF(("frag %d, holes %d\n", frag->fr_id, frag->fr_holes));
+ DPFPRINTF(PF_DEBUG_MISC, "frag %d, holes %d",
+ frag->fr_id, frag->fr_holes);
return (PF_PASS); /* drop because *m0 is NULL, no error */
}
@@ -872,14 +873,14 @@ pf_reassemble(struct mbuf **m0, u_short *reason)
ip->ip_off &= ~(IP_MF|IP_OFFMASK);
if (hdrlen + total > IP_MAXPACKET) {
- DPFPRINTF(("drop: too big: %d\n", total));
+ DPFPRINTF(PF_DEBUG_MISC, "drop: too big: %d", total);
ip->ip_len = 0;
REASON_SET(reason, PFRES_SHORT);
/* PF_DROP requires a valid mbuf *m0 in pf_test() */
return (PF_DROP);
}
- DPFPRINTF(("complete: %p(%d)\n", m, ntohs(ip->ip_len)));
+ DPFPRINTF(PF_DEBUG_MISC, "complete: %p(%d)", m, ntohs(ip->ip_len));
return (PF_PASS);
}
#endif /* INET */
@@ -931,8 +932,8 @@ pf_reassemble6(struct mbuf **m0, struct ip6_frag *fraghdr,
m = *m0 = NULL;
if (frag->fr_holes) {
- DPFPRINTF(("frag %d, holes %d\n", frag->fr_id,
- frag->fr_holes));
+ DPFPRINTF(PF_DEBUG_MISC, "frag %d, holes %d", frag->fr_id,
+ frag->fr_holes);
PF_FRAG_UNLOCK();
return (PF_PASS); /* Drop because *m0 is NULL, no error. */
}
@@ -993,14 +994,15 @@ pf_reassemble6(struct mbuf **m0, struct ip6_frag *fraghdr,
ip6->ip6_nxt = proto;
if (hdrlen - sizeof(struct ip6_hdr) + total > IPV6_MAXPACKET) {
- DPFPRINTF(("drop: too big: %d\n", total));
+ DPFPRINTF(PF_DEBUG_MISC, "drop: too big: %d", total);
ip6->ip6_plen = 0;
REASON_SET(reason, PFRES_SHORT);
/* PF_DROP requires a valid mbuf *m0 in pf_test6(). */
return (PF_DROP);
}
- DPFPRINTF(("complete: %p(%d)\n", m, ntohs(ip6->ip6_plen)));
+ DPFPRINTF(PF_DEBUG_MISC, "complete: %p(%d)", m,
+ ntohs(ip6->ip6_plen));
return (PF_PASS);
fail:
@@ -1090,7 +1092,7 @@ pf_refragment6(struct ifnet *ifp, struct mbuf **m0, struct m_tag *mtag,
action = PF_PASS;
} else {
/* Drop expects an mbuf to free. */
- DPFPRINTF(("refragment error %d\n", error));
+ DPFPRINTF(PF_DEBUG_MISC, "refragment error %d", error);
action = PF_DROP;
}
for (; m; m = t) {
@@ -1230,7 +1232,7 @@ pf_normalize_ip(u_short *reason, struct pf_pdesc *pd)
* no-df above, fine. Otherwise drop it.
*/
if (h->ip_off & htons(IP_DF)) {
- DPFPRINTF(("IP_DF\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "IP_DF");
goto bad;
}
@@ -1238,13 +1240,13 @@ pf_normalize_ip(u_short *reason, struct pf_pdesc *pd)
/* All fragments are 8 byte aligned */
if (mff && (ip_len & 0x7)) {
- DPFPRINTF(("mff and %d\n", ip_len));
+ DPFPRINTF(PF_DEBUG_MISC, "mff and %d", ip_len);
goto bad;
}
/* Respect maximum length */
if (fragoff + ip_len > IP_MAXPACKET) {
- DPFPRINTF(("max packet %d\n", fragoff + ip_len));
+ DPFPRINTF(PF_DEBUG_MISC, "max packet %d", fragoff + ip_len);
goto bad;
}
@@ -1256,7 +1258,8 @@ pf_normalize_ip(u_short *reason, struct pf_pdesc *pd)
/* Fully buffer all of the fragments
* Might return a completely reassembled mbuf, or NULL */
PF_FRAG_LOCK();
- DPFPRINTF(("reass frag %d @ %d-%d\n", h->ip_id, fragoff, max));
+ DPFPRINTF(PF_DEBUG_MISC, "reass frag %d @ %d-%d",
+ h->ip_id, fragoff, max);
verdict = pf_reassemble(&pd->m, reason);
PF_FRAG_UNLOCK();
@@ -1282,7 +1285,7 @@ pf_normalize_ip(u_short *reason, struct pf_pdesc *pd)
return (PF_PASS);
bad:
- DPFPRINTF(("dropping bad fragment\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "dropping bad fragment");
REASON_SET(reason, PFRES_FRAG);
drop:
if (r != NULL && r->log)
@@ -1711,7 +1714,7 @@ pf_normalize_tcp_stateful(struct pf_pdesc *pd,
(uptime.tv_sec - src->scrub->pfss_last.tv_sec > TS_MAX_IDLE ||
time_uptime - (state->creation / 1000) > TS_MAX_CONN)) {
if (V_pf_status.debug >= PF_DEBUG_MISC) {
- DPFPRINTF(("src idled out of PAWS\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "src idled out of PAWS");
pf_print_state(state);
printf("\n");
}
@@ -1721,7 +1724,7 @@ pf_normalize_tcp_stateful(struct pf_pdesc *pd,
if (dst->scrub && (dst->scrub->pfss_flags & PFSS_PAWS) &&
uptime.tv_sec - dst->scrub->pfss_last.tv_sec > TS_MAX_IDLE) {
if (V_pf_status.debug >= PF_DEBUG_MISC) {
- DPFPRINTF(("dst idled out of PAWS\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "dst idled out of PAWS");
pf_print_state(state);
printf("\n");
}
@@ -1826,22 +1829,22 @@ pf_normalize_tcp_stateful(struct pf_pdesc *pd,
* an old timestamp.
*/
- DPFPRINTF(("Timestamp failed %c%c%c%c\n",
+ DPFPRINTF(PF_DEBUG_MISC, "Timestamp failed %c%c%c%c",
SEQ_LT(tsval, dst->scrub->pfss_tsecr) ? '0' : ' ',
SEQ_GT(tsval, src->scrub->pfss_tsval +
tsval_from_last) ? '1' : ' ',
SEQ_GT(tsecr, dst->scrub->pfss_tsval) ? '2' : ' ',
- SEQ_LT(tsecr, dst->scrub->pfss_tsval0)? '3' : ' '));
- DPFPRINTF((" tsval: %u tsecr: %u +ticks: %u "
- "idle: %jus %lums\n",
+ SEQ_LT(tsecr, dst->scrub->pfss_tsval0)? '3' : ' ');
+ DPFPRINTF(PF_DEBUG_MISC, " tsval: %u tsecr: %u +ticks: "
+ "%u idle: %jus %lums",
tsval, tsecr, tsval_from_last,
(uintmax_t)delta_ts.tv_sec,
- delta_ts.tv_usec / 1000));
- DPFPRINTF((" src->tsval: %u tsecr: %u\n",
- src->scrub->pfss_tsval, src->scrub->pfss_tsecr));
- DPFPRINTF((" dst->tsval: %u tsecr: %u tsval0: %u"
- "\n", dst->scrub->pfss_tsval,
- dst->scrub->pfss_tsecr, dst->scrub->pfss_tsval0));
+ delta_ts.tv_usec / 1000);
+ DPFPRINTF(PF_DEBUG_MISC, " src->tsval: %u tsecr: %u",
+ src->scrub->pfss_tsval, src->scrub->pfss_tsecr);
+ DPFPRINTF(PF_DEBUG_MISC, " dst->tsval: %u tsecr: %u "
+ "tsval0: %u", dst->scrub->pfss_tsval,
+ dst->scrub->pfss_tsecr, dst->scrub->pfss_tsval0);
if (V_pf_status.debug >= PF_DEBUG_MISC) {
pf_print_state(state);
pf_print_flags(tcp_get_flags(th));
@@ -1891,8 +1894,8 @@ pf_normalize_tcp_stateful(struct pf_pdesc *pd,
* stack changed its RFC1323 behavior?!?!
*/
if (V_pf_status.debug >= PF_DEBUG_MISC) {
- DPFPRINTF(("Did not receive expected RFC1323 "
- "timestamp\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "Did not receive expected "
+ "RFC1323 timestamp");
pf_print_state(state);
pf_print_flags(tcp_get_flags(th));
printf("\n");
@@ -1919,9 +1922,9 @@ pf_normalize_tcp_stateful(struct pf_pdesc *pd,
if (V_pf_status.debug >= PF_DEBUG_MISC && dst->scrub &&
(dst->scrub->pfss_flags & PFSS_TIMESTAMP)) {
/* Don't warn if other host rejected RFC1323 */
- DPFPRINTF(("Broken RFC1323 stack did not "
- "timestamp data packet. Disabled PAWS "
- "security.\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "Broken RFC1323 stack did "
+ "not timestamp data packet. Disabled PAWS "
+ "security.");
pf_print_state(state);
pf_print_flags(tcp_get_flags(th));
printf("\n");
diff --git a/sys/netpfil/pf/pf_osfp.c b/sys/netpfil/pf/pf_osfp.c
index 3e00cc7c80a2..150626c5f3fb 100644
--- a/sys/netpfil/pf/pf_osfp.c
+++ b/sys/netpfil/pf/pf_osfp.c
@@ -40,9 +40,6 @@
#endif
static MALLOC_DEFINE(M_PFOSFP, "pf_osfp", "pf(4) operating system fingerprints");
-#define DPFPRINTF(format, x...) \
- if (V_pf_status.debug >= PF_DEBUG_NOISY) \
- printf(format , ##x)
SLIST_HEAD(pf_osfp_list, pf_os_fingerprint);
VNET_DEFINE_STATIC(struct pf_osfp_list, pf_osfp_list) =
@@ -189,8 +186,8 @@ pf_osfp_fingerprint_hdr(const struct ip *ip, const struct ip6_hdr *ip6, const st
optlen = MAX(optlen, 1); /* paranoia */
}
- DPFPRINTF("fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) "
- "(TS=%s,M=%s%d,W=%s%d)\n",
+ DPFPRINTF(PF_DEBUG_NOISY, "fingerprinted %s:%d %d:%d:%d:%d:%llx (%d) "
+ "(TS=%s,M=%s%d,W=%s%d)",
srcname, ntohs(tcp->th_sport),
fp.fp_wsize, fp.fp_ttl, (fp.fp_flags & PF_OSFP_DF) != 0,
fp.fp_psize, (long long int)fp.fp_tcpopts, fp.fp_optcnt,
@@ -219,7 +216,7 @@ pf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os)
if (os == PF_OSFP_ANY)
return (1);
if (list == NULL) {
- DPFPRINTF("osfp no match against %x\n", os);
+ DPFPRINTF(PF_DEBUG_NOISY, "osfp no match against %x", os);
return (os == PF_OSFP_UNKNOWN);
}
PF_OSFP_UNPACK(os, os_class, os_version, os_subtype);
@@ -228,13 +225,13 @@ pf_osfp_match(struct pf_osfp_enlist *list, pf_osfp_t os)
if ((os_class == PF_OSFP_ANY || en_class == os_class) &&
(os_version == PF_OSFP_ANY || en_version == os_version) &&
(os_subtype == PF_OSFP_ANY || en_subtype == os_subtype)) {
- DPFPRINTF("osfp matched %s %s %s %x==%x\n",
+ DPFPRINTF(PF_DEBUG_NOISY, "osfp matched %s %s %s %x==%x",
entry->fp_class_nm, entry->fp_version_nm,
entry->fp_subtype_nm, os, entry->fp_os);
return (1);
}
}
- DPFPRINTF("fingerprint 0x%x didn't match\n", os);
+ DPFPRINTF(PF_DEBUG_NOISY, "fingerprint 0x%x didn't match", os);
return (0);
}
@@ -275,8 +272,8 @@ pf_osfp_add(struct pf_osfp_ioctl *fpioc)
fpadd.fp_ttl = fpioc->fp_ttl;
#if 0 /* XXX RYAN wants to fix logging */
- DPFPRINTF("adding osfp %s %s %s = %s%d:%d:%d:%s%d:0x%llx %d "
- "(TS=%s,M=%s%d,W=%s%d) %x\n",
+ DPFPRINTF(PF_DEBUG_NOISY, "adding osfp %s %s %s ="
+ " %s%d:%d:%d:%s%d:0x%llx %d (TS=%s,M=%s%d,W=%s%d) %x",
fpioc->fp_os.fp_class_nm, fpioc->fp_os.fp_version_nm,
fpioc->fp_os.fp_subtype_nm,
(fpadd.fp_flags & PF_OSFP_WSIZE_MOD) ? "%" :
diff --git a/sys/netpfil/pf/pf_ruleset.c b/sys/netpfil/pf/pf_ruleset.c
index 2e5165a9900c..43b51f2933f4 100644
--- a/sys/netpfil/pf/pf_ruleset.c
+++ b/sys/netpfil/pf/pf_ruleset.c
@@ -59,9 +59,6 @@
#error "Kernel only file. Please use sbin/pfctl/pf_ruleset.c instead."
#endif
-#define DPFPRINTF(format, x...) \
- if (V_pf_status.debug >= PF_DEBUG_NOISY) \
- printf(format , ##x)
#define rs_malloc(x) malloc(x, M_TEMP, M_NOWAIT|M_ZERO)
#define rs_free(x) free(x, M_TEMP)
@@ -386,7 +383,8 @@ pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
strlcpy(path, s->anchor->path, MAXPATHLEN);
while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
if (!path[0]) {
- DPFPRINTF("%s: .. beyond root\n", __func__);
+ DPFPRINTF(PF_DEBUG_NOISY, "%s: .. beyond root",
+ __func__);
rs_free(path);
return (1);
}
@@ -408,7 +406,7 @@ pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
ruleset = pf_find_or_create_kruleset(path);
rs_free(path);
if (ruleset == NULL || ruleset == &pf_main_ruleset) {
- DPFPRINTF("%s: ruleset\n", __func__);
+ DPFPRINTF(PF_DEBUG_NOISY, "%s: ruleset", __func__);
return (1);
}
r->anchor = ruleset->anchor;
@@ -690,7 +688,8 @@ pf_keth_anchor_setup(struct pf_keth_rule *r, const struct pf_keth_ruleset *s,
strlcpy(path, s->anchor->path, MAXPATHLEN);
while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
if (!path[0]) {
- DPFPRINTF("%s: .. beyond root\n", __func__);
+ DPFPRINTF(PF_DEBUG_NOISY, "%s: .. beyond root",
+ __func__);
rs_free(path);
return (1);
}
@@ -712,7 +711,7 @@ pf_keth_anchor_setup(struct pf_keth_rule *r, const struct pf_keth_ruleset *s,
ruleset = pf_find_or_create_keth_ruleset(path);
rs_free(path);
if (ruleset == NULL || ruleset->anchor == NULL) {
- DPFPRINTF("%s: ruleset\n", __func__);
+ DPFPRINTF(PF_DEBUG_NOISY, "%s: ruleset", __func__);
return (1);
}
r->anchor = ruleset->anchor;
diff --git a/sys/netpfil/pf/pf_syncookies.c b/sys/netpfil/pf/pf_syncookies.c
index 66757fa4b756..4a935bc65767 100644
--- a/sys/netpfil/pf/pf_syncookies.c
+++ b/sys/netpfil/pf/pf_syncookies.c
@@ -88,8 +88,6 @@
#include <net/pfvar.h>
#include <netpfil/pf/pf_nv.h>
-#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
-
union pf_syncookie {
uint8_t cookie;
struct {
@@ -281,7 +279,7 @@ pf_synflood_check(struct pf_pdesc *pd)
pf_syncookie_rotate, curvnet);
V_pf_status.syncookies_active = true;
DPFPRINTF(LOG_WARNING,
- ("synflood detected, enabling syncookies\n"));
+ "synflood detected, enabling syncookies");
// XXXTODO V_pf_status.lcounters[LCNT_SYNFLOODS]++;
}
@@ -367,7 +365,7 @@ pf_syncookie_rotate(void *arg)
V_pf_status.syncookies_mode == PF_SYNCOOKIES_NEVER)
) {
V_pf_status.syncookies_active = false;
- DPFPRINTF(PF_DEBUG_MISC, ("syncookies disabled\n"));
+ DPFPRINTF(PF_DEBUG_MISC, "syncookies disabled");
}
/* nothing in flight any more? delete keys and return */
diff --git a/sys/netpfil/pf/pf_table.c b/sys/netpfil/pf/pf_table.c
index 9c0151b7da2b..ecc185f89ad7 100644
--- a/sys/netpfil/pf/pf_table.c
+++ b/sys/netpfil/pf/pf_table.c
@@ -49,8 +49,6 @@
#include <net/vnet.h>
#include <net/pfvar.h>
-#define DPFPRINTF(n, x) if (V_pf_status.debug >= (n)) printf x
-
#define ACCEPT_FLAGS(flags, oklist) \
do { \
if ((flags & ~(oklist)) & \
@@ -2189,7 +2187,7 @@ pfr_update_stats(struct pfr_ktable *kt, struct pf_addr *a, sa_family_t af,
if ((ke == NULL || ke->pfrke_not) != notrule) {
if (op_pass != PFR_OP_PASS)
DPFPRINTF(PF_DEBUG_URGENT,
- ("pfr_update_stats: assertion failed.\n"));
+ "pfr_update_stats: assertion failed.");
op_pass = PFR_OP_XPASS;
}
pfr_kstate_counter_add(&kt->pfrkt_packets[dir_out][op_pass], 1);
diff --git a/sys/netsmb/smb_conn.c b/sys/netsmb/smb_conn.c
index 259635e2d8d5..ab6cd130a057 100644
--- a/sys/netsmb/smb_conn.c
+++ b/sys/netsmb/smb_conn.c
@@ -422,7 +422,7 @@ smb_vc_create(struct smb_vcspec *vcspec,
if (uid == SMBM_ANY_OWNER)
uid = realuid;
if (gid == SMBM_ANY_GROUP)
- gid = cred->cr_groups[0];
+ gid = cred->cr_gid;
vcp->vc_uid = uid;
vcp->vc_grp = gid;
@@ -765,7 +765,7 @@ smb_share_create(struct smb_vc *vcp, struct smb_sharespec *shspec,
if (uid == SMBM_ANY_OWNER)
uid = realuid;
if (gid == SMBM_ANY_GROUP)
- gid = cred->cr_groups[0];
+ gid = cred->cr_gid;
ssp = smb_zmalloc(sizeof(*ssp), M_SMBCONN, M_WAITOK);
smb_co_init(SSTOCP(ssp), SMBL_SHARE, "smbss ilock", "smbss");
ssp->obj.co_free = smb_share_free;
diff --git a/sys/riscv/allwinner/files.allwinner b/sys/riscv/allwinner/files.allwinner
index 73fa9660e2d2..7a4ff6b9c62e 100644
--- a/sys/riscv/allwinner/files.allwinner
+++ b/sys/riscv/allwinner/files.allwinner
@@ -1,5 +1,6 @@
arm/allwinner/aw_gpio.c optional gpio aw_gpio fdt
+arm/allwinner/aw_mmc.c optional mmc aw_mmc fdt | mmccam aw_mmc fdt
arm/allwinner/aw_rtc.c optional aw_rtc fdt
arm/allwinner/aw_syscon.c optional syscon
arm/allwinner/aw_sid.c optional aw_sid nvmem
diff --git a/sys/riscv/conf/std.allwinner b/sys/riscv/conf/std.allwinner
index 2b1e0d4e09dc..34fe195b01ba 100644
--- a/sys/riscv/conf/std.allwinner
+++ b/sys/riscv/conf/std.allwinner
@@ -7,6 +7,7 @@ options SOC_ALLWINNER_D1
device aw_ccu # Allwinner clock controller
device aw_gpio # Allwinner GPIO controller
+device aw_mmc # Allwinner SD/MMC controller
device aw_rtc # Allwinner Real-time Clock
device aw_sid # Allwinner Secure ID EFUSE
device aw_timer # Allwinner Timer
diff --git a/sys/riscv/include/vmm_dev.h b/sys/riscv/include/vmm_dev.h
index 856ff0778b95..4d30d5a1c35b 100644
--- a/sys/riscv/include/vmm_dev.h
+++ b/sys/riscv/include/vmm_dev.h
@@ -34,6 +34,8 @@
#ifndef _VMM_DEV_H_
#define _VMM_DEV_H_
+#include <sys/domainset.h>
+
#include <machine/vmm.h>
struct vm_memmap {
@@ -56,6 +58,9 @@ struct vm_memseg {
int segid;
size_t len;
char name[VM_MAX_SUFFIXLEN + 1];
+ domainset_t *ds_mask;
+ size_t ds_mask_size;
+ int ds_policy;
};
struct vm_register {
diff --git a/sys/rpc/authunix_prot.c b/sys/rpc/authunix_prot.c
index 91fb96f44397..7b531946488a 100644
--- a/sys/rpc/authunix_prot.c
+++ b/sys/rpc/authunix_prot.c
@@ -93,9 +93,10 @@ xdr_authunix_parms(XDR *xdrs, uint32_t *time, struct xucred *cred)
if (!xdr_uint32_t(xdrs, &cred->cr_uid))
return (FALSE);
- if (!xdr_uint32_t(xdrs, &cred->cr_groups[0]))
+ if (!xdr_uint32_t(xdrs, &cred->cr_gid))
return (FALSE);
+ /* XXXKE Fix this is cr_gid gets separated out. */
if (xdrs->x_op == XDR_ENCODE) {
ngroups = cred->cr_ngroups - 1;
if (ngroups > NGRPS)
@@ -105,7 +106,7 @@ xdr_authunix_parms(XDR *xdrs, uint32_t *time, struct xucred *cred)
if (!xdr_uint32_t(xdrs, &ngroups))
return (FALSE);
for (i = 0; i < ngroups; i++) {
- if (i + 1 < ngroups_max + 1) {
+ if (i < ngroups_max) {
if (!xdr_uint32_t(xdrs, &cred->cr_groups[i + 1]))
return (FALSE);
} else {
@@ -115,7 +116,7 @@ xdr_authunix_parms(XDR *xdrs, uint32_t *time, struct xucred *cred)
}
if (xdrs->x_op == XDR_DECODE) {
- if (ngroups + 1 > ngroups_max + 1)
+ if (ngroups > ngroups_max)
cred->cr_ngroups = ngroups_max + 1;
else
cred->cr_ngroups = ngroups + 1;
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/rpc/svc_auth_unix.c b/sys/rpc/svc_auth_unix.c
index 5d6402a05006..b10ef33be704 100644
--- a/sys/rpc/svc_auth_unix.c
+++ b/sys/rpc/svc_auth_unix.c
@@ -83,12 +83,13 @@ _svcauth_unix(struct svc_req *rqst, struct rpc_msg *msg)
str_len = RNDUP(str_len);
buf += str_len / sizeof (int32_t);
xcr->cr_uid = IXDR_GET_UINT32(buf);
- xcr->cr_groups[0] = IXDR_GET_UINT32(buf);
+ xcr->cr_gid = IXDR_GET_UINT32(buf);
gid_len = (size_t)IXDR_GET_UINT32(buf);
if (gid_len > NGRPS) {
stat = AUTH_BADCRED;
goto done;
}
+ /* XXXKE Fix this if cr_gid gets separated out. */
for (i = 0; i < gid_len; i++) {
if (i + 1 < XU_NGROUPS)
xcr->cr_groups[i + 1] = IXDR_GET_INT32(buf);
diff --git a/sys/security/audit/audit.c b/sys/security/audit/audit.c
index 05928f1c33e8..7ec50d990d4e 100644
--- a/sys/security/audit/audit.c
+++ b/sys/security/audit/audit.c
@@ -279,7 +279,7 @@ audit_record_ctor(void *mem, int size, void *arg, int flags)
cru2x(cred, &ar->k_ar.ar_subj_cred);
ar->k_ar.ar_subj_ruid = cred->cr_ruid;
ar->k_ar.ar_subj_rgid = cred->cr_rgid;
- ar->k_ar.ar_subj_egid = cred->cr_groups[0];
+ ar->k_ar.ar_subj_egid = cred->cr_gid;
ar->k_ar.ar_subj_auid = cred->cr_audit.ai_auid;
ar->k_ar.ar_subj_asid = cred->cr_audit.ai_asid;
ar->k_ar.ar_subj_pid = td->td_proc->p_pid;
diff --git a/sys/security/audit/audit_arg.c b/sys/security/audit/audit_arg.c
index c667d3968817..3ea645373dbe 100644
--- a/sys/security/audit/audit_arg.c
+++ b/sys/security/audit/audit_arg.c
@@ -408,7 +408,7 @@ audit_arg_process(struct proc *p)
cred = p->p_ucred;
ar->k_ar.ar_arg_auid = cred->cr_audit.ai_auid;
ar->k_ar.ar_arg_euid = cred->cr_uid;
- ar->k_ar.ar_arg_egid = cred->cr_groups[0];
+ ar->k_ar.ar_arg_egid = cred->cr_gid;
ar->k_ar.ar_arg_ruid = cred->cr_ruid;
ar->k_ar.ar_arg_rgid = cred->cr_rgid;
ar->k_ar.ar_arg_asid = cred->cr_audit.ai_asid;
diff --git a/sys/sys/compressor.h b/sys/sys/compressor.h
index cad9080b46ff..e59eeabec2cd 100644
--- a/sys/sys/compressor.h
+++ b/sys/sys/compressor.h
@@ -42,6 +42,7 @@ struct compressor;
bool compressor_avail(int format);
struct compressor *compressor_init(compressor_cb_t cb, int format,
size_t maxiosize, int level, void *arg);
+int compressor_format(const struct compressor *stream);
void compressor_reset(struct compressor *stream);
int compressor_write(struct compressor *stream, void *data,
size_t len);
diff --git a/sys/sys/domainset.h b/sys/sys/domainset.h
index f98b175e9bc8..f3dc92ec6383 100644
--- a/sys/sys/domainset.h
+++ b/sys/sys/domainset.h
@@ -113,6 +113,20 @@ void domainset_zero(void);
* returned value will not match the key pointer.
*/
struct domainset *domainset_create(const struct domainset *);
+
+/*
+ * Remove empty domains from a given domainset.
+ * Returns 'false' if the domainset consists entirely of empty domains.
+ */
+bool domainset_empty_vm(struct domainset *domain);
+
+/*
+ * Validate and populate a domainset structure according to the specified
+ * policy and mask.
+ */
+int domainset_populate(struct domainset *domain, const domainset_t *mask, int policy,
+ size_t mask_size);
+
#ifdef _SYS_SYSCTL_H_
int sysctl_handle_domainset(SYSCTL_HANDLER_ARGS);
#endif
diff --git a/sys/sys/efi.h b/sys/sys/efi.h
index 95a433a950db..89c8b15519de 100644
--- a/sys/sys/efi.h
+++ b/sys/sys/efi.h
@@ -42,6 +42,8 @@
{0xb122a263,0x3661,0x4f68,{0x99,0x29,0x78,0xf8,0xb0,0xd6,0x21,0x80}}
#define EFI_PROPERTIES_TABLE \
{0x880aaca3,0x4adc,0x4a04,{0x90,0x79,0xb7,0x47,0x34,0x08,0x25,0xe5}}
+#define EFI_MEMORY_ATTRIBUTES_TABLE \
+ {0xdcfa911d,0x26eb,0x469f,{0xa2,0x20,0x38,0xb7,0xdc,0x46,0x12,0x20}}
#define LINUX_EFI_MEMRESERVE_TABLE \
{0x888eb0c6,0x8ede,0x4ff5,{0xa8,0xf0,0x9a,0xee,0x5c,0xb9,0x77,0xc2}}
@@ -166,6 +168,22 @@ struct efi_prop_table {
uint64_t memory_protection_attribute;
};
+struct efi_memory_descriptor {
+ uint32_t type;
+ caddr_t phy_addr;
+ caddr_t virt_addr;
+ uint64_t pages;
+ uint64_t attrs;
+};
+
+struct efi_memory_attribute_table {
+ uint32_t version;
+ uint32_t num_ents;
+ uint32_t descriptor_size;
+ uint32_t flags;
+ struct efi_memory_descriptor tables[];
+};
+
#ifdef _KERNEL
#ifdef EFIABI_ATTR
diff --git a/sys/sys/exec.h b/sys/sys/exec.h
index 4bf114a7c698..580a5372c4db 100644
--- a/sys/sys/exec.h
+++ b/sys/sys/exec.h
@@ -57,16 +57,6 @@ struct ps_strings {
unsigned int ps_nenvstr; /* the number of environment strings */
};
-/* Coredump output parameters. */
-struct coredump_params {
- off_t offset;
- struct ucred *active_cred;
- struct ucred *file_cred;
- struct thread *td;
- struct vnode *vp;
- struct compressor *comp;
-};
-
struct image_params;
struct execsw {
@@ -105,16 +95,6 @@ int exec_unregister(const struct execsw *);
enum uio_seg;
-#define CORE_BUF_SIZE (16 * 1024)
-
-int core_write(struct coredump_params *, const void *, size_t, off_t,
- enum uio_seg, size_t *);
-int core_output(char *, size_t, off_t, struct coredump_params *, void *);
-int sbuf_drain_core_output(void *, const char *, int);
-
-extern int coredump_pack_fileinfo;
-extern int coredump_pack_vmmapinfo;
-
/*
* note: name##_mod cannot be const storage because the
* linker_file_sysinit() function modifies _file in the
diff --git a/sys/sys/exterr_cat.h b/sys/sys/exterr_cat.h
index cab94ac511a5..a8e1f56e132e 100644
--- a/sys/sys/exterr_cat.h
+++ b/sys/sys/exterr_cat.h
@@ -18,6 +18,7 @@
#define EXTERR_CAT_FUSE 4
#define EXTERR_CAT_INOTIFY 5
#define EXTERR_CAT_GENIO 6
+#define EXTERR_CAT_BRIDGE 7
#endif
diff --git a/sys/sys/imgact_elf.h b/sys/sys/imgact_elf.h
index c9444e5aec41..2845a9dbc1e2 100644
--- a/sys/sys/imgact_elf.h
+++ b/sys/sys/imgact_elf.h
@@ -45,6 +45,7 @@
{(pos)->a_type = (id); (pos)->a_un.a_ptr = (ptr); (pos)++;}
#endif
+struct coredump_writer;
struct image_params;
struct thread;
struct vnode;
@@ -114,7 +115,7 @@ bool __elfN(brand_inuse)(Elf_Brandinfo *entry);
int __elfN(insert_brand_entry)(Elf_Brandinfo *entry);
int __elfN(remove_brand_entry)(Elf_Brandinfo *entry);
int __elfN(freebsd_fixup)(uintptr_t *, struct image_params *);
-int __elfN(coredump)(struct thread *, struct vnode *, off_t, int);
+int __elfN(coredump)(struct thread *, struct coredump_writer *, off_t, int);
size_t __elfN(populate_note)(int, void *, void *, size_t, void **);
int __elfN(freebsd_copyout_auxargs)(struct image_params *, uintptr_t);
void __elfN(puthdr)(struct thread *, void *, size_t, int, size_t, int);
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/jail.h b/sys/sys/jail.h
index 08caa9f49270..24c420e2c976 100644
--- a/sys/sys/jail.h
+++ b/sys/sys/jail.h
@@ -435,7 +435,7 @@ void prison0_init(void);
bool prison_allow(struct ucred *, unsigned);
int prison_check(struct ucred *cred1, struct ucred *cred2);
bool prison_check_nfsd(struct ucred *cred);
-bool prison_owns_vnet(struct ucred *);
+bool prison_owns_vnet(struct prison *pr);
int prison_canseemount(struct ucred *cred, struct mount *mp);
void prison_enforce_statfs(struct ucred *cred, struct mount *mp,
struct statfs *sp);
diff --git a/sys/sys/mbuf.h b/sys/sys/mbuf.h
index c75094aea450..304bd019c9fc 100644
--- a/sys/sys/mbuf.h
+++ b/sys/sys/mbuf.h
@@ -1391,6 +1391,7 @@ extern bool mb_use_ext_pgs; /* Use ext_pgs for sendfile */
#define PACKET_TAG_PF_REASSEMBLED 31
#define PACKET_TAG_IPSEC_ACCEL_OUT 32 /* IPSEC accel out */
#define PACKET_TAG_IPSEC_ACCEL_IN 33 /* IPSEC accel in */
+#define PACKET_TAG_OVPN 34 /* if_ovpn */
/* Specific cookies and tags. */
diff --git a/sys/sys/param.h b/sys/sys/param.h
index a8e9635242dd..33d61e8a1619 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 1500052
+#define __FreeBSD_version 1500055
/*
* __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/sys/signalvar.h b/sys/sys/signalvar.h
index 23e8426b26ee..8f181b7beee6 100644
--- a/sys/sys/signalvar.h
+++ b/sys/sys/signalvar.h
@@ -403,6 +403,7 @@ int sigev_findtd(struct proc *p, struct sigevent *sigev, struct thread **);
void sigfastblock_clear(struct thread *td);
void sigfastblock_fetch(struct thread *td);
int sig_intr(void);
+bool sig_do_core(int);
void siginit(struct proc *p);
void signotify(struct thread *td);
void sigqueue_delete(struct sigqueue *queue, int sig);
diff --git a/sys/sys/sockbuf.h b/sys/sys/sockbuf.h
index 7f6234ade6f4..b4593f38f592 100644
--- a/sys/sys/sockbuf.h
+++ b/sys/sys/sockbuf.h
@@ -40,7 +40,7 @@
#define SB_SEL 0x08 /* someone is selecting */
#define SB_ASYNC 0x10 /* ASYNC I/O, need signals */
#define SB_UPCALL 0x20 /* someone wants an upcall */
-/* was SB_NOINTR 0x40 */
+#define SB_AUTOLOWAT 0x40 /* sendfile(2) may autotune sb_lowat */
#define SB_AIO 0x80 /* AIO operations queued */
#define SB_KNOTE 0x100 /* kernel note attached */
#define SB_NOCOALESCE 0x200 /* don't coalesce new data into existing mbufs */
@@ -210,8 +210,6 @@ typedef enum { SO_RCV, SO_SND } sb_which;
* Socket buffer private mbuf(9) flags.
*/
#define M_NOTREADY M_PROTO1 /* m_data not populated yet */
-#define M_BLOCKED M_PROTO2 /* M_NOTREADY in front of m */
-#define M_NOTAVAIL (M_NOTREADY | M_BLOCKED)
void sbappend(struct sockbuf *sb, struct mbuf *m, int flags);
void sbappend_locked(struct sockbuf *sb, struct mbuf *m, int flags);
diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h
index fd183ffbc7a4..8237165b84ce 100644
--- a/sys/sys/syscallsubr.h
+++ b/sys/sys/syscallsubr.h
@@ -60,6 +60,7 @@ struct rusage;
struct sched_param;
struct sembuf;
union semun;
+struct shmfd;
struct sockaddr;
struct spacectl_range;
struct stat;
@@ -337,7 +338,7 @@ int kern_shm_open(struct thread *td, const char *userpath, int flags,
mode_t mode, struct filecaps *fcaps);
int kern_shm_open2(struct thread *td, const char *path, int flags,
mode_t mode, int shmflags, struct filecaps *fcaps,
- const char *name);
+ const char *name, struct shmfd *shmfd);
int kern_shmat(struct thread *td, int shmid, const void *shmaddr,
int shmflg);
int kern_shmctl(struct thread *td, int shmid, int cmd, void *buf,
diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h
index 4ddfc8516053..1714fa5a7416 100644
--- a/sys/sys/sysent.h
+++ b/sys/sys/sysent.h
@@ -90,6 +90,7 @@ struct sysent { /* system call table */
#define SY_THR_STATIC_KLD SY_THR_STATIC
#endif
+struct coredump_writer;
struct image_params;
struct proc;
struct __sigset;
@@ -108,7 +109,8 @@ struct sysentvec {
int *sv_szsigcode; /* size of sigtramp code */
int sv_sigcodeoff;
char *sv_name; /* name of binary type */
- int (*sv_coredump)(struct thread *, struct vnode *, off_t, int);
+ int (*sv_coredump)(struct thread *, struct coredump_writer *,
+ off_t, int);
/* function to dump core, or NULL */
int sv_elf_core_osabi;
const char *sv_elf_core_abi_vendor;
diff --git a/sys/sys/ucoredump.h b/sys/sys/ucoredump.h
new file mode 100644
index 000000000000..0a51ee7f50c8
--- /dev/null
+++ b/sys/sys/ucoredump.h
@@ -0,0 +1,99 @@
+/*
+ *
+ * Copyright (c) 2015 Mark Johnston <markj@FreeBSD.org>
+ * Copyright (c) 2025 Kyle Evans <kevans@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ */
+
+#ifndef _SYS_UCOREDUMP_H_
+#define _SYS_UCOREDUMP_H_
+
+#ifdef _KERNEL
+
+#include <sys/_uio.h>
+#include <sys/blockcount.h>
+#include <sys/queue.h>
+
+/* Coredump output parameters. */
+struct coredump_params;
+struct coredump_writer;
+struct thread;
+struct ucred;
+
+typedef int coredump_init_fn(const struct coredump_writer *,
+ const struct coredump_params *);
+typedef int coredump_write_fn(const struct coredump_writer *, const void *, size_t,
+ off_t, enum uio_seg, struct ucred *, size_t *, struct thread *);
+typedef int coredump_extend_fn(const struct coredump_writer *, off_t,
+ struct ucred *);
+
+struct coredump_vnode_ctx {
+ struct vnode *vp;
+ struct ucred *fcred;
+};
+
+coredump_write_fn core_vn_write;
+coredump_extend_fn core_vn_extend;
+
+struct coredump_writer {
+ void *ctx;
+ coredump_init_fn *init_fn;
+ coredump_write_fn *write_fn;
+ coredump_extend_fn *extend_fn;
+};
+
+struct coredump_params {
+ off_t offset;
+ struct ucred *active_cred;
+ struct thread *td;
+ const struct coredump_writer *cdw;
+ struct compressor *comp;
+};
+
+#define CORE_BUF_SIZE (16 * 1024)
+
+int core_write(struct coredump_params *, const void *, size_t, off_t,
+ enum uio_seg, size_t *);
+int core_output(char *, size_t, off_t, struct coredump_params *, void *);
+int sbuf_drain_core_output(void *, const char *, int);
+
+extern int coredump_pack_fileinfo;
+extern int coredump_pack_vmmapinfo;
+
+extern int compress_user_cores;
+extern int compress_user_cores_level;
+
+typedef int coredumper_probe_fn(struct thread *);
+
+/*
+ * Some arbitrary values for coredumper probes to return. The highest priority
+ * we can find wins. It's somewhat expected that a coredumper may want to bid
+ * differently based on the process in question. Note that probe functions will
+ * be called with the proc lock held, so they must not sleep.
+ */
+#define COREDUMPER_NOMATCH (-1) /* Decline to touch it */
+#define COREDUMPER_GENERIC (0) /* I handle coredumps */
+#define COREDUMPER_SPECIAL (50) /* Special handler */
+#define COREDUMPER_HIGH_PRIORITY (100) /* High-priority handler */
+
+/*
+ * The handle functions will be called with the proc lock held, and should
+ * return with the proc lock dropped.
+ */
+typedef int coredumper_handle_fn(struct thread *, off_t);
+
+struct coredumper {
+ SLIST_ENTRY(coredumper) cd_entry;
+ const char *cd_name;
+ coredumper_probe_fn *cd_probe;
+ coredumper_handle_fn *cd_handle;
+ blockcount_t cd_refcount;
+};
+
+void coredumper_register(struct coredumper *);
+void coredumper_unregister(struct coredumper *);
+
+#endif /* _KERNEL */
+#endif /* _SYS_UCOREDUMP_H_ */
diff --git a/sys/sys/unistd.h b/sys/sys/unistd.h
index c291c1dc2b95..85ed93fd359d 100644
--- a/sys/sys/unistd.h
+++ b/sys/sys/unistd.h
@@ -156,6 +156,8 @@
#define _PC_DEALLOC_PRESENT 65
#define _PC_NAMEDATTR_ENABLED 66
#define _PC_HAS_NAMEDATTR 67
+#define _PC_XATTR_ENABLED _PC_NAMEDATTR_ENABLED /* Solaris Compatible */
+#define _PC_XATTR_EXISTS _PC_HAS_NAMEDATTR /* Solaris Compatible */
#define _PC_HAS_HIDDENSYSTEM 68
#endif
diff --git a/sys/sys/vnode.h b/sys/sys/vnode.h
index 2c6947103c94..a416fddcddc3 100644
--- a/sys/sys/vnode.h
+++ b/sys/sys/vnode.h
@@ -939,7 +939,6 @@ void vop_mknod_post(void *a, int rc);
void vop_open_post(void *a, int rc);
void vop_read_post(void *a, int rc);
void vop_read_pgcache_post(void *ap, int rc);
-void vop_readdir_post(void *a, int rc);
void vop_reclaim_post(void *a, int rc);
void vop_remove_pre(void *a);
void vop_remove_post(void *a, int rc);
@@ -1015,7 +1014,36 @@ void vop_rename_fail(struct vop_rename_args *ap);
_error; \
})
-#define VOP_WRITE_PRE(ap) \
+#ifdef INVARIANTS
+#define vop_readdir_pre_assert(ap) \
+ ssize_t nresid, oresid; \
+ \
+ oresid = (ap)->a_uio->uio_resid;
+
+#define vop_readdir_post_assert(ap, ret) \
+ nresid = (ap)->a_uio->uio_resid; \
+ if ((ret) == 0 && (ap)->a_eofflag != NULL) { \
+ VNASSERT(oresid == 0 || nresid != oresid || \
+ *(ap)->a_eofflag == 1, \
+ (ap)->a_vp, ("VOP_READDIR: eofflag not set")); \
+ }
+#else
+#define vop_readdir_pre_assert(ap)
+#define vop_readdir_post_assert(ap, ret)
+#endif
+
+#define vop_readdir_pre(ap) do { \
+ vop_readdir_pre_assert(ap)
+
+#define vop_readdir_post(ap, ret) \
+ vop_readdir_post_assert(ap, ret); \
+ if ((ret) == 0) { \
+ VFS_KNOTE_LOCKED((ap)->a_vp, NOTE_READ); \
+ INOTIFY((ap)->a_vp, IN_ACCESS); \
+ } \
+} while (0)
+
+#define vop_write_pre(ap) \
struct vattr va; \
int error; \
off_t osize, ooffset, noffset; \
@@ -1029,7 +1057,7 @@ void vop_rename_fail(struct vop_rename_args *ap);
osize = (off_t)va.va_size; \
}
-#define VOP_WRITE_POST(ap, ret) \
+#define vop_write_post(ap, ret) \
noffset = (ap)->a_uio->uio_offset; \
if (noffset > ooffset) { \
if (!VN_KNLIST_EMPTY((ap)->a_vp)) { \
diff --git a/sys/ufs/ufs/ufs_vnops.c b/sys/ufs/ufs/ufs_vnops.c
index 53fac4b0665e..2757fb066981 100644
--- a/sys/ufs/ufs/ufs_vnops.c
+++ b/sys/ufs/ufs/ufs_vnops.c
@@ -1268,7 +1268,8 @@ ufs_rename(
struct inode *fip, *tip, *tdp, *fdp;
struct direct newdir;
off_t endoff;
- int doingdirectory, newparent;
+ int doingdirectory;
+ u_int newparent;
int error = 0;
struct mount *mp;
ino_t ino;
@@ -1475,7 +1476,7 @@ relock:
* the user must have write permission in the source so
* as to be able to change "..".
*/
- if (doingdirectory && newparent) {
+ if (doingdirectory && newparent != 0) {
error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, curthread);
if (error)
goto unlockout;
@@ -1538,7 +1539,7 @@ relock:
if (tip == NULL) {
if (ITODEV(tdp) != ITODEV(fip))
panic("ufs_rename: EXDEV");
- if (doingdirectory && newparent) {
+ if (doingdirectory && newparent != 0) {
/*
* Account for ".." in new directory.
* When source and destination have the same
@@ -1631,7 +1632,7 @@ relock:
goto bad;
}
if (doingdirectory) {
- if (!newparent) {
+ if (newparent == 0) {
tdp->i_effnlink--;
if (DOINGSOFTDEP(tdvp))
softdep_change_linkcnt(tdp);
@@ -1641,11 +1642,10 @@ relock:
softdep_change_linkcnt(tip);
}
error = ufs_dirrewrite(tdp, tip, fip->i_number,
- IFTODT(fip->i_mode),
- (doingdirectory && newparent) ? newparent : doingdirectory);
+ IFTODT(fip->i_mode), doingdirectory);
if (error) {
if (doingdirectory) {
- if (!newparent) {
+ if (newparent == 0) {
tdp->i_effnlink++;
if (DOINGSOFTDEP(tdvp))
softdep_change_linkcnt(tdp);
@@ -1668,7 +1668,7 @@ relock:
* disk, so when running with that code we avoid doing
* them now.
*/
- if (!newparent) {
+ if (newparent == 0) {
tdp->i_nlink--;
DIP_SET_NLINK(tdp, tdp->i_nlink);
UFS_INODE_SET_FLAG(tdp, IN_CHANGE);
@@ -1697,7 +1697,7 @@ relock:
* parent directory must be decremented
* and ".." set to point to the new parent.
*/
- if (doingdirectory && newparent) {
+ if (doingdirectory && newparent != 0) {
/*
* Set the directory depth based on its new parent.
*/
@@ -2064,9 +2064,13 @@ ufs_mkdir(
*/
ucred.cr_ref = 1;
ucred.cr_uid = ip->i_uid;
+
+ /*
+ * XXXKE Fix this is cr_gid gets separated out
+ */
ucred.cr_ngroups = 1;
ucred.cr_groups = &ucred_group;
- ucred.cr_groups[0] = dp->i_gid;
+ ucred.cr_gid = ucred_group = dp->i_gid;
ucp = &ucred;
}
#endif
@@ -2823,9 +2827,13 @@ ufs_makeinode(int mode, struct vnode *dvp, struct vnode **vpp,
*/
ucred.cr_ref = 1;
ucred.cr_uid = ip->i_uid;
+
+ /*
+ * XXXKE Fix this is cr_gid gets separated out
+ */
ucred.cr_ngroups = 1;
ucred.cr_groups = &ucred_group;
- ucred.cr_groups[0] = pdir->i_gid;
+ ucred.cr_gid = ucred_group = pdir->i_gid;
ucp = &ucred;
#endif
} else {
diff --git a/sys/vm/vm_page.c b/sys/vm/vm_page.c
index bbae55895c2c..b239a6ffb4ce 100644
--- a/sys/vm/vm_page.c
+++ b/sys/vm/vm_page.c
@@ -396,7 +396,7 @@ vm_page_blacklist_load(char **list, char **end)
}
*list = ptr;
if (ptr != NULL)
- *end = ptr + len;
+ *end = ptr + len - 1;
else
*end = NULL;
return;
diff --git a/targets/pseudo/userland/misc/Makefile.depend b/targets/pseudo/userland/misc/Makefile.depend
index d3c97fc56b40..546800004d11 100644
--- a/targets/pseudo/userland/misc/Makefile.depend
+++ b/targets/pseudo/userland/misc/Makefile.depend
@@ -54,7 +54,6 @@ DIRDEPS.x86sys= \
.if ${MK_ZFS} != "no"
DIRDEPS.x86sys+= \
stand/i386/gptzfsboot \
- stand/i386/zfsboot \
stand/i386/zfsloader \
DIRDEPS+= \
diff --git a/tests/ci/Makefile b/tests/ci/Makefile
index 44b19663fc49..48e638fdb79c 100644
--- a/tests/ci/Makefile
+++ b/tests/ci/Makefile
@@ -33,11 +33,11 @@ EXTRA_MAKE_FLAGS?=
TARGET= ${MACHINE}
.endif
.if !defined(TARGET_ARCH) || empty(TARGET_ARCH)
-.if ${TARGET} == ${MACHINE}
+. if ${TARGET} == ${MACHINE}
TARGET_ARCH= ${MACHINE_ARCH}
-.else
+. else
TARGET_ARCH= ${TARGET}
-.endif
+. endif
.endif
IMAKE= ${MAKE} TARGET=${TARGET} TARGET_ARCH=${TARGET_ARCH}
@@ -47,20 +47,20 @@ CROSS_TOOLCHAIN_PARAM= "CROSS_TOOLCHAIN=${CROSS_TOOLCHAIN}"
# Define OSRELEASE by using newvers.sh
.if !defined(OSRELEASE) || empty(OSRELEASE)
-.for _V in TYPE BRANCH REVISION
-. if !defined(${_V}) || empty(${_V})
+. for _V in TYPE BRANCH REVISION
+. if !defined(${_V}) || empty(${_V})
${_V}!= eval $$(awk '/^${_V}=/{print}' ${.CURDIR}/../../sys/conf/newvers.sh); echo $$${_V}
-. endif
-.endfor
-.for _V in ${TARGET_ARCH}
-.if !empty(TARGET:M${_V})
+. endif
+. endfor
+. for _V in ${TARGET_ARCH}
+. if !empty(TARGET:M${_V})
OSRELEASE= ${TYPE}-${REVISION}-${BRANCH}-${TARGET}
VOLUME_LABEL= ${REVISION:C/[.-]/_/g}_${BRANCH:C/[.-]/_/g}_${TARGET}
-.else
+. else
OSRELEASE= ${TYPE}-${REVISION}-${BRANCH}-${TARGET}-${TARGET_ARCH}
VOLUME_LABEL= ${REVISION:C/[.-]/_/g}_${BRANCH:C/[.-]/_/g}_${TARGET_ARCH}
-.endif
-.endfor
+. endif
+. endfor
.endif
.if exists(${.CURDIR}/tools/ci.conf) && !defined(CICONF)
@@ -104,13 +104,13 @@ TIMEOUT_VM=$$((${TIMEOUT_EXPECT} - 120))
. include "${.CURDIR}/Makefile.${TARGET_ARCH}"
.endif
.if ${TARGET_ARCH} != ${MACHINE_ARCH}
-.if ( ${TARGET_ARCH} != "i386" ) || ( ${MACHINE_ARCH} != "amd64" )
+. if ( ${TARGET_ARCH} != "i386" ) || ( ${MACHINE_ARCH} != "amd64" )
QEMUSTATIC=/usr/local/bin/qemu-${QEMU_ARCH}-static
QEMUTGT=portinstall-qemu
-.endif
+. endif
.endif
QEMUTGT?=
-QEMU_DEVICES?=-device virtio-blk,drive=hd0
+QEMU_DEVICES?=
QEMU_EXTRA_PARAM?=
QEMU_MACHINE?=virt
QEMUBIN=/usr/local/bin/qemu-system-${QEMU_ARCH}
@@ -134,7 +134,8 @@ METAMODE?=-DWITH_META_MODE
.endif
CLEANFILES+= ${.OBJDIR}/${CIIMAGE} ${.OBJDIR}/ci.img ${META_TAR}
-CLEANDIRS+= ${.OBJDIR}/ci-buildimage
+IMAGEDIR= ${.OBJDIR}/ci-buildimage
+CLEANDIRS+= ${IMAGEDIR}
portinstall: portinstall-pkg portinstall-qemu portinstall-expect portinstall-${TARGET_ARCH:tl} .PHONY
@@ -157,7 +158,7 @@ portinstall-expect: portinstall-pkg .PHONY
.endif
beforeclean: .PHONY
- chflags -R noschg ${.OBJDIR}/${.TARGET}
+ chflags -R noschg ${IMAGEDIR}
.include <bsd.obj.mk>
clean: beforeclean .PHONY
@@ -205,6 +206,7 @@ ci-create-meta: .PHONY
ci-extract-meta: .PHONY
tar xfv ${META_TAR} -C ${META_DIROUT}
+ rm -rf ${META_TAR} ${META_DIR}
@echo "Extracted kyua reports to ${META_DIROUT}"
ci-runtest: ci-buildimage-${TARGET_ARCH:tl} portinstall .PHONY
@@ -235,8 +237,10 @@ ci-runtest: ci-buildimage-${TARGET_ARCH:tl} portinstall .PHONY
-nographic \
-no-reboot \
${QEMU_EXTRA_PARAM} \
- -drive if=none,file=${CIDISK},format=raw,id=hd0 \
- -drive if=none,file=${META_TAR},format=raw,id=hd1 \
+ -device virtio-blk,drive=hd0 \
+ -device virtio-blk,drive=hd1 \
+ -blockdev driver=raw,node-name=hd0,file.driver=file,file.filename=${CIDISK} \
+ -blockdev driver=raw,node-name=hd1,file.driver=file,file.filename=${META_TAR} \
${QEMU_DEVICES}
.endif
@@ -254,7 +258,7 @@ ci-checktarget: .PHONY
ci-smoke: ci-set-smoke-var ci-create-meta ci-checktarget .WAIT ci-runtest-${TARGET_ARCH:tl} .PHONY
-ci-full: ci-set-full-var ci-create-meta ci-checktarget .WAIT ci-runtest-${TARGET_ARCH:tl} ci-extract-meta .PHONY
+ci-full: ci-set-full-var ci-create-meta ci-checktarget .WAIT ci-runtest-${TARGET_ARCH:tl} .WAIT ci-extract-meta .PHONY
ci: ci-${CITYPE:tl} .PHONY
diff --git a/tests/ci/Makefile.aarch64 b/tests/ci/Makefile.aarch64
index 9cbec6010a36..5a62e73d8eaa 100644
--- a/tests/ci/Makefile.aarch64
+++ b/tests/ci/Makefile.aarch64
@@ -8,7 +8,7 @@
# CI Makefile for aarch64.
#
QEMU_ARCH=aarch64
-QEMU_DEVICES=-device virtio-blk,drive=hd0 -device ahci,id=ahci
+QEMU_DEVICES=-device ahci,id=ahci
QEMU_EXTRA_PARAM=-bios /usr/local/share/u-boot/u-boot-qemu-arm64/u-boot.bin -cpu cortex-a57
QEMU_MAX_CPU_COUNT=64
QEMU_MAX_MEM_SIZE=64
diff --git a/tests/ci/Makefile.armv7 b/tests/ci/Makefile.armv7
index 21ee6b387b05..3b0d180fa352 100644
--- a/tests/ci/Makefile.armv7
+++ b/tests/ci/Makefile.armv7
@@ -8,7 +8,7 @@
# CI Makefile for armv7.
#
QEMU_ARCH=arm
-QEMU_DEVICES=-device virtio-blk,drive=hd0 -device ahci,id=ahci
+QEMU_DEVICES=-device ahci,id=ahci
QEMU_EXTRA_PARAM=-bios /usr/local/share/u-boot/u-boot-qemu-arm/u-boot.bin
QEMU_MAX_CPU_COUNT=1
QEMU_MAX_MEM_SIZE=3
diff --git a/tests/ci/Makefile.powerpc64 b/tests/ci/Makefile.powerpc64
index 26712b45f30b..d4e8e2cdc778 100644
--- a/tests/ci/Makefile.powerpc64
+++ b/tests/ci/Makefile.powerpc64
@@ -8,7 +8,6 @@
# CI Makefile for powerpc64.
#
QEMU_ARCH=ppc64
-QEMU_DEVICES=-device virtio-blk,drive=hd0
QEMU_EXTRA_PARAM=-vga none -accel tcg,thread=multi
QEMU_MACHINE=pseries,cap-hpt-max-page-size=16M
QEMU_MAX_CPU_COUNT=1
diff --git a/tests/ci/Makefile.powerpc64le b/tests/ci/Makefile.powerpc64le
index 974ab04b8eed..60c255f569fa 100644
--- a/tests/ci/Makefile.powerpc64le
+++ b/tests/ci/Makefile.powerpc64le
@@ -8,7 +8,6 @@
# CI Makefile for powerpc64le.
#
QEMU_ARCH=ppc64
-QEMU_DEVICES=-device virtio-blk,drive=hd0
QEMU_EXTRA_PARAM=-vga none -accel tcg,thread=multi
QEMU_MACHINE=pseries,cap-hpt-max-page-size=16M
QEMU_MAX_CPU_COUNT=1
diff --git a/tests/ci/Makefile.riscv64 b/tests/ci/Makefile.riscv64
index 749df3f0b369..d494fc4f43f5 100644
--- a/tests/ci/Makefile.riscv64
+++ b/tests/ci/Makefile.riscv64
@@ -8,7 +8,6 @@
# CI Makefile for riscv64.
#
QEMU_ARCH=riscv64
-QEMU_DEVICES=-device virtio-blk-device,drive=hd0
QEMU_EXTRA_PARAM=-bios /usr/local/share/opensbi/lp64/generic/firmware/fw_jump.elf -kernel /usr/local/share/u-boot/u-boot-qemu-riscv64/u-boot.bin
QEMU_MAX_CPU_COUNT=16
QEMU_MAX_MEM_SIZE=64
diff --git a/tests/sys/cam/ctl/ctl.subr b/tests/sys/cam/ctl/ctl.subr
index 5da441b806f0..6cc02d774bdb 100644
--- a/tests/sys/cam/ctl/ctl.subr
+++ b/tests/sys/cam/ctl/ctl.subr
@@ -25,15 +25,6 @@
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-load_modules() {
- if ! kldstat -q -m ctl; then
- kldload ctl || atf_skip "could not load ctl kernel mod"
- fi
- if ! ctladm port -o on -p 0; then
- atf_skip "could not enable the camsim frontend"
- fi
-}
-
find_device() {
LUN=$1
diff --git a/tests/sys/fs/fusefs/Makefile b/tests/sys/fs/fusefs/Makefile
index b11f11bdfa98..a21512798597 100644
--- a/tests/sys/fs/fusefs/Makefile
+++ b/tests/sys/fs/fusefs/Makefile
@@ -70,7 +70,8 @@ TEST_METADATA.nfs+= required_user="root"
TEST_METADATA.ctl+= is_exclusive="true"
TEST_METADATA.ctl+= required_user="root"
-TEST_METADATA+= timeout=10
+TEST_METADATA+= timeout=10
+TEST_METADATA+= required_kmods="fusefs"
FUSEFS= ${SRCTOP}/sys/fs/fuse
# Suppress warnings that GCC generates for the libc++ and gtest headers.
diff --git a/tests/sys/mac/bsdextended/Makefile b/tests/sys/mac/bsdextended/Makefile
index 69cd27c0e321..cc3a3f8ea534 100644
--- a/tests/sys/mac/bsdextended/Makefile
+++ b/tests/sys/mac/bsdextended/Makefile
@@ -9,5 +9,6 @@ TEST_METADATA.ugidfw_test+= required_user="root"
# Each test case of matches_test reuses the same ruleset number, so they cannot
# be run simultaneously
TEST_METADATA.matches_test+= is_exclusive=true
+TEST_METADATA+= required_kmods="mac_bsdextended"
.include <bsd.test.mk>
diff --git a/tests/sys/mac/bsdextended/matches_test.sh b/tests/sys/mac/bsdextended/matches_test.sh
index 2a28be0f231b..41fa04f221e3 100644
--- a/tests/sys/mac/bsdextended/matches_test.sh
+++ b/tests/sys/mac/bsdextended/matches_test.sh
@@ -12,9 +12,6 @@ gidoutrange="daemon" # We expect $uidinrange in this group
check_ko()
{
- if ! sysctl -N security.mac.bsdextended >/dev/null 2>&1; then
- atf_skip "mac_bsdextended(4) support isn't available"
- fi
if [ $(sysctl -n security.mac.bsdextended.enabled) = "0" ]; then
# The kernel module is loaded but disabled. Enable it for the
# duration of the test.
diff --git a/tests/sys/mac/portacl/Makefile b/tests/sys/mac/portacl/Makefile
index c9fb6bbaae3e..856a85d331d5 100644
--- a/tests/sys/mac/portacl/Makefile
+++ b/tests/sys/mac/portacl/Makefile
@@ -10,6 +10,7 @@ TAP_TESTS_SH+= root_test
.for t in ${TAP_TESTS_SH}
TEST_METADATA.$t+= required_user="root"
TEST_METADATA.$t+= timeout="450"
+TEST_METADATA.$t+= is_exclusive="true"
.endfor
.include <bsd.test.mk>
diff --git a/tests/sys/net/if_bridge_test.sh b/tests/sys/net/if_bridge_test.sh
index cc0b212aebd2..c0c085f22273 100755
--- a/tests/sys/net/if_bridge_test.sh
+++ b/tests/sys/net/if_bridge_test.sh
@@ -537,7 +537,7 @@ get_mtu()
{
intf=$1
- ifconfig ${intf} ether | awk '$5 == "mtu" { print $6 }'
+ ifconfig ${intf} | awk '$5 == "mtu" { print $6 }'
}
check_mtu()
@@ -546,7 +546,7 @@ check_mtu()
expected=$2
mtu=$(get_mtu $intf)
- if [ $mtu -ne $expected ];
+ if [ "$mtu" -ne "$expected" ];
then
atf_fail "Expected MTU of $expected on $intf but found $mtu"
fi
@@ -1221,6 +1221,29 @@ vlan_qinq_cleanup()
vnet_cleanup
}
+# Adding a bridge SVI to a bridge should not be allowed.
+atf_test_case "bridge_svi_in_bridge" "cleanup"
+bridge_svi_in_bridge_head()
+{
+ atf_set descr 'adding a bridge SVI to a bridge is not allowed (1)'
+ atf_set require.user root
+}
+
+bridge_svi_in_bridge_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ bridge=$(vnet_mkbridge)
+ atf_check -s exit:0 ifconfig ${bridge}.1 create
+ atf_check -s exit:1 -e ignore ifconfig ${bridge} addm ${bridge}.1
+}
+
+bridge_svi_in_bridge_cleanup()
+{
+ vnet_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "bridge_transmit_ipv4_unicast"
@@ -1247,4 +1270,5 @@ atf_init_test_cases()
atf_add_test_case "vlan_ifconfig_tagged"
atf_add_test_case "vlan_svi"
atf_add_test_case "vlan_qinq"
+ atf_add_test_case "bridge_svi_in_bridge"
}
diff --git a/tests/sys/net/if_ovpn/if_ovpn.sh b/tests/sys/net/if_ovpn/if_ovpn.sh
index 2138e0f666ec..c42344da1a3b 100644
--- a/tests/sys/net/if_ovpn/if_ovpn.sh
+++ b/tests/sys/net/if_ovpn/if_ovpn.sh
@@ -1149,6 +1149,261 @@ destroy_unused_cleanup()
ovpn_cleanup
}
+atf_test_case "multihome4" "cleanup"
+multihome4_head()
+{
+ atf_set descr 'Test multihome IPv4 with OpenVPN'
+ atf_set require.user root
+ atf_set require.progs openvpn
+}
+
+multihome4_body()
+{
+ pft_init
+ ovpn_init
+
+ l=$(vnet_mkepair)
+
+ vnet_mkjail a ${l}a
+ atf_check jexec a ifconfig ${l}a inet 192.0.2.1/24
+ atf_check jexec a ifconfig ${l}a alias 192.0.2.2/24
+ vnet_mkjail b ${l}b
+ atf_check jexec b ifconfig ${l}b inet 192.0.2.3/24
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore jexec b ping -c 1 192.0.2.1
+ atf_check -s exit:0 -o ignore jexec b ping -c 1 192.0.2.2
+
+ ovpn_start a "
+ dev ovpn0
+ dev-type tun
+ proto udp4
+
+ cipher AES-256-GCM
+ auth SHA256
+
+ multihome
+ server 198.51.100.0 255.255.255.0
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/server.crt
+ key $(atf_get_srcdir)/server.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ mode server
+ script-security 2
+ auth-user-pass-verify /usr/bin/true via-env
+ topology subnet
+
+ keepalive 100 600
+ "
+ ovpn_start b "
+ dev tun0
+ dev-type tun
+
+ client
+
+ remote 192.0.2.2
+ auth-user-pass $(atf_get_srcdir)/user.pass
+
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/client.crt
+ key $(atf_get_srcdir)/client.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ keepalive 100 600
+ "
+
+ # Block packets from the primary address, openvpn should only use the
+ # configured remote address.
+ jexec b pfctl -e
+ pft_set_rules b \
+ "block in quick from 192.0.2.1 to any" \
+ "pass all"
+
+ # Give the tunnel time to come up
+ sleep 10
+
+ atf_check -s exit:0 -o ignore jexec b ping -c 3 198.51.100.1
+}
+
+multihome4_cleanup()
+{
+ ovpn_cleanup
+ pft_cleanup
+}
+
+multihome6_head()
+{
+ atf_set descr 'Test multihome IPv6 with OpenVPN'
+ atf_set require.user root
+ atf_set require.progs openvpn
+}
+
+multihome6_body()
+{
+ ovpn_init
+
+ l=$(vnet_mkepair)
+
+ vnet_mkjail a ${l}a
+ atf_check jexec a ifconfig ${l}a inet6 2001:db8::1/64 no_dad
+ atf_check jexec a ifconfig ${l}a inet6 alias 2001:db8::2/64 no_dad
+ vnet_mkjail b ${l}b
+ atf_check jexec b ifconfig ${l}b inet6 2001:db8::3/64 no_dad
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore jexec b ping6 -c 1 2001:db8::1
+ atf_check -s exit:0 -o ignore jexec b ping6 -c 1 2001:db8::2
+
+ ovpn_start a "
+ dev ovpn0
+ dev-type tun
+ proto udp6
+
+ cipher AES-256-GCM
+ auth SHA256
+
+ multihome
+ server-ipv6 2001:db8:1::/64
+
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/server.crt
+ key $(atf_get_srcdir)/server.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ mode server
+ script-security 2
+ auth-user-pass-verify /usr/bin/true via-env
+ topology subnet
+
+ keepalive 100 600
+ "
+ ovpn_start b "
+ dev tun0
+ dev-type tun
+
+ client
+
+ remote 2001:db8::2
+ auth-user-pass $(atf_get_srcdir)/user.pass
+
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/client.crt
+ key $(atf_get_srcdir)/client.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ keepalive 100 600
+ "
+
+ # Block packets from the primary address, openvpn should only use the
+ # configured remote address.
+ jexec b pfctl -e
+ pft_set_rules b \
+ "block in quick from 2001:db8::1 to any" \
+ "pass all"
+
+ # Give the tunnel time to come up
+ sleep 10
+
+ atf_check -s exit:0 -o ignore jexec b ping6 -c 3 2001:db8:1::1
+ atf_check -s exit:0 -o ignore jexec b ping6 -c 3 -z 16 2001:db8:1::1
+}
+
+multihome6_cleanup()
+{
+ ovpn_cleanup
+}
+
+atf_test_case "float" "cleanup"
+float_head()
+{
+ atf_set descr 'Test peer float notification'
+ atf_set require.user root
+}
+
+float_body()
+{
+ ovpn_init
+
+ l=$(vnet_mkepair)
+
+ vnet_mkjail a ${l}a
+ jexec a ifconfig ${l}a 192.0.2.1/24 up
+ jexec a ifconfig lo0 127.0.0.1/8 up
+ vnet_mkjail b ${l}b
+ jexec b ifconfig ${l}b 192.0.2.2/24 up
+
+ # Sanity check
+ atf_check -s exit:0 -o ignore jexec a ping -c 1 192.0.2.2
+
+ ovpn_start a "
+ dev ovpn0
+ dev-type tun
+ proto udp4
+
+ cipher AES-256-GCM
+ auth SHA256
+
+ local 192.0.2.1
+ server 198.51.100.0 255.255.255.0
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/server.crt
+ key $(atf_get_srcdir)/server.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ mode server
+ script-security 2
+ auth-user-pass-verify /usr/bin/true via-env
+ topology subnet
+
+ keepalive 2 10
+
+ management 192.0.2.1 1234
+ "
+ ovpn_start b "
+ dev tun0
+ dev-type tun
+
+ client
+
+ remote 192.0.2.1
+ auth-user-pass $(atf_get_srcdir)/user.pass
+
+ ca $(atf_get_srcdir)/ca.crt
+ cert $(atf_get_srcdir)/client.crt
+ key $(atf_get_srcdir)/client.key
+ dh $(atf_get_srcdir)/dh.pem
+
+ keepalive 2 10
+ "
+
+ # Give the tunnel time to come up
+ sleep 10
+
+ atf_check -s exit:0 -o ignore jexec b ping -c 3 198.51.100.1
+
+ # We expect the client on 192.0.2.2
+ if ! echo "status" | jexec a nc -N 192.0.2.1 1234 | grep 192.0.2.2; then
+ atf_fail "Client not found in status list!"
+ fi
+
+ # Now change the client IP
+ jexec b ifconfig ${l}b 192.0.2.3/24 up
+
+ # And wait for keepalives to trigger the float notification
+ sleep 5
+
+ # So the client now has the new address in userspace
+ if ! echo "status" | jexec a nc -N 192.0.2.1 1234 | grep 192.0.2.3; then
+ atf_fail "Client not found in status list!"
+ fi
+}
+
+float_cleanup()
+{
+ ovpn_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "4in4"
@@ -1165,4 +1420,7 @@ atf_init_test_cases()
atf_add_test_case "chacha"
atf_add_test_case "gcm_128"
atf_add_test_case "destroy_unused"
+ atf_add_test_case "multihome4"
+ atf_add_test_case "multihome6"
+ atf_add_test_case "float"
}
diff --git a/tests/sys/net/if_vlan.sh b/tests/sys/net/if_vlan.sh
index 424eac705b94..8122203337e2 100755
--- a/tests/sys/net/if_vlan.sh
+++ b/tests/sys/net/if_vlan.sh
@@ -333,6 +333,32 @@ conflict_id_cleanup()
}
+# If a vlan interface is in a bridge, changing the vlandev to refer to
+# a bridge should not be allowed.
+atf_test_case "bridge_vlandev" "cleanup"
+bridge_vlandev_head()
+{
+ atf_set descr 'transforming a bridge member vlan into an SVI is not allowed'
+ atf_set require.user root
+}
+
+bridge_vlandev_body()
+{
+ vnet_init
+ vnet_init_bridge
+
+ bridge=$(vnet_mkbridge)
+ vlan=$(vnet_mkvlan)
+
+ atf_check -s exit:0 ifconfig ${bridge} addm ${vlan}
+ atf_check -s exit:1 -e ignore ifconfig ${vlan} vlan 1 vlandev ${bridge}
+}
+
+bridge_vlandev_cleanup()
+{
+ vnet_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "basic"
@@ -343,4 +369,5 @@ atf_init_test_cases()
atf_add_test_case "qinq_setflags"
atf_add_test_case "bpf_pcp"
atf_add_test_case "conflict_id"
+ atf_add_test_case "bridge_vlandev"
}
diff --git a/tests/sys/netpfil/common/dummynet.sh b/tests/sys/netpfil/common/dummynet.sh
index b77b2df84010..66736fbecdb7 100644
--- a/tests/sys/netpfil/common/dummynet.sh
+++ b/tests/sys/netpfil/common/dummynet.sh
@@ -265,10 +265,6 @@ queue_body()
{
fw=$1
- if [ $fw = "ipfw" ] && [ "$(atf_config_get ci false)" = "true" ]; then
- atf_skip "https://bugs.freebsd.org/264805"
- fi
-
firewall_init $fw
dummynet_init $fw
diff --git a/tests/sys/netpfil/pf/Makefile b/tests/sys/netpfil/pf/Makefile
index 3adaef09ddbd..404d5adfb07a 100644
--- a/tests/sys/netpfil/pf/Makefile
+++ b/tests/sys/netpfil/pf/Makefile
@@ -58,6 +58,8 @@ ATF_TESTS_SH+= altq \
ATF_TESTS_PYTEST+= frag6.py
ATF_TESTS_PYTEST+= header.py
ATF_TESTS_PYTEST+= icmp.py
+ATF_TESTS_PYTEST+= igmp.py
+ATF_TESTS_PYTEST+= mld.py
ATF_TESTS_PYTEST+= nat64.py
ATF_TESTS_PYTEST+= nat66.py
ATF_TESTS_PYTEST+= return.py
diff --git a/tests/sys/netpfil/pf/forward.sh b/tests/sys/netpfil/pf/forward.sh
index 5d7d48a5dd9a..e9539bc9d278 100644
--- a/tests/sys/netpfil/pf/forward.sh
+++ b/tests/sys/netpfil/pf/forward.sh
@@ -101,10 +101,6 @@ v6_body()
{
pft_init
- if [ "$(atf_config_get ci false)" = "true" ]; then
- atf_skip "https://bugs.freebsd.org/260460"
- fi
-
epair_send=$(vnet_mkepair)
epair_recv=$(vnet_mkepair)
diff --git a/tests/sys/netpfil/pf/icmp.py b/tests/sys/netpfil/pf/icmp.py
index 59f2e8190b30..c5e945d60e99 100644
--- a/tests/sys/netpfil/pf/icmp.py
+++ b/tests/sys/netpfil/pf/icmp.py
@@ -136,8 +136,7 @@ class TestICMP(VnetTestTemplate):
/ sp.ICMP(type='echo-request') \
/ sp.raw(bytes.fromhex('f0') * payload_size)
- p = sp.sr1(packet, iface=self.vnet.iface_alias_map["if1"].name,
- timeout=3)
+ p = sp.sr1(packet, timeout=3)
p.show()
ip = p.getlayer(sp.IP)
@@ -176,6 +175,22 @@ class TestICMP(VnetTestTemplate):
self.check_icmp_echo(sp, 1464)
self.check_icmp_echo(sp, 1468)
+ @pytest.mark.require_user("root")
+ @pytest.mark.require_progs(["scapy"])
+ def test_truncated_opts(self):
+ ToolsHelper.print_output("/sbin/route add default 192.0.2.1")
+
+ # Import in the correct vnet, so at to not confuse Scapy
+ import scapy.all as sp
+
+ packet = sp.IP(dst="198.51.100.2", flags="DF") \
+ / sp.ICMP(type='dest-unreach', length=108) \
+ / sp.IP(src="198.51.100.2", dst="192.0.2.2", len=1000, \
+ ihl=(120 >> 2), options=[ \
+ sp.IPOption_Security(length=100)])
+ packet.show()
+ sp.sr1(packet, timeout=3)
+
class TestICMP_NAT(VnetTestTemplate):
REQUIRED_MODULES = [ "pf" ]
TOPOLOGY = {
diff --git a/tests/sys/netpfil/pf/igmp.py b/tests/sys/netpfil/pf/igmp.py
new file mode 100644
index 000000000000..b339a2825082
--- /dev/null
+++ b/tests/sys/netpfil/pf/igmp.py
@@ -0,0 +1,95 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2025 Rubicon Communications, LLC (Netgate)
+#
+# 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.
+
+import pytest
+from utils import DelayedSend
+from atf_python.sys.net.tools import ToolsHelper
+from atf_python.sys.net.vnet import VnetTestTemplate
+
+class TestIGMP(VnetTestTemplate):
+ REQUIRED_MODULES = [ "pf" ]
+ TOPOLOGY = {
+ "vnet1": {"ifaces": ["if1"]},
+ "vnet2": {"ifaces": ["if1"]},
+ "if1": {"prefixes4": [("192.0.2.2/24", "192.0.2.1/24")]},
+ }
+
+ def vnet2_handler(self, vnet):
+ ifname = vnet.iface_alias_map["if1"].name
+ ToolsHelper.print_output("/sbin/pfctl -e")
+ ToolsHelper.pf_rules([
+ "pass",
+ ])
+ ToolsHelper.print_output("/sbin/pfctl -x loud")
+ ToolsHelper.print_output("echo \"j 230.0.0.1 %s\ns 3600\nq\" | /usr/sbin/mtest" % ifname)
+
+ def find_igmp_reply(self, pkt, ifname):
+ pkt.show()
+ s = DelayedSend(pkt)
+
+ found = False
+ packets = self.sp.sniff(iface=ifname, timeout=5)
+ for r in packets:
+ r.show()
+ igmp = r.getlayer(self.sc.igmp.IGMP)
+ if not igmp:
+ continue
+ igmp.show()
+ if not igmp.gaddr == "230.0.0.1":
+ continue
+ found = True
+ return found
+
+ @pytest.mark.require_user("root")
+ @pytest.mark.require_progs(["scapy"])
+ def test_ip_opts(self):
+ """Verify that we allow IGMP packets with IP options"""
+ ifname = self.vnet.iface_alias_map["if1"].name
+
+ # Import in the correct vnet, so at to not confuse Scapy
+ import scapy.all as sp
+ import scapy.contrib as sc
+ import scapy.contrib.igmp
+ self.sp = sp
+ self.sc = sc
+
+ # We allow IGMP packets with the router alert option
+ pkt = sp.IP(dst="224.0.0.1%%%s" % ifname, ttl=1,
+ options=[sp.IPOption_Router_Alert()]) \
+ / sc.igmp.IGMP(type=0x11, mrcode=1)
+ assert self.find_igmp_reply(pkt, ifname)
+
+ # But not with other options
+ pkt = sp.IP(dst="224.0.0.1%%%s" % ifname, ttl=1,
+ options=[sp.IPOption_NOP()]) \
+ / sc.igmp.IGMP(type=0x11, mrcode=1)
+ assert not self.find_igmp_reply(pkt, ifname)
+
+ # Or with the wrong TTL
+ pkt = sp.IP(dst="224.0.0.1%%%s" % ifname, ttl=2,
+ options=[sp.IPOption_Router_Alert()]) \
+ / sc.igmp.IGMP(type=0x11, mrcode=1)
+ assert not self.find_igmp_reply(pkt, ifname)
diff --git a/tests/sys/netpfil/pf/killstate.sh b/tests/sys/netpfil/pf/killstate.sh
index 447a4e388f11..0d98db822535 100644
--- a/tests/sys/netpfil/pf/killstate.sh
+++ b/tests/sys/netpfil/pf/killstate.sh
@@ -117,10 +117,6 @@ v6_body()
{
pft_init
- if [ "$(atf_config_get ci false)" = "true" ]; then
- atf_skip "https://bugs.freebsd.org/260458"
- fi
-
epair=$(vnet_mkepair)
ifconfig ${epair}a inet6 2001:db8::1/64 up no_dad
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/mld.py b/tests/sys/netpfil/pf/mld.py
new file mode 100644
index 000000000000..d118a34c8a7d
--- /dev/null
+++ b/tests/sys/netpfil/pf/mld.py
@@ -0,0 +1,95 @@
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+# Copyright (c) 2025 Rubicon Communications, LLC (Netgate)
+#
+# 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.
+
+import pytest
+from utils import DelayedSend
+from atf_python.sys.net.tools import ToolsHelper
+from atf_python.sys.net.vnet import VnetTestTemplate
+
+class TestMLD(VnetTestTemplate):
+ REQUIRED_MODULES = [ "pf" ]
+ TOPOLOGY = {
+ "vnet1": {"ifaces": ["if1"]},
+ "vnet2": {"ifaces": ["if1"]},
+ "if1": {"prefixes6": [("2001:db8::2/64", "2001:db8::1/64")]},
+ }
+
+ def vnet2_handler(self, vnet):
+ ifname = vnet.iface_alias_map["if1"].name
+ #ToolsHelper.print_output("/sbin/pfctl -e")
+ ToolsHelper.pf_rules([
+ "pass",
+ ])
+ ToolsHelper.print_output("/sbin/pfctl -x loud")
+ #ToolsHelper.print_output("echo \"j 230.0.0.1 %s\ns 3600\nq\" | /usr/sbin/mtest" % ifname)
+
+ def find_mld_reply(self, pkt, ifname):
+ pkt.show()
+ s = DelayedSend(pkt)
+
+ found = False
+ packets = self.sp.sniff(iface=ifname, timeout=5)
+ for r in packets:
+ r.show()
+ mld = r.getlayer(self.sp.ICMPv6MLReport2)
+ if not mld:
+ continue
+ mld.show()
+ found = True
+ return found
+
+ @pytest.mark.require_user("root")
+ @pytest.mark.require_progs(["scapy"])
+ def test_router_alert(self):
+ """Verify that we allow MLD packets with router alert extension header"""
+ ifname = self.vnet.iface_alias_map["if1"].name
+ #ToolsHelper.print_output("/sbin/ifconfig %s inet6 -ifdisable" % ifname)
+ ToolsHelper.print_output("/sbin/ifconfig")
+
+ # Import in the correct vnet, so at to not confuse Scapy
+ import scapy.all as sp
+ import scapy.contrib as sc
+ import scapy.contrib.igmp
+ self.sp = sp
+ self.sc = sc
+
+ # A correct MLD query gets a reply
+ pkt = sp.IPv6(src="fe80::1%%%s" % ifname, dst="ff02::1", hlim=1) \
+ / sp.RouterAlert(value=0) \
+ / sp.ICMPv6MLQuery2()
+ assert self.find_mld_reply(pkt, ifname)
+
+ # The wrong extension header does not
+ pkt = sp.IPv6(src="fe80::1%%%s" % ifname, dst="ff02::1", hlim=1) \
+ / sp.IPv6ExtHdrRouting() \
+ / sp.ICMPv6MLQuery2()
+ assert not self.find_mld_reply(pkt, ifname)
+
+ # Neither does an incorrect hop limit
+ pkt = sp.IPv6(src="fe80::1%%%s" % ifname, dst="ff02::1", hlim=2) \
+ / sp.RouterAlert(value=0) \
+ / sp.ICMPv6MLQuery2()
+ assert not self.find_mld_reply(pkt, ifname)
diff --git a/tests/sys/netpfil/pf/set_tos.sh b/tests/sys/netpfil/pf/set_tos.sh
index 75b96edbab6e..842377ee97c6 100644
--- a/tests/sys/netpfil/pf/set_tos.sh
+++ b/tests/sys/netpfil/pf/set_tos.sh
@@ -129,10 +129,6 @@ v6_body()
{
pft_init
- if [ "$(atf_config_get ci false)" = "true" ]; then
- atf_skip "https://bugs.freebsd.org/260459"
- fi
-
epair=$(vnet_mkepair)
ifconfig ${epair}a inet6 add 2001:db8:192::1
vnet_mkjail alcatraz ${epair}b
diff --git a/tests/sys/netpfil/pf/table.sh b/tests/sys/netpfil/pf/table.sh
index 78320375db7c..5e5fccdaca20 100644
--- a/tests/sys/netpfil/pf/table.sh
+++ b/tests/sys/netpfil/pf/table.sh
@@ -582,6 +582,34 @@ anchor_cleanup()
pft_cleanup
}
+atf_test_case "flush" "cleanup"
+flush_head()
+{
+ atf_set descr 'Test flushing addresses from tables'
+ atf_set require.user root
+}
+
+flush_body()
+{
+ pft_init
+
+ vnet_mkjail alcatraz
+
+ atf_check -s exit:0 -e match:"1/1 addresses added." \
+ jexec alcatraz pfctl -t foo -T add 1.2.3.4
+ atf_check -s exit:0 -o match:" 1.2.3.4" \
+ jexec alcatraz pfctl -t foo -T show
+ atf_check -s exit:0 -e match:"1 addresses deleted." \
+ jexec alcatraz pfctl -t foo -T flush
+ atf_check -s exit:0 -o not-match:"1.2.3.4" \
+ jexec alcatraz pfctl -t foo -T show
+}
+
+flush_cleanup()
+{
+ pft_cleanup
+}
+
atf_init_test_cases()
{
atf_add_test_case "v4_counters"
@@ -596,4 +624,5 @@ atf_init_test_cases()
atf_add_test_case "pr259689"
atf_add_test_case "precreate"
atf_add_test_case "anchor"
+ atf_add_test_case "flush"
}
diff --git a/tools/boot/install-boot.sh b/tools/boot/install-boot.sh
index 217bf0ff1457..10e62dd32ba8 100755
--- a/tools/boot/install-boot.sh
+++ b/tools/boot/install-boot.sh
@@ -294,27 +294,9 @@ boot_nogeli_mbr_ufs_both() {
boot_nogeli_mbr_ufs_uefi $1 $2 $3
}
+# ZFS+MBR+BIOS is not a supported configuration
boot_nogeli_mbr_zfs_legacy() {
- dev=$1
- dst=$2
-
- # search to find the BSD slice
- s=$(find_part $dev "freebsd")
- if [ -z "$s" ] ; then
- die "No BSD slice found"
- fi
- idx=$(find_part ${dev}s${s} "freebsd-zfs")
- if [ -z "$idx" ] ; then
- die "No freebsd-zfs slice found"
- fi
- # search to find the freebsd-zfs partition within the slice
- # Or just assume it is 'a' because it has to be since it fails otherwise
- doit gpart bootcode -b ${dst}/boot/mbr ${dev}
- dd if=${dst}/boot/zfsboot of=/tmp/zfsboot1 count=1
- doit gpart bootcode -b /tmp/zfsboot1 ${dev}s${s} # Put boot1 into the start of part
- sysctl kern.geom.debugflags=0x10 # Put boot2 into ZFS boot slot
- doit dd if=${dst}/boot/zfsboot of=/dev/${dev}s${s}a skip=1 seek=1024
- sysctl kern.geom.debugflags=0x0
+ exit 1
}
boot_nogeli_mbr_zfs_uefi() {
@@ -322,7 +304,6 @@ boot_nogeli_mbr_zfs_uefi() {
}
boot_nogeli_mbr_zfs_both() {
- boot_nogeli_mbr_zfs_legacy $1 $2 $3
boot_nogeli_mbr_zfs_uefi $1 $2 $3
}
diff --git a/tools/boot/rootgen.sh b/tools/boot/rootgen.sh
index d87eb481e2c1..2cd65bdd180d 100755
--- a/tools/boot/rootgen.sh
+++ b/tools/boot/rootgen.sh
@@ -202,33 +202,6 @@ mk_nogeli_mbr_ufs_both() {
rm -f ${src}/etc/fstab
}
-mk_nogeli_mbr_zfs_legacy() {
- src=$1
- img=$2
- mntpt=$3
- geli=$4
- scheme=$5
- fs=$6
- bios=$7
- pool=nogeli-mbr-zfs-legacy
-
- zfs_extra $src $dst
- makefs -t zfs -s 200m \
- -o poolname=${pool} -o bootfs=${pool} -o rootpath=/ \
- ${img}.s1a ${src} ${dst}
- # The old boot1/boot2 boot split is also used by zfs. We need to extract zfsboot1
- # from this image. Since there's no room in the mbr format for the rest of the loader,
- # it will load the zfsboot loader from the reserved for bootloader area of the ZFS volume
- # being booted, hence the need to dd it into the raw img later.
- # Please note: zfsboot only works with partition 'a' which must be the root
- # partition / zfs volume
- dd if=${src}/boot/zfsboot of=${dst}/zfsboot1 count=1
- mkimg -s bsd -b ${dst}zfsboot1 -p freebsd-zfs:=${img}.s1a -o ${img}.s1
- dd if=${src}/boot/zfsboot of=${img}.s1a skip=1 seek=1024
- mkimg -a 1 -s mbr -b ${src}/boot/mbr -p freebsd:=${img}.s1 -o ${img}
- rm -rf ${dst}
-}
-
mk_nogeli_mbr_zfs_uefi() {
src=$1
img=$2
@@ -244,38 +217,11 @@ mk_nogeli_mbr_zfs_uefi() {
makefs -t zfs -s 200m \
-o poolname=${pool} -o bootfs=${pool} -o rootpath=/ \
${img}.s2a ${src} ${dst}
- mkimg -s bsd -b ${dst}zfsboot1 -p freebsd-zfs:=${img}.s2a -o ${img}.s2
+ mkimg -s bsd -p freebsd-zfs:=${img}.s2a -o ${img}.s2
mkimg -a 1 -s mbr -b ${src}/boot/mbr -p efi:=${img}.s1 -p freebsd:=${img}.s2 -o ${img}
rm -rf ${dst}
}
-mk_nogeli_mbr_zfs_both() {
- src=$1
- img=$2
- mntpt=$3
- geli=$4
- scheme=$5
- fs=$6
- bios=$7
- pool=nogeli-mbr-zfs-both
-
- zfs_extra $src $dst
- make_esp_file ${img}.s1 ${espsize} ${src}/boot/loader.efi
- makefs -t zfs -s 200m \
- -o poolname=${pool} -o bootfs=${pool} -o rootpath=/ \
- ${img}.s2a ${src} ${dst}
- # The old boot1/boot2 boot split is also used by zfs. We need to extract zfsboot1
- # from this image. Since there's no room in the mbr format for the rest of the loader,
- # it will load the zfsboot loader from the reserved for bootloader area of the ZFS volume
- # being booted, hence the need to dd it into the raw img later.
- # Please note: zfsboot only works with partition 'a' which must be the root
- # partition / zfs volume
- dd if=${src}/boot/zfsboot of=${dst}/zfsboot1 count=1
- mkimg -s bsd -b ${dst}zfsboot1 -p freebsd-zfs:=${img}.s2a -o ${img}.s2
- dd if=${src}/boot/zfsboot of=${img}.s1a skip=1 seek=1024
- mkimg -a 1 -s mbr -b ${src}/boot/mbr -p efi:=${img}.s1 -p freebsd:=${img}.s2 -o ${img}
-}
-
mk_geli_gpt_ufs_legacy() {
src=$1
img=$2
@@ -728,6 +674,10 @@ for arch in amd64; do
for scheme in gpt mbr; do
for fs in ufs zfs; do
for bios in legacy uefi both; do
+ # ZFS+MBR+BIOS is not supported
+ if [ "$scheme" = "mbr" -a "$fs" = "zfs" -a "$bios" != "uefi" ]; then
+ continue
+ fi
make_one_image ${arch} ${geli} ${scheme} ${fs} ${bios}
done
done
@@ -750,6 +700,11 @@ for arch in i386; do
for bios in legacy; do
# The legacy boot is shared with amd64 so those routines could
# likely be used here.
+
+ # ZFS+MBR+BIOS is not supported
+ if [ "$scheme" = "mbr" -a "$fs" = "zfs" -a "$bios" != "uefi" ]; then
+ continue
+ fi
make_one_image ${arch} ${geli} ${scheme} ${fs} ${bios}
done
done
diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc
index 1e63e4616909..580be4362a18 100644
--- a/tools/build/mk/OptionalObsoleteFiles.inc
+++ b/tools/build/mk/OptionalObsoleteFiles.inc
@@ -357,7 +357,6 @@ OLD_FILES+=boot/shortcuts.4th
OLD_FILES+=boot/support.4th
OLD_FILES+=boot/userboot.so
OLD_FILES+=boot/version.4th
-OLD_FILES+=boot/zfsboot
OLD_FILES+=boot/zfsloader
OLD_FILES+=usr/lib/kgzldr.o
OLD_FILES+=usr/share/man/man5/loader.conf.5.gz
@@ -374,7 +373,6 @@ OLD_FILES+=usr/share/man/man8/menu.4th.8.gz
OLD_FILES+=usr/share/man/man8/menusets.4th.8.gz
OLD_FILES+=usr/share/man/man8/pxeboot.8.gz
OLD_FILES+=usr/share/man/man8/version.4th.8.gz
-OLD_FILES+=usr/share/man/man8/zfsboot.8.gz
OLD_FILES+=usr/share/man/man8/zfsloader.8.gz
.endif
@@ -461,7 +459,7 @@ OLD_FILES+=usr/include/bsnmp/snmpclient.h
OLD_FILES+=usr/include/bsnmp/snmpmod.h
OLD_FILES+=usr/lib/libbsnmp.a
OLD_FILES+=usr/lib/libbsnmp.so
-OLD_LIBS+=usr/lib/libbsnmp.so.6
+OLD_LIBS+=usr/lib/libbsnmp.so.7
OLD_FILES+=usr/lib/libbsnmp_p.a
OLD_FILES+=usr/lib/libbsnmptools.a
OLD_FILES+=usr/lib/libbsnmptools.so
@@ -1441,6 +1439,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
@@ -1469,12 +1471,12 @@ OLD_DIRS+=usr/share/dict
.endif
.if ${MK_DMAGENT} == no
+OLD_FILES+=etc/dma/auth.conf
OLD_FILES+=etc/dma/dma.conf
OLD_DIRS+=etc/dma
OLD_FILES+=usr/libexec/dma
OLD_FILES+=usr/libexec/dma-mbox-create
OLD_FILES+=usr/share/man/man8/dma.8.gz
-OLD_FILES+=usr/share/examples/dma/auth.conf
OLD_FILES+=usr/share/examples/dma/mailer.conf
OLD_DIRS+=usr/share/examples/dma
.endif
@@ -3709,33 +3711,33 @@ OLD_FILES+=usr/lib/krb5/plugins/preauth/test.so
OLD_FILES+=usr/lib/krb5/plugins/tls/k5tls.so
OLD_FILES+=usr/lib/libcom_err.a
OLD_LIBS+=usr/lib/libcom_err.so
-OLD_LIBS+=usr/lib/libcom_err.so.121
+OLD_LIBS+=usr/lib/libcom_err.so.122
OLD_FILES+=usr/lib/libgssapi_krb5.so
-OLD_LIBS+=usr/lib/libgssapi_krb5.so.121
+OLD_LIBS+=usr/lib/libgssapi_krb5.so.122
OLD_FILES+=usr/lib/libgssrpc.so
-OLD_LIBS+=usr/lib/libgssrpc.so.121
+OLD_LIBS+=usr/lib/libgssrpc.so.122
OLD_FILES+=usr/lib/libk5crypto.so
-OLD_LIBS+=usr/lib/libk5crypto.so.121
+OLD_LIBS+=usr/lib/libk5crypto.so.122
OLD_FILES+=usr/lib/libkadm5clnt.so
OLD_FILES+=usr/lib/libkadm5clnt_mit.so
-OLD_LIBS+=usr/lib/libkadm5clnt_mit.so.121
+OLD_LIBS+=usr/lib/libkadm5clnt_mit.so.122
OLD_FILES+=usr/lib/libkadm5srv.so
OLD_FILES+=usr/lib/libkadm5srv_mit.so
-OLD_LIBS+=usr/lib/libkadm5srv_mit.so.121
+OLD_LIBS+=usr/lib/libkadm5srv_mit.so.122
OLD_FILES+=usr/lib/libkdb5.so
-OLD_LIBS+=usr/lib/libkdb5.so.121
+OLD_LIBS+=usr/lib/libkdb5.so.122
OLD_FILES+=usr/lib/libkrad.so
-OLD_LIBS+=usr/lib/libkrad.so.121
+OLD_LIBS+=usr/lib/libkrad.so.122
OLD_FILES+=usr/lib/libkrb5.so
-OLD_LIBS+=usr/lib/libkrb5.so.121
+OLD_LIBS+=usr/lib/libkrb5.so.122
OLD_FILES+=usr/lib/libkrb5profile.a
OLD_FILES+=usr/lib/libkrb5profile.so
-OLD_LIBS+=usr/lib/libkrb5profile.so.121
+OLD_LIBS+=usr/lib/libkrb5profile.so.122
OLD_FILES+=usr/lib/libkrb5support.a
OLD_FILES+=usr/lib/libkrb5support.so
-OLD_LIBS+=usr/lib/libkrb5support.so.121
+OLD_LIBS+=usr/lib/libkrb5support.so.122
OLD_FILES+=usr/lib/libverto.so
-OLD_LIBS+=usr/lib/libverto.so.121
+OLD_LIBS+=usr/lib/libverto.so.122
OLD_FILES+=usr/libdata/pkgconfig/gssrpc.pc
OLD_FILES+=usr/libdata/pkgconfig/kadm-client.pc
OLD_FILES+=usr/libdata/pkgconfig/kadm-server.pc
@@ -5766,36 +5768,36 @@ OLD_FILES+=usr/lib/krb5/plugins/preauth/pkinit.so
OLD_FILES+=usr/lib/krb5/plugins/preauth/spake.so
OLD_FILES+=usr/lib/krb5/plugins/preauth/test.so
OLD_FILES+=usr/lib/krb5/plugins/tls/k5tls.so
-OLD_LIBS+=usr/lib/libcom_err.so.121
-OLD_LIBS+=usr/lib/libgssapi_krb5.so.121
+OLD_LIBS+=usr/lib/libcom_err.so.122
+OLD_LIBS+=usr/lib/libgssapi_krb5.so.122
OLD_FILES+=usr/lib/libgssrpc.a
OLD_FILES+=usr/lib/libgssrpc.so
-OLD_LIBS+=usr/lib/libgssrpc.so.121
+OLD_LIBS+=usr/lib/libgssrpc.so.122
OLD_FILES+=usr/lib/libk5crypto.a
OLD_FILES+=usr/lib/libk5crypto.so
-OLD_LIBS+=usr/lib/libk5crypto.so.121
+OLD_LIBS+=usr/lib/libk5crypto.so.122
OLD_FILES+=usr/lib/libkadm5clnt_mit.a
OLD_FILES+=usr/lib/libkadm5clnt_mit.so
-OLD_LIBS+=usr/lib/libkadm5clnt_mit.so.121
+OLD_LIBS+=usr/lib/libkadm5clnt_mit.so.122
OLD_FILES+=usr/lib/libkadm5srv_mit.a
OLD_FILES+=usr/lib/libkadm5srv_mit.so
-OLD_LIBS+=usr/lib/libkadm5srv_mit.so.121
+OLD_LIBS+=usr/lib/libkadm5srv_mit.so.122
OLD_FILES+=usr/lib/libkdb5.a
OLD_FILES+=usr/lib/libkdb5.so
-OLD_LIBS+=usr/lib/libkdb5.so.121
+OLD_LIBS+=usr/lib/libkdb5.so.122
OLD_FILES+=usr/lib/libkrad.so
OLD_FILES+=usr/lib/libkrad.a
-OLD_LIBS+=usr/lib/libkrad.so.121
-OLD_LIBS+=usr/lib/libkrb5.so.121
+OLD_LIBS+=usr/lib/libkrad.so.122
+OLD_LIBS+=usr/lib/libkrb5.so.122
OLD_FILES+=usr/lib/libkrb5profile.a
OLD_FILES+=usr/lib/libkrb5profile.so
-OLD_LIBS+=usr/lib/libkrb5profile.so.121
+OLD_LIBS+=usr/lib/libkrb5profile.so.122
OLD_FILES+=usr/lib/libkrb5support.a
OLD_FILES+=usr/lib/libkrb5support.so
-OLD_LIBS+=usr/lib/libkrb5support.so.121
+OLD_LIBS+=usr/lib/libkrb5support.so.122
OLD_FILES+=usr/lib/libverto.a
OLD_FILES+=usr/lib/libverto.so
-OLD_LIBS+=usr/lib/libverto.so.121
+OLD_LIBS+=usr/lib/libverto.so.122
OLD_FILES+=usr/libdata/pkgconfig/gssrpc.pc
OLD_FILES+=usr/libdata/pkgconfig/kadm-client.pc
OLD_FILES+=usr/libdata/pkgconfig/kadm-server.pc
@@ -12273,7 +12275,6 @@ OLD_FILES+=usr/share/snmp/mibs/BEGEMOT-WIRELESS-MIB.txt
.if ${MK_ZFS} == no
OLD_FILES+=boot/gptzfsboot
-OLD_FILES+=boot/zfsboot
OLD_FILES+=boot/zfsloader
OLD_FILES+=etc/rc.d/zfs
OLD_FILES+=etc/rc.d/zfsbe
@@ -12376,7 +12377,6 @@ OLD_FILES+=usr/share/man/man8/gptzfsboot.8.gz
OLD_FILES+=usr/share/man/man8/zdb.8.gz
OLD_FILES+=usr/share/man/man8/zfs-program.8.gz
OLD_FILES+=usr/share/man/man8/zfs.8.gz
-OLD_FILES+=usr/share/man/man8/zfsboot.8.gz
OLD_FILES+=usr/share/man/man8/zfsbootcfg.8.gz
OLD_FILES+=usr/share/man/man8/zfsd.8.gz
OLD_FILES+=usr/share/man/man8/zfsloader.8.gz
diff --git a/tools/build/options/WITH_LLVM_ASSERTIONS b/tools/build/options/WITH_LLVM_ASSERTIONS
index 0e7fbfbda0a3..6af75221a206 100644
--- a/tools/build/options/WITH_LLVM_ASSERTIONS
+++ b/tools/build/options/WITH_LLVM_ASSERTIONS
@@ -1 +1,2 @@
Enable debugging assertions in LLVM.
+Use when working on or requesting help with LLVM components.
diff --git a/tools/test/stress2/misc/fullpath2.sh b/tools/test/stress2/misc/fullpath2.sh
index f0037851482d..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_fullpath: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/tools/vt/mkkfont/Makefile b/tools/tools/vt/mkkfont/Makefile
index f9758be0ef15..1e8a9bcdafd7 100644
--- a/tools/tools/vt/mkkfont/Makefile
+++ b/tools/tools/vt/mkkfont/Makefile
@@ -1,4 +1,4 @@
PROG= mkkfont
-MAN1=
+MAN=
.include <bsd.prog.mk>
diff --git a/usr.bin/asa/asa.1 b/usr.bin/asa/asa.1
index da1af0e8ce84..68d0735774a6 100644
--- a/usr.bin/asa/asa.1
+++ b/usr.bin/asa/asa.1
@@ -84,8 +84,6 @@ To format the output of a
program and redirect it to a line-printer:
.Pp
.Dl "a.out | asa | lpr"
-.Sh SEE ALSO
-.Xr f77 1
.Sh STANDARDS
The
.Nm
diff --git a/usr.bin/bmake/Makefile b/usr.bin/bmake/Makefile
index a8bcdfd9f859..bbceea3ae8c2 100644
--- a/usr.bin/bmake/Makefile
+++ b/usr.bin/bmake/Makefile
@@ -99,8 +99,6 @@ COPTS.filemon_ktrace.c+= -Wno-error=unused-parameter
SUBDIR.${MK_TESTS}+= unit-tests
.endif
-MAN1= ${MAN}
-
.if ${MK_GEN_MAN:Uno} == "yes"
# we use this to generate ${MAN}
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/Makefile.inc b/usr.bin/bmake/Makefile.inc
index 5140bd18bb37..a064563a2283 100644
--- a/usr.bin/bmake/Makefile.inc
+++ b/usr.bin/bmake/Makefile.inc
@@ -3,6 +3,8 @@ MK_host_egacy= no
.sinclude <src.opts.mk>
+PACKAGE?= bmake
+
.if defined(.PARSEDIR)
# make sure this is available to unit-tests/Makefile
.export SRCTOP
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/clang/clang-scan-deps/Makefile b/usr.bin/clang/clang-scan-deps/Makefile
index 16fecdb88867..8da12faccc45 100644
--- a/usr.bin/clang/clang-scan-deps/Makefile
+++ b/usr.bin/clang/clang-scan-deps/Makefile
@@ -10,13 +10,14 @@ SRCS+= ClangScanDeps.cpp \
.include "${SRCTOP}/lib/clang/clang.pre.mk"
CFLAGS+= -I${.OBJDIR}
-TDFILE= Opts.td
-INCFILE= ${TDFILE:.td=.inc}
+
+INCFILE= Opts.inc
+TDFILE= ${LLVM_BASE}/${SRCDIR}/Opts.td
GENOPT= -gen-opt-parser-defs
${INCFILE}: ${TDFILE}
${LLVM_TBLGEN} ${GENOPT} -I ${LLVM_SRCS}/include -d ${.TARGET:C/$/.d/} \
- -o ${.TARGET} ${.ALLSRC}
+ -o ${.TARGET} ${TDFILE}
TGHDRS+= ${INCFILE}
DEPENDFILES+= ${TGHDRS:C/$/.d/}
diff --git a/usr.bin/clang/clang.prog.mk b/usr.bin/clang/clang.prog.mk
index 36c601bcbe36..3baf3d0baf0f 100644
--- a/usr.bin/clang/clang.prog.mk
+++ b/usr.bin/clang/clang.prog.mk
@@ -31,7 +31,7 @@ DPADD+= ${OBJTOP}/lib/clang/lib${lib}/lib${LIBPRIV}${lib}.${LIBEXT}
LDADD+= ${OBJTOP}/lib/clang/lib${lib}/lib${LIBPRIV}${lib}.${LIBEXT}
.endfor
-PACKAGE= clang
+PACKAGE?= clang
.if ${.MAKE.OS} == "FreeBSD" || !defined(BOOTSTRAPPING)
LIBADD+= execinfo
diff --git a/usr.bin/clang/llvm-ar/Makefile b/usr.bin/clang/llvm-ar/Makefile
index fd12b1ddef57..e019c89b3581 100644
--- a/usr.bin/clang/llvm-ar/Makefile
+++ b/usr.bin/clang/llvm-ar/Makefile
@@ -1,5 +1,6 @@
.include <src.opts.mk>
+PACKAGE= toolchain
PROG_CXX= llvm-ar
MAN= llvm-ar.1 llvm-ranlib.1
diff --git a/usr.bin/clang/llvm-nm/Makefile b/usr.bin/clang/llvm-nm/Makefile
index 825faf74719b..7e089d1b408d 100644
--- a/usr.bin/clang/llvm-nm/Makefile
+++ b/usr.bin/clang/llvm-nm/Makefile
@@ -1,5 +1,6 @@
.include <src.opts.mk>
+PACKAGE= toolchain
PROG_CXX= llvm-nm
SRCDIR= llvm/tools/llvm-nm
diff --git a/usr.bin/clang/llvm-size/Makefile b/usr.bin/clang/llvm-size/Makefile
index 2860a0069538..9d3505cdd319 100644
--- a/usr.bin/clang/llvm-size/Makefile
+++ b/usr.bin/clang/llvm-size/Makefile
@@ -1,5 +1,6 @@
.include <src.opts.mk>
+PACKAGE= toolchain
PROG_CXX= llvm-size
SRCDIR= llvm/tools/llvm-size
diff --git a/usr.bin/clang/llvm.prog.mk b/usr.bin/clang/llvm.prog.mk
index f702082e31bd..c369fe8d5944 100644
--- a/usr.bin/clang/llvm.prog.mk
+++ b/usr.bin/clang/llvm.prog.mk
@@ -25,7 +25,7 @@ DPADD+= ${OBJTOP}/lib/clang/lib${lib}/lib${LIBPRIV}${lib}.${LIBEXT}
LDADD+= ${OBJTOP}/lib/clang/lib${lib}/lib${LIBPRIV}${lib}.${LIBEXT}
.endfor
-PACKAGE= clang
+PACKAGE?= clang
.if ${.MAKE.OS} == "FreeBSD" || !defined(BOOTSTRAPPING)
LIBADD+= execinfo
diff --git a/usr.bin/find/Makefile b/usr.bin/find/Makefile
index 904c08620833..48b164133bb0 100644
--- a/usr.bin/find/Makefile
+++ b/usr.bin/find/Makefile
@@ -3,7 +3,7 @@
PACKAGE= runtime
PROG= find
-SRCS= find.c function.c ls.c main.c misc.c operator.c option.c \
+SRCS= find.c function.c ls.c main.c misc.c operator.c option.c printf.c \
getdate.y
YFLAGS=
CFLAGS.clang+= -Werror=undef
diff --git a/usr.bin/find/extern.h b/usr.bin/find/extern.h
index feb2e0202056..02c85d06a34c 100644
--- a/usr.bin/find/extern.h
+++ b/usr.bin/find/extern.h
@@ -44,6 +44,8 @@ void printlong(char *, char *, struct stat *);
int queryuser(char **);
OPTION *lookup_option(const char *);
void finish_execplus(void);
+void do_printf(PLAN *plan, FTSENT *entry, FILE *fout);
+
creat_f c_Xmin;
creat_f c_Xtime;
@@ -55,6 +57,7 @@ creat_f c_empty;
creat_f c_exec;
creat_f c_flags;
creat_f c_follow;
+creat_f c_fprint;
creat_f c_fstype;
creat_f c_group;
creat_f c_ignore_readdir_race;
@@ -68,6 +71,7 @@ creat_f c_nogroup;
creat_f c_nouser;
creat_f c_perm;
creat_f c_print;
+creat_f c_printf;
creat_f c_regex;
creat_f c_samefile;
creat_f c_simple;
@@ -90,6 +94,8 @@ exec_f f_executable;
exec_f f_expr;
exec_f f_false;
exec_f f_flags;
+exec_f f_fprint;
+exec_f f_fprint0;
exec_f f_fstype;
exec_f f_group;
exec_f f_inum;
@@ -106,6 +112,7 @@ exec_f f_path;
exec_f f_perm;
exec_f f_print;
exec_f f_print0;
+exec_f f_printf;
exec_f f_prune;
exec_f f_quit;
exec_f f_readable;
diff --git a/usr.bin/find/find.1 b/usr.bin/find/find.1
index 8c2d8624a82a..b16c4bcc95a2 100644
--- a/usr.bin/find/find.1
+++ b/usr.bin/find/find.1
@@ -28,7 +28,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd November 23, 2024
+.Dd July 26, 2025
.Dt FIND 1
.Os
.Sh NAME
@@ -515,6 +515,28 @@ and none of the
.Ar flags
bits match those of
.Ar notflags .
+.It Ic -fprint Ar filename
+This primary always evaluates to true.
+This creates
+.Ar filename
+or truncates the file if it already exists.
+The file is created at startup.
+It writes the pathname of the current file to this file, followed
+by a newline character.
+The file will be empty if no files are matched.
+.Pp
+.It Ic -fprint0 Ar filename
+This primary always evaluates to true.
+This creates
+.Ar filename
+or truncates the file if it already exists.
+The file is created at startup.
+It writes the pathname of the current file to this file, followed
+by an ASCII
+.Dv NUL
+character (character code 0).
+The file will be empty if no files are matched.
+.Pp
.It Ic -fstype Ar type
True if the file is contained in a file system of type
.Ar type .
@@ -821,6 +843,17 @@ It prints the pathname of the current file to standard output, followed by an
ASCII
.Dv NUL
character (character code 0).
+.It Ic -printf Ar fmt
+This primary always evaluates to true.
+It prints information about the file, interpreting
+.Sq \
+and
+.Sq %
+escape sequences as described in the PRINTF FORMATS section.
+Unlike
+.Ic -print ,
+.Ic -printf
+does not add a newline automatically.
.It Ic -prune
This primary always evaluates to true.
It causes
@@ -993,6 +1026,149 @@ All operands and primaries must be separate arguments to
Primaries which themselves take arguments expect each argument
to be a separate argument to
.Nm .
+.Sh PRINTF FORMATS
+The following
+.Sq \e
+escapes are recognized:
+.Bl -tag -width Ds -offset indent -compact
+.It Cm \ea
+Write a <bell> character.
+.It Cm \eb
+Write a <backspace> character.
+.It Cm \ec
+Writes no characters, but terminates the string and flushes the output so far
+after each match.
+.It Cm \ef
+Write a <form-feed> character.
+.It Cm \en
+Write a <new-line> character.
+.It Cm \er
+Write a <carriage return> character.
+.It Cm \et
+Write a <tab> character.
+.It Cm \ev
+Write a <vertical tab> character.
+.It Cm \e\'
+Write a <single quote> character.
+.It Cm \e\e
+Write a backslash character.
+.It Cm \e Ns Ar num
+Write a byte whose
+value is the 1-, 2-, or 3-digit
+octal number
+.Ar num .
+Multibyte characters can be constructed using multiple
+.Cm \e Ns Ar num
+sequences.
+.El
+.Pp
+Each format specification is introduced by the percent character
+(``%'').
+The remainder of the format specification includes,
+in the following order:
+.Bl -tag -width Ds
+.It "Zero or more of the following flags:"
+.Bl -tag -width Ds
+.It Cm #
+A `#' character, has no effect on almost all formats.
+It is not yet implemented.
+.It Cm \&\-
+A minus sign `\-' which specifies
+.Em left adjustment
+of the output in the indicated field;
+It is not yet implemented.
+.It "Field Width:"
+An optional digit string specifying a
+.Em field width ;
+if the output string has fewer bytes than the field width it will
+be blank-padded on the left (or right, if the left-adjustment indicator
+has been given) to make up the field width (note that a leading zero
+is a flag, but an embedded zero is part of a field width);
+It is not yet implemented.
+.It Precision:
+An optional period,
+.Sq Cm \&.\& ,
+followed by an optional digit string giving a
+.Em precision
+which specifies the maximum number of bytes to be printed
+from a string; if the digit string is missing, the precision is treated
+as zero;
+It is not yet implemented.
+.It Format:
+One or two characters, described below, which indicates the information to display.
+.Bl -tag -width Ds
+.It p
+Path to file
+.It f
+Filename without directories.
+.It h
+Path relative to the starting point, or '.' if that's empty for some reason.
+.It P
+Unimplemented -- File with command line arg.
+.It H
+Unimplemented -- Command line arg.
+.It g
+gid in human readable form.
+.It G
+gid as a number.
+.It h
+uid in human readable form.
+.It U
+uid as a number.
+.It m
+File permission mode in octal.
+.It M
+File mode in
+.Xr ls 1
+standard form.
+.It k
+File size in KiB (units of 1024 bytes).
+.It b
+File size in blocks (Always 512 byte units, even if underlying storage
+size differs).
+.It s
+Size in bytes of the file.
+.It S
+Sparseness of the file.
+The blocks the file occupies times 512 divided by the file size.
+.It d
+Depth in the tree
+.It D
+Device number for the file.
+.It F
+Unimplemented -- Filesystem type where the file resides.
+.It l
+Object of the symbolic link.
+.It i
+Inode of the file.
+.It n
+Number of hard links.
+.It y
+Unimplemented -- Type of the file
+.It Y
+Unimplemented -- Type of the file with loop detection
+.It a
+Access time of the file.
+.It A
+Access time of the file in strftime format.
+Takes an additional argument.
+.It B
+Birth time of the file in strftime format.
+Takes an additional argument.
+.It c
+Creation time of the file.
+.It C
+Creation time of the file in strftime format.
+Takes an additional argument.
+.It t
+Modification time of the file.
+.It T
+Modification time of the file in strftime format.
+Takes an additional argument.
+.El
+Any format not listed is not supported, though the error changes.
+.El
+.El
.Sh ENVIRONMENT
The
.Ev LANG , LC_ALL , LC_COLLATE , LC_CTYPE , LC_MESSAGES
diff --git a/usr.bin/find/find.h b/usr.bin/find/find.h
index 1664eeb9a93f..e8bb0ca8c649 100644
--- a/usr.bin/find/find.h
+++ b/usr.bin/find/find.h
@@ -97,6 +97,8 @@ typedef struct _plandata *creat_f(struct _option *, char ***);
#define F_TIME2_B 0x00080000 /* one of -newer?B */
#endif
#define F_LINK 0x00100000 /* lname or ilname */
+/* Notes about execution */
+#define F_HAS_WARNED 0x10000000 /* Has issued a warning for maybe bad input */
/* node definition */
typedef struct _plandata {
@@ -133,6 +135,7 @@ typedef struct _plandata {
char *_a_data[2]; /* array of char pointers */
char *_c_data; /* char pointer */
regex_t *_re_data; /* regex */
+ FILE *_fprint_file; /* file stream for -fprint */
} p_un;
} PLAN;
#define a_data p_un._a_data
@@ -160,6 +163,7 @@ typedef struct _plandata {
#define e_pbsize p_un.ex._e_pbsize
#define e_psizemax p_un.ex._e_psizemax
#define e_next p_un.ex._e_next
+#define fprint_file p_un._fprint_file
typedef struct _option {
const char *name; /* option name */
diff --git a/usr.bin/find/function.c b/usr.bin/find/function.c
index ef610903cc00..11455b395022 100644
--- a/usr.bin/find/function.c
+++ b/usr.bin/find/function.c
@@ -866,6 +866,49 @@ c_follow(OPTION *option, char ***argvp __unused)
return palloc(option);
}
+/*
+ * -fprint functions --
+ *
+ * Always true, causes the current pathname to be written to
+ * specified file followed by a newline
+ */
+int
+f_fprint(PLAN *plan, FTSENT *entry)
+{
+ fprintf(plan->fprint_file, "%s\n", entry->fts_path);
+ return 1;
+}
+
+PLAN *
+c_fprint(OPTION *option, char ***argvp)
+{
+ PLAN *new;
+ char *fn;
+
+ isoutput = 1;
+
+ new = palloc(option);
+ fn = nextarg(option, argvp);
+ new->fprint_file = fopen(fn, "w");
+ if (new->fprint_file == NULL)
+ err(1, "fprint: cannot create %s", fn);
+
+ return (new);
+}
+
+/*
+ * -fprint0 functions --
+ *
+ * Always true, causes the current pathname to be written to
+ * specified file followed by a NUL
+ */
+int
+f_fprint0(PLAN *plan, FTSENT *entry)
+{
+ fprintf(plan->fprint_file, "%s%c", entry->fts_path, '\0');
+ return 1;
+}
+
#if HAVE_STRUCT_STATFS_F_FSTYPENAME
/*
* -fstype functions --
@@ -1389,6 +1432,36 @@ f_print0(PLAN *plan __unused, FTSENT *entry)
/* c_print0 is the same as c_print */
/*
+ * -printf functions --
+ *
+ * Always true. Causes information as specified in the
+ * argument to be written to standard output.
+ */
+int
+f_printf(PLAN *plan, FTSENT *entry)
+{
+ do_printf(plan, entry, stdout);
+ return 1;
+}
+
+PLAN *
+c_printf(OPTION *option, char ***argvp)
+{
+ PLAN *new;
+
+ isoutput = 1;
+ /*
+ * XXX We could scan the format looking for stat-dependent formats, and
+ * turn off the stat if there's none: `%p`/`%f`/`%h` don't need a stat.
+ */
+
+ new = palloc(option);
+ new->c_data = nextarg(option, argvp);
+
+ return (new);
+}
+
+/*
* -prune functions --
*
* Prune a portion of the hierarchy.
diff --git a/usr.bin/find/option.c b/usr.bin/find/option.c
index 268803343a8d..fa09231a3152 100644
--- a/usr.bin/find/option.c
+++ b/usr.bin/find/option.c
@@ -83,8 +83,8 @@ static OPTION const options[] = {
#endif
// -fls
{ "-follow", c_follow, f_always_true, 0 },
-// -fprint
-// -fprint0
+ { "-fprint", c_fprint, f_fprint, 0 },
+ { "-fprint0", c_fprint, f_fprint0, 0 },
// -fprintf
#if HAVE_STRUCT_STATFS_F_FSTYPENAME
{ "-fstype", c_fstype, f_fstype, 0 },
@@ -148,7 +148,7 @@ static OPTION const options[] = {
{ "-perm", c_perm, f_perm, 0 },
{ "-print", c_print, f_print, 0 },
{ "-print0", c_print, f_print0, 0 },
-// -printf
+ { "-printf", c_printf, f_printf, 0 },
{ "-prune", c_simple, f_prune, 0 },
{ "-quit", c_simple, f_quit, 0 },
{ "-readable", c_simple, f_readable, 0 },
diff --git a/usr.bin/find/printf.c b/usr.bin/find/printf.c
new file mode 100644
index 000000000000..671d1d1dbb9a
--- /dev/null
+++ b/usr.bin/find/printf.c
@@ -0,0 +1,307 @@
+/*-
+ * Copyright (c) 2023, Netflix, Inc
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <sys/types.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <err.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
+#include <time.h>
+
+#include "find.h"
+
+/* translate \X to proper escape, or to itself if no special meaning */
+static const char *esc = "\a\bcde\fghijklm\nopq\rs\tu\v";
+
+static inline bool
+isoct(char c)
+{
+ return (c >= '0' && c <= '7');
+}
+
+static inline bool
+isesc(char c)
+{
+ return (c >= 'a' && c <= 'v' && esc[c - 'a'] != c);
+}
+
+static const char *
+escape(const char *str, bool *flush, bool *warned)
+{
+ char c;
+ int value;
+ char *tmpstr;
+ size_t tmplen;
+ FILE *fp;
+
+ fp = open_memstream(&tmpstr, &tmplen);
+
+ /*
+ * Copy the str string into a new struct sbuf and return that expanding
+ * the different ANSI escape sequences.
+ */
+ *flush = false;
+ for (c = *str++; c; c = *str++) {
+ if (c != '\\') {
+ putc(c, fp);
+ continue;
+ }
+ c = *str++;
+
+ /*
+ * User error \ at end of string
+ */
+ if (c == '\0') {
+ putc('\\', fp);
+ break;
+ }
+
+ /*
+ * \c terminates output now and is supposed to flush the output
+ * too...
+ */
+ if (c == 'c') {
+ *flush = true;
+ break;
+ }
+
+ /*
+ * Is it octal? If so, decode up to 3 octal characters.
+ */
+ if (isoct(c)) {
+ value = 0;
+ for (int i = 3; i-- > 0 && isoct(c);
+ c = *str++) {
+ value <<= 3;
+ value += c - '0';
+ }
+ str--;
+ putc((char)value, fp);
+ continue;
+ }
+
+ /*
+ * It's an ANSI X3.159-1989 escape, use the mini-escape lookup
+ * table to translate.
+ */
+ if (isesc(c)) {
+ putc(esc[c - 'a'], fp);
+ continue;
+ }
+
+ /*
+ * Otherwise, it's self inserting. gnu find specifically says
+ * not to rely on this behavior though. gnu find will issue
+ * a warning here, while printf(1) won't.
+ */
+ if (!*warned) {
+ warn("Unknown character %c after \\.", c);
+ *warned = true;
+ }
+ putc(c, fp);
+ }
+ fclose(fp);
+
+ return (tmpstr);
+}
+
+static void
+fp_ctime(FILE *fp, time_t t)
+{
+ char s[26];
+
+ ctime_r(&t, s);
+ s[24] = '\0'; /* kill newline, though gnu find info silent on issue */
+ fputs(s, fp);
+}
+
+/*
+ * Assumes all times are displayed in UTC rather than local time, gnu find info
+ * page silent on the issue.
+ *
+ * Also assumes that gnu find doesn't support multiple character escape sequences,
+ * which it's info page is also silent on.
+ */
+static void
+fp_strftime(FILE *fp, time_t t, char mod)
+{
+ struct tm tm;
+ char buffer[128];
+ char fmt[3] = "% ";
+
+ /*
+ * Gnu libc extension we don't yet support -- seconds since epoch
+ * Used in Linux kernel build, so we kinda have to support it here
+ */
+ if (mod == '@') {
+ fprintf(fp, "%ju", (uintmax_t)t);
+ return;
+ }
+
+ gmtime_r(&t, &tm);
+ fmt[1] = mod;
+ printf("fmt is '%s'\n", fmt);
+ if (strftime(buffer, sizeof(buffer), fmt, &tm) == 0)
+ errx(1, "Format bad or data too long for buffer"); /* Can't really happen ??? */
+ fputs(buffer, fp);
+}
+
+void
+do_printf(PLAN *plan, FTSENT *entry, FILE *fout)
+{
+ const char *fmt, *path, *pend, *all;
+ char c;
+ FILE *fp;
+ bool flush, warned;
+ struct stat *sb;
+ char *tmp;
+ size_t tmplen;
+
+ fp = open_memstream(&tmp, &tmplen);
+ warned = (plan->flags & F_HAS_WARNED) != 0;
+ all = fmt = escape(plan->c_data, &flush, &warned);
+ if (warned)
+ plan->flags |= F_HAS_WARNED;
+ sb = entry->fts_statp;
+ for (c = *fmt++; c; c = *fmt++) {
+ if (c != '%') {
+ putc(c, fp);
+ continue;
+ }
+ c = *fmt++;
+ /* Style(9) deviation: case order same as gnu find info doc */
+ switch (c) {
+ case '%':
+ putc(c, fp);
+ break;
+ case 'p': /* Path to file */
+ fputs(entry->fts_path, fp);
+ break;
+ case 'f': /* filename w/o dirs */
+ fputs(entry->fts_name, fp);
+ break;
+ case 'h':
+ /*
+ * path, relative to the starting point, of the file, or
+ * '.' if that's empty for some reason.
+ */
+ path = entry->fts_path;
+ pend = strrchr(path, '/');
+ if (pend == NULL)
+ putc('.', fp);
+ else {
+ char *t = malloc(pend - path + 1);
+ memcpy(t, path, pend - path);
+ t[pend - path] = '\0';
+ fputs(t, fp);
+ free(t);
+ }
+ break;
+ case 'P': /* file with command line arg rm'd -- HOW? fts_parent? */
+ errx(1, "%%%c is unimplemented", c);
+ case 'H': /* Command line arg -- HOW? */
+ errx(1, "%%%c is unimplemented", c);
+ case 'g': /* gid human readable */
+ fputs(group_from_gid(sb->st_gid, 0), fp);
+ break;
+ case 'G': /* gid numeric */
+ fprintf(fp, "%d", sb->st_gid);
+ break;
+ case 'u': /* uid human readable */
+ fputs(user_from_uid(sb->st_uid, 0), fp);
+ break;
+ case 'U': /* uid numeric */
+ fprintf(fp, "%d", sb->st_uid);
+ break;
+ case 'm': /* mode in octal */
+ fprintf(fp, "%o", sb->st_mode & 07777);
+ break;
+ case 'M': { /* Mode in ls-standard form */
+ char mode[12];
+ strmode(sb->st_mode, mode);
+ fputs(mode, fp);
+ break;
+ }
+ case 'k': /* kbytes used by file */
+ fprintf(fp, "%jd", (intmax_t)sb->st_blocks / 2);
+ break;
+ case 'b': /* blocks used by file */
+ fprintf(fp, "%jd", (intmax_t)sb->st_blocks);
+ break;
+ case 's': /* size in bytes of file */
+ fprintf(fp, "%ju", (uintmax_t)sb->st_size);
+ break;
+ case 'S': /* sparseness of file */
+ fprintf(fp, "%3.1f",
+ (float)sb->st_blocks * 512 / (float)sb->st_size);
+ break;
+ case 'd': /* Depth in tree */
+ fprintf(fp, "%ld", entry->fts_level);
+ break;
+ case 'D': /* device number */
+ fprintf(fp, "%ju", (uintmax_t)sb->st_dev);
+ break;
+ case 'F': /* Filesystem type */
+ errx(1, "%%%c is unimplemented", c);
+ case 'l': /* object of symbolic link */
+ fprintf(fp, "%s", entry->fts_accpath);
+ break;
+ case 'i': /* inode # */
+ fprintf(fp, "%ju", (uintmax_t)sb->st_ino);
+ break;
+ case 'n': /* number of hard links */
+ fprintf(fp, "%ju", (uintmax_t)sb->st_nlink);
+ break;
+ case 'y': /* -type of file, incl 'l' */
+ errx(1, "%%%c is unimplemented", c);
+ case 'Y': /* -type of file, following 'l' types L loop ? error */
+ errx(1, "%%%c is unimplemented", c);
+ case 'a': /* access time ctime */
+ fp_ctime(fp, sb->st_atime);
+ break;
+ case 'A': /* access time with next char strftime format */
+ fp_strftime(fp, sb->st_atime, *fmt++);
+ break;
+ case 'B': /* birth time with next char strftime format */
+#ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
+ if (sb->st_birthtime != 0)
+ fp_strftime(fp, sb->st_birthtime, *fmt);
+#endif
+ fmt++;
+ break; /* blank on systems that don't support it */
+ case 'c': /* status change time ctime */
+ fp_ctime(fp, sb->st_ctime);
+ break;
+ case 'C': /* status change time with next char strftime format */
+ fp_strftime(fp, sb->st_ctime, *fmt++);
+ break;
+ case 't': /* modification change time ctime */
+ fp_ctime(fp, sb->st_mtime);
+ break;
+ case 'T': /* modification time with next char strftime format */
+ fp_strftime(fp, sb->st_mtime, *fmt++);
+ break;
+ case 'Z': /* empty string for compat SELinux context string */
+ break;
+ /* Modifier parsing here, but also need to modify above somehow */
+ case '#': case '-': case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9': case '.':
+ errx(1, "Format modifier %c not yet supported: '%s'", c, all);
+ /* Any FeeeBSD-specific modifications here -- none yet */
+ default:
+ errx(1, "Unknown format %c '%s'", c, all);
+ }
+ }
+ fputs(tmp, fout);
+ if (flush)
+ fflush(fout);
+ free(__DECONST(char *, fmt));
+ free(tmp);
+}
diff --git a/usr.bin/fstat/Makefile b/usr.bin/fstat/Makefile
index fa51a92eb52f..f8617fd0c6a4 100644
--- a/usr.bin/fstat/Makefile
+++ b/usr.bin/fstat/Makefile
@@ -3,6 +3,6 @@ SRCS= fstat.c fuser.c main.c
LINKS= ${BINDIR}/fstat ${BINDIR}/fuser
LIBADD= procstat
-MAN1= fuser.1 fstat.1
+MAN= fuser.1 fstat.1
.include <bsd.prog.mk>
diff --git a/usr.bin/grep/Makefile b/usr.bin/grep/Makefile
index 2204758ece5a..c72b86656148 100644
--- a/usr.bin/grep/Makefile
+++ b/usr.bin/grep/Makefile
@@ -6,7 +6,7 @@
PACKAGE= runtime
PROG= grep
-MAN1= grep.1 zgrep.1
+MAN= grep.1 zgrep.1
SRCS= file.c grep.c queue.c util.c
diff --git a/usr.bin/man/man.sh b/usr.bin/man/man.sh
index ec20fc813bf4..18595042da5f 100755
--- a/usr.bin/man/man.sh
+++ b/usr.bin/man/man.sh
@@ -313,6 +313,8 @@ manpath_warnings() {
# redirected to another source file.
man_check_for_so() {
local IFS line tstr
+ local counter_so=0
+ local counter_so_limit=32
unset IFS
if [ -n "$catpage" ]; then
@@ -320,13 +322,16 @@ man_check_for_so() {
fi
# We need to loop to accommodate multiple .so directives.
- while true
+ while [ $counter_so -lt $counter_so_limit ]
do
+ counter_so=$((counter_so + 1))
+
line=$($cattool "$manpage" 2>/dev/null | grep -E -m1 -v '^\.\\"[ ]*|^[ ]*$')
case "$line" in
'.so /'*) break ;; # ignore absolute path
'.so '*) trim "${line#.so}"
- decho "$manpage includes $tstr"
+ decho "$manpage includes $tstri level=$counter_so"
+
# Glob and check for the file.
if ! check_man "$1/$tstr" ""; then
decho " Unable to find $tstr"
@@ -337,6 +342,10 @@ man_check_for_so() {
esac
done
+ if [ $counter_so -ge $counter_so_limit ]; then
+ decho ".so include limit of $counter_so_limit reached, stop"
+ fi
+
return 0
}
diff --git a/usr.bin/pom/pom.6 b/usr.bin/pom/pom.6
index a3dc68b0a46b..a4dbdde2d4f5 100644
--- a/usr.bin/pom/pom.6
+++ b/usr.bin/pom/pom.6
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 14, 2010
+.Dd July 24, 2025
.Dt POM 6
.Os
.Sh NAME
@@ -60,4 +60,10 @@ but not
has been specified, it will calculate the phase of the moon on that
day at midnight.
.Sh SEE ALSO
-`Practical Astronomy with Your Calculator' by Duffett-Smith.
+.Rs
+.%A Peter Duffett-Smith
+.%B Practical Astronomy with Your Calculator
+.%I Cambridge University Press
+.%C Cambridge, UK
+.%D 1979
+.Re
diff --git a/usr.bin/pom/pom.c b/usr.bin/pom/pom.c
index db0033373b47..bcfbcadc8238 100644
--- a/usr.bin/pom/pom.c
+++ b/usr.bin/pom/pom.c
@@ -83,6 +83,7 @@ main(int argc, char **argv)
err(1, "unable to limit capabitilities for stdio");
caph_cache_catpages();
+ caph_cache_tzdata();
if (caph_enter() < 0)
err(1, "unable to enter capability mode");
diff --git a/usr.bin/sdiff/Makefile b/usr.bin/sdiff/Makefile
index 03587f373098..af9a037e9a58 100644
--- a/usr.bin/sdiff/Makefile
+++ b/usr.bin/sdiff/Makefile
@@ -3,7 +3,7 @@
PROG= sdiff
SRCS= edit.c sdiff.c
-MAN1= sdiff.1
+MAN= sdiff.1
HAS_TESTS=
SUBDIR.${MK_TESTS}+= tests
diff --git a/usr.bin/strings/Makefile b/usr.bin/strings/Makefile
index 8e2572810947..c01e775b0b89 100644
--- a/usr.bin/strings/Makefile
+++ b/usr.bin/strings/Makefile
@@ -1,5 +1,7 @@
.include <src.opts.mk>
+PACKAGE= toolchain
+
ELFTCDIR= ${SRCTOP}/contrib/elftoolchain
.PATH: ${ELFTCDIR}/strings
diff --git a/usr.bin/top/top.1 b/usr.bin/top/top.1
index 53b078839526..9b1860246de9 100644
--- a/usr.bin/top/top.1
+++ b/usr.bin/top/top.1
@@ -189,7 +189,7 @@ This option makes them visible.
Set the delay between screen updates to
.Ar time
seconds, which may be fractional.
-The default delay between updates is 1 second.
+The default delay between updates is 2 seconds.
.It Fl T
Toggle displaying thread ID (tid) instead of process id (pid).
.It Fl t
diff --git a/usr.bin/vtfontcvt/Makefile b/usr.bin/vtfontcvt/Makefile
index de011660ca28..13e60c406b26 100644
--- a/usr.bin/vtfontcvt/Makefile
+++ b/usr.bin/vtfontcvt/Makefile
@@ -1,6 +1,6 @@
PROG= vtfontcvt
SRCS= vtfontcvt.c lz4.c
-MAN8= vtfontcvt.8
+MAN= vtfontcvt.8
# lz4 compression functionality
.PATH: ${SRCTOP}/sys/cddl/contrib/opensolaris/common/lz4
diff --git a/usr.bin/xargs/tests/Makefile b/usr.bin/xargs/tests/Makefile
index b1e6782069de..9fa8ff11fac2 100644
--- a/usr.bin/xargs/tests/Makefile
+++ b/usr.bin/xargs/tests/Makefile
@@ -1,6 +1,6 @@
PACKAGE= tests
-TAP_TESTS_SH= legacy_test
+ATF_TESTS_SH= xargs_test
${PACKAGE}FILES+= regress.0.in
${PACKAGE}FILES+= regress.0.out
@@ -17,12 +17,11 @@ ${PACKAGE}FILES+= regress.R-1.out
${PACKAGE}FILES+= regress.in
${PACKAGE}FILES+= regress.n1.out
${PACKAGE}FILES+= regress.n2.out
-${PACKAGE}FILES+= regress.n2147483647.out
+${PACKAGE}FILES+= regress.nargmax.out
${PACKAGE}FILES+= regress.n2P0.out
${PACKAGE}FILES+= regress.n3.out
${PACKAGE}FILES+= regress.normal.out
${PACKAGE}FILES+= regress.quotes.in
${PACKAGE}FILES+= regress.quotes.out
-${PACKAGE}FILES+= regress.sh
.include <bsd.test.mk>
diff --git a/usr.bin/xargs/tests/legacy_test.sh b/usr.bin/xargs/tests/legacy_test.sh
deleted file mode 100644
index 3c7842d07bf0..000000000000
--- a/usr.bin/xargs/tests/legacy_test.sh
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-
-SRCDIR="$(dirname "${0}")"; export SRCDIR
-
-m4 "${SRCDIR}/../regress.m4" "${SRCDIR}/regress.sh" | sh
diff --git a/usr.bin/xargs/tests/regress.n2147483647.out b/usr.bin/xargs/tests/regress.nargmax.out
index cc32a92a2199..cc32a92a2199 100644
--- a/usr.bin/xargs/tests/regress.n2147483647.out
+++ b/usr.bin/xargs/tests/regress.nargmax.out
diff --git a/usr.bin/xargs/tests/regress.sh b/usr.bin/xargs/tests/regress.sh
deleted file mode 100644
index 9b4839d2a8ec..000000000000
--- a/usr.bin/xargs/tests/regress.sh
+++ /dev/null
@@ -1,32 +0,0 @@
-
-echo 1..21
-
-REGRESSION_START($1)
-
-REGRESSION_TEST(`normal', `xargs echo The <${SRCDIR}/regress.in')
-REGRESSION_TEST(`I', `xargs -I% echo The % % % %% % % <${SRCDIR}/regress.in')
-REGRESSION_TEST(`J', `xargs -J% echo The % again. <${SRCDIR}/regress.in')
-REGRESSION_TEST(`L', `xargs -L3 echo <${SRCDIR}/regress.in')
-REGRESSION_TEST(`P1', `xargs -P1 echo <${SRCDIR}/regress.in')
-REGRESSION_TEST(`R', `xargs -I% -R1 echo The % % % %% % % <${SRCDIR}/regress.in')
-REGRESSION_TEST(`R-1', `xargs -I% -R-1 echo The % % % %% % % <${SRCDIR}/regress.in')
-REGRESSION_TEST(`n1', `xargs -n1 echo <${SRCDIR}/regress.in')
-REGRESSION_TEST(`n2', `xargs -n2 echo <${SRCDIR}/regress.in')
-# This test may consume a large amount of memory, making it unsuited to CI
-# environments. Disable it for now.
-#REGRESSION_TEST(`n2147483647', `xargs -n2147483647 <${SRCDIR}/regress.in')
-REGRESSION_TEST(`n2P0',`xargs -n2 -P0 echo <${SRCDIR}/regress.in | sort')
-REGRESSION_TEST(`n3', `xargs -n3 echo <${SRCDIR}/regress.in')
-REGRESSION_TEST(`0', `xargs -0 -n1 echo <${SRCDIR}/regress.0.in')
-REGRESSION_TEST(`0I', `xargs -0 -I% echo The % %% % <${SRCDIR}/regress.0.in')
-REGRESSION_TEST(`0J', `xargs -0 -J% echo The % again. <${SRCDIR}/regress.0.in')
-REGRESSION_TEST(`0L', `xargs -0 -L2 echo <${SRCDIR}/regress.0.in')
-REGRESSION_TEST(`0P1', `xargs -0 -P1 echo <${SRCDIR}/regress.0.in')
-REGRESSION_TEST(`quotes', `xargs -n1 echo <${SRCDIR}/regress.quotes.in')
-
-REGRESSION_TEST_FREEFORM(`parallel1', `echo /var/empty /var/empty | xargs -n1 -P2 test -d; [ $? = 0 ]')
-REGRESSION_TEST_FREEFORM(`parallel2', `echo /var/empty /var/empty/nodir | xargs -n1 -P2 test -d; [ $? = 1 ]')
-REGRESSION_TEST_FREEFORM(`parallel3', `echo /var/empty/nodir /var/empty | xargs -n1 -P2 test -d; [ $? = 1 ]')
-REGRESSION_TEST_FREEFORM(`parallel4', `echo /var/empty/nodir /var/empty/nodir | xargs -n1 -P2 test -d; [ $? = 1 ]')
-
-REGRESSION_END()
diff --git a/usr.bin/xargs/tests/xargs_test.sh b/usr.bin/xargs/tests/xargs_test.sh
new file mode 100755
index 000000000000..12c9407a7e45
--- /dev/null
+++ b/usr.bin/xargs/tests/xargs_test.sh
@@ -0,0 +1,193 @@
+#
+# Copyright (c) 2002 Juli Mallett <jmallett@FreeBSD.org>
+# Copyright (c) 2025 Dag-Erling Smørgrav <des@FreeBSD.org>
+#
+# SPDX-License-Identifier: BSD-2-Clause
+#
+
+SRCDIR=$(atf_get_srcdir)
+
+atf_test_case xargs_normal
+xargs_normal_body()
+{
+ atf_check -o file:${SRCDIR}/regress.normal.out \
+ xargs echo The <${SRCDIR}/regress.in
+}
+
+atf_test_case xargs_I
+xargs_I_body()
+{
+ atf_check -o file:${SRCDIR}/regress.I.out \
+ xargs -I% echo The % % % %% % % <${SRCDIR}/regress.in
+}
+
+atf_test_case xargs_J
+xargs_J_body()
+{
+ atf_check -o file:${SRCDIR}/regress.J.out \
+ xargs -J% echo The % again. <${SRCDIR}/regress.in
+}
+
+atf_test_case xargs_L
+xargs_L_body()
+{
+ atf_check -o file:${SRCDIR}/regress.L.out \
+ xargs -L3 echo <${SRCDIR}/regress.in
+}
+
+atf_test_case xargs_P1
+xargs_P1_body()
+{
+ atf_check -o file:${SRCDIR}/regress.P1.out \
+ xargs -P1 echo <${SRCDIR}/regress.in
+}
+
+atf_test_case xargs_R
+xargs_R_body()
+{
+ atf_check -o file:${SRCDIR}/regress.R.out \
+ xargs -I% -R1 echo The % % % %% % % <${SRCDIR}/regress.in
+}
+
+atf_test_case xargs_R_1
+xargs_R_1_body()
+{
+ atf_check -o file:${SRCDIR}/regress.R-1.out \
+ xargs -I% -R-1 echo The % % % %% % % <${SRCDIR}/regress.in
+}
+
+atf_test_case xargs_n1
+xargs_n1_body()
+{
+ atf_check -o file:${SRCDIR}/regress.n1.out \
+ xargs -n1 echo <${SRCDIR}/regress.in
+}
+
+atf_test_case xargs_n2
+xargs_n2_body()
+{
+ atf_check -o file:${SRCDIR}/regress.n2.out \
+ xargs -n2 echo <${SRCDIR}/regress.in
+}
+
+atf_test_case xargs_nargmax
+xargs_nargmax_body()
+{
+ argmax=$(sysctl -n kern.argmax)
+ atf_check -o file:${SRCDIR}/regress.nargmax.out \
+ xargs -n$((argmax)) <${SRCDIR}/regress.in
+ atf_check -s exit:1 -e match:"too large" \
+ xargs -n$((argmax+1)) <${SRCDIR}/regress.in
+}
+
+atf_test_case xargs_n2P0
+xargs_n2P0_body()
+{
+ atf_check -o save:regress.out \
+ xargs -n2 -P0 echo <${SRCDIR}/regress.in
+ atf_check -o file:${SRCDIR}/regress.n2P0.out \
+ sort regress.out
+}
+
+atf_test_case xargs_n3
+xargs_n3_body()
+{
+ atf_check -o file:${SRCDIR}/regress.n3.out \
+ xargs -n3 echo <${SRCDIR}/regress.in
+}
+
+atf_test_case xargs_0
+xargs_0_body()
+{
+ atf_check -o file:${SRCDIR}/regress.0.out \
+ xargs -0 -n1 echo <${SRCDIR}/regress.0.in
+}
+
+atf_test_case xargs_0I
+xargs_0I_body()
+{
+ atf_check -o file:${SRCDIR}/regress.0I.out \
+ xargs -0 -I% echo The % %% % <${SRCDIR}/regress.0.in
+}
+
+atf_test_case xargs_0J
+xargs_0J_body()
+{
+ atf_check -o file:${SRCDIR}/regress.0J.out \
+ xargs -0 -J% echo The % again. <${SRCDIR}/regress.0.in
+}
+
+atf_test_case xargs_0L
+xargs_0L_body()
+{
+ atf_check -o file:${SRCDIR}/regress.0L.out \
+ xargs -0 -L2 echo <${SRCDIR}/regress.0.in
+}
+
+atf_test_case xargs_0P1
+xargs_0P1_body()
+{
+ atf_check -o file:${SRCDIR}/regress.0P1.out \
+ xargs -0 -P1 echo <${SRCDIR}/regress.0.in
+}
+
+atf_test_case xargs_quotes
+xargs_quotes_body()
+{
+ atf_check -o file:${SRCDIR}/regress.quotes.out \
+ xargs -n1 echo <${SRCDIR}/regress.quotes.in
+}
+
+atf_test_case xargs_parallel1
+xargs_parallel1_body()
+{
+ echo /var/empty /var/empty >input
+ atf_check xargs -n1 -P2 test -d <input
+}
+
+atf_test_case xargs_parallel2
+xargs_parallel2_body()
+{
+ echo /var/empty /var/empty/nodir >input
+ atf_check -s exit:1 xargs -n1 -P2 test -d <input
+}
+
+atf_test_case xargs_parallel3
+xargs_parallel3_body()
+{
+ echo /var/empty/nodir /var/empty >input
+ atf_check -s exit:1 xargs -n1 -P2 test -d <input
+}
+
+atf_test_case xargs_parallel4
+xargs_parallel4_body()
+{
+ echo /var/empty/nodir /var/empty/nodir >input
+ atf_check -s exit:1 xargs -n1 -P2 test -d <input
+}
+
+atf_init_test_cases()
+{
+ atf_add_test_case xargs_normal
+ atf_add_test_case xargs_I
+ atf_add_test_case xargs_J
+ atf_add_test_case xargs_L
+ atf_add_test_case xargs_P1
+ atf_add_test_case xargs_R
+ atf_add_test_case xargs_R_1
+ atf_add_test_case xargs_n1
+ atf_add_test_case xargs_n2
+ atf_add_test_case xargs_nargmax
+ atf_add_test_case xargs_n2P0
+ atf_add_test_case xargs_n3
+ atf_add_test_case xargs_0
+ atf_add_test_case xargs_0I
+ atf_add_test_case xargs_0J
+ atf_add_test_case xargs_0L
+ atf_add_test_case xargs_0P1
+ atf_add_test_case xargs_quotes
+ atf_add_test_case xargs_parallel1
+ atf_add_test_case xargs_parallel2
+ atf_add_test_case xargs_parallel3
+ atf_add_test_case xargs_parallel4
+}
diff --git a/usr.bin/xargs/xargs.c b/usr.bin/xargs/xargs.c
index 237beff26504..2a7f026e5066 100644
--- a/usr.bin/xargs/xargs.c
+++ b/usr.bin/xargs/xargs.c
@@ -166,7 +166,7 @@ main(int argc, char *argv[])
break;
case 'n':
nflag = 1;
- nargs = (int)strtonum(optarg, 1, INT_MAX, &errstr);
+ nargs = (int)strtonum(optarg, 1, arg_max, &errstr);
if (errstr)
errx(1, "-%c %s: %s", ch, optarg, errstr);
break;
diff --git a/usr.sbin/bhyve/acpi.c b/usr.sbin/bhyve/acpi.c
index 85864da57af2..6ff8dd8e273b 100644
--- a/usr.sbin/bhyve/acpi.c
+++ b/usr.sbin/bhyve/acpi.c
@@ -37,9 +37,12 @@
*/
#include <sys/param.h>
+#include <sys/cpuset.h>
+#include <sys/domainset.h>
#include <sys/endian.h>
#include <sys/errno.h>
#include <sys/stat.h>
+#include <sys/tree.h>
#include <err.h>
#include <paths.h>
@@ -50,7 +53,9 @@
#include <string.h>
#include <unistd.h>
+#include <dev/vmm/vmm_mem.h>
#include <machine/vmm.h>
+#include <machine/vmm_dev.h>
#include <vmmapi.h>
#include "bhyverun.h"
@@ -79,6 +84,22 @@ static char basl_template[MAXPATHLEN];
static char basl_stemplate[MAXPATHLEN];
/*
+ * SRAT vCPU affinity info.
+ */
+struct acpi_vcpu_affinity_entry {
+ RB_ENTRY(acpi_vcpu_affinity_entry) entry;
+ int vcpuid;
+ int domain;
+};
+
+static int vcpu_affinity_cmp(struct acpi_vcpu_affinity_entry *const a1,
+ struct acpi_vcpu_affinity_entry *const a2);
+static RB_HEAD(vcpu_affinities,
+ acpi_vcpu_affinity_entry) aff_head = RB_INITIALIZER(&aff_head);
+RB_GENERATE_STATIC(vcpu_affinities, acpi_vcpu_affinity_entry, entry,
+ vcpu_affinity_cmp);
+
+/*
* State for dsdt_line(), dsdt_indent(), and dsdt_unindent().
*/
static FILE *dsdt_fp;
@@ -121,6 +142,31 @@ acpi_tables_add_device(const struct acpi_device *const dev)
return (0);
}
+static int
+vcpu_affinity_cmp(struct acpi_vcpu_affinity_entry *a1,
+ struct acpi_vcpu_affinity_entry *a2)
+{
+ return (a1->vcpuid < a2->vcpuid ? -1 : a1->vcpuid > a2->vcpuid);
+}
+
+int
+acpi_add_vcpu_affinity(int vcpuid, int domain)
+{
+ struct acpi_vcpu_affinity_entry *entry = calloc(1, sizeof(*entry));
+ if (entry == NULL) {
+ return (ENOMEM);
+ }
+
+ entry->vcpuid = vcpuid;
+ entry->domain = domain;
+ if (RB_INSERT(vcpu_affinities, &aff_head, entry) != NULL) {
+ free(entry);
+ return (EEXIST);
+ }
+
+ return (0);
+}
+
/*
* Helper routines for writing to the DSDT from other modules.
*/
@@ -726,6 +772,83 @@ build_spcr(struct vmctx *const ctx)
return (0);
}
+static int
+build_srat(struct vmctx *const ctx)
+{
+ ACPI_TABLE_SRAT srat;
+ ACPI_SRAT_MEM_AFFINITY srat_mem_affinity;
+ ACPI_SRAT_CPU_AFFINITY srat_cpu_affinity;
+
+ struct acpi_vcpu_affinity_entry *ep;
+ struct basl_table *table;
+ int segid, domain;
+ int _flags, _prot;
+ vm_ooffset_t _off;
+ size_t maplen;
+ uint64_t gpa;
+ int ret;
+
+ if (RB_EMPTY(&aff_head))
+ return (0);
+
+ memset(&srat, 0, sizeof(srat));
+ BASL_EXEC(basl_table_create(&table, ctx, ACPI_SIG_SRAT,
+ BASL_TABLE_ALIGNMENT));
+ BASL_EXEC(basl_table_append_header(table, ACPI_SIG_SRAT, 1, 1));
+ srat.TableRevision = 1;
+ BASL_EXEC(basl_table_append_content(table, &srat, sizeof(srat)));
+
+ /*
+ * Iterate over the VM's memory maps and add
+ * a 'Memory Affinity Structure' for each mapping.
+ */
+ gpa = 0;
+ while (1) {
+ ret = vm_mmap_getnext(ctx, &gpa, &segid, &_off, &maplen, &_prot,
+ &_flags);
+ if (ret) {
+ break;
+ }
+
+ if (segid >= VM_SYSMEM && segid < VM_BOOTROM) {
+ domain = segid - VM_SYSMEM;
+ } else {
+ /* Treat devmem segs as domain 0. */
+ domain = 0;
+ }
+ memset(&srat_mem_affinity, 0, sizeof(srat_mem_affinity));
+ srat_mem_affinity.Header.Type = ACPI_SRAT_TYPE_MEMORY_AFFINITY;
+ srat_mem_affinity.Header.Length = sizeof(srat_mem_affinity);
+ srat_mem_affinity.Flags |= ACPI_SRAT_MEM_ENABLED;
+ srat_mem_affinity.ProximityDomain = htole32(domain);
+ srat_mem_affinity.BaseAddress = htole64(gpa);
+ srat_mem_affinity.Length = htole64(maplen);
+ srat_mem_affinity.Flags = htole32(ACPI_SRAT_MEM_ENABLED);
+ BASL_EXEC(basl_table_append_bytes(table, &srat_mem_affinity,
+ sizeof(srat_mem_affinity)));
+ gpa += maplen;
+ }
+
+ /*
+ * Iterate over each "vCPUid to domain id" mapping and emit a
+ * 'Processor Local APIC/SAPIC Affinity Structure' for each entry.
+ */
+ RB_FOREACH(ep, vcpu_affinities, &aff_head) {
+ memset(&srat_cpu_affinity, 0, sizeof(srat_cpu_affinity));
+ srat_cpu_affinity.Header.Type = ACPI_SRAT_TYPE_CPU_AFFINITY;
+ srat_cpu_affinity.Header.Length = sizeof(srat_cpu_affinity);
+ srat_cpu_affinity.ProximityDomainLo = (uint8_t)ep->domain;
+ srat_cpu_affinity.ApicId = (uint8_t)ep->vcpuid;
+ srat_cpu_affinity.Flags = htole32(ACPI_SRAT_CPU_USE_AFFINITY);
+ BASL_EXEC(basl_table_append_bytes(table, &srat_cpu_affinity,
+ sizeof(srat_cpu_affinity)));
+ }
+
+ BASL_EXEC(basl_table_register_to_rsdt(table));
+
+ return (0);
+}
+
int
acpi_build(struct vmctx *ctx, int ncpu)
{
@@ -765,6 +888,7 @@ acpi_build(struct vmctx *ctx, int ncpu)
BASL_EXEC(build_mcfg(ctx));
BASL_EXEC(build_facs(ctx));
BASL_EXEC(build_spcr(ctx));
+ BASL_EXEC(build_srat(ctx));
/* Build ACPI device-specific tables such as a TPM2 table. */
const struct acpi_device_list_entry *entry;
diff --git a/usr.sbin/bhyve/acpi.h b/usr.sbin/bhyve/acpi.h
index 4b557993d67f..f4d24d63800e 100644
--- a/usr.sbin/bhyve/acpi.h
+++ b/usr.sbin/bhyve/acpi.h
@@ -56,7 +56,8 @@ struct vmctx;
int acpi_build(struct vmctx *ctx, int ncpu);
void acpi_raise_gpe(struct vmctx *ctx, unsigned bit);
int acpi_tables_add_device(const struct acpi_device *const dev);
-void dsdt_line(const char *fmt, ...);
+int acpi_add_vcpu_affinity(int vcpuid, int domain);
+void dsdt_line(const char *fmt, ...) __printflike(1, 2);
void dsdt_fixed_ioport(uint16_t iobase, uint16_t length);
void dsdt_fixed_irq(uint8_t irq);
void dsdt_fixed_mem32(uint32_t base, uint32_t length);
diff --git a/usr.sbin/bhyve/amd64/bhyverun_machdep.c b/usr.sbin/bhyve/amd64/bhyverun_machdep.c
index 85af124b5536..dad8f1e52e4e 100644
--- a/usr.sbin/bhyve/amd64/bhyverun_machdep.c
+++ b/usr.sbin/bhyve/amd64/bhyverun_machdep.c
@@ -91,6 +91,7 @@ bhyve_usage(int code)
" -K: PS2 keyboard layout\n"
" -l: LPC device configuration\n"
" -m: memory size\n"
+ " -n: NUMA domain specification\n"
" -o: set config 'var' to 'value'\n"
" -P: vmexit from the guest on pause\n"
" -p: pin 'vcpu' to 'hostcpu'\n"
@@ -117,9 +118,9 @@ bhyve_optparse(int argc, char **argv)
int c;
#ifdef BHYVE_SNAPSHOT
- optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:r:";
+ optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:n:l:K:U:r:";
#else
- optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:l:K:U:";
+ optstr = "aehuwxACDHIPSWYk:f:o:p:G:c:s:m:n:l:K:U:";
#endif
while ((c = getopt(argc, argv, optstr)) != -1) {
switch (c) {
@@ -194,6 +195,15 @@ bhyve_optparse(int argc, char **argv)
case 'm':
set_config_value("memory.size", optarg);
break;
+ case 'n':
+ if (bhyve_numa_parse(optarg) != 0)
+ errx(EX_USAGE,
+ "invalid NUMA configuration "
+ "'%s'",
+ optarg);
+ if (!get_config_bool("acpi_tables"))
+ errx(EX_USAGE, "NUMA emulation requires ACPI");
+ break;
case 'o':
if (!bhyve_parse_config_option(optarg)) {
errx(EX_USAGE,
diff --git a/usr.sbin/bhyve/amd64/xmsr.c b/usr.sbin/bhyve/amd64/xmsr.c
index cd80e4ef782e..7c174728f4fa 100644
--- a/usr.sbin/bhyve/amd64/xmsr.c
+++ b/usr.sbin/bhyve/amd64/xmsr.c
@@ -204,6 +204,15 @@ emulate_rdmsr(struct vcpu *vcpu __unused, uint32_t num, uint64_t *val)
*val = 1;
break;
+ case MSR_VM_CR:
+ /*
+ * We currently don't support nested virt.
+ * Windows seems to ignore the cpuid bits and reads this
+ * MSR anyways.
+ */
+ *val = VM_CR_SVMDIS;
+ break;
+
default:
error = -1;
break;
diff --git a/usr.sbin/bhyve/bhyve.8 b/usr.sbin/bhyve/bhyve.8
index 62e567fd359d..89c0b23961a8 100644
--- a/usr.sbin/bhyve/bhyve.8
+++ b/usr.sbin/bhyve/bhyve.8
@@ -269,8 +269,56 @@ or
(either upper or lower case)
to indicate a multiple of kilobytes, megabytes, gigabytes, or terabytes.
If no suffix is given, the value is assumed to be in megabytes.
-.Pp
The default is 256M.
+.Pp
+.It Fl n Ar id Ns Cm \&, Ns Ar size Ns Cm \&, Ns Ar cpus Ns Op Cm \&, Ns Ar domain_policy
+Configure guest NUMA domains.
+This option applies only to the amd64 platform.
+.Pp
+The
+.Fl n
+option allows the guest physical address space to be partitioned into domains.
+The layout of each domain is encoded in an ACPI table
+visible to the guest operating system.
+The
+.Fl n
+option also allows the specification of a
+.Xr domainset 9
+memory allocation policy for the host memory backing a given NUMA domain.
+A guest can have up to 8 NUMA domains.
+This feature requires that the guest use a boot ROM, and in
+particular cannot be used if the guest was initialized using
+.Xr bhyveload 8 .
+.Pp
+Each domain is identified by a numerical
+.Em id .
+The domain memory
+.Em size
+is specified using the same format as the
+.Fl m
+flag.
+The sum of all
+.Em size
+parameters overrides the total VM memory size specified by the
+.Fl m
+flag.
+However, if at least one domain memory size parameter is
+missing, the total VM memory size will be equally distributed across
+all emulated domains.
+The
+.Em cpuset
+parameter specifies the set of CPUs that are part of the domain.
+The
+.Em domain_policy
+parameter may be optionally used to configure the
+.Xr domainset 9
+host NUMA memory allocation policy for an emulated
+domain.
+See the
+.Ar -n
+flag in
+.Xr cpuset 1
+for a list of valid NUMA memory allocation policies and their formats.
.It Fl o Ar var Ns Cm = Ns Ar value
Set the configuration variable
.Ar var
@@ -1202,6 +1250,33 @@ using this configuration file, use flag
.Bd -literal -offset indent
/usr/sbin/bhyve -k configfile vm0
.Ed
+.Pp
+Run a UEFI virtual machine with four CPUs and two emulated NUMA domains:
+.Bd -literal -offset indent
+bhyve -c 4 -w -H \\
+ -s 0,hostbridge \\
+ -s 4,ahci-hd,disk.img \\
+ -s 31,lpc -l com1,stdio \\
+ -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \\
+ -n id=0,size=4G,cpus=0-1 \\
+ -n id=1,size=4G,cpus=2-3 \\
+ numavm
+.Ed
+.Pp
+Assuming a host machine with two NUMA domains,
+run a UEFI virtual machine with four CPUs using a
+.Ar prefer
+.Xr domainset 9
+policy to allocate guest memory from the first host NUMA domain only.
+.Bd -literal -offset indent
+bhyve -c 2 -w -H \\
+ -s 0,hostbridge \\
+ -s 4,ahci-hd,disk.img \\
+ -s 31,lpc -l com1,stdio \\
+ -l bootrom,/usr/local/share/uefi-firmware/BHYVE_UEFI.fd \\
+ -n id=0,size=4G,cpus=0-1,domain_policy=prefer:0 \\
+ numavm
+.Ed
.Sh SEE ALSO
.Xr bhyve 4 ,
.Xr netgraph 4 ,
@@ -1211,7 +1286,8 @@ using this configuration file, use flag
.Xr bhyve_config 5 ,
.Xr ethers 5 ,
.Xr bhyvectl 8 ,
-.Xr bhyveload 8
+.Xr bhyveload 8 ,
+.Xr domainset 9
.Pp
.Rs
.%A Intel
diff --git a/usr.sbin/bhyve/bhyverun.c b/usr.sbin/bhyve/bhyverun.c
index be9cd1611700..9ead49582a7d 100644
--- a/usr.sbin/bhyve/bhyverun.c
+++ b/usr.sbin/bhyve/bhyverun.c
@@ -30,6 +30,8 @@
#ifndef WITHOUT_CAPSICUM
#include <sys/capsicum.h>
#endif
+#include <sys/cpuset.h>
+#include <sys/domainset.h>
#include <sys/mman.h>
#ifdef BHYVE_SNAPSHOT
#include <sys/socket.h>
@@ -54,6 +56,7 @@
#include <fcntl.h>
#endif
#include <libgen.h>
+#include <libutil.h>
#include <unistd.h>
#include <assert.h>
#include <pthread.h>
@@ -68,6 +71,7 @@
#include <libxo/xo.h>
#endif
+#include <dev/vmm/vmm_mem.h>
#include <vmmapi.h>
#include "acpi.h"
@@ -108,6 +112,9 @@ static const int BSP = 0;
static cpuset_t cpumask;
+static struct vm_mem_domain guest_domains[VM_MAXMEMDOM];
+static int guest_ndomains = 0;
+
static void vm_loop(struct vmctx *ctx, struct vcpu *vcpu);
static struct vcpu_info {
@@ -179,6 +186,118 @@ parse_int_value(const char *key, const char *value, int minval, int maxval)
return (lval);
}
+int
+bhyve_numa_parse(const char *opt)
+{
+ int id = -1;
+ nvlist_t *nvl;
+ char *cp, *str, *tofree;
+ char pathbuf[64] = { 0 };
+ char *size = NULL, *cpus = NULL, *domain_policy = NULL;
+
+ if (*opt == '\0') {
+ return (-1);
+ }
+
+ tofree = str = strdup(opt);
+ if (str == NULL)
+ errx(4, "Failed to allocate memory");
+
+ while ((cp = strsep(&str, ",")) != NULL) {
+ if (strncmp(cp, "id=", strlen("id=")) == 0)
+ id = parse_int_value("id", cp + strlen("id="), 0,
+ UINT8_MAX);
+ else if (strncmp(cp, "size=", strlen("size=")) == 0)
+ size = cp + strlen("size=");
+ else if (strncmp(cp,
+ "domain_policy=", strlen("domain_policy=")) == 0)
+ domain_policy = cp + strlen("domain_policy=");
+ else if (strncmp(cp, "cpus=", strlen("cpus=")) == 0)
+ cpus = cp + strlen("cpus=");
+ }
+
+ if (id == -1) {
+ EPRINTLN("Missing NUMA domain ID in '%s'", opt);
+ goto out;
+ }
+
+ snprintf(pathbuf, sizeof(pathbuf), "domains.%d", id);
+ nvl = find_config_node(pathbuf);
+ if (nvl == NULL)
+ nvl = create_config_node(pathbuf);
+ if (size != NULL)
+ set_config_value_node(nvl, "size", size);
+ if (domain_policy != NULL)
+ set_config_value_node(nvl, "domain_policy", domain_policy);
+ if (cpus != NULL)
+ set_config_value_node(nvl, "cpus", cpus);
+
+ free(tofree);
+ return (0);
+
+out:
+ free(tofree);
+ return (-1);
+}
+
+static void
+calc_mem_affinity(size_t vm_memsize)
+{
+ int i;
+ nvlist_t *nvl;
+ bool need_recalc;
+ const char *value;
+ struct vm_mem_domain *dom;
+ char pathbuf[64] = { 0 };
+
+ need_recalc = false;
+ for (i = 0; i < VM_MAXMEMDOM; i++) {
+ dom = &guest_domains[i];
+ snprintf(pathbuf, sizeof(pathbuf), "domains.%d", i);
+ nvl = find_config_node(pathbuf);
+ if (nvl == NULL) {
+ break;
+ }
+
+ value = get_config_value_node(nvl, "size");
+ need_recalc |= value == NULL;
+ if (value != NULL && vm_parse_memsize(value, &dom->size)) {
+ errx(EX_USAGE, "invalid memsize for domain %d: '%s'", i,
+ value);
+ }
+
+ dom->ds_mask = calloc(1, sizeof(domainset_t));
+ if (dom->ds_mask == NULL) {
+ errx(EX_OSERR, "Failed to allocate domainset mask");
+ }
+ dom->ds_size = sizeof(domainset_t);
+ value = get_config_value_node(nvl, "domain_policy");
+ if (value == NULL) {
+ dom->ds_policy = DOMAINSET_POLICY_INVALID;
+ DOMAINSET_ZERO(dom->ds_mask);
+ } else if (domainset_parselist(value, dom->ds_mask, &dom->ds_policy) !=
+ CPUSET_PARSE_OK) {
+ errx(EX_USAGE, "failed to parse domain policy '%s'", value);
+ }
+ }
+
+ guest_ndomains = i;
+ if (guest_ndomains == 0) {
+ /*
+ * No domains were specified - create domain
+ * 0 holding all CPUs and memory.
+ */
+ guest_ndomains = 1;
+ guest_domains[0].size = vm_memsize;
+ } else if (need_recalc) {
+ warnx("At least one domain memory size was not specified, distributing"
+ " total VM memory size across all domains");
+ for (i = 0; i < guest_ndomains; i++) {
+ guest_domains[i].size = vm_memsize / guest_ndomains;
+ }
+ }
+}
+
/*
* Set the sockets, cores, threads, and guest_cpus variables based on
* the configured topology.
@@ -340,6 +459,56 @@ build_vcpumaps(void)
}
}
+static void
+set_vcpu_affinities(void)
+{
+ int cpu, error;
+ nvlist_t *nvl = NULL;
+ cpuset_t cpus;
+ const char *value;
+ char pathbuf[64] = { 0 };
+
+ for (int dom = 0; dom < guest_ndomains; dom++) {
+ snprintf(pathbuf, sizeof(pathbuf), "domains.%d", dom);
+ nvl = find_config_node(pathbuf);
+ if (nvl == NULL)
+ break;
+
+ value = get_config_value_node(nvl, "cpus");
+ if (value == NULL) {
+ EPRINTLN("Missing CPU set for domain %d", dom);
+ exit(4);
+ }
+
+ parse_cpuset(dom, value, &cpus);
+ CPU_FOREACH_ISSET(cpu, &cpus) {
+ error = acpi_add_vcpu_affinity(cpu, dom);
+ if (error) {
+ EPRINTLN(
+ "Unable to set vCPU %d affinity for domain %d: %s",
+ cpu, dom, strerror(errno));
+ exit(4);
+ }
+ }
+ }
+ if (guest_ndomains > 1 || nvl != NULL)
+ return;
+
+ /*
+ * If we're dealing with one domain and no cpuset was provided, create a
+ * default one holding all cpus.
+ */
+ for (cpu = 0; cpu < guest_ncpus; cpu++) {
+ error = acpi_add_vcpu_affinity(cpu, 0);
+ if (error) {
+ EPRINTLN(
+ "Unable to set vCPU %d affinity for domain %d: %s",
+ cpu, 0, strerror(errno));
+ exit(4);
+ }
+ }
+}
+
void *
paddr_guest2host(struct vmctx *ctx, uintptr_t gaddr, size_t len)
{
@@ -713,18 +882,21 @@ main(int argc, char *argv[])
vcpu_info[vcpuid].vcpu = vm_vcpu_open(ctx, vcpuid);
}
+ calc_mem_affinity(memsize);
memflags = 0;
if (get_config_bool_default("memory.wired", false))
memflags |= VM_MEM_F_WIRED;
if (get_config_bool_default("memory.guest_in_core", false))
memflags |= VM_MEM_F_INCORE;
vm_set_memflags(ctx, memflags);
- error = vm_setup_memory(ctx, memsize, VM_MMAP_ALL);
+ error = vm_setup_memory_domains(ctx, VM_MMAP_ALL, guest_domains,
+ guest_ndomains);
if (error) {
fprintf(stderr, "Unable to setup memory (%d)\n", errno);
exit(4);
}
+ set_vcpu_affinities();
init_mem(guest_ncpus);
init_bootrom(ctx);
if (bhyve_init_platform(ctx, bsp) != 0)
diff --git a/usr.sbin/bhyve/bhyverun.h b/usr.sbin/bhyve/bhyverun.h
index 005de6dc5410..0a7bbd72a19c 100644
--- a/usr.sbin/bhyve/bhyverun.h
+++ b/usr.sbin/bhyve/bhyverun.h
@@ -73,6 +73,7 @@ void bhyve_parse_gdb_options(const char *opt);
#endif
int bhyve_pincpu_parse(const char *opt);
int bhyve_topology_parse(const char *opt);
+int bhyve_numa_parse(const char *opt);
void bhyve_init_vcpu(struct vcpu *vcpu);
void bhyve_start_vcpu(struct vcpu *vcpu, bool bsp);
diff --git a/usr.sbin/bhyve/bootrom.c b/usr.sbin/bhyve/bootrom.c
index e4adaca55947..339974cb2017 100644
--- a/usr.sbin/bhyve/bootrom.c
+++ b/usr.sbin/bhyve/bootrom.c
@@ -31,6 +31,7 @@
#include <sys/mman.h>
#include <sys/stat.h>
+#include <dev/vmm/vmm_mem.h>
#include <machine/vmm.h>
#include <err.h>
diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c
index 2f04a488d9c1..9d6060e3e254 100644
--- a/usr.sbin/bhyve/pci_emul.c
+++ b/usr.sbin/bhyve/pci_emul.c
@@ -42,6 +42,7 @@
#include <stdbool.h>
#include <sysexits.h>
+#include <dev/vmm/vmm_mem.h>
#include <machine/vmm.h>
#include <machine/vmm_snapshot.h>
#include <vmmapi.h>
diff --git a/usr.sbin/bhyve/pci_fbuf.c b/usr.sbin/bhyve/pci_fbuf.c
index 125428e0b772..1e3ec77c15b0 100644
--- a/usr.sbin/bhyve/pci_fbuf.c
+++ b/usr.sbin/bhyve/pci_fbuf.c
@@ -29,6 +29,7 @@
#include <sys/types.h>
#include <sys/mman.h>
+#include <dev/vmm/vmm_mem.h>
#include <machine/vmm.h>
#include <machine/vmm_snapshot.h>
#include <vmmapi.h>
diff --git a/usr.sbin/bhyve/pci_passthru.c b/usr.sbin/bhyve/pci_passthru.c
index 9d38ae9168a1..a82078f6e036 100644
--- a/usr.sbin/bhyve/pci_passthru.c
+++ b/usr.sbin/bhyve/pci_passthru.c
@@ -38,6 +38,7 @@
#include <dev/io/iodev.h>
#include <dev/pci/pcireg.h>
+#include <dev/vmm/vmm_mem.h>
#include <vm/vm.h>
diff --git a/usr.sbin/bhyve/pci_xhci.c b/usr.sbin/bhyve/pci_xhci.c
index 5b21361f2823..0871bbb87fe5 100644
--- a/usr.sbin/bhyve/pci_xhci.c
+++ b/usr.sbin/bhyve/pci_xhci.c
@@ -2588,7 +2588,7 @@ pci_xhci_reset_port(struct pci_xhci_softc *sc, int portn, int warm)
if (dev) {
port->portsc &= ~(XHCI_PS_PLS_MASK | XHCI_PS_PR | XHCI_PS_PRC);
port->portsc |= XHCI_PS_PED |
- XHCI_PS_SPEED_SET(dev->dev_ue->ue_usbspeed);
+ XHCI_PS_SPEED_SET(dev->hci.hci_speed);
if (warm && dev->dev_ue->ue_usbver == 3) {
port->portsc |= XHCI_PS_WRC;
@@ -2622,11 +2622,11 @@ pci_xhci_init_port(struct pci_xhci_softc *sc, int portn)
if (dev->dev_ue->ue_usbver == 2) {
port->portsc |= XHCI_PS_PLS_SET(UPS_PORT_LS_POLL) |
- XHCI_PS_SPEED_SET(dev->dev_ue->ue_usbspeed);
+ XHCI_PS_SPEED_SET(dev->hci.hci_speed);
} else {
port->portsc |= XHCI_PS_PLS_SET(UPS_PORT_LS_U0) |
- XHCI_PS_PED | /* enabled */
- XHCI_PS_SPEED_SET(dev->dev_ue->ue_usbspeed);
+ XHCI_PS_PED | /* enabled */
+ XHCI_PS_SPEED_SET(dev->hci.hci_speed);
}
DPRINTF(("Init port %d 0x%x", portn, port->portsc));
@@ -2833,6 +2833,7 @@ pci_xhci_parse_devices(struct pci_xhci_softc *sc, nvlist_t *nvl)
dev->hci.hci_sc = dev;
dev->hci.hci_intr = pci_xhci_dev_intr;
dev->hci.hci_event = pci_xhci_dev_event;
+ dev->hci.hci_speed = USB_SPEED_MAX;
if (ue->ue_usbver == 2) {
if (usb2_port == sc->usb2_port_start +
@@ -2863,6 +2864,8 @@ pci_xhci_parse_devices(struct pci_xhci_softc *sc, nvlist_t *nvl)
dev->dev_ue = ue;
dev->dev_sc = devsc;
+ if (dev->hci.hci_speed == USB_SPEED_MAX)
+ dev->hci.hci_speed = ue->ue_usbspeed;
XHCI_SLOTDEV_PTR(sc, slot) = dev;
ndevices++;
@@ -3228,6 +3231,7 @@ pci_xhci_snapshot(struct vm_snapshot_meta *meta)
/* devices[i]->hci */
SNAPSHOT_VAR_OR_LEAVE(dev->hci.hci_address, meta, ret, done);
SNAPSHOT_VAR_OR_LEAVE(dev->hci.hci_port, meta, ret, done);
+ SNAPSHOT_VAR_OR_LEAVE(dev->hci.hci_speed, meta, ret, done);
}
SNAPSHOT_VAR_OR_LEAVE(sc->usb2_port_start, meta, ret, done);
diff --git a/usr.sbin/bhyve/tpm_ppi_qemu.c b/usr.sbin/bhyve/tpm_ppi_qemu.c
index 01b8493e7273..6974b574b983 100644
--- a/usr.sbin/bhyve/tpm_ppi_qemu.c
+++ b/usr.sbin/bhyve/tpm_ppi_qemu.c
@@ -207,7 +207,7 @@ tpm_ppi_write_dsdt_regions(void *sc __unused)
* Used for TCG Platform Reset Attack Mitigation
*/
dsdt_line("OperationRegion(TPP3, SystemMemory, 0x%8x, 1)",
- TPM_PPI_ADDRESS + sizeof(struct tpm_ppi_qemu));
+ TPM_PPI_ADDRESS + (uint32_t)sizeof(struct tpm_ppi_qemu));
dsdt_line("Field(TPP3, ByteAcc, NoLock, Preserve)");
dsdt_line("{");
dsdt_line(" MOVV, 8,");
diff --git a/usr.sbin/bhyve/usb_emul.h b/usr.sbin/bhyve/usb_emul.h
index 8e0afcb2878b..85dedfeacd3b 100644
--- a/usr.sbin/bhyve/usb_emul.h
+++ b/usr.sbin/bhyve/usb_emul.h
@@ -85,6 +85,7 @@ struct usb_hci {
/* controller managed fields */
int hci_address;
int hci_port;
+ int hci_speed;
};
/*
diff --git a/usr.sbin/bluetooth/sdpd/server.c b/usr.sbin/bluetooth/sdpd/server.c
index ab398cd9339f..05a4cb5f0236 100644
--- a/usr.sbin/bluetooth/sdpd/server.c
+++ b/usr.sbin/bluetooth/sdpd/server.c
@@ -345,14 +345,12 @@ server_accept_client(server_p srv, int32_t fd)
return;
}
} else {
- struct xucred cr;
+ uid_t uid;
+ gid_t gid;
struct passwd *pw;
/* Get peer's credentials */
- memset(&cr, 0, sizeof(cr));
- size = sizeof(cr);
-
- if (getsockopt(cfd, 0, LOCAL_PEERCRED, &cr, &size) < 0) {
+ if (getpeereid(cfd, &uid, &gid) < 0) {
log_err("Could not get peer's credentials. %s (%d)",
strerror(errno), errno);
close(cfd);
@@ -360,12 +358,12 @@ server_accept_client(server_p srv, int32_t fd)
}
/* Check credentials */
- pw = getpwuid(cr.cr_uid);
+ pw = getpwuid(uid);
if (pw != NULL)
priv = (strcmp(pw->pw_name, "root") == 0);
else
log_warning("Could not verify credentials for uid %d",
- cr.cr_uid);
+ uid);
memcpy(&srv->req_sa.l2cap_bdaddr, NG_HCI_BDADDR_ANY,
sizeof(srv->req_sa.l2cap_bdaddr));
diff --git a/usr.sbin/bsdinstall/Makefile b/usr.sbin/bsdinstall/Makefile
index 75db149b814b..e5bb3197fa05 100644
--- a/usr.sbin/bsdinstall/Makefile
+++ b/usr.sbin/bsdinstall/Makefile
@@ -22,8 +22,11 @@ REVISION?= ${_REVISION}
.if ${BRANCH} == CURRENT || ${BRANCH} == STABLE
SUBURL= base_latest
-.else
+.elif ${BRANCH} == RELEASE
SUBURL= base_release_${REVISION:C/[0-9]+\.//}
+.else
+.warning Invalid branch "${BRANCH}"
+SUBURL= base_latest
.endif
FreeBSD-base.conf: FreeBSD-base.conf.in
diff --git a/usr.sbin/bsdinstall/bsdinstall.8 b/usr.sbin/bsdinstall/bsdinstall.8
index 8fadacab9189..181abdcf9d05 100644
--- a/usr.sbin/bsdinstall/bsdinstall.8
+++ b/usr.sbin/bsdinstall/bsdinstall.8
@@ -451,7 +451,7 @@ Each option must be preceded by the -O flag to be taken into consideration
or the pool will not be created due to errors using the command
.Cm zpool .
Default:
-.Dq Li "-O compress=lz4 -O atime=off"
+.Dq Li "-O compression=on -O atime=off"
.It Ev ZFSBOOT_BEROOT_NAME
Name for the boot environment parent dataset.
This is a non-mountable dataset meant to be a parent dataset where different
diff --git a/usr.sbin/bsdinstall/scripts/bootconfig b/usr.sbin/bsdinstall/scripts/bootconfig
index 9b330801e409..41243ad14b9b 100755
--- a/usr.sbin/bsdinstall/scripts/bootconfig
+++ b/usr.sbin/bsdinstall/scripts/bootconfig
@@ -74,7 +74,7 @@ update_uefi_bootentry()
fi
$DIALOG --backtitle "$OSNAME Installer" --title 'Boot Configuration' \
- --yesno "There are multiple \"$OSNAME\" EFI boot entries. Would you like to remove them all and add a new one?" 0 0
+ --yesno "One or more \"$OSNAME\" EFI boot manager entries already exist. Would you like to remove them all and add a new one?" 0 0
if [ $? -eq $DIALOG_OK ]; then
for entry in $(efibootmgr | awk "\$NF == \"$EFI_LABEL_NAME\" { sub(/.*Boot/,\"\", \$1); sub(/\*/,\"\", \$1); print \$1 }"); do
efibootmgr -B -b ${entry}
diff --git a/usr.sbin/bsdinstall/scripts/pkgbase.in b/usr.sbin/bsdinstall/scripts/pkgbase.in
index 1ff93afe817b..cf8e84de6923 100755
--- a/usr.sbin/bsdinstall/scripts/pkgbase.in
+++ b/usr.sbin/bsdinstall/scripts/pkgbase.in
@@ -234,12 +234,17 @@ local function pkgbase()
local chroot = assert(os.getenv("BSDINSTALL_CHROOT"))
assert(os.execute("mkdir -p " .. chroot))
+ -- Always install the default FreeBSD-base.conf file to the chroot, even
+ -- if we don't actually fetch the packages from the repository specified
+ -- there (e.g. because we are performing an offline installation).
+ local chroot_repos_dir = chroot .. "/usr/local/etc/pkg/repos/"
+ assert(os.execute("mkdir -p " .. chroot_repos_dir))
+ assert(os.execute("cp /usr/share/bsdinstall/FreeBSD-base.conf " ..
+ chroot_repos_dir))
+
local repos_dir = os.getenv("BSDINSTALL_PKG_REPOS_DIR")
if not repos_dir then
- repos_dir = chroot .. "/usr/local/etc/pkg/repos/"
- assert(os.execute("mkdir -p " .. repos_dir))
- assert(os.execute("cp /usr/share/bsdinstall/FreeBSD-base.conf " .. repos_dir))
-
+ repos_dir = chroot_repos_dir
-- Since pkg always interprets fingerprints paths as relative to
-- the --rootdir we must copy the key from the host.
assert(os.execute("mkdir -p " .. chroot .. "/usr/share/keys"))
diff --git a/usr.sbin/bsdinstall/scripts/zfsboot b/usr.sbin/bsdinstall/scripts/zfsboot
index 493f137092ec..a3c1e2ddb89f 100755
--- a/usr.sbin/bsdinstall/scripts/zfsboot
+++ b/usr.sbin/bsdinstall/scripts/zfsboot
@@ -51,7 +51,7 @@ f_include $BSDCFG_SHARE/variable.subr
#
# Default options to use when creating zroot pool
#
-: ${ZFSBOOT_POOL_CREATE_OPTIONS:=-O compress=lz4 -O atime=off}
+: ${ZFSBOOT_POOL_CREATE_OPTIONS:=-O compression=on -O atime=off}
#
# Default name for the boot environment parent dataset
@@ -86,7 +86,7 @@ f_include $BSDCFG_SHARE/variable.subr
#
# Create a separate boot pool?
-# NB: Automatically set when using geli(8) or MBR
+# NB: Automatically set when using geli(8)
#
: ${ZFSBOOT_BOOT_POOL=}
@@ -96,12 +96,12 @@ f_include $BSDCFG_SHARE/variable.subr
: ${ZFSBOOT_BOOT_POOL_CREATE_OPTIONS:=}
#
-# Default name for boot pool when enabled (e.g., geli(8) or MBR)
+# Default name for boot pool when enabled (e.g., geli(8))
#
: ${ZFSBOOT_BOOT_POOL_NAME:=bootpool}
#
-# Default size for boot pool when enabled (e.g., geli(8) or MBR)
+# Default size for boot pool when enabled (e.g., geli(8))
#
: ${ZFSBOOT_BOOT_POOL_SIZE:=2g}
@@ -790,7 +790,7 @@ zfs_create_diskpart()
# Check for unknown partition scheme before proceeding further
case "$ZFSBOOT_PARTITION_SCHEME" in
- ""|MBR|GPT*) : known good ;;
+ ""|GPT*) : known good ;;
*)
f_dprintf "$funcname: %s is an unsupported partition scheme" \
"$ZFSBOOT_PARTITION_SCHEME"
@@ -825,14 +825,11 @@ zfs_create_diskpart()
#
# Lay down the desired type of partition scheme
#
- local setsize mbrindex align_small align_big
+ local setsize align_small align_big
#
# If user has requested 4 K alignment, add these params to the
# gpart add calls. With GPT, we align large partitions to 1 M for
- # improved performance on SSDs. MBR does not always play well with gaps
- # between partitions, so all alignment is only 4k for that case.
- # With MBR, we align the BSD partition that contains the MBR, otherwise
- # the system fails to boot.
+ # improved performance on SSDs.
#
if [ "$ZFSBOOT_FORCE_4K_SECTORS" ]; then
align_small="-a 4k"
@@ -974,90 +971,6 @@ zfs_create_diskpart()
/dev/$disk$targetpart
;;
- MBR) f_dprintf "$funcname: Creating MBR layout..."
- #
- # Enable boot pool if encryption is desired
- #
- [ "$ZFSBOOT_GELI_ENCRYPTION" ] && ZFSBOOT_BOOT_POOL=1
- #
- # 1. Create MBR layout (no labels)
- #
- f_eval_catch $funcname gpart "$GPART_CREATE" mbr $disk ||
- return $FAILURE
- f_eval_catch $funcname gpart "$GPART_BOOTCODE" /boot/mbr \
- $disk || return $FAILURE
-
- #
- # 2. Add freebsd slice with all available space
- #
- f_eval_catch $funcname gpart "$GPART_ADD_ALIGN" \
- "$align_small" freebsd $disk || return $FAILURE
- f_eval_catch $funcname gpart "$GPART_SET_ACTIVE" 1 $disk ||
- return $FAILURE
- # Pedantically nuke any old labels
- f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
- /dev/${disk}s1
- # Pedantically nuke any old scheme
- f_eval_catch -d $funcname gpart "$GPART_DESTROY_F" ${disk}s1
-
- #
- # 3. Write BSD scheme to the freebsd slice
- #
- f_eval_catch $funcname gpart "$GPART_CREATE" BSD ${disk}s1 ||
- return $FAILURE
-
- # NB: ZFS pools will use s1a (no labels)
- bootpart=s1a swappart=s1b targetpart=s1d mbrindex=4
-
- #
- # Always prepare a boot pool on MBR
- # Do not align this partition, there must not be a gap
- #
- ZFSBOOT_BOOT_POOL=1
- f_eval_catch $funcname gpart \
- "$GPART_ADD_ALIGN_INDEX_WITH_SIZE" \
- "" 1 freebsd-zfs ${bootsize}b ${disk}s1 ||
- return $FAILURE
- # Pedantically nuke any old labels
- f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
- /dev/$disk$bootpart
- if [ "$ZFSBOOT_GELI_ENCRYPTION" ]; then
- # Pedantically detach targetpart for later
- f_eval_catch -d $funcname geli \
- "$GELI_DETACH_F" \
- /dev/$disk$targetpart
- fi
-
- #
- # 4. Add freebsd-swap partition
- #
- if [ ${swapsize:-0} -gt 0 ]; then
- f_eval_catch $funcname gpart \
- "$GPART_ADD_ALIGN_INDEX_WITH_SIZE" \
- "$align_small" 2 freebsd-swap \
- ${swapsize}b ${disk}s1 || return $FAILURE
- # Pedantically nuke any old labels on the swap
- f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
- /dev/${disk}s1b
- fi
-
- #
- # 5. Add freebsd-zfs partition for zroot
- #
- if [ "$ZFSBOOT_POOL_SIZE" ]; then
- f_eval_catch $funcname gpart "$GPART_ADD_ALIGN_INDEX_WITH_SIZE" \
- "$align_small" $mbrindex freebsd-zfs $ZFSBOOT_POOL_SIZE ${disk}s1 || return $FAILURE
- else
- f_eval_catch $funcname gpart "$GPART_ADD_ALIGN_INDEX" \
- "$align_small" $mbrindex freebsd-zfs ${disk}s1 || return $FAILURE
- fi
- f_eval_catch -d $funcname zpool "$ZPOOL_LABELCLEAR_F" \
- /dev/$disk$targetpart # Pedantic
- f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \
- /boot/zfsboot /dev/${disk}s1 count=1 ||
- return $FAILURE
- ;;
-
esac # $ZFSBOOT_PARTITION_SCHEME
# Update fstab(5)
@@ -1102,7 +1015,7 @@ zfs_create_boot()
local zroot_vdevtype="$2"
local zroot_vdevs= # Calculated below
local swap_devs= # Calculated below
- local boot_vdevs= # Used for geli(8) and/or MBR layouts
+ local boot_vdevs= # Used for geli(8) layouts
shift 2 # poolname vdev_type
local disks="$*" disk
local isswapmirror
@@ -1191,7 +1104,6 @@ zfs_create_boot()
f_dprintf "$funcname: With 4K sectors..."
f_eval_catch $funcname sysctl "$SYSCTL_ZFS_MIN_ASHIFT_12" \
|| return $FAILURE
- sysctl kern.geom.part.mbr.enforce_chs=0
fi
local n=0
for disk in $disks; do
@@ -1415,40 +1327,6 @@ zfs_create_boot()
"bootfs=\"$zroot_name/$zroot_bootfs\"" "$zroot_name" ||
return $FAILURE
- # MBR boot loader touch-up
- if [ "$ZFSBOOT_PARTITION_SCHEME" = "MBR" ]; then
- # Export the pool(s)
- f_dprintf "$funcname: Temporarily exporting ZFS pool(s)..."
- f_eval_catch $funcname zpool "$ZPOOL_EXPORT" "$zroot_name" ||
- return $FAILURE
- if [ "$ZFSBOOT_BOOT_POOL" ]; then
- f_eval_catch $funcname zpool "$ZPOOL_EXPORT" \
- "$bootpool_name" || return $FAILURE
- fi
-
- f_dprintf "$funcname: Updating MBR boot loader on disks..."
- # Stick the ZFS boot loader in the "convenient hole" after
- # the ZFS internal metadata
- for disk in $disks; do
- f_eval_catch $funcname dd "$DD_WITH_OPTIONS" \
- /boot/zfsboot /dev/$disk$bootpart \
- "skip=1 seek=1024" || return $FAILURE
- done
-
- # Re-import the ZFS pool(s)
- f_dprintf "$funcname: Re-importing ZFS pool(s)..."
- f_eval_catch $funcname zpool "$ZPOOL_IMPORT_WITH_OPTIONS" \
- "-o altroot=\"$BSDINSTALL_CHROOT\"" \
- "$zroot_name" || return $FAILURE
- if [ "$ZFSBOOT_BOOT_POOL" ]; then
- # Import the bootpool, but do not mount it yet
- f_eval_catch $funcname zpool \
- "$ZPOOL_IMPORT_WITH_OPTIONS" \
- "-o altroot=\"$BSDINSTALL_CHROOT\" -N" \
- "$bootpool_name" || return $FAILURE
- fi
- fi
-
# Remount bootpool and create symlink(s)
if [ "$ZFSBOOT_BOOT_POOL" ]; then
f_eval_catch $funcname zfs "$ZFS_MOUNT" "$bootpool_name" ||
@@ -1793,7 +1671,7 @@ while :; do
fi
;;
?" $msg_partition_scheme")
- # Toggle between GPT (BIOS), GPT (UEFI) and MBR
+ # Toggle between partition schemes
if [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT" -a \
"$ZFSBOOT_BOOT_TYPE" = "BIOS" ]
then
@@ -1805,9 +1683,6 @@ while :; do
ZFSBOOT_PARTITION_SCHEME="GPT"
ZFSBOOT_BOOT_TYPE="BIOS+UEFI"
elif [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT" ]; then
- ZFSBOOT_PARTITION_SCHEME="MBR"
- ZFSBOOT_BOOT_TYPE="BIOS"
- elif [ "$ZFSBOOT_PARTITION_SCHEME" = "MBR" ]; then
ZFSBOOT_PARTITION_SCHEME="GPT + Active"
ZFSBOOT_BOOT_TYPE="BIOS"
elif [ "$ZFSBOOT_PARTITION_SCHEME" = "GPT + Active" ]; then
diff --git a/usr.sbin/bsnmpd/bsnmpd/Makefile b/usr.sbin/bsnmpd/bsnmpd/Makefile
index e7c7a87eec7c..601fc31ec475 100644
--- a/usr.sbin/bsnmpd/bsnmpd/Makefile
+++ b/usr.sbin/bsnmpd/bsnmpd/Makefile
@@ -9,7 +9,7 @@ CONTRIB=${SRCTOP}/contrib/bsnmp
CONFS= snmpd.config
CONFSMODE= 600
PROG= bsnmpd
-SRCS= main.c action.c config.c export.c trap.c trans_udp.c trans_lsock.c
+SRCS= main.c action.c config.c export.c trap.c trans_lsock.c
SRCS+= trans_inet.c oid.h tree.c tree.h
XSYM= snmpMIB begemotSnmpdModuleTable begemotSnmpd begemotTrapSinkTable \
sysUpTime snmpTrapOID coldStart authenticationFailure \
diff --git a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
index b4613763fff5..d8fbb55290a8 100644
--- a/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
+++ b/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
@@ -881,12 +881,11 @@ parse_local_path(char *opt_arg)
{
assert(opt_arg != NULL);
- if (sizeof(opt_arg) > sizeof(SNMP_LOCAL_PATH)) {
+ if (strlcpy(snmp_client.local_path, opt_arg,
+ sizeof(snmp_client.local_path)) >= sizeof(snmp_client.local_path)) {
warnx("Filename too long - %s", opt_arg);
return (-1);
}
-
- strlcpy(snmp_client.local_path, opt_arg, sizeof(SNMP_LOCAL_PATH));
return (2);
}
diff --git a/usr.sbin/chroot/chroot.8 b/usr.sbin/chroot/chroot.8
index f26b7e937da9..4a1a5a396631 100644
--- a/usr.sbin/chroot/chroot.8
+++ b/usr.sbin/chroot/chroot.8
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd July 20, 2021
+.Dd July 25, 2025
.Dt CHROOT 8
.Os
.Sh NAME
@@ -52,13 +52,15 @@ or an interactive copy of the user's login shell.
The options are as follows:
.Bl -tag -width "-G group[,group ...]"
.It Fl G Ar group Ns Op Cm \&, Ns Ar group ...
-Run the command with the permissions of the specified groups.
+Run the command with the specified groups as supplementary groups.
.It Fl g Ar group
-Run the command with the permissions of the specified
-.Ar group .
+Run the command with the specified
+.Ar group
+as the real, effective and saved groups.
.It Fl u Ar user
-Run the command as the
-.Ar user .
+Run the command with the specified
+.Ar user
+as the real, effective and saved users.
.It Fl n
Use the
.Dv PROC_NO_NEW_PRIVS_CTL
diff --git a/usr.sbin/chroot/chroot.c b/usr.sbin/chroot/chroot.c
index 32becaf12588..bd4932ee9b48 100644
--- a/usr.sbin/chroot/chroot.c
+++ b/usr.sbin/chroot/chroot.c
@@ -111,7 +111,12 @@ main(int argc, char *argv[])
ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1;
if ((gidlist = malloc(sizeof(gid_t) * ngroups_max)) == NULL)
err(1, "malloc");
- for (gids = 0;
+ /* Populate the egid slot in our groups to avoid accidents. */
+ if (gid == 0)
+ gidlist[0] = getegid();
+ else
+ gidlist[0] = gid;
+ for (gids = 1;
(p = strsep(&grouplist, ",")) != NULL && gids < ngroups_max; ) {
if (*p == '\0')
continue;
diff --git a/usr.sbin/ctladm/tests/port.sh b/usr.sbin/ctladm/tests/port.sh
index 5bc5d879c983..d966529a85ae 100644
--- a/usr.sbin/ctladm/tests/port.sh
+++ b/usr.sbin/ctladm/tests/port.sh
@@ -38,12 +38,6 @@
# PGTAG,TARGET pair must be globally unique.
PGTAG=30257
-load_cfiscsi() {
- if ! kldstat -q -m cfiscsi; then
- kldload cfiscsi || atf_skip "could not load cfscsi kernel mod"
- fi
-}
-
skip_if_ctld() {
if service ctld onestatus > /dev/null; then
# If ctld is running on this server, let's not interfere.
@@ -118,11 +112,11 @@ create_iscsi_head()
atf_set "descr" "ctladm can create a new iscsi port"
atf_set "require.user" "root"
atf_set "require.progs" ctladm
+ atf_set "require.kmods" "cfiscsi"
}
create_iscsi_body()
{
skip_if_ctld
- load_cfiscsi
TARGET=iqn.2018-10.myhost.create_iscsi
atf_check -o save:port-create.txt ctladm port -c -d "iscsi" -O cfiscsi_portal_group_tag=$PGTAG -O cfiscsi_target="$TARGET"
@@ -146,11 +140,11 @@ create_iscsi_alias_head()
atf_set "descr" "ctladm can create a new iscsi port with a target alias"
atf_set "require.user" "root"
atf_set "require.progs" ctladm
+ atf_set "require.kmods" "cfiscsi"
}
create_iscsi_alias_body()
{
skip_if_ctld
- load_cfiscsi
TARGET=iqn.2018-10.myhost.create_iscsi_alias
ALIAS="foobar"
@@ -173,11 +167,11 @@ create_iscsi_without_required_args_head()
atf_set "descr" "ctladm will gracefully fail to create an iSCSI target if required arguments are missing"
atf_set "require.user" "root"
atf_set "require.progs" ctladm
+ atf_set "require.kmods" "cfiscsi"
}
create_iscsi_without_required_args_body()
{
skip_if_ctld
- load_cfiscsi
TARGET=iqn.2018-10.myhost.create_iscsi
atf_check -s exit:1 -e match:"Missing required argument: cfiscsi_target" ctladm port -c -d "iscsi" -O cfiscsi_portal_group_tag=$PGTAG
@@ -288,11 +282,11 @@ remove_iscsi_head()
atf_set "descr" "ctladm can remove an iscsi port"
atf_set "require.user" "root"
atf_set "require.progs" ctladm
+ atf_set "require.kmods" "cfiscsi"
}
remove_iscsi_body()
{
skip_if_ctld
- load_cfiscsi
TARGET=iqn.2018-10.myhost.remove_iscsi
atf_check -o save:port-create.txt ctladm port -c -d "iscsi" -O cfiscsi_portal_group_tag=$PGTAG -O cfiscsi_target="$TARGET"
@@ -314,11 +308,11 @@ remove_iscsi_without_required_args_head()
atf_set "descr" "ctladm will gracefully fail to remove an iSCSI target if required arguments are missing"
atf_set "require.user" "root"
atf_set "require.progs" ctladm
+ atf_set "require.kmods" "cfiscsi"
}
remove_iscsi_without_required_args_body()
{
skip_if_ctld
- load_cfiscsi
TARGET=iqn.2018-10.myhost.remove_iscsi_without_required_args
atf_check -o save:port-create.txt ctladm port -c -d "iscsi" -O cfiscsi_portal_group_tag=$PGTAG -O cfiscsi_target="$TARGET"
diff --git a/usr.sbin/devinfo/devinfo.c b/usr.sbin/devinfo/devinfo.c
index 629a04ba6687..4163151ec840 100644
--- a/usr.sbin/devinfo/devinfo.c
+++ b/usr.sbin/devinfo/devinfo.c
@@ -100,7 +100,7 @@ print_kvlist(char *s)
while ((kv = strsep(&copy, " ")) != NULL) {
char* k = strsep(&kv, "=");
- xo_emit("{ea:%s/%s} {d:%s}={d:%s}", k, kv, k, kv);
+ xo_emit("{ea:%s/%s} {d:key/%s}={d:value/%s}", k, kv, k, kv);
}
free(copy);
}
@@ -200,7 +200,7 @@ print_device_rman_resources(struct devinfo_rman *rman, void *arg)
/* there are, print header */
safe_desc = xml_safe_string(rman->dm_desc);
print_indent(indent);
- xo_emit("{d:%s}:\n", rman->dm_desc);
+ xo_emit("<{:description/%s}>\n", rman->dm_desc);
xo_open_list(safe_desc);
/* print resources */
@@ -220,8 +220,7 @@ print_device_props(struct devinfo_dev *dev)
{
if (vflag) {
if (*dev->dd_desc) {
- xo_emit(" <{d:%s}>", dev->dd_desc);
- xo_emit("{e:description/%s}", dev->dd_desc);
+ xo_emit("<{:description/%s}>", dev->dd_desc);
}
if (*dev->dd_pnpinfo) {
xo_open_container("pnpinfo");
@@ -273,7 +272,7 @@ print_device(struct devinfo_dev *dev, void *arg)
print_indent(indent);
xo_open_container(devname);
- xo_emit("{d:%s}", devname);
+ xo_emit("{d:devicename/%s}", devname);
print_device_props(dev);
xo_emit("\n");
@@ -367,7 +366,7 @@ print_rman(struct devinfo_rman *rman, void *arg __unused)
{
char* safe_desc = xml_safe_string(rman->dm_desc);
- xo_emit("{d:%s}:\n", rman->dm_desc);
+ xo_emit("<{:description/%s}\n>", rman->dm_desc);
xo_open_container(safe_desc);
devinfo_foreach_rman_resource(rman, print_rman_resource, 0);
@@ -385,7 +384,7 @@ print_device_path_entry(struct devinfo_dev *dev)
xo_open_container(devname);
open_tag_count++;
- xo_emit("{d:%s }", devname);
+ xo_emit("{:devicename/%s} ", devname);
print_device_props(dev);
if (vflag)
xo_emit("\n");
diff --git a/usr.sbin/efitable/efitable.8 b/usr.sbin/efitable/efitable.8
index bb8a9cc3d0e1..52949abcb853 100644
--- a/usr.sbin/efitable/efitable.8
+++ b/usr.sbin/efitable/efitable.8
@@ -1,4 +1,6 @@
.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
.\" Copyright (c) 2021 3mdeb Embedded Systems Consulting <contact@3mdeb.com>
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -27,7 +29,7 @@
.Os
.Sh NAME
.Nm efitable
-.Nd Dump UEFI tables
+.Nd dump UEFI tables
.Sh SYNOPSIS
.Nm
.Op Fl u Ar uuid | Fl t Ar name
@@ -39,7 +41,7 @@ This program prints data from
tables.
.Pp
The following options are available:
-.Bl -tag -width 20m
+.Bl -tag -width "-t name | --table name"
.It Fl -libxo
Generate output via
.Xr libxo 3
@@ -47,20 +49,21 @@ in a selection of different human and machine readable formats.
See
.Xr xo_options 7
for details on command line arguments.
-.It Fl t Ar name Fl -table Ar name
+.It Fl t Ar name | Fl -table Ar name
Specify the name of the table to print.
Currently supported tables:
.Pp
.Bl -tag -width indent -compact
.It Cm esrt
EFI System Resource Table
+.It Cm memory
+EFI Memory Attributes Table
.It Cm prop
EFI Properties Table
.El
-.It Fl u Ar uuid Fl -uuid Ar uuid
+.It Fl u Ar uuid | Fl -uuid Ar uuid
Specify the UUID of the table to print.
.El
-.Pp
.Sh HISTORY
The
.Nm
diff --git a/usr.sbin/efitable/efitable.c b/usr.sbin/efitable/efitable.c
index 0eee72801592..a506b4dea311 100644
--- a/usr.sbin/efitable/efitable.c
+++ b/usr.sbin/efitable/efitable.c
@@ -44,6 +44,7 @@
static void efi_table_print_esrt(const void *data);
static void efi_table_print_prop(const void *data);
+static void efi_table_print_memory(const void *data);
static void usage(void) __dead2;
struct efi_table_op {
@@ -56,7 +57,9 @@ static const struct efi_table_op efi_table_ops[] = {
{ .name = "esrt", .parse = efi_table_print_esrt,
.guid = EFI_TABLE_ESRT },
{ .name = "prop", .parse = efi_table_print_prop,
- .guid = EFI_PROPERTIES_TABLE }
+ .guid = EFI_PROPERTIES_TABLE },
+ { .name = "memory", .parse = efi_table_print_memory,
+ .guid = EFI_MEMORY_ATTRIBUTES_TABLE }
};
int
@@ -239,6 +242,51 @@ efi_table_print_prop(const void *data)
xo_err(EX_IOERR, "stdout");
}
+static void
+efi_table_print_memory(const void *data)
+{
+ const struct efi_memory_attribute_table *attr =
+ (const struct efi_memory_attribute_table *)data;
+ const struct efi_memory_descriptor *desc;
+ int i, nentries;
+
+ nentries = attr->num_ents;
+ desc = attr->tables;
+
+ xo_set_version(EFITABLE_XO_VERSION);
+
+ xo_open_container("memory");
+ xo_emit("{Lwc:Version}{:version/%#x}\n", attr->version);
+ xo_emit("{Lwc:Length}{:length/%u}\n", attr->descriptor_size);
+ xo_emit("{Lwc:Entries}{:entries/%u}\n", attr->num_ents);
+
+ xo_open_container("attributes");
+
+ /*
+ * According to https://forum.osdev.org/viewtopic.php?t=32953, the size
+ * of records into the attribute table never equals to
+ * sizeof(efi_memory_descriptor). The correct one for indexing the array
+ * resides in the attributet table.
+ */
+ for (i = 0; i < nentries; i++) {
+ xo_emit("{Lwc:ID}{:id/%#x}\n", i);
+ xo_emit("{Lwc:Attributes}{:attributes/%#x}\n", desc->attrs);
+ xo_emit("{Lwc:Type}{:type/%#x}\n", desc->type);
+ xo_emit("{Lwc:Pages}{:pages/%#x}\n", desc->pages);
+ xo_emit("{Lwc:Phyaddr}{:phyaddr/%#p}\n", desc->phy_addr);
+ xo_emit("{Lwc:Virtaddr}{:virtaddr/%#p}\n", desc->virt_addr);
+ desc = (const struct efi_memory_descriptor *)(const void *)
+ ((const char *)desc + attr->descriptor_size);
+ }
+
+ xo_close_container("attributes");
+
+ xo_close_container("memory");
+
+ if (xo_finish() < 0)
+ xo_err(EX_IOERR, "stdout");
+}
+
static void usage(void)
{
xo_error("usage: efitable [-g guid | -t name] [--libxo]\n");
diff --git a/usr.sbin/getfmac/getfmac.8 b/usr.sbin/getfmac/getfmac.8
index eb930e0044f9..6176bfa09271 100644
--- a/usr.sbin/getfmac/getfmac.8
+++ b/usr.sbin/getfmac/getfmac.8
@@ -51,5 +51,8 @@ specified files.
.Xr mac 3 ,
.Xr mac_get_file 3 ,
.Xr mac 4 ,
+.Xr maclabel 7 ,
+.Xr getpmac 8 ,
.Xr setfmac 8 ,
+.Xr setpmac 8 ,
.Xr mac 9
diff --git a/usr.sbin/gssd/Makefile b/usr.sbin/gssd/Makefile
index 7ad1cae7eb55..569e2c7e18f5 100644
--- a/usr.sbin/gssd/Makefile
+++ b/usr.sbin/gssd/Makefile
@@ -1,6 +1,6 @@
.include <src.opts.mk>
-PACKAGE= kerberos
+PACKAGE= gssd
PROG= gssd
MAN= gssd.8
diff --git a/usr.sbin/jail/command.c b/usr.sbin/jail/command.c
index 8ea3f3ee8795..9da4fe51673a 100644
--- a/usr.sbin/jail/command.c
+++ b/usr.sbin/jail/command.c
@@ -290,7 +290,7 @@ run_command(struct cfjail *j)
const struct cfstring *comstring, *s;
login_cap_t *lcap;
const char **argv;
- char *acs, *ajidstr, *cs, *comcs, *devpath;
+ char *acs, *cs, *comcs, *devpath;
const char *jidstr, *conslog, *fmt, *path, *ruleset, *term, *username;
enum intparam comparam;
size_t comlen, ret;
@@ -332,6 +332,25 @@ run_command(struct cfjail *j)
printf("%d\n", j->jid);
if (verbose >= 0 && (j->name || verbose > 0))
jail_note(j, "created\n");
+
+ /*
+ * Populate our jid and name parameters if they were not
+ * provided. This simplifies later logic that wants to
+ * use the jid or name to be able to do so reliably.
+ */
+ if (j->intparams[KP_JID] == NULL) {
+ char ljidstr[16];
+
+ (void)snprintf(ljidstr, sizeof(ljidstr), "%d",
+ j->jid);
+ add_param(j, NULL, KP_JID, ljidstr);
+ }
+
+ /* This matches the kernel behavior. */
+ if (j->intparams[KP_NAME] == NULL)
+ add_param(j, j->intparams[KP_JID], KP_NAME,
+ NULL);
+
dep_done(j, DF_LIGHT);
}
return 0;
@@ -456,8 +475,7 @@ run_command(struct cfjail *j)
argv[0] = _PATH_IFCONFIG;
argv[1] = comstring->s;
argv[2] = down ? "-vnet" : "vnet";
- jidstr = string_param(j->intparams[KP_JID]);
- argv[3] = jidstr ? jidstr : string_param(j->intparams[KP_NAME]);
+ argv[3] = string_param(j->intparams[KP_JID]);
argv[4] = NULL;
break;
@@ -592,9 +610,7 @@ run_command(struct cfjail *j)
case IP_ZFS_DATASET:
argv = alloca(4 * sizeof(char *));
- jidstr = string_param(j->intparams[KP_JID]) ?
- string_param(j->intparams[KP_JID]) :
- string_param(j->intparams[KP_NAME]);
+ jidstr = string_param(j->intparams[KP_JID]);
fmt = "if [ $(/sbin/zfs get -H -o value jailed %s) = on ]; then /sbin/zfs jail %s %s || echo error, attaching %s to jail %s failed; else echo error, you need to set jailed=on for dataset %s; fi";
comlen = strlen(fmt)
+ 2 * strlen(jidstr)
@@ -796,14 +812,10 @@ run_command(struct cfjail *j)
endpwent();
}
if (!injail) {
- if (asprintf(&ajidstr, "%d", j->jid) == -1) {
- jail_warnx(j, "asprintf jid=%d: %s", j->jid,
- strerror(errno));
- exit(1);
- }
- setenv("JID", ajidstr, 1);
- free(ajidstr);
+ if (string_param(j->intparams[KP_JID]))
+ setenv("JID", string_param(j->intparams[KP_JID]), 1);
setenv("JNAME", string_param(j->intparams[KP_NAME]), 1);
+
path = string_param(j->intparams[KP_PATH]);
setenv("JPATH", path ? path : "", 1);
}
diff --git a/usr.sbin/jail/config.c b/usr.sbin/jail/config.c
index 3af0088626c9..70de82e662e7 100644
--- a/usr.sbin/jail/config.c
+++ b/usr.sbin/jail/config.c
@@ -156,11 +156,14 @@ load_config(const char *cfname)
TAILQ_CONCAT(&opp, &j->params, tq);
/*
* The jail name implies its "name" or "jid" parameter,
- * though they may also be explicitly set later on.
+ * though they may also be explicitly set later on. After we
+ * collect other parameters, we'll go back and ensure they're
+ * both set if we need to do so here.
*/
add_param(j, NULL,
strtol(j->name, &ep, 10) && !*ep ? KP_JID : KP_NAME,
j->name);
+
/*
* Collect parameters for the jail, global parameters/variables,
* and any matching wildcard jails.
@@ -180,6 +183,14 @@ load_config(const char *cfname)
TAILQ_FOREACH(p, &opp, tq)
add_param(j, p, 0, NULL);
+ /*
+ * We only backfill if it's the name that wasn't set; if it was
+ * the jid, we can assume that will be populated later when the
+ * jail is created or found.
+ */
+ if (j->intparams[KP_NAME] == NULL)
+ add_param(j, j->intparams[KP_JID], KP_NAME, NULL);
+
/* Resolve any variable substitutions. */
pgen = 0;
TAILQ_FOREACH(p, &j->params, tq) {
diff --git a/usr.sbin/jail/jail.c b/usr.sbin/jail/jail.c
index 27769cc14958..46cabf76ae11 100644
--- a/usr.sbin/jail/jail.c
+++ b/usr.sbin/jail/jail.c
@@ -890,7 +890,14 @@ running_jid(struct cfjail *j)
j->jid = -1;
return;
}
+
j->jid = jail_get(jiov, 2, 0);
+ if (j->jid > 0 && j->intparams[KP_JID] == NULL) {
+ char jidstr[16];
+
+ (void)snprintf(jidstr, sizeof(jidstr), "%d", j->jid);
+ add_param(j, NULL, KP_JID, jidstr);
+ }
}
static void
diff --git a/usr.sbin/jail/tests/commands.jail.conf b/usr.sbin/jail/tests/commands.jail.conf
index afd56d1fa5d6..ad152a28b7fe 100644
--- a/usr.sbin/jail/tests/commands.jail.conf
+++ b/usr.sbin/jail/tests/commands.jail.conf
@@ -4,6 +4,4 @@ exec.prestart = "echo START";
exec.poststart = "env";
persist;
-path = "/tmp/test_${name}_root";
-
basejail {}
diff --git a/usr.sbin/jail/tests/jail_basic_test.sh b/usr.sbin/jail/tests/jail_basic_test.sh
index 6498eb1c1fdc..509900e8569c 100755
--- a/usr.sbin/jail/tests/jail_basic_test.sh
+++ b/usr.sbin/jail/tests/jail_basic_test.sh
@@ -129,36 +129,168 @@ commands_head()
{
atf_set descr 'Commands jail test'
atf_set require.user root
- mkdir /tmp/test_basejail_root
}
commands_body()
{
+ cp "$(atf_get_srcdir)/commands.jail.conf" jail.conf
+ echo "path = \"$PWD\";" >> jail.conf
+
# exec.prestart (START) and exec.poststart (env)
- atf_check -s exit:0 -o save:stdout -e empty \
- jail -f $(atf_get_srcdir)/commands.jail.conf -qc basejail
- grep -E '^START$' stdout || atf_fail "exec.prestart output not found"
- grep -E '^JID=[0-9]+' stdout || atf_fail "JID not found in exec.poststart env output"
- grep -E '^JNAME=basejail$' stdout || atf_fail "JNAME not found in exec.poststart env output"
- grep -E '^JPATH=/tmp/test_basejail_root$' stdout || atf_fail "JPATH not found in exec.poststart env output"
+ atf_check -o save:stdout -e empty \
+ jail -f jail.conf -qc basejail
+
+ # exec.prestart output is missing
+ atf_check grep -qE '^START$' stdout
+ # JID was not set in the exec.poststart env
+ atf_check grep -qE '^JID=[0-9]+' stdout
+ # JNAME was not set in the exec.poststart env
+ atf_check grep -qE '^JNAME=basejail$' stdout
+ # JPATH was not set in the exec.poststart env
+ atf_check grep -qE "^JPATH=$PWD$" stdout
# exec.prestop by jailname
atf_check -s exit:0 -o inline:"STOP\n" \
- jail -f $(atf_get_srcdir)/commands.jail.conf -qr basejail
+ jail -f jail.conf -qr basejail
# exec.prestop by jid
- jail -f $(atf_get_srcdir)/commands.jail.conf -qc basejail
+ jail -f jail.conf -qc basejail
atf_check -s exit:0 -o inline:"STOP\n" \
- jail -f $(atf_get_srcdir)/commands.jail.conf -qr `jls -j basejail jid`
+ jail -f jail.conf -qr `jls -j basejail jid`
}
-commands_cleanup()
+commands_cleanup()
{
- jls -j basejail > /dev/null 2>&1
- if [ $? -e 0 ]
- then
+ if jls -j basejail > /dev/null 2>&1; then
jail -r basejail
fi
- rmdir /tmp/test_basejail_root
+}
+
+atf_test_case "jid_name_set" "cleanup"
+jid_name_set_head()
+{
+ atf_set descr 'Test that one can set both the jid and name in a config file'
+ atf_set require.user root
+}
+
+find_unused_jid()
+{
+ : ${JAIL_MAX=999999}
+
+ # We'll start at a higher jid number and roll through the space until
+ # we find one that isn't taken. We start high to avoid racing parallel
+ # activity for the 'next available', though ideally we don't have a lot
+ # of parallel jail activity like that.
+ jid=5309
+ while jls -cj "$jid"; do
+ if [ "$jid" -eq "$JAIL_MAX" ]; then
+ atf_skip "System has too many jail, cannot find free slot"
+ fi
+
+ jid=$((jid + 1))
+ done
+
+ echo "$jid" | tee -a jails.lst
+}
+clean_jails()
+{
+ if [ ! -s jails.lst ]; then
+ return 0
+ fi
+
+ while read jail; do
+ if jls -e -j "$jail"; then
+ jail -r "$jail"
+ fi
+ done < jails.lst
+}
+
+jid_name_set_body()
+{
+ local jid=$(find_unused_jid)
+
+ echo "basejail" >> jails.lst
+ echo "$jid { name = basejail; persist; }" > jail.conf
+ atf_check -o match:"$jid: created" jail -f jail.conf -c "$jid"
+ atf_check -o match:"$jid: removed" jail -f jail.conf -r "$jid"
+
+ echo "basejail { jid = $jid; persist; }" > jail.conf
+ atf_check -o match:"basejail: created" jail -f jail.conf -c basejail
+ atf_check -o match:"basejail: removed" jail -f jail.conf -r basejail
+}
+
+jid_name_set_cleanup()
+{
+ clean_jails
+}
+
+atf_test_case "param_consistency" "cleanup"
+param_consistency_head()
+{
+ atf_set descr 'Test for consistency in jid/name params being set implicitly'
+ atf_set require.user root
+}
+
+param_consistency_body()
+{
+ local iface jid
+
+ echo "basejail" >> jails.lst
+
+ # Most basic test: exec.poststart running a command without a jail
+ # config. This would previously crash as we only had the jid and name
+ # as populated at creation time.
+ atf_check jail -c path=/ exec.poststart="true" command=/usr/bin/true
+
+ iface=$(ifconfig lo create)
+ atf_check test -n "$iface"
+ echo "$iface" >> interfaces.lst
+
+ # Now do it again but exercising IP_VNET_INTERFACE, which is an
+ # implied command that wants to use the jid or name. This would crash
+ # as neither KP_JID or KP_NAME are populated when a jail is created,
+ # just as above- just at a different spot.
+ atf_check jail -c \
+ path=/ vnet=new vnet.interface="$iface" command=/usr/bin/true
+
+ # Test that a jail that we only know by name will have its jid resolved
+ # and added to its param set.
+ echo "basejail {path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
+
+ atf_check -o ignore jail -f jail.conf -c basejail
+ atf_check -o match:"STOP" jail -f jail.conf -r basejail
+
+ # Do the same sequence as above, but use a jail with a jid-ish name.
+ jid=$(find_unused_jid)
+ echo "$jid {path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
+
+ atf_check -o ignore jail -f jail.conf -c "$jid"
+ atf_check -o match:"STOP" jail -f jail.conf -r "$jid"
+
+ # Ditto, but now we set a name for that jid-jail.
+ echo "$jid {name = basejail; path = /; exec.prestop = 'echo STOP'; persist; }" > jail.conf
+
+ atf_check -o ignore jail -f jail.conf -c "$jid"
+ atf_check -o match:"STOP" jail -f jail.conf -r "$jid"
+
+ # Confirm that we have a valid jid available in exec.poststop. It's
+ # probably debatable whether we should or not.
+ echo "basejail {path = /; exec.poststop = 'echo JID=\$JID'; persist; }" > jail.conf
+ atf_check -o ignore jail -f jail.conf -c basejail
+ jid=$(jls -j basejail jid)
+
+ atf_check -o match:"JID=$jid" jail -f jail.conf -r basejail
+
+}
+
+param_consistency_cleanup()
+{
+ clean_jails
+
+ if [ -f "interfaces.lst" ]; then
+ while read iface; do
+ ifconfig "$iface" destroy
+ done < interfaces.lst
+ fi
}
atf_init_test_cases()
@@ -167,4 +299,6 @@ atf_init_test_cases()
atf_add_test_case "list"
atf_add_test_case "nested"
atf_add_test_case "commands"
+ atf_add_test_case "jid_name_set"
+ atf_add_test_case "param_consistency"
}
diff --git a/usr.sbin/jls/jls.8 b/usr.sbin/jls/jls.8
index f7a5eeb321ef..715033082963 100644
--- a/usr.sbin/jls/jls.8
+++ b/usr.sbin/jls/jls.8
@@ -23,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 13, 2025
+.Dd July 25, 2025
.Dt JLS 8
.Os
.Sh NAME
@@ -35,6 +35,10 @@
.Op Fl dhNnqsv
.Op Fl j Ar jail
.Op Ar parameter ...
+.Nm
+.Fl c
+.Op Fl d
+.Fl j Ar jail
.Sh DESCRIPTION
The
.Nm
@@ -54,11 +58,21 @@ for a description of some core parameters.
If no
.Ar parameters
or any of the options
-.Fl hns
+.Fl chns
are given, the following four columns will be printed:
jail identifier (jid), IP address (ip4.addr), hostname (host.hostname),
and path (path).
.Pp
+When the
+.Fl c
+option is used,
+.Nm
+will not emit any output except for usage errors.
+This mode is intended solely to check for a single jail's existence, and it does
+not accept any
+.Ar parameter
+or print-option flags.
+.Pp
The following options are available:
.Bl -tag -width indent
.It Fl -libxo
@@ -68,6 +82,8 @@ in a selection of different human and machine readable formats.
See
.Xr xo_options 7
for details on command line arguments.
+.It Fl c
+Only check for the jail's existence.
.It Fl d
List
.Va dying
diff --git a/usr.sbin/jls/jls.c b/usr.sbin/jls/jls.c
index bd193a69c458..4f697a5bb382 100644
--- a/usr.sbin/jls/jls.c
+++ b/usr.sbin/jls/jls.c
@@ -37,6 +37,7 @@
#include <arpa/inet.h>
#include <netinet/in.h>
+#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <jail.h>
@@ -59,6 +60,7 @@
#define PRINT_SKIP 0x10
#define PRINT_VERBOSE 0x20
#define PRINT_JAIL_NAME 0x40
+#define PRINT_EXISTS 0x80
static struct jailparam *params;
static int *param_parent;
@@ -81,6 +83,14 @@ static void quoted_print(int pflags, char *name, char *value);
static void emit_ip_addr_list(int af_family, const char *list_name,
struct jailparam *param);
+static void
+usage(void)
+{
+ xo_errx(1,
+ "usage: jls [-dhNnqv] [-j jail] [param ...]\n"
+ " jls -c [-d] -j jail");
+}
+
int
main(int argc, char **argv)
{
@@ -94,12 +104,15 @@ main(int argc, char **argv)
xo_set_version(JLS_XO_VERSION);
jname = NULL;
pflags = jflags = jid = 0;
- while ((c = getopt(argc, argv, "adj:hNnqsv")) >= 0)
+ while ((c = getopt(argc, argv, "acdj:hNnqsv")) >= 0)
switch (c) {
case 'a':
case 'd':
jflags |= JAIL_DYING;
break;
+ case 'c':
+ pflags |= PRINT_EXISTS;
+ break;
case 'j':
jid = strtoul(optarg, &ep, 10);
if (!jid || *ep) {
@@ -130,7 +143,7 @@ main(int argc, char **argv)
PRINT_VERBOSE;
break;
default:
- xo_errx(1, "usage: jls [-dhNnqv] [-j jail] [param ...]");
+ usage();
}
#ifdef INET6
@@ -140,8 +153,28 @@ main(int argc, char **argv)
ip4_ok = feature_present("inet");
#endif
+ argc -= optind;
+ argv += optind;
+
/* Add the parameters to print. */
- if (optind == argc) {
+ if ((pflags & PRINT_EXISTS) != 0) {
+ if ((pflags & ~PRINT_EXISTS) != 0) {
+ xo_warnx("-c is incompatible with other print options");
+ usage();
+ } else if (argc != 0) {
+ xo_warnx("-c does not accept non-option arguments");
+ usage();
+ } else if (jid == 0 && jname == NULL) {
+ xo_warnx("-j jail to check must be provided for -c");
+ usage();
+ }
+
+ /*
+ * Force libxo to be silent, as well -- we're only wanting our
+ * exit status.
+ */
+ xo_set_style(NULL, XO_STYLE_TEXT);
+ } else if (argc == 0) {
if (pflags & (PRINT_HEADER | PRINT_NAMEVAL))
add_param("all", NULL, (size_t)0, NULL, JP_USER);
else if (pflags & PRINT_VERBOSE) {
@@ -179,9 +212,8 @@ main(int argc, char **argv)
}
} else {
pflags &= ~PRINT_VERBOSE;
- while (optind < argc)
- add_param(argv[optind++], NULL, (size_t)0, NULL,
- JP_USER);
+ for (i = 0; i < argc; i++)
+ add_param(argv[i], NULL, (size_t)0, NULL, JP_USER);
}
if (pflags & PRINT_SKIP) {
@@ -237,9 +269,17 @@ main(int argc, char **argv)
xo_open_list("jail");
/* Fetch the jail(s) and print the parameters. */
if (jid != 0 || jname != NULL) {
- if (print_jail(pflags, jflags) < 0)
+ if (print_jail(pflags, jflags) < 0) {
+ /*
+ * We omit errors from existential issues if we're just
+ * doing a -c check that the jail exists.
+ */
+ if (pflags & PRINT_EXISTS)
+ exit(1);
xo_errx(1, "%s", jail_errmsg);
+ }
} else {
+ assert((pflags & PRINT_EXISTS) == 0);
for (lastjid = 0;
(lastjid = print_jail(pflags, jflags)) >= 0; )
;
@@ -390,6 +430,8 @@ print_jail(int pflags, int jflags)
jid = jailparam_get(params, nparams, jflags);
if (jid < 0)
return jid;
+ else if (pflags & PRINT_EXISTS)
+ return 0;
xo_open_instance("jail");
diff --git a/usr.sbin/makefs/makefs.8 b/usr.sbin/makefs/makefs.8
index a11eaf8206e9..d20f69d87559 100644
--- a/usr.sbin/makefs/makefs.8
+++ b/usr.sbin/makefs/makefs.8
@@ -33,8 +33,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd January 19, 2024
-
+.Dd July 19, 2025
.Dt MAKEFS 8
.Os
.Sh NAME
@@ -551,6 +550,12 @@ This option allows the default heuristic to be overridden.
.It verify-txgs
Prompt OpenZFS to verify pool metadata during import.
This is disabled by default as it may significantly increase import times.
+.It poolguid
+Use the specified 64-bit integer as the pool GUID.
+If this option is not specified, the pool GUID will be random but fixed
+across multiple identical invocations of
+.Nm .
+This option is useful for testing but not required for reproducibility.
.It poolname
The name of the ZFS pool.
This option must be specified.
@@ -596,10 +601,17 @@ The following properties may be set for a dataset:
.Bl -tag -compact -offset indent
.It atime
.It canmount
+.It compression
.It exec
.It mountpoint
.It setuid
.El
+Note that
+.Nm
+does not implement compression of files included in the image,
+regardless of the value of the
+.Dv compression
+property.
.El
.Sh SEE ALSO
.Xr mtree 5 ,
diff --git a/usr.sbin/makefs/tests/Makefile b/usr.sbin/makefs/tests/Makefile
index 345b728651d6..748bafa06211 100644
--- a/usr.sbin/makefs/tests/Makefile
+++ b/usr.sbin/makefs/tests/Makefile
@@ -7,10 +7,6 @@ ATF_TESTS_SH+= makefs_msdos_tests
TEST_METADATA.makefs_msdos_tests+= required_files="/sbin/mount_msdosfs"
.if ${MK_ZFS} != "no"
ATF_TESTS_SH+= makefs_zfs_tests
-# ZFS pools created by makefs always have the same GUID, so OpenZFS
-# refuses to import more than one at a time. Thus the ZFS tests cannot
-# be run in parallel for now.
-TEST_METADATA.makefs_zfs_tests+= is_exclusive="true"
.endif
BINDIR= ${TESTSDIR}
diff --git a/usr.sbin/makefs/tests/makefs_zfs_tests.sh b/usr.sbin/makefs/tests/makefs_zfs_tests.sh
index 520d1f211ac3..2fafce85b347 100644
--- a/usr.sbin/makefs/tests/makefs_zfs_tests.sh
+++ b/usr.sbin/makefs/tests/makefs_zfs_tests.sh
@@ -28,7 +28,7 @@
# SUCH DAMAGE.
#
-MAKEFS="makefs -t zfs -o verify-txgs=true"
+MAKEFS="makefs -t zfs -o verify-txgs=true -o poolguid=$$"
ZFS_POOL_NAME="makefstest$$"
TEST_ZFS_POOL_NAME="$TMPDIR/poolname"
@@ -124,6 +124,95 @@ basic_cleanup()
common_cleanup
}
+#
+# Try configuring various compression algorithms.
+#
+atf_test_case compression cleanup
+compression_body()
+{
+ create_test_inputs
+
+ cd $TEST_INPUTS_DIR
+ mkdir dir
+ mkdir dir2
+ cd -
+
+ for alg in off on lzjb gzip gzip-1 gzip-2 gzip-3 gzip-4 \
+ gzip-5 gzip-6 gzip-7 gzip-8 gzip-9 zle lz4 zstd; do
+ atf_check $MAKEFS -s 1g -o rootpath=/ \
+ -o poolname=$ZFS_POOL_NAME \
+ -o fs=${ZFS_POOL_NAME}\;compression=$alg \
+ -o fs=${ZFS_POOL_NAME}/dir \
+ -o fs=${ZFS_POOL_NAME}/dir2\;compression=off \
+ $TEST_IMAGE $TEST_INPUTS_DIR
+
+ import_image
+
+ check_image_contents
+
+ if [ $alg = gzip-6 ]; then
+ # ZFS reports gzip-6 as just gzip since it uses
+ # a default compression level of 6.
+ alg=gzip
+ fi
+ # The "dir" dataset's compression algorithm should be
+ # inherited from the root dataset.
+ atf_check -o inline:$alg\\n -e empty -s exit:0 \
+ zfs get -H -o value compression ${ZFS_POOL_NAME}
+ atf_check -o inline:$alg\\n -e empty -s exit:0 \
+ zfs get -H -o value compression ${ZFS_POOL_NAME}/dir
+ atf_check -o inline:off\\n -e empty -s exit:0 \
+ zfs get -H -o value compression ${ZFS_POOL_NAME}/dir2
+
+ atf_check -e ignore dd if=/dev/random \
+ of=${TEST_MOUNT_DIR}/dir/random bs=1M count=10
+ atf_check -e ignore dd if=/dev/zero \
+ of=${TEST_MOUNT_DIR}/dir/zero bs=1M count=10
+ atf_check -e ignore dd if=/dev/zero \
+ of=${TEST_MOUNT_DIR}/dir2/zero bs=1M count=10
+
+ # Export and reimport to ensure that everything is
+ # flushed to disk.
+ atf_check zpool export ${ZFS_POOL_NAME}
+ atf_check -o ignore -e empty -s exit:0 \
+ zdb -e -p /dev/$(cat $TEST_MD_DEVICE_FILE) -mmm -ddddd \
+ $ZFS_POOL_NAME
+ atf_check zpool import -R $TEST_MOUNT_DIR $ZFS_POOL_NAME
+
+ if [ $alg = off ]; then
+ # If compression is off, the files should be the
+ # same size as the input.
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/random" \
+ du -m ${TEST_MOUNT_DIR}/dir/random
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir/zero
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir2/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir2/zero
+ else
+ # If compression is on, the dir/zero file ought
+ # to be smaller.
+ atf_check -o match:"^1[[:space:]]+${TEST_MOUNT_DIR}/dir/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir/zero
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir/random" \
+ du -m ${TEST_MOUNT_DIR}/dir/random
+ atf_check -o match:"^11[[:space:]]+${TEST_MOUNT_DIR}/dir2/zero" \
+ du -m ${TEST_MOUNT_DIR}/dir2/zero
+ fi
+
+ atf_check zpool destroy ${ZFS_POOL_NAME}
+ atf_check rm -f ${TEST_ZFS_POOL_NAME}
+ atf_check mdconfig -d -u $(cat ${TEST_MD_DEVICE_FILE})
+ atf_check rm -f ${TEST_MD_DEVICE_FILE}
+ done
+}
+compression_cleanup()
+{
+ common_cleanup
+}
+
+#
+# Try destroying a dataset that was created by makefs.
+#
atf_test_case dataset_removal cleanup
dataset_removal_body()
{
@@ -939,6 +1028,7 @@ atf_init_test_cases()
{
atf_add_test_case autoexpand
atf_add_test_case basic
+ atf_add_test_case compression
atf_add_test_case dataset_removal
atf_add_test_case devfs
atf_add_test_case empty_dir
diff --git a/usr.sbin/makefs/zfs.c b/usr.sbin/makefs/zfs.c
index 66e7f8dafc9c..8d50c450541b 100644
--- a/usr.sbin/makefs/zfs.c
+++ b/usr.sbin/makefs/zfs.c
@@ -38,6 +38,7 @@
#include <stdalign.h>
#include <stdbool.h>
#include <stddef.h>
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
@@ -85,6 +86,8 @@ zfs_prep_opts(fsinfo_t *fsopts)
0, 0, "Bootable dataset" },
{ '\0', "mssize", &zfs->mssize, OPT_INT64,
MINMSSIZE, MAXMSSIZE, "Metaslab size" },
+ { '\0', "poolguid", &zfs->poolguid, OPT_INT64,
+ 0, INT64_MAX, "ZFS pool GUID" },
{ '\0', "poolname", &zfs->poolname, OPT_STRPTR,
0, 0, "ZFS pool name" },
{ '\0', "rootpath", &zfs->rootpath, OPT_STRPTR,
@@ -547,7 +550,8 @@ pool_init(zfs_opt_t *zfs)
{
uint64_t dnid;
- zfs->poolguid = randomguid();
+ if (zfs->poolguid == 0)
+ zfs->poolguid = randomguid();
zfs->vdevguid = randomguid();
zfs->mos = objset_alloc(zfs, DMU_OST_META);
diff --git a/usr.sbin/makefs/zfs/dsl.c b/usr.sbin/makefs/zfs/dsl.c
index f7264b9d2ca7..8a8cee7c82b2 100644
--- a/usr.sbin/makefs/zfs/dsl.c
+++ b/usr.sbin/makefs/zfs/dsl.c
@@ -193,6 +193,39 @@ dsl_dir_set_prop(zfs_opt_t *zfs, zfs_dsl_dir_t *dir, const char *key,
nvlist_add_uint64(nvl, key, 0);
else
errx(1, "invalid value `%s' for %s", val, key);
+ } else if (strcmp(key, "compression") == 0) {
+ size_t i;
+
+ const struct zfs_compression_algorithm {
+ const char *name;
+ enum zio_compress alg;
+ } compression_algorithms[] = {
+ { "off", ZIO_COMPRESS_OFF },
+ { "on", ZIO_COMPRESS_ON },
+ { "lzjb", ZIO_COMPRESS_LZJB },
+ { "gzip", ZIO_COMPRESS_GZIP_6 },
+ { "gzip-1", ZIO_COMPRESS_GZIP_1 },
+ { "gzip-2", ZIO_COMPRESS_GZIP_2 },
+ { "gzip-3", ZIO_COMPRESS_GZIP_3 },
+ { "gzip-4", ZIO_COMPRESS_GZIP_4 },
+ { "gzip-5", ZIO_COMPRESS_GZIP_5 },
+ { "gzip-6", ZIO_COMPRESS_GZIP_6 },
+ { "gzip-7", ZIO_COMPRESS_GZIP_7 },
+ { "gzip-8", ZIO_COMPRESS_GZIP_8 },
+ { "gzip-9", ZIO_COMPRESS_GZIP_9 },
+ { "zle", ZIO_COMPRESS_ZLE },
+ { "lz4", ZIO_COMPRESS_LZ4 },
+ { "zstd", ZIO_COMPRESS_ZSTD },
+ };
+ for (i = 0; i < nitems(compression_algorithms); i++) {
+ if (strcmp(val, compression_algorithms[i].name) == 0) {
+ nvlist_add_uint64(nvl, key,
+ compression_algorithms[i].alg);
+ break;
+ }
+ }
+ if (i == nitems(compression_algorithms))
+ errx(1, "invalid compression algorithm `%s'", val);
} else {
errx(1, "unknown property `%s'", key);
}
@@ -236,9 +269,6 @@ dsl_init(zfs_opt_t *zfs)
zfs->rootdsldir = dsl_dir_alloc(zfs, NULL);
- nvlist_add_uint64(zfs->rootdsldir->propsnv, "compression",
- ZIO_COMPRESS_OFF);
-
zfs->rootds = dsl_dataset_alloc(zfs, zfs->rootdsldir);
zfs->rootdsldir->headds = zfs->rootds;
@@ -288,9 +318,13 @@ dsl_init(zfs_opt_t *zfs)
}
/*
- * Set the root dataset's mount point if the user didn't override the
- * default.
+ * Set the root dataset's mount point and compression strategy if the
+ * user didn't override the defaults.
*/
+ if (nvpair_find(zfs->rootdsldir->propsnv, "compression") == NULL) {
+ nvlist_add_uint64(zfs->rootdsldir->propsnv, "compression",
+ ZIO_COMPRESS_OFF);
+ }
if (nvpair_find(zfs->rootdsldir->propsnv, "mountpoint") == NULL) {
nvlist_add_string(zfs->rootdsldir->propsnv, "mountpoint",
zfs->rootpath);
diff --git a/usr.sbin/mfiutil/Makefile b/usr.sbin/mfiutil/Makefile
index 85b66d4b6f49..49c0e688e8e2 100644
--- a/usr.sbin/mfiutil/Makefile
+++ b/usr.sbin/mfiutil/Makefile
@@ -4,7 +4,7 @@ LINKS= ${BINDIR}/mfiutil ${BINDIR}/mrsasutil
SRCS= mfiutil.c mfi_bbu.c mfi_cmd.c mfi_config.c mfi_drive.c mfi_evt.c \
mfi_flash.c mfi_patrol.c mfi_show.c mfi_volume.c mfi_foreign.c \
mfi_properties.c
-MAN8= mfiutil.8
+MAN= mfiutil.8
MLINKS= mfiutil.8 mrsasutil.8
CFLAGS.gcc+= -fno-builtin-strftime
diff --git a/usr.sbin/rpc.lockd/kern.c b/usr.sbin/rpc.lockd/kern.c
index c24b81159ea5..1945bd68328a 100644
--- a/usr.sbin/rpc.lockd/kern.c
+++ b/usr.sbin/rpc.lockd/kern.c
@@ -39,6 +39,7 @@
#include <netinet/in.h>
#include <arpa/inet.h>
+#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@@ -232,17 +233,29 @@ void
set_auth(CLIENT *cl, struct xucred *xucred)
{
int ngroups;
+ gid_t *groups;
- ngroups = xucred->cr_ngroups - 1;
+ /*
+ * Exclude the first element if it is actually the egid, but account for
+ * the possibility that we could eventually exclude the egid from the
+ * exported group list some day.
+ */
+ ngroups = xucred->cr_ngroups;
+ groups = &xucred->cr_groups[0];
+ if (groups == &xucred->cr_gid) {
+ assert(ngroups > 0);
+ ngroups--;
+ groups++;
+ }
if (ngroups > NGRPS)
ngroups = NGRPS;
if (cl->cl_auth != NULL)
cl->cl_auth->ah_ops->ah_destroy(cl->cl_auth);
cl->cl_auth = authunix_create(hostname,
xucred->cr_uid,
- xucred->cr_groups[0],
+ xucred->cr_gid,
ngroups,
- &xucred->cr_groups[1]);
+ groups);
}
diff --git a/usr.sbin/rwhod/rwhod.c b/usr.sbin/rwhod/rwhod.c
index 237663eef74d..b99e4ea74b5a 100644
--- a/usr.sbin/rwhod/rwhod.c
+++ b/usr.sbin/rwhod/rwhod.c
@@ -246,12 +246,12 @@ main(int argc, char *argv[])
syslog(LOG_ERR, "bind: %m");
exit(1);
}
- if (setgid(unpriv_gid) != 0) {
- syslog(LOG_ERR, "setgid: %m");
+ if (setgroups(0, NULL) != 0) {
+ syslog(LOG_ERR, "setgroups: %m");
exit(1);
}
- if (setgroups(1, &unpriv_gid) != 0) { /* XXX BOGUS groups[0] = egid */
- syslog(LOG_ERR, "setgroups: %m");
+ if (setgid(unpriv_gid) != 0) {
+ syslog(LOG_ERR, "setgid: %m");
exit(1);
}
if (setuid(unpriv_uid) != 0) {
diff --git a/usr.sbin/spi/Makefile b/usr.sbin/spi/Makefile
index 73f5af6fc3cc..fee967f6a234 100644
--- a/usr.sbin/spi/Makefile
+++ b/usr.sbin/spi/Makefile
@@ -2,6 +2,6 @@
PROG= spi
-MAN8= spi.8
+MAN= spi.8
.include <bsd.prog.mk>
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);
}
diff --git a/usr.sbin/ypldap/ldapclient.c b/usr.sbin/ypldap/ldapclient.c
index acd4410d939f..a246a25a9605 100644
--- a/usr.sbin/ypldap/ldapclient.c
+++ b/usr.sbin/ypldap/ldapclient.c
@@ -385,7 +385,7 @@ ldapclient(int pipe_main2client[2])
ypldap_process = PROC_CLIENT;
#ifndef DEBUG
- if (setgroups(1, &pw->pw_gid) ||
+ if (setgroups(0, NULL) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
fatal("cannot drop privileges");
diff --git a/usr.sbin/ypldap/ypldap.c b/usr.sbin/ypldap/ypldap.c
index 01b5955aa822..b9e938227831 100644
--- a/usr.sbin/ypldap/ypldap.c
+++ b/usr.sbin/ypldap/ypldap.c
@@ -602,7 +602,7 @@ main(int argc, char *argv[])
fatal("getpwnam");
#ifndef DEBUG
- if (setgroups(1, &pw->pw_gid) ||
+ if (setgroups(0, NULL) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
fatal("cannot drop privileges");
diff --git a/usr.sbin/ypldap/ypldap_dns.c b/usr.sbin/ypldap/ypldap_dns.c
index 09ce636ebdc8..9dbbf26d237b 100644
--- a/usr.sbin/ypldap/ypldap_dns.c
+++ b/usr.sbin/ypldap/ypldap_dns.c
@@ -91,7 +91,7 @@ ypldap_dns(int pipe_ntp[2], struct passwd *pw)
setproctitle("dns engine");
close(pipe_ntp[0]);
- if (setgroups(1, &pw->pw_gid) ||
+ if (setgroups(0, NULL) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
fatal("can't drop privileges");