aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--UPDATING6
-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/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/tzcode/localtime.c2
-rw-r--r--lib/libsys/fhopen.24
-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--libexec/rc/rc.conf2
-rw-r--r--libexec/rtld-elf/map_object.c2
-rw-r--r--release/packages/ucl/krb5-all.ucl4
-rw-r--r--release/packages/ucl/krb5-lib-all.ucl4
-rw-r--r--share/man/man4/sa.43
-rw-r--r--share/misc/committers-src.dot5
-rw-r--r--sys/amd64/amd64/pmap.c66
-rw-r--r--sys/amd64/include/pmap.h7
-rw-r--r--sys/amd64/include/vmparam.h6
-rw-r--r--sys/arm64/broadcom/genet/if_genet.c4
-rw-r--r--sys/dev/ice/ice_iov.c17
-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/fs/nfs/nfs_commonsubs.c32
-rw-r--r--sys/fs/nfs/nfs_var.h8
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c3
-rw-r--r--sys/fs/nfsclient/nfs_clstate.c2
-rw-r--r--sys/fs/nfsserver/nfs_nfsdport.c41
-rw-r--r--sys/fs/nfsserver/nfs_nfsdserv.c29
-rw-r--r--sys/netinet/tcp_hpts.c73
-rw-r--r--sys/netinet/tcp_hpts.h17
-rw-r--r--sys/netinet/tcp_input.c17
-rw-r--r--sys/netinet/tcp_log_buf.c2
-rw-r--r--sys/netinet/tcp_log_buf.h8
-rw-r--r--sys/netinet/tcp_stacks/rack.c29
-rw-r--r--sys/netinet6/mld6.c29
-rw-r--r--sys/rpc/clnt_rc.c7
-rw-r--r--sys/rpc/rpcsec_gss/rpcsec_gss.c14
-rw-r--r--sys/sys/param.h2
-rw-r--r--sys/sys/random.h3
-rwxr-xr-xtools/test/stress2/misc/fullpath2.sh2
-rw-r--r--usr.bin/bmake/Makefile.config2
-rw-r--r--usr.bin/bmake/unit-tests/Makefile7
-rw-r--r--usr.bin/calendar/calendars/calendar.freebsd1
-rwxr-xr-xusr.bin/man/man.sh13
-rw-r--r--usr.sbin/trim/trim.818
-rw-r--r--usr.sbin/trim/trim.c11
203 files changed, 1973 insertions, 1015 deletions
diff --git a/UPDATING b/UPDATING
index 2b8320c1204d..196443581158 100644
--- a/UPDATING
+++ b/UPDATING
@@ -27,6 +27,12 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 15.x IS SLOW:
world, or to merely disable the most expensive debugging functionality
at runtime, run "ln -s 'abort:false,junk:false' /etc/malloc.conf".)
+20250719:
+ Commits 392a82b225 and c00baac0ab both changed the
+ internal API between the NFS modules. As such, all
+ these modules need to be rebuilt from sources.
+ __FreeBSD_version was bumped to 1500053 for this.
+
20250710:
The shar(1) utility has been removed from base. The
sysutils/freebsd-shar port was created to maintain this version of
diff --git a/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/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/tzcode/localtime.c b/contrib/tzcode/localtime.c
index 5c3ef7ed47af..a6ec3d8e4e21 100644
--- a/contrib/tzcode/localtime.c
+++ b/contrib/tzcode/localtime.c
@@ -514,6 +514,8 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
return errno;
case 0:
return 0;
+ case 1:
+ break;
}
}
fid = _open(name, O_RDONLY | O_BINARY);
diff --git a/lib/libsys/fhopen.2 b/lib/libsys/fhopen.2
index aba53f1dd907..b281ac3d8949 100644
--- a/lib/libsys/fhopen.2
+++ b/lib/libsys/fhopen.2
@@ -31,7 +31,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd April 6, 2025
+.Dd July 20, 2025
.Dt FHOPEN 2
.Os
.Sh NAME
@@ -140,7 +140,7 @@ is no longer valid.
.Xr fstatfs 2 ,
.Xr getfh 2 ,
.Xr open 2 ,
-.Xr named_attribute 9
+.Xr named_attribute 7
.Sh HISTORY
The
.Fn fhopen ,
diff --git a/lib/libsys/statfs.2 b/lib/libsys/statfs.2
index 49e8b5120558..ab65def11ebb 100644
--- a/lib/libsys/statfs.2
+++ b/lib/libsys/statfs.2
@@ -25,7 +25,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd April 7, 2025
+.Dd July 20, 2025
.Dt STATFS 2
.Os
.Sh NAME
@@ -127,7 +127,7 @@ Mandatory Access Control (MAC) support for individual objects
.Xr mac 4 ) .
.It Dv MNT_NAMEDATTR
The file system supports named attributes as described in
-.Xr named_attribute 9 .
+.Xr named_attribute 7 .
.It Dv MNT_NFS4ACLS
ACLs in NFSv4 variant are supported.
.It Dv MNT_NOATIME
@@ -264,7 +264,7 @@ each file or directory name or disk label
.Sh SEE ALSO
.Xr fhstatfs 2 ,
.Xr getfsstat 2 ,
-.Xr named_attribute 9
+.Xr named_attribute 7
.Sh HISTORY
The
.Fn statfs
diff --git a/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/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/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/release/packages/ucl/krb5-all.ucl b/release/packages/ucl/krb5-all.ucl
new file mode 100644
index 000000000000..e269aabe1e85
--- /dev/null
+++ b/release/packages/ucl/krb5-all.ucl
@@ -0,0 +1,4 @@
+comment = "KRB5 Utilities"
+desc = <<EOD
+KRB5 Utilities
+EOD
diff --git a/release/packages/ucl/krb5-lib-all.ucl b/release/packages/ucl/krb5-lib-all.ucl
new file mode 100644
index 000000000000..854b8a9f85df
--- /dev/null
+++ b/release/packages/ucl/krb5-lib-all.ucl
@@ -0,0 +1,4 @@
+comment = "KRB5 Libraries"
+desc = <<EOD
+KRB5 Libraries
+EOD
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/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/sys/amd64/amd64/pmap.c b/sys/amd64/amd64/pmap.c
index 14f57ca94ba7..b2bfe633adcc 100644
--- a/sys/amd64/amd64/pmap.c
+++ b/sys/amd64/amd64/pmap.c
@@ -497,8 +497,8 @@ struct kva_layout_s kva_layout_la57 = {
.kva_min = KV5ADDR(NPML5EPG / 2, 0, 0, 0, 0), /* == rec_pt */
.dmap_low = KV5ADDR(DMPML5I, 0, 0, 0, 0),
.dmap_high = KV5ADDR(DMPML5I + NDMPML5E, 0, 0, 0, 0),
- .lm_low = KV4ADDR(LMSPML4I, 0, 0, 0),
- .lm_high = KV4ADDR(LMEPML4I + 1, 0, 0, 0),
+ .lm_low = KV5ADDR(LMSPML5I, 0, 0, 0, 0),
+ .lm_high = KV5ADDR(LMEPML5I + 1, 0, 0, 0, 0),
.km_low = KV4ADDR(KPML4BASE, 0, 0, 0),
.km_high = KV4ADDR(KPML4BASE + NKPML4E - 1, NPDPEPG - 1,
NPDEPG - 1, NPTEPG - 1),
@@ -2475,6 +2475,7 @@ pmap_init(void)
struct pmap_preinit_mapping *ppim;
vm_page_t m, mpte;
pml4_entry_t *pml4e;
+ unsigned long lm_max;
int error, i, ret, skz63;
/* L1TF, reserve page @0 unconditionally */
@@ -2600,10 +2601,15 @@ pmap_init(void)
lm_ents = 8;
TUNABLE_INT_FETCH("vm.pmap.large_map_pml4_entries", &lm_ents);
- if (lm_ents > LMEPML4I - LMSPML4I + 1)
- lm_ents = LMEPML4I - LMSPML4I + 1;
+ lm_max = (kva_layout.lm_high - kva_layout.lm_low) / NBPML4;
+ if (lm_ents > lm_max) {
+ printf(
+ "pmap: shrinking large map from requested %d slots to %ld slots\n",
+ lm_ents, lm_max);
+ lm_ents = lm_max;
+ }
#ifdef KMSAN
- if (lm_ents > KMSANORIGPML4I - LMSPML4I) {
+ if (!la57 && lm_ents > KMSANORIGPML4I - LMSPML4I) {
printf(
"pmap: shrinking large map for KMSAN (%d slots to %ld slots)\n",
lm_ents, KMSANORIGPML4I - LMSPML4I);
@@ -2615,12 +2621,20 @@ pmap_init(void)
lm_ents, (u_long)lm_ents * (NBPML4 / 1024 / 1024 / 1024));
if (lm_ents != 0) {
large_vmem = vmem_create("large", kva_layout.lm_low,
- (vmem_size_t)kva_layout.lm_high - kva_layout.lm_low,
- PAGE_SIZE, 0, M_WAITOK);
+ (vmem_size_t)lm_ents * NBPML4, PAGE_SIZE, 0, M_WAITOK);
if (large_vmem == NULL) {
printf("pmap: cannot create large map\n");
lm_ents = 0;
}
+ if (la57) {
+ for (i = 0; i < howmany((vm_offset_t)NBPML4 *
+ lm_ents, NBPML5); i++) {
+ m = pmap_large_map_getptp_unlocked();
+ kernel_pmap->pm_pmltop[LMSPML5I + i] = X86_PG_V |
+ X86_PG_RW | X86_PG_A | X86_PG_M |
+ pg_nx | VM_PAGE_TO_PHYS(m);
+ }
+ }
for (i = 0; i < lm_ents; i++) {
m = pmap_large_map_getptp_unlocked();
pml4e = pmap_pml4e(kernel_pmap, kva_layout.lm_low +
@@ -10763,19 +10777,28 @@ pmap_large_map_getptp(void)
static pdp_entry_t *
pmap_large_map_pdpe(vm_offset_t va)
{
+ pml4_entry_t *pml4;
vm_pindex_t pml4_idx;
vm_paddr_t mphys;
- pml4_idx = pmap_pml4e_index(va);
- KASSERT(LMSPML4I <= pml4_idx && pml4_idx < LMSPML4I + lm_ents,
- ("pmap_large_map_pdpe: va %#jx out of range idx %#jx LMSPML4I "
- "%#jx lm_ents %d",
- (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
- KASSERT((kernel_pml4[pml4_idx] & X86_PG_V) != 0,
- ("pmap_large_map_pdpe: invalid pml4 for va %#jx idx %#jx "
- "LMSPML4I %#jx lm_ents %d",
- (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
- mphys = kernel_pml4[pml4_idx] & PG_FRAME;
+ KASSERT(va >= kva_layout.lm_low && va < kva_layout.lm_low +
+ (vm_offset_t)NBPML4 * lm_ents, ("va %#lx not in large map", va));
+ if (la57) {
+ pml4 = pmap_pml4e(kernel_pmap, va);
+ mphys = *pml4 & PG_FRAME;
+ } else {
+ pml4_idx = pmap_pml4e_index(va);
+
+ KASSERT(LMSPML4I <= pml4_idx && pml4_idx < LMSPML4I + lm_ents,
+ ("pmap_large_map_pdpe: va %#jx out of range idx %#jx "
+ "LMSPML4I %#jx lm_ents %d",
+ (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
+ KASSERT((kernel_pml4[pml4_idx] & X86_PG_V) != 0,
+ ("pmap_large_map_pdpe: invalid pml4 for va %#jx idx %#jx "
+ "LMSPML4I %#jx lm_ents %d",
+ (uintmax_t)va, (uintmax_t)pml4_idx, LMSPML4I, lm_ents));
+ mphys = kernel_pml4[pml4_idx] & PG_FRAME;
+ }
return ((pdp_entry_t *)PHYS_TO_DMAP(mphys) + pmap_pdpe_index(va));
}
@@ -12144,10 +12167,12 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
for (sva = 0, i = pmap_pml4e_index(sva); i < NPML4EPG; i++) {
switch (i) {
case PML4PML4I:
- sbuf_printf(sb, "\nRecursive map:\n");
+ if (!la57)
+ sbuf_printf(sb, "\nRecursive map:\n");
break;
case DMPML4I:
- sbuf_printf(sb, "\nDirect map:\n");
+ if (!la57)
+ sbuf_printf(sb, "\nDirect map:\n");
break;
#ifdef KASAN
case KASANPML4I:
@@ -12166,7 +12191,8 @@ sysctl_kmaps(SYSCTL_HANDLER_ARGS)
sbuf_printf(sb, "\nKernel map:\n");
break;
case LMSPML4I:
- sbuf_printf(sb, "\nLarge map:\n");
+ if (!la57)
+ sbuf_printf(sb, "\nLarge map:\n");
break;
}
diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h
index 08e96027a5ed..a0ca97f2d5a0 100644
--- a/sys/amd64/include/pmap.h
+++ b/sys/amd64/include/pmap.h
@@ -202,9 +202,14 @@
#define KMSANSHADPML4I (KPML4BASE - NKMSANSHADPML4E)
#define KMSANORIGPML4I (DMPML4I - NKMSANORIGPML4E)
-/* Large map: index of the first and max last pml4 entry */
+/*
+ * Large map: index of the first and max last pml4/la48 and pml5/la57
+ * entry.
+ */
#define LMSPML4I (PML4PML4I + 1)
#define LMEPML4I (KASANPML4I - 1)
+#define LMSPML5I (DMPML5I + NDMPML5E)
+#define LMEPML5I (LMSPML5I + 32 - 1) /* 32 slots for large map */
/*
* XXX doesn't really belong here I guess...
diff --git a/sys/amd64/include/vmparam.h b/sys/amd64/include/vmparam.h
index e4cc05cbb889..ef352e776af6 100644
--- a/sys/amd64/include/vmparam.h
+++ b/sys/amd64/include/vmparam.h
@@ -181,9 +181,9 @@
* 0x0100000000000000 - 0xf0ffffffffffffff does not exist (hole)
* 0xff00000000000000 - 0xff00ffffffffffff recursive page table (2048TB slot)
* 0xff01000000000000 - 0xff20ffffffffffff direct map (32 x 2048TB slots)
- * 0xff21000000000000 - 0xffff807fffffffff unused
- * 0xffff808000000000 - 0xffff847fffffffff large map (can be tuned up)
- * 0xffff848000000000 - 0xfffff77fffffffff unused (large map extends there)
+ * 0xff21000000000000 - 0xff40ffffffffffff large map
+ * 0xff41000000000000 - 0xffff7fffffffffff unused
+ * 0xffff800000000000 - 0xfffff5ffffffffff unused (start of kernel pml4 entry)
* 0xfffff60000000000 - 0xfffff7ffffffffff 2TB KMSAN origin map, optional
* 0xfffff78000000000 - 0xfffff7bfffffffff 512GB KASAN shadow map, optional
* 0xfffff80000000000 - 0xfffffbffffffffff 4TB unused
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/dev/ice/ice_iov.c b/sys/dev/ice/ice_iov.c
index e06c7eb56f7a..c5a3e1060e44 100644
--- a/sys/dev/ice/ice_iov.c
+++ b/sys/dev/ice/ice_iov.c
@@ -345,7 +345,7 @@ ice_iov_add_vf(struct ice_softc *sc, uint16_t vfnum, const nvlist_t *params)
if (nvlist_exists_binary(params, "mac-addr")) {
mac = nvlist_get_binary(params, "mac-addr", &size);
- bcopy(mac, vf->mac, ETHER_ADDR_LEN);
+ memcpy(vf->mac, mac, ETHER_ADDR_LEN);
if (nvlist_get_bool(params, "allow-set-mac"))
vf->vf_flags |= VF_FLAG_SET_MAC_CAP;
@@ -617,12 +617,14 @@ 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 = (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;
@@ -643,10 +645,13 @@ ice_vc_get_vf_res_msg(struct ice_softc *sc, struct ice_vf *vf, u8 *msg_buf)
vf_res->vf_cap_flags |= VIRTCHNL_VF_OFFLOAD_WB_ON_ITR;
}
- vf_res->vsi_res[0].vsi_id = vf->vsi->idx;
- vf_res->vsi_res[0].num_queue_pairs = vf->vsi->num_tx_queues;
- vf_res->vsi_res[0].vsi_type = VIRTCHNL_VSI_SRIOV;
- vf_res->vsi_res[0].qset_handle = 0;
+ 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);
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/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c
index 4c498e96a3c0..a957315aaa12 100644
--- a/sys/fs/nfs/nfs_commonsubs.c
+++ b/sys/fs/nfs/nfs_commonsubs.c
@@ -647,7 +647,8 @@ nfscl_fillsattr(struct nfsrv_descript *nd, struct vattr *vap,
NFSATTRBIT_TIMECREATE))
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE);
(void) nfsv4_fillattr(nd, vp->v_mount, vp, NULL, vap, NULL, 0,
- &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
+ &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL,
+ false, false, false);
break;
}
}
@@ -2646,7 +2647,8 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
NFSACL_T *saclp, struct vattr *vap, fhandle_t *fhp, int rderror,
nfsattrbit_t *attrbitp, struct ucred *cred, NFSPROC_T *p, int isdgram,
int reterr, int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
- struct statfs *pnfssf)
+ struct statfs *pnfssf, bool xattrsupp, bool has_hiddensystem,
+ bool has_namedattr)
{
int bitpos, retnum = 0;
u_int32_t *tl;
@@ -2660,10 +2662,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
struct nfsfsinfo fsinf;
struct timespec temptime;
NFSACL_T *aclp, *naclp = NULL;
- size_t atsiz;
- bool xattrsupp;
short irflag;
- long has_pathconf;
#ifdef QUOTA
struct dqblk dqb;
uid_t savuid;
@@ -2747,18 +2746,6 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
}
}
- /* Check to see if Extended Attributes are supported. */
- xattrsupp = false;
- if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_XATTRSUPPORT)) {
- if (NFSVOPLOCK(vp, LK_SHARED) == 0) {
- error = VOP_GETEXTATTR(vp, EXTATTR_NAMESPACE_USER,
- "xxx", NULL, &atsiz, cred, p);
- NFSVOPUNLOCK(vp);
- if (error != EOPNOTSUPP)
- xattrsupp = true;
- }
- }
-
/*
* Put out the attribute bitmap for the ones being filled in
* and get the field for the number of attributes returned.
@@ -2780,11 +2767,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT);
NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL);
}
- if (cred == NULL || p == NULL || vp == NULL ||
- VOP_PATHCONF(vp, _PC_HAS_HIDDENSYSTEM,
- &has_pathconf) != 0)
- has_pathconf = 0;
- if (has_pathconf == 0) {
+ if (!has_hiddensystem) {
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN);
NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM);
}
@@ -2828,10 +2811,7 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp,
break;
case NFSATTRBIT_NAMEDATTR:
NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
- if (VOP_PATHCONF(vp, _PC_HAS_NAMEDATTR,
- &has_pathconf) != 0)
- has_pathconf = 0;
- if (has_pathconf != 0)
+ if (has_namedattr)
*tl = newnfs_true;
else
*tl = newnfs_false;
diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h
index 3b6c1ec90c06..54f60a753c50 100644
--- a/sys/fs/nfs/nfs_var.h
+++ b/sys/fs/nfs/nfs_var.h
@@ -395,8 +395,9 @@ int nfsrv_putopbit(struct nfsrv_descript *, nfsopbit_t *);
void nfsrv_wcc(struct nfsrv_descript *, int, struct nfsvattr *, int,
struct nfsvattr *);
int nfsv4_fillattr(struct nfsrv_descript *, struct mount *, vnode_t, NFSACL_T *,
- struct vattr *, fhandle_t *, int, nfsattrbit_t *,
- struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t, struct statfs *);
+ struct vattr *, fhandle_t *, int, nfsattrbit_t *, struct ucred *,
+ NFSPROC_T *, int, int, int, int, uint64_t, struct statfs *, bool, bool,
+ bool);
void nfsrv_fillattr(struct nfsrv_descript *, struct nfsvattr *);
struct mbuf *nfsrv_adj(struct mbuf *, int, int);
void nfsrv_postopattr(struct nfsrv_descript *, int, struct nfsvattr *);
@@ -735,7 +736,8 @@ int nfsvno_updfilerev(vnode_t, struct nfsvattr *, struct nfsrv_descript *,
NFSPROC_T *);
int nfsvno_fillattr(struct nfsrv_descript *, struct mount *, vnode_t,
struct nfsvattr *, fhandle_t *, int, nfsattrbit_t *,
- struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t);
+ struct ucred *, NFSPROC_T *, int, int, int, int, uint64_t, bool, bool,
+ bool);
int nfsrv_sattr(struct nfsrv_descript *, vnode_t, struct nfsvattr *, nfsattrbit_t *,
NFSACL_T *, NFSPROC_T *);
int nfsv4_sattr(struct nfsrv_descript *, vnode_t, struct nfsvattr *, nfsattrbit_t *,
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index e0e66baca44d..2f3c59b68518 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -5436,7 +5436,8 @@ nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
NFSZERO_ATTRBIT(&attrbits);
NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
(void) nfsv4_fillattr(nd, vp->v_mount, vp, aclp, NULL, NULL, 0,
- &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
+ &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL, false, false,
+ false);
error = nfscl_request(nd, vp, p, cred);
if (error)
return (error);
diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c
index 1ae5ed1a75ca..99a781640c53 100644
--- a/sys/fs/nfsclient/nfs_clstate.c
+++ b/sys/fs/nfsclient/nfs_clstate.c
@@ -3701,7 +3701,7 @@ nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p)
if (!error)
(void) nfsv4_fillattr(nd, NULL, NULL, NULL, &va,
NULL, 0, &rattrbits, NULL, p, 0, 0, 0, 0,
- (uint64_t)0, NULL);
+ (uint64_t)0, NULL, false, false, false);
break;
case NFSV4OP_CBRECALL:
NFSCL_DEBUG(4, "cbrecall\n");
diff --git a/sys/fs/nfsserver/nfs_nfsdport.c b/sys/fs/nfsserver/nfs_nfsdport.c
index 43ee0383669f..4f0d5946d6b9 100644
--- a/sys/fs/nfsserver/nfs_nfsdport.c
+++ b/sys/fs/nfsserver/nfs_nfsdport.c
@@ -2112,7 +2112,8 @@ int
nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp,
struct nfsvattr *nvap, fhandle_t *fhp, int rderror, nfsattrbit_t *attrbitp,
struct ucred *cred, struct thread *p, int isdgram, int reterr,
- int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno)
+ int supports_nfsv4acls, int at_root, uint64_t mounted_on_fileno,
+ bool xattrsupp, bool has_hiddensystem, bool has_namedattr)
{
struct statfs *sf;
int error;
@@ -2131,7 +2132,7 @@ nfsvno_fillattr(struct nfsrv_descript *nd, struct mount *mp, struct vnode *vp,
}
error = nfsv4_fillattr(nd, mp, vp, NULL, &nvap->na_vattr, fhp, rderror,
attrbitp, cred, p, isdgram, reterr, supports_nfsv4acls, at_root,
- mounted_on_fileno, sf);
+ mounted_on_fileno, sf, xattrsupp, has_hiddensystem, has_namedattr);
free(sf, M_TEMP);
NFSEXITCODE2(0, nd);
return (error);
@@ -2448,7 +2449,7 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
struct nfsvattr nva, at, *nvap = &nva;
struct mbuf *mb0, *mb1;
struct nfsreferral *refp;
- int nlen, r, error = 0, getret = 1, usevget = 1;
+ int nlen, r, error = 0, getret = 1, ret, usevget = 1;
int siz, cnt, fullsiz, eofflag, ncookies, entrycnt;
caddr_t bpos0, bpos1;
u_int64_t off, toff, verf __unused;
@@ -2462,6 +2463,9 @@ nfsrvd_readdirplus(struct nfsrv_descript *nd, int isdgram,
uint64_t mounted_on_fileno;
struct thread *p = curthread;
int bextpg0, bextpg1, bextpgsiz0, bextpgsiz1;
+ size_t atsiz;
+ long pathval;
+ bool has_hiddensystem, has_namedattr, xattrsupp;
if (nd->nd_repstat) {
nfsrv_postopattr(nd, getret, &at);
@@ -2936,9 +2940,32 @@ again:
*tl++ = newnfs_true;
txdr_hyper(*cookiep, tl);
dirlen += nfsm_strtom(nd, dp->d_name, nlen);
+ xattrsupp = false;
+ has_hiddensystem = false;
+ has_namedattr = false;
if (nvp != NULL) {
supports_nfsv4acls =
nfs_supportsnfsv4acls(nvp);
+ if (NFSISSET_ATTRBIT(&attrbits,
+ NFSATTRBIT_XATTRSUPPORT)) {
+ ret = VOP_GETEXTATTR(nvp,
+ EXTATTR_NAMESPACE_USER,
+ "xxx", NULL, &atsiz,
+ nd->nd_cred, p);
+ xattrsupp = ret != EOPNOTSUPP;
+ }
+ if (VOP_PATHCONF(nvp,
+ _PC_HAS_HIDDENSYSTEM, &pathval) !=
+ 0)
+ pathval = 0;
+ has_hiddensystem = pathval > 0;
+ pathval = 0;
+ if (NFSISSET_ATTRBIT(&attrbits,
+ NFSATTRBIT_NAMEDATTR) &&
+ VOP_PATHCONF(nvp, _PC_HAS_NAMEDATTR,
+ &pathval) != 0)
+ pathval = 0;
+ has_namedattr = pathval > 0;
NFSVOPUNLOCK(nvp);
} else
supports_nfsv4acls = 0;
@@ -2958,13 +2985,15 @@ again:
nvp, nvap, &nfh, r, &rderrbits,
nd->nd_cred, p, isdgram, 0,
supports_nfsv4acls, at_root,
- mounted_on_fileno);
+ mounted_on_fileno, xattrsupp,
+ has_hiddensystem, has_namedattr);
} else {
dirlen += nfsvno_fillattr(nd, new_mp,
nvp, nvap, &nfh, r, &attrbits,
nd->nd_cred, p, isdgram, 0,
supports_nfsv4acls, at_root,
- mounted_on_fileno);
+ mounted_on_fileno, xattrsupp,
+ has_hiddensystem, has_namedattr);
}
if (nvp != NULL)
vrele(nvp);
@@ -6356,7 +6385,7 @@ nfsrv_setacldsdorpc(fhandle_t *fhp, struct ucred *cred, NFSPROC_T *p,
* the same type (VREG).
*/
nfsv4_fillattr(nd, NULL, vp, aclp, NULL, NULL, 0, &attrbits, NULL,
- NULL, 0, 0, 0, 0, 0, NULL);
+ NULL, 0, 0, 0, 0, 0, NULL, false, false, false);
error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
if (error != 0) {
diff --git a/sys/fs/nfsserver/nfs_nfsdserv.c b/sys/fs/nfsserver/nfs_nfsdserv.c
index 3acf07d5253b..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);
diff --git a/sys/netinet/tcp_hpts.c b/sys/netinet/tcp_hpts.c
index 91f8251589e4..b60cdf45af52 100644
--- a/sys/netinet/tcp_hpts.c
+++ b/sys/netinet/tcp_hpts.c
@@ -433,38 +433,40 @@ static void
tcp_hpts_log(struct tcp_hpts_entry *hpts, struct tcpcb *tp, struct timeval *tv,
int slots_to_run, int idx, bool from_callout)
{
- union tcp_log_stackspecific log;
- /*
- * Unused logs are
- * 64 bit - delRate, rttProp, bw_inuse
- * 16 bit - cwnd_gain
- * 8 bit - bbr_state, bbr_substate, inhpts;
- */
- memset(&log, 0, sizeof(log));
- log.u_bbr.flex1 = hpts->p_nxt_slot;
- log.u_bbr.flex2 = hpts->p_cur_slot;
- log.u_bbr.flex3 = hpts->p_prev_slot;
- log.u_bbr.flex4 = idx;
- log.u_bbr.flex5 = hpts->p_curtick;
- log.u_bbr.flex6 = hpts->p_on_queue_cnt;
- log.u_bbr.flex7 = hpts->p_cpu;
- log.u_bbr.flex8 = (uint8_t)from_callout;
- log.u_bbr.inflight = slots_to_run;
- log.u_bbr.applimited = hpts->overidden_sleep;
- log.u_bbr.delivered = hpts->saved_curtick;
- log.u_bbr.timeStamp = tcp_tv_to_usectick(tv);
- log.u_bbr.epoch = hpts->saved_curslot;
- log.u_bbr.lt_epoch = hpts->saved_prev_slot;
- log.u_bbr.pkts_out = hpts->p_delayed_by;
- log.u_bbr.lost = hpts->p_hpts_sleep_time;
- log.u_bbr.pacing_gain = hpts->p_cpu;
- log.u_bbr.pkt_epoch = hpts->p_runningslot;
- log.u_bbr.use_lt_bw = 1;
- TCP_LOG_EVENTP(tp, NULL,
- &tptosocket(tp)->so_rcv,
- &tptosocket(tp)->so_snd,
- BBR_LOG_HPTSDIAG, 0,
- 0, &log, false, tv);
+ if (hpts_does_tp_logging && tcp_bblogging_on(tp)) {
+ union tcp_log_stackspecific log;
+ /*
+ * Unused logs are
+ * 64 bit - delRate, rttProp, bw_inuse
+ * 16 bit - cwnd_gain
+ * 8 bit - bbr_state, bbr_substate, inhpts;
+ */
+ memset(&log, 0, sizeof(log));
+ log.u_bbr.flex1 = hpts->p_nxt_slot;
+ log.u_bbr.flex2 = hpts->p_cur_slot;
+ log.u_bbr.flex3 = hpts->p_prev_slot;
+ log.u_bbr.flex4 = idx;
+ log.u_bbr.flex5 = hpts->p_curtick;
+ log.u_bbr.flex6 = hpts->p_on_queue_cnt;
+ log.u_bbr.flex7 = hpts->p_cpu;
+ log.u_bbr.flex8 = (uint8_t)from_callout;
+ log.u_bbr.inflight = slots_to_run;
+ log.u_bbr.applimited = hpts->overidden_sleep;
+ log.u_bbr.delivered = hpts->saved_curtick;
+ log.u_bbr.timeStamp = tcp_tv_to_usectick(tv);
+ log.u_bbr.epoch = hpts->saved_curslot;
+ log.u_bbr.lt_epoch = hpts->saved_prev_slot;
+ log.u_bbr.pkts_out = hpts->p_delayed_by;
+ log.u_bbr.lost = hpts->p_hpts_sleep_time;
+ log.u_bbr.pacing_gain = hpts->p_cpu;
+ log.u_bbr.pkt_epoch = hpts->p_runningslot;
+ log.u_bbr.use_lt_bw = 1;
+ TCP_LOG_EVENTP(tp, NULL,
+ &tptosocket(tp)->so_rcv,
+ &tptosocket(tp)->so_snd,
+ BBR_LOG_HPTSDIAG, 0,
+ 0, &log, false, tv);
+ }
}
static void
@@ -1353,10 +1355,7 @@ again:
}
CURVNET_SET(inp->inp_vnet);
/* Lets do any logging that we might want to */
- if (hpts_does_tp_logging && tcp_bblogging_on(tp)) {
- tcp_hpts_log(hpts, tp, &tv, slots_to_run, i,
- from_callout);
- }
+ tcp_hpts_log(hpts, tp, &tv, slots_to_run, i, from_callout);
if (tp->t_fb_ptr != NULL) {
kern_prefetch(tp->t_fb_ptr, &did_prefetch);
@@ -1487,7 +1486,7 @@ no_run:
}
void
-__tcp_set_hpts(struct tcpcb *tp, int32_t line)
+tcp_set_hpts(struct tcpcb *tp)
{
struct tcp_hpts_entry *hpts;
int failed;
diff --git a/sys/netinet/tcp_hpts.h b/sys/netinet/tcp_hpts.h
index b097a2b98db9..f5856ed8e688 100644
--- a/sys/netinet/tcp_hpts.h
+++ b/sys/netinet/tcp_hpts.h
@@ -149,8 +149,7 @@ uint32_t tcp_hpts_insert_diag(struct tcpcb *tp, uint32_t slot, int32_t line,
#define tcp_hpts_insert(inp, slot) \
tcp_hpts_insert_diag((inp), (slot), __LINE__, NULL)
-void __tcp_set_hpts(struct tcpcb *tp, int32_t line);
-#define tcp_set_hpts(a) __tcp_set_hpts(a, __LINE__)
+void tcp_set_hpts(struct tcpcb *tp);
void tcp_set_inp_to_drop(struct inpcb *inp, uint16_t reason);
@@ -165,25 +164,25 @@ extern int32_t tcp_min_hptsi_time;
* The following functions should also be available
* to userspace as well.
*/
-static __inline uint32_t
+static inline uint32_t
tcp_tv_to_hptstick(const struct timeval *sv)
{
return ((sv->tv_sec * 100000) + (sv->tv_usec / HPTS_TICKS_PER_SLOT));
}
-static __inline uint32_t
+static inline uint32_t
tcp_tv_to_usectick(const struct timeval *sv)
{
return ((uint32_t) ((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec));
}
-static __inline uint32_t
+static inline uint32_t
tcp_tv_to_mssectick(const struct timeval *sv)
{
return ((uint32_t) ((sv->tv_sec * HPTS_MSEC_IN_SEC) + (sv->tv_usec/HPTS_USEC_IN_MSEC)));
}
-static __inline uint64_t
+static inline uint64_t
tcp_tv_to_lusectick(const struct timeval *sv)
{
return ((uint64_t)((sv->tv_sec * HPTS_USEC_IN_SEC) + sv->tv_usec));
@@ -199,7 +198,7 @@ get_hpts_min_sleep_time(void)
return (tcp_min_hptsi_time + HPTS_TICKS_PER_SLOT);
}
-static __inline uint32_t
+static inline uint32_t
tcp_gethptstick(struct timeval *sv)
{
struct timeval tv;
@@ -210,7 +209,7 @@ tcp_gethptstick(struct timeval *sv)
return (tcp_tv_to_hptstick(sv));
}
-static __inline uint64_t
+static inline uint64_t
tcp_get_u64_usecs(struct timeval *tv)
{
struct timeval tvd;
@@ -221,7 +220,7 @@ tcp_get_u64_usecs(struct timeval *tv)
return (tcp_tv_to_lusectick(tv));
}
-static __inline uint32_t
+static inline uint32_t
tcp_get_usecs(struct timeval *tv)
{
struct timeval tvd;
diff --git a/sys/netinet/tcp_input.c b/sys/netinet/tcp_input.c
index 7c032e13f37a..1f60c0e07b13 100644
--- a/sys/netinet/tcp_input.c
+++ b/sys/netinet/tcp_input.c
@@ -1055,6 +1055,8 @@ findpcb:
* socket appended to the listen queue in SYN_RECEIVED state.
*/
if ((thflags & (TH_RST|TH_ACK|TH_SYN)) == TH_ACK) {
+ int result;
+
/*
* Parse the TCP options here because
* syncookies need access to the reflected
@@ -1064,8 +1066,8 @@ findpcb:
/*
* NB: syncache_expand() doesn't unlock inp.
*/
- rstreason = syncache_expand(&inc, &to, th, &so, m, port);
- if (rstreason < 0) {
+ result = syncache_expand(&inc, &to, th, &so, m, port);
+ if (result < 0) {
/*
* A failing TCP MD5 signature comparison
* must result in the segment being dropped
@@ -1073,7 +1075,7 @@ findpcb:
* to the sender.
*/
goto dropunlock;
- } else if (rstreason == 0) {
+ } else if (result == 0) {
/*
* No syncache entry, or ACK was not for our
* SYN/ACK. Do our protection against double
@@ -1515,7 +1517,9 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
struct tcpopt to;
int tfo_syn;
u_int maxseg = 0;
+ bool no_data;
+ no_data = (tlen == 0);
thflags = tcp_get_flags(th);
tp->sackhint.last_sack_ack = 0;
sack_changed = SACK_NOCHANGE;
@@ -1754,7 +1758,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
tp->ts_recent = to.to_tsval;
}
- if (tlen == 0) {
+ if (no_data) {
if (SEQ_GT(th->th_ack, tp->snd_una) &&
SEQ_LEQ(th->th_ack, tp->snd_max) &&
!IN_RECOVERY(tp->t_flags) &&
@@ -2557,7 +2561,7 @@ tcp_do_segment(struct tcpcb *tp, struct mbuf *m, struct tcphdr *th,
if (SEQ_LEQ(th->th_ack, tp->snd_una)) {
maxseg = tcp_maxseg(tp);
- if (tlen == 0 &&
+ if (no_data &&
(tiwin == tp->snd_wnd ||
(tp->t_flags & TF_SACK_PERMIT))) {
/*
@@ -3113,8 +3117,7 @@ step6:
(tp->snd_wl1 == th->th_seq && (SEQ_LT(tp->snd_wl2, th->th_ack) ||
(tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd))))) {
/* keep track of pure window updates */
- if (tlen == 0 &&
- tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
+ if (no_data && tp->snd_wl2 == th->th_ack && tiwin > tp->snd_wnd)
TCPSTAT_INC(tcps_rcvwinupd);
tp->snd_wnd = tiwin;
tp->snd_wl1 = th->th_seq;
diff --git a/sys/netinet/tcp_log_buf.c b/sys/netinet/tcp_log_buf.c
index 75d693bc019b..e24790ece43d 100644
--- a/sys/netinet/tcp_log_buf.c
+++ b/sys/netinet/tcp_log_buf.c
@@ -2878,7 +2878,7 @@ tcp_log_sendfile(struct socket *so, off_t offset, size_t nbytes, int flags)
/* double check log state now that we have the lock */
if (inp->inp_flags & INP_DROPPED)
goto done;
- if (tp->_t_logstate != TCP_LOG_STATE_OFF) {
+ if (tcp_bblogging_on(tp)) {
struct timeval tv;
tcp_log_eventspecific_t log;
diff --git a/sys/netinet/tcp_log_buf.h b/sys/netinet/tcp_log_buf.h
index fef32e16b2e4..3e7eef8a1cda 100644
--- a/sys/netinet/tcp_log_buf.h
+++ b/sys/netinet/tcp_log_buf.h
@@ -539,12 +539,12 @@ struct tcpcb;
NULL, NULL, 0, NULL); \
} while (0)
#endif /* TCP_LOG_FORCEVERBOSE */
+/* Assumes/requires the caller has already checked tcp_bblogging_on(tp). */
#define TCP_LOG_EVENTP(tp, th, rxbuf, txbuf, eventid, errornum, len, stackinfo, th_hostorder, tv) \
do { \
- if (tcp_bblogging_on(tp)) \
- tcp_log_event(tp, th, rxbuf, txbuf, eventid, \
- errornum, len, stackinfo, th_hostorder, \
- NULL, NULL, 0, tv); \
+ KASSERT(tcp_bblogging_on(tp), ("bblogging is off")); \
+ tcp_log_event(tp, th, rxbuf, txbuf, eventid, errornum, len, \
+ stackinfo, th_hostorder, NULL, NULL, 0, tv); \
} while (0)
#ifdef TCP_BLACKBOX
diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c
index 8e05498863b9..f52e6fbddfef 100644
--- a/sys/netinet/tcp_stacks/rack.c
+++ b/sys/netinet/tcp_stacks/rack.c
@@ -198,7 +198,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 +938,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),
@@ -3554,8 +3554,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 +5792,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 +5903,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
@@ -7096,7 +7095,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
@@ -8137,7 +8136,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 +8831,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 +10368,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 +11064,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;
@@ -16919,7 +16918,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 +17545,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
@@ -20043,7 +20042,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 +21030,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)
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/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/sys/param.h b/sys/sys/param.h
index a8e9635242dd..bd739eacae6f 100644
--- a/sys/sys/param.h
+++ b/sys/sys/param.h
@@ -74,7 +74,7 @@
* cannot include sys/param.h and should only be updated here.
*/
#undef __FreeBSD_version
-#define __FreeBSD_version 1500052
+#define __FreeBSD_version 1500053
/*
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
diff --git a/sys/sys/random.h b/sys/sys/random.h
index 254ba9451d0a..5abf762cd200 100644
--- a/sys/sys/random.h
+++ b/sys/sys/random.h
@@ -85,7 +85,8 @@ enum random_entropy_source {
RANDOM_FS_ATIME,
RANDOM_UMA, /* Special!! UMA/SLAB Allocator */
RANDOM_CALLOUT,
- RANDOM_ENVIRONMENTAL_END = RANDOM_CALLOUT,
+ RANDOM_RANDOMDEV,
+ RANDOM_ENVIRONMENTAL_END = RANDOM_RANDOMDEV,
/* Fast hardware random-number sources from here on. */
RANDOM_PURE_START,
RANDOM_PURE_OCTEON = RANDOM_PURE_START,
diff --git a/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/usr.bin/bmake/Makefile.config b/usr.bin/bmake/Makefile.config
index 78babc2f1382..8ff6c81b8c78 100644
--- a/usr.bin/bmake/Makefile.config
+++ b/usr.bin/bmake/Makefile.config
@@ -6,7 +6,7 @@ SRCTOP?= ${.CURDIR:H:H}
# things set by configure
-_MAKE_VERSION?=20250618
+_MAKE_VERSION?=20250707
prefix?= /usr
srcdir= ${SRCTOP}/contrib/bmake
diff --git a/usr.bin/bmake/unit-tests/Makefile b/usr.bin/bmake/unit-tests/Makefile
index 1b9a47febe11..d4ee6f33f862 100644
--- a/usr.bin/bmake/unit-tests/Makefile
+++ b/usr.bin/bmake/unit-tests/Makefile
@@ -1,9 +1,9 @@
# This is a generated file, do NOT edit!
# See contrib/bmake/bsd.after-import.mk
#
-# $Id: Makefile,v 1.239 2025/06/15 21:32:16 sjg Exp $
+# $Id: Makefile,v 1.240 2025/06/30 18:40:54 sjg Exp $
#
-# $NetBSD: Makefile,v 1.367 2025/06/13 20:23:16 rillig Exp $
+# $NetBSD: Makefile,v 1.369 2025/06/29 09:40:13 rillig Exp $
#
# Unit tests for make(1)
#
@@ -61,6 +61,7 @@ rm-tmpdir: .NOMETA
# src/tests/usr.bin/make/t_make.sh as well.
#TESTS+= archive
#TESTS+= archive-suffix
+TESTS+= char-005c-reverse-solidus
TESTS+= cmd-errors
TESTS+= cmd-errors-jobs
TESTS+= cmd-errors-lint
@@ -416,6 +417,7 @@ TESTS+= varmod-to-upper
TESTS+= varmod-undefined
TESTS+= varmod-unique
TESTS+= varname
+TESTS+= varname-circumflex
TESTS+= varname-dollar
TESTS+= varname-dot-alltargets
TESTS+= varname-dot-curdir
@@ -544,7 +546,6 @@ TESTS:= ${TESTS:${BROKEN_TESTS:S,^,N,:ts:}}
# Ideas for more tests:
# char-0020-space.mk
-# char-005C-backslash.mk
# escape-cond-str.mk
# escape-cond-func-arg.mk
# escape-varmod.mk
diff --git a/usr.bin/calendar/calendars/calendar.freebsd b/usr.bin/calendar/calendars/calendar.freebsd
index 0b1a37f43723..1ca63b371f65 100644
--- a/usr.bin/calendar/calendars/calendar.freebsd
+++ b/usr.bin/calendar/calendars/calendar.freebsd
@@ -259,6 +259,7 @@
06/11 Alonso Cardenas Marquez <acm@FreeBSD.org> born in Arequipa, Peru, 1979
06/14 Josh Paetzel <jpaetzel@FreeBSD.org> born in Minneapolis, Minnesota, United States, 1973
06/15 Second quarterly status reports are due on 06/30
+06/15 Aymeric Wibo <obiwac@FreeBSD.org> born in Plaistow, London, United Kingdom, 2004
06/17 Tilman Linneweh <arved@FreeBSD.org> born in Weinheim, Baden-Wuerttemberg, Germany, 1978
06/18 Li-Wen Hsu <lwhsu@FreeBSD.org> born in Taipei, Taiwan, Republic of China, 1984
06/18 Roman Bogorodskiy <novel@FreeBSD.org> born in Saratov, Russian Federation, 1986
diff --git a/usr.bin/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.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);
}